add some code

This commit is contained in:
2025-09-05 13:25:11 +08:00
parent 9ff0a99e7a
commit 3cf1229a85
8911 changed files with 2535396 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components"
"../../button")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(button_test)

View File

@@ -0,0 +1,9 @@
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0")
list(APPEND PRIVREQ esp_adc)
endif()
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES esp_event
PRIV_INCLUDE_DIRS "."
PRIV_REQUIRES unity test_utils button ${PRIVREQ}
WHOLE_ARCHIVE)

View File

@@ -0,0 +1,134 @@
/* 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/queue.h"
#include "freertos/timers.h"
#include "freertos/semphr.h"
#include "freertos/event_groups.h"
#include "esp_idf_version.h"
#include "esp_log.h"
#include "unity.h"
#include "iot_button.h"
#include "button_adc.h"
static const char *TAG = "ADC BUTTON TEST";
static void button_event_cb(void *arg, void *data)
{
button_event_t event = iot_button_get_event(arg);
ESP_LOGI(TAG, "BTN[%d] %s", (int)data, iot_button_get_event_str(event));
if (BUTTON_PRESS_REPEAT == event || BUTTON_PRESS_REPEAT_DONE == event) {
ESP_LOGI(TAG, "\tREPEAT[%d]", iot_button_get_repeat(arg));
}
if (BUTTON_PRESS_UP == event || BUTTON_LONG_PRESS_HOLD == event || BUTTON_LONG_PRESS_UP == event) {
ESP_LOGI(TAG, "\tTICKS[%"PRIu32"]", iot_button_get_ticks_time(arg));
}
if (BUTTON_MULTIPLE_CLICK == event) {
ESP_LOGI(TAG, "\tMULTIPLE[%d]", (int)data);
}
}
TEST_CASE("adc button test", "[button][adc]")
{
/** ESP32-S3-Korvo2 board */
const button_config_t btn_cfg = {0};
button_adc_config_t btn_adc_cfg = {
.unit_id = ADC_UNIT_1,
.adc_channel = 4,
};
button_handle_t btns[6] = {NULL};
const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
for (size_t i = 0; i < 6; i++) {
btn_adc_cfg.button_index = i;
if (i == 0) {
btn_adc_cfg.min = (0 + vol[i]) / 2;
} else {
btn_adc_cfg.min = (vol[i - 1] + vol[i]) / 2;
}
if (i == 5) {
btn_adc_cfg.max = (vol[i] + 3000) / 2;
} else {
btn_adc_cfg.max = (vol[i] + vol[i + 1]) / 2;
}
esp_err_t ret = iot_button_new_adc_device(&btn_cfg, &btn_adc_cfg, &btns[i]);
TEST_ASSERT(ret == ESP_OK);
TEST_ASSERT_NOT_NULL(btns[i]);
iot_button_register_cb(btns[i], BUTTON_PRESS_DOWN, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_UP, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_REPEAT, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_SINGLE_CLICK, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_DOUBLE_CLICK, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_LONG_PRESS_START, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_LONG_PRESS_UP, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_END, NULL, button_event_cb, (void *)i);
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
for (size_t i = 0; i < 6; i++) {
iot_button_delete(btns[i]);
}
}
TEST_CASE("adc button test memory leak", "[button][adc][memory leak]")
{
/** ESP32-S3-Korvo2 board */
const button_config_t btn_cfg = {0};
button_adc_config_t btn_adc_cfg = {
.unit_id = ADC_UNIT_1,
.adc_channel = 4,
};
button_handle_t btns[6] = {NULL};
const uint16_t vol[6] = {380, 820, 1180, 1570, 1980, 2410};
for (size_t i = 0; i < 6; i++) {
btn_adc_cfg.button_index = i;
if (i == 0) {
btn_adc_cfg.min = (0 + vol[i]) / 2;
} else {
btn_adc_cfg.min = (vol[i - 1] + vol[i]) / 2;
}
if (i == 5) {
btn_adc_cfg.max = (vol[i] + 3000) / 2;
} else {
btn_adc_cfg.max = (vol[i] + vol[i + 1]) / 2;
}
esp_err_t ret = iot_button_new_adc_device(&btn_cfg, &btn_adc_cfg, &btns[i]);
TEST_ASSERT(ret == ESP_OK);
TEST_ASSERT_NOT_NULL(btns[i]);
iot_button_register_cb(btns[i], BUTTON_PRESS_DOWN, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_UP, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_REPEAT, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_SINGLE_CLICK, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_DOUBLE_CLICK, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_LONG_PRESS_START, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_LONG_PRESS_UP, NULL, button_event_cb, (void *)i);
iot_button_register_cb(btns[i], BUTTON_PRESS_END, NULL, button_event_cb, (void *)i);
}
for (size_t i = 0; i < 6; i++) {
iot_button_delete(btns[i]);
}
}

