289 lines
10 KiB
C
289 lines
10 KiB
C
/* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
#include "freertos/semphr.h"
|
|
#include "freertos/event_groups.h"
|
|
#include "esp_log.h"
|
|
#include "unity.h"
|
|
#include "iot_button.h"
|
|
#include "button_gpio.h"
|
|
#include "driver/gpio.h"
|
|
|
|
static const char *TAG = "BUTTON AUTO TEST";
|
|
|
|
#define GPIO_OUTPUT_IO_45 45
|
|
#define BUTTON_IO_NUM 0
|
|
#define BUTTON_ACTIVE_LEVEL 0
|
|
|
|
static EventGroupHandle_t g_check = NULL;
|
|
static SemaphoreHandle_t g_auto_check_pass = NULL;
|
|
|
|
static button_event_t state = BUTTON_PRESS_DOWN;
|
|
|
|
static void button_auto_press_test_task(void *arg)
|
|
{
|
|
// test BUTTON_PRESS_DOWN
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
// // test BUTTON_PRESS_UP
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(200));
|
|
|
|
// test BUTTON_PRESS_REPEAT
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
// test BUTTON_PRESS_REPEAT_DONE
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(200));
|
|
|
|
// test BUTTON_SINGLE_CLICK
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(200));
|
|
|
|
// test BUTTON_DOUBLE_CLICK
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(200));
|
|
|
|
// test BUTTON_MULTIPLE_CLICK
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
for (int i = 0; i < 4; i++) {
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
}
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
|
|
// test BUTTON_LONG_PRESS_START
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(1600));
|
|
|
|
// test BUTTON_LONG_PRESS_HOLD and BUTTON_LONG_PRESS_UP
|
|
xEventGroupWaitBits(g_check, BIT(0) | BIT(1), pdTRUE, pdTRUE, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
|
|
ESP_LOGI(TAG, "Auto Press Success!");
|
|
vTaskDelete(NULL);
|
|
}
|
|
static void button_auto_check_cb_1(void *arg, void *data)
|
|
{
|
|
if (iot_button_get_event(arg) == state) {
|
|
xEventGroupSetBits(g_check, BIT(1));
|
|
}
|
|
}
|
|
static void button_auto_check_cb(void *arg, void *data)
|
|
{
|
|
if (iot_button_get_event(arg) == state) {
|
|
ESP_LOGI(TAG, "Auto check: button event %s pass", iot_button_get_event_str(state));
|
|
xEventGroupSetBits(g_check, BIT(0));
|
|
if (++state >= BUTTON_EVENT_MAX) {
|
|
xSemaphoreGive(g_auto_check_pass);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_CASE("gpio button auto-test", "[button][iot][auto]")
|
|
{
|
|
state = BUTTON_PRESS_DOWN;
|
|
g_check = xEventGroupCreate();
|
|
g_auto_check_pass = xSemaphoreCreateBinary();
|
|
xEventGroupSetBits(g_check, BIT(0) | BIT(1));
|
|
const button_config_t btn_cfg = {0};
|
|
const button_gpio_config_t btn_gpio_cfg = {
|
|
.gpio_num = BUTTON_IO_NUM,
|
|
.active_level = BUTTON_ACTIVE_LEVEL,
|
|
};
|
|
|
|
button_handle_t btn = NULL;
|
|
esp_err_t ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &btn);
|
|
TEST_ASSERT(ret == ESP_OK);
|
|
TEST_ASSERT_NOT_NULL(btn);
|
|
|
|
/* register iot_button callback for all the button_event */
|
|
for (uint8_t i = 0; i < BUTTON_EVENT_MAX; i++) {
|
|
if (i == BUTTON_MULTIPLE_CLICK) {
|
|
button_event_args_t args = {
|
|
.multiple_clicks.clicks = 4,
|
|
};
|
|
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_auto_check_cb_1, NULL);
|
|
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_auto_check_cb, NULL);
|
|
} else {
|
|
iot_button_register_cb(btn, i, NULL, button_auto_check_cb_1, NULL);
|
|
iot_button_register_cb(btn, i, NULL, button_auto_check_cb, NULL);
|
|
}
|
|
}
|
|
|
|
TEST_ASSERT_EQUAL(ESP_OK, iot_button_set_param(btn, BUTTON_LONG_PRESS_TIME_MS, (void *)1500));
|
|
|
|
gpio_config_t io_conf = {
|
|
.intr_type = GPIO_INTR_DISABLE,
|
|
.mode = GPIO_MODE_OUTPUT,
|
|
.pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45),
|
|
.pull_down_en = 0,
|
|
.pull_up_en = 0,
|
|
};
|
|
gpio_config(&io_conf);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
|
|
xTaskCreate(button_auto_press_test_task, "button_auto_press_test_task", 1024 * 4, NULL, 10, NULL);
|
|
|
|
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(g_auto_check_pass, pdMS_TO_TICKS(6000)));
|
|
|
|
for (uint8_t i = 0; i < BUTTON_EVENT_MAX; i++) {
|
|
button_event_args_t args;
|
|
|
|
if (i == BUTTON_MULTIPLE_CLICK) {
|
|
args.multiple_clicks.clicks = 4;
|
|
iot_button_unregister_cb(btn, i, &args);
|
|
} else if (i == BUTTON_LONG_PRESS_UP || i == BUTTON_LONG_PRESS_START) {
|
|
args.long_press.press_time = 1500;
|
|
iot_button_unregister_cb(btn, i, &args);
|
|
} else {
|
|
iot_button_unregister_cb(btn, i, NULL);
|
|
}
|
|
}
|
|
|
|
TEST_ASSERT_EQUAL(ESP_OK, iot_button_delete(btn));
|
|
vEventGroupDelete(g_check);
|
|
vSemaphoreDelete(g_auto_check_pass);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
}
|
|
|
|
#define TOLERANCE (CONFIG_BUTTON_PERIOD_TIME_MS * 4)
|
|
|
|
uint16_t long_press_time[5] = {2000, 2500, 3000, 3500, 4000};
|
|
static SemaphoreHandle_t long_press_check = NULL;
|
|
static SemaphoreHandle_t long_press_auto_check_pass = NULL;
|
|
unsigned int status = 0;
|
|
|
|
static void button_auto_long_press_test_task(void *arg)
|
|
{
|
|
// Test for BUTTON_LONG_PRESS_START
|
|
for (int i = 0; i < 5; i++) {
|
|
xSemaphoreTake(long_press_check, portMAX_DELAY);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
status = (BUTTON_LONG_PRESS_START << 16) | long_press_time[i];
|
|
if (i > 0) {
|
|
vTaskDelay(pdMS_TO_TICKS(long_press_time[i] - long_press_time[i - 1]));
|
|
} else {
|
|
vTaskDelay(pdMS_TO_TICKS(long_press_time[i]));
|
|
}
|
|
}
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
xSemaphoreGive(long_press_auto_check_pass);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
// Test for BUTTON_LONG_PRESS_UP
|
|
for (int i = 0; i < 5; i++) {
|
|
xSemaphoreTake(long_press_check, portMAX_DELAY);
|
|
status = (BUTTON_LONG_PRESS_UP << 16) | long_press_time[i];
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 0);
|
|
vTaskDelay(pdMS_TO_TICKS(long_press_time[i] + 10));
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Auto Long Press Success!");
|
|
vTaskDelete(NULL);
|
|
}
|
|
|
|
static void button_long_press_auto_check_cb(void *arg, void *data)
|
|
{
|
|
uint32_t value = (uint32_t)data;
|
|
uint16_t event = (0xffff0000 & value) >> 16;
|
|
uint16_t time = 0xffff & value;
|
|
uint32_t ticks_time = iot_button_get_ticks_time(arg);
|
|
int32_t diff = ticks_time - time;
|
|
if (status == value && abs(diff) <= TOLERANCE) {
|
|
ESP_LOGI(TAG, "Auto check: button event: %s and time: %d pass", iot_button_get_event_str(event), time);
|
|
|
|
if (event == BUTTON_LONG_PRESS_UP && time == long_press_time[4]) {
|
|
xSemaphoreGive(long_press_auto_check_pass);
|
|
}
|
|
|
|
xSemaphoreGive(long_press_check);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("gpio button long_press auto-test", "[button][long_press][auto]")
|
|
{
|
|
ESP_LOGI(TAG, "Starting the test");
|
|
long_press_check = xSemaphoreCreateBinary();
|
|
long_press_auto_check_pass = xSemaphoreCreateBinary();
|
|
xSemaphoreGive(long_press_check);
|
|
const button_config_t btn_cfg = {0};
|
|
const button_gpio_config_t btn_gpio_cfg = {
|
|
.gpio_num = BUTTON_IO_NUM,
|
|
.active_level = BUTTON_ACTIVE_LEVEL,
|
|
};
|
|
|
|
button_handle_t btn = NULL;
|
|
esp_err_t ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &btn);
|
|
TEST_ASSERT(ret == ESP_OK);
|
|
TEST_ASSERT_NOT_NULL(btn);
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
button_event_args_t args = {
|
|
.long_press.press_time = long_press_time[i],
|
|
};
|
|
|
|
uint32_t data = (BUTTON_LONG_PRESS_START << 16) | long_press_time[i];
|
|
iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, &args, button_long_press_auto_check_cb, (void*)data);
|
|
}
|
|
|
|
gpio_config_t io_conf = {
|
|
.intr_type = GPIO_INTR_DISABLE,
|
|
.mode = GPIO_MODE_OUTPUT,
|
|
.pin_bit_mask = (1ULL << GPIO_OUTPUT_IO_45),
|
|
.pull_down_en = 0,
|
|
.pull_up_en = 0,
|
|
};
|
|
gpio_config(&io_conf);
|
|
gpio_set_level(GPIO_OUTPUT_IO_45, 1);
|
|
xTaskCreate(button_auto_long_press_test_task, "button_auto_long_press_test_task", 1024 * 4, NULL, 10, NULL);
|
|
|
|
xSemaphoreTake(long_press_auto_check_pass, portMAX_DELAY);
|
|
iot_button_unregister_cb(btn, BUTTON_LONG_PRESS_START, NULL);
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
button_event_args_t args = {
|
|
.long_press.press_time = long_press_time[i]
|
|
};
|
|
|
|
uint32_t data = (BUTTON_LONG_PRESS_UP << 16) | long_press_time[i];
|
|
iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, &args, button_long_press_auto_check_cb, (void*)data);
|
|
}
|
|
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(long_press_auto_check_pass, pdMS_TO_TICKS(17000)));
|
|
TEST_ASSERT_EQUAL(ESP_OK, iot_button_delete(btn));
|
|
vSemaphoreDelete(long_press_check);
|
|
vSemaphoreDelete(long_press_auto_check_pass);
|
|
vTaskDelay(pdMS_TO_TICKS(100));
|
|
}
|