View File

@@ -0,0 +1,288 @@
/* 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));
}

View File

@@ -0,0 +1,41 @@
/* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"
#include "esp_heap_caps.h"
#include "sdkconfig.h"
#define LEAKS (400)
void setUp(void)
{
unity_utils_record_free_mem();
}
void tearDown(void)
{
unity_utils_evaluate_leaks_direct(LEAKS);
}
void app_main(void)
{
/*
* ____ _ _ _______ _
*| _ \ | | | | |__ __| | |
*| |_) | _ _ | |_ | |_ ___ _ __ | | ___ ___ | |_
*| _ < | | | || __|| __|/ _ \ | '_ \ | | / _ \/ __|| __|
*| |_) || |_| || |_ | |_| (_) || | | | | || __/\__ \| |_
*|____/ \__,_| \__| \__|\___/ |_| |_| |_| \___||___/ \__|
*/
printf(" ____ _ _ _______ _ \n");
printf(" | _ \\ | | | | |__ __| | | \n");
printf(" | |_) | _ _ | |_ | |_ ___ _ __ | | ___ ___ | |_ \n");
printf(" | _ < | | | || __|| __|/ _ \\ | '_ \\ | | / _ \\/ __|| __|\n");
printf(" | |_) || |_| || |_ | |_| (_) || | | | | || __/\\__ \\| |_ \n");
printf(" |____/ \\__,_| \\__| \\__|\\___/ |_| |_| |_| \\___||___/ \\__|\n");
unity_run_menu();
}

View File

@@ -0,0 +1,104 @@
/* 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 "esp_log.h"
#include "unity.h"
#include "iot_button.h"
#include "driver/gpio.h"
static const char *TAG = "CUSTOM BUTTON TEST";
#define BUTTON_IO_NUM 0
#define BUTTON_ACTIVE_LEVEL 0
static void button_event_cb(void *arg, void *data)
{
button_event_t event = iot_button_get_event(arg);
ESP_LOGI(TAG, "%s", iot_button_get_event_str(event));
if (BUTTON_PRESS_REPEAT == event || BUTTON_PRESS_REPEAT_DONE == event) {
ESP_LOGI(TAG, "\tREPEAT[%d]", iot_button_get_repeat(arg));
}
if (BUTTON_PRESS_UP == event || BUTTON_LONG_PRESS_HOLD == event || BUTTON_LONG_PRESS_UP == event) {
ESP_LOGI(TAG, "\tTICKS[%"PRIu32"]", iot_button_get_ticks_time(arg));
}
if (BUTTON_MULTIPLE_CLICK == event) {
ESP_LOGI(TAG, "\tMULTIPLE[%d]", (int)data);
}
}
typedef struct {
button_driver_t base;
int32_t gpio_num; /**< num of gpio */
uint8_t active_level; /**< gpio level when press down */
} custom_gpio_obj;
static uint8_t button_get_key_level(button_driver_t *button_driver)
{
custom_gpio_obj *custom_btn = __containerof(button_driver, custom_gpio_obj, base);
int level = gpio_get_level(custom_btn->gpio_num);
return level == custom_btn->active_level ? 1 : 0;
}
static esp_err_t button_del(button_driver_t *button_driver)
{
return ESP_OK;
}
TEST_CASE("custom button test", "[button][custom]")
{
gpio_config_t gpio_conf = {
.pin_bit_mask = 1ULL << BUTTON_IO_NUM,
.mode = GPIO_MODE_INPUT,
.pull_up_en = 1,
.pull_down_en = 0,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&gpio_conf);
custom_gpio_obj *custom_btn = (custom_gpio_obj *)calloc(1, sizeof(custom_gpio_obj));
TEST_ASSERT_NOT_NULL(custom_btn);
custom_btn->active_level = BUTTON_ACTIVE_LEVEL;
custom_btn->gpio_num = BUTTON_IO_NUM;
button_handle_t btn = NULL;
const button_config_t btn_cfg = {0};
custom_btn->base.get_key_level = button_get_key_level;
custom_btn->base.del = button_del;
esp_err_t ret = iot_button_create(&btn_cfg, &custom_btn->base, &btn);
TEST_ASSERT(ESP_OK == ret);
TEST_ASSERT_NOT_NULL(btn);
iot_button_register_cb(btn, BUTTON_PRESS_DOWN, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_SINGLE_CLICK, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_DOUBLE_CLICK, NULL, button_event_cb, NULL);
/*!< Multiple Click must provide button_event_args_t */
/*!< Double Click */
button_event_args_t args = {
.multiple_clicks.clicks = 2,
};
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)2);
/*!< Triple Click */
args.multiple_clicks.clicks = 3;
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)3);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_END, NULL, button_event_cb, NULL);
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
iot_button_delete(btn);
}

View File

@@ -0,0 +1,186 @@
/* 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 "esp_log.h"
#include "unity.h"
#include "iot_button.h"
#include "button_gpio.h"
static const char *TAG = "GPIO BUTTON TEST";
#define BUTTON_IO_NUM 0
#define BUTTON_ACTIVE_LEVEL 0
static void button_event_cb(void *arg, void *data)
{
button_event_t event = iot_button_get_event(arg);
ESP_LOGI(TAG, "%s", iot_button_get_event_str(event));
if (BUTTON_PRESS_REPEAT == event || BUTTON_PRESS_REPEAT_DONE == event) {
ESP_LOGI(TAG, "\tREPEAT[%d]", iot_button_get_repeat(arg));
}
if (BUTTON_PRESS_UP == event || BUTTON_LONG_PRESS_HOLD == event || BUTTON_LONG_PRESS_UP == event) {
ESP_LOGI(TAG, "\tTICKS[%"PRIu32"]", iot_button_get_ticks_time(arg));
}
if (BUTTON_MULTIPLE_CLICK == event) {
ESP_LOGI(TAG, "\tMULTIPLE[%d]", (int)data);
}
}
TEST_CASE("gpio button test", "[button][gpio]")
{
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);
iot_button_register_cb(btn, BUTTON_PRESS_DOWN, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_SINGLE_CLICK, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_DOUBLE_CLICK, NULL, button_event_cb, NULL);
/*!< Multiple Click must provide button_event_args_t */
/*!< Double Click */
button_event_args_t args = {
.multiple_clicks.clicks = 2,
};
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)2);
/*!< Triple Click */
args.multiple_clicks.clicks = 3;
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)3);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_END, NULL, button_event_cb, NULL);
uint8_t level = 0;
level = iot_button_get_key_level(btn);
ESP_LOGI(TAG, "button level is %d", level);
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
iot_button_delete(btn);
}
TEST_CASE("gpio button get event test", "[button][gpio][event test]")
{
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);
uint8_t level = 0;
level = iot_button_get_key_level(btn);
ESP_LOGI(TAG, "button level is %d", level);
while (1) {
button_event_t event = iot_button_get_event(btn);
if (event != BUTTON_NONE_PRESS) {
ESP_LOGI(TAG, "event is %s", iot_button_get_event_str(event));
}
vTaskDelay(pdMS_TO_TICKS(1));
}
iot_button_delete(btn);
}
TEST_CASE("gpio button test power save", "[button][gpio][power save]")
{
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,
.enable_power_save = true,
};
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);
iot_button_register_cb(btn, BUTTON_PRESS_DOWN, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_SINGLE_CLICK, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_DOUBLE_CLICK, NULL, button_event_cb, NULL);
/*!< Multiple Click must provide button_event_args_t */
/*!< Double Click */
button_event_args_t args = {
.multiple_clicks.clicks = 2,
};
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)2);
/*!< Triple Click */
args.multiple_clicks.clicks = 3;
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)3);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_END, NULL, button_event_cb, NULL);
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
iot_button_delete(btn);
}
TEST_CASE("gpio button test memory leak", "[button][gpio][memory leak]")
{
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);
iot_button_register_cb(btn, BUTTON_PRESS_DOWN, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_SINGLE_CLICK, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_DOUBLE_CLICK, NULL, button_event_cb, NULL);
/*!< Multiple Click must provide button_event_args_t */
/*!< Double Click */
button_event_args_t args = {
.multiple_clicks.clicks = 2,
};
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)2);
/*!< Triple Click */
args.multiple_clicks.clicks = 3;
iot_button_register_cb(btn, BUTTON_MULTIPLE_CLICK, &args, button_event_cb, (void *)3);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_START, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_LONG_PRESS_UP, NULL, button_event_cb, NULL);
iot_button_register_cb(btn, BUTTON_PRESS_END, NULL, button_event_cb, NULL);
iot_button_delete(btn);
}

View File

@@ -0,0 +1,75 @@
/* 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 "esp_log.h"
#include "unity.h"
#include "iot_button.h"
#include "button_matrix.h"
static const char *TAG = "MATRIX BUTTON TEST";
static void button_event_cb(void *arg, void *data)
{
button_event_t event = iot_button_get_event(arg);
ESP_LOGI(TAG, "BUTTON[%d] %s", (int)data, iot_button_get_event_str(event));
if (BUTTON_PRESS_REPEAT == event || BUTTON_PRESS_REPEAT_DONE == event) {
ESP_LOGI(TAG, "\tREPEAT[%d]", iot_button_get_repeat(arg));
}
if (BUTTON_PRESS_UP == event || BUTTON_LONG_PRESS_HOLD == event || BUTTON_LONG_PRESS_UP == event) {
ESP_LOGI(TAG, "\tTICKS[%"PRIu32"]", iot_button_get_ticks_time(arg));
}
if (BUTTON_MULTIPLE_CLICK == event) {
ESP_LOGI(TAG, "\tMULTIPLE[%d]", (int)data);
}
}
TEST_CASE("matrix keyboard button test", "[button][matrix key]")
{
const button_config_t btn_cfg = {0};
const button_matrix_config_t matrix_cfg = {
.row_gpios = (int32_t[]){4, 5, 6, 7},
.col_gpios = (int32_t[]){3, 8, 16, 15},
.row_gpio_num = 4,
.col_gpio_num = 4,
};
button_handle_t btns[16] = {0};
size_t btn_num = 16;
esp_err_t ret = iot_button_new_matrix_device(&btn_cfg, &matrix_cfg, btns, &btn_num);
TEST_ASSERT(ret == ESP_OK);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
int index = i * 4 + j;
TEST_ASSERT_NOT_NULL(btns[index]);
iot_button_register_cb(btns[index], BUTTON_PRESS_DOWN, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_PRESS_UP, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_PRESS_REPEAT, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_PRESS_REPEAT_DONE, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_SINGLE_CLICK, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_DOUBLE_CLICK, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_LONG_PRESS_START, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_LONG_PRESS_HOLD, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_LONG_PRESS_UP, NULL, button_event_cb, (void *)index);
iot_button_register_cb(btns[index], BUTTON_PRESS_END, NULL, button_event_cb, (void *)index);
}
}
while (1) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
iot_button_delete(btns[i * 4 + j]);
}
}
}

View File

@@ -0,0 +1,29 @@
# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
'''
Steps to run these cases:
- Build
- . ${IDF_PATH}/export.sh
- pip install idf_build_apps
- python tools/build_apps.py components/button/test_apps -t esp32s3
- Test
- pip install -r tools/requirements/requirement.pytest.txt
- pytest components/button/test_apps --target esp32s3
'''
import pytest
from pytest_embedded import Dut
@pytest.mark.target('esp32s3')
@pytest.mark.env('button')
@pytest.mark.parametrize(
'config',
[
'defaults',
],
)
def test_button(dut: Dut)-> None:
dut.expect_exact('Press ENTER to see the list of tests.')
dut.write('[auto]')
dut.expect_unity_test_output(timeout = 300)

View File

@@ -0,0 +1,9 @@
# For IDF 5.0
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
# For IDF4.4
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP_TASK_WDT=n