Skip to content

Commit

Permalink
Merge branch 'fix/button_unregister' into 'master'
Browse files Browse the repository at this point in the history
Fix: button unregister_event error on realloc with 0 size & support power save

See merge request ae_group/esp-iot-solution!846
  • Loading branch information
leeebo committed Sep 5, 2023
2 parents 2227f0c + 4f643a9 commit cec4efa
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 35 deletions.
8 changes: 8 additions & 0 deletions components/button/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# ChangeLog

## v3.0.1 - 2023-9-1

### Enhancements:

* Resolves bug for iot_button_unregister_event function returned error when reallocating with 0 byte.
* Update Test cases to test iot_button_unregister_event_cb
* Add api iot_button_stop & iot_button_resume for power save.

## v3.0.0 - 2023-8-15

### Enhancements:
Expand Down
2 changes: 1 addition & 1 deletion components/button/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "3.0.0"
version: "3.0.1"
description: GPIO and ADC button driver
url: https://github.com/espressif/esp-iot-solution/tree/master/components/button
repository: https://github.com/espressif/esp-iot-solution.git
Expand Down
18 changes: 18 additions & 0 deletions components/button/include/iot_button.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,24 @@ uint16_t iot_button_get_long_press_hold_cnt(button_handle_t btn_handle);
*/
esp_err_t iot_button_set_param(button_handle_t btn_handle, button_param_t param, void *value);

/**
* @brief resume button timer, if button timer is stopped. Make sure iot_button_create() is called before calling this API.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE timer state is invalid.
*/
esp_err_t iot_button_resume(void);

/**
* @brief stop button timer, if button timer is running. Make sure iot_button_create() is called before calling this API.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE timer state is invalid
*/
esp_err_t iot_button_stop(void);

#ifdef __cplusplus
}
#endif
38 changes: 33 additions & 5 deletions components/button/iot_button.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ typedef struct Button {

//button handle list head.
static button_dev_t *g_head_handle = NULL;
static esp_timer_handle_t g_button_timer_handle;
static esp_timer_handle_t g_button_timer_handle = NULL;
static bool g_is_timer_running = false;

#define TICKS_INTERVAL CONFIG_BUTTON_PERIOD_TIME_MS
Expand Down Expand Up @@ -586,10 +586,16 @@ esp_err_t iot_button_unregister_event(button_handle_t btn_handle, button_event_c
btn->cb_info[event][j] = btn->cb_info[event][j + 1];
}

button_cb_info_t *p = realloc(btn->cb_info[event], sizeof(button_cb_info_t) * (btn->size[event] - 1));
BTN_CHECK(NULL != p, "realloc cb_info failed", ESP_ERR_NO_MEM);
btn->cb_info[event] = p;
btn->size[event]--;
if (btn->size[event] != 1) {
button_cb_info_t *p = realloc(btn->cb_info[event], sizeof(button_cb_info_t) * (btn->size[event] - 1));
BTN_CHECK(NULL != p, "realloc cb_info failed", ESP_ERR_NO_MEM);
btn->cb_info[event] = p;
btn->size[event]--;
} else {
free(btn->cb_info[event]);
btn->cb_info[event] = NULL;
btn->size[event] = 0;
}
break;
}
}
Expand Down Expand Up @@ -665,3 +671,25 @@ esp_err_t iot_button_set_param(button_handle_t btn_handle, button_param_t param,
BUTTON_EXIT_CRITICAL();
return ESP_OK;
}

esp_err_t iot_button_resume(void)
{
BTN_CHECK(g_button_timer_handle, "Button timer handle is invalid", ESP_ERR_INVALID_STATE);
BTN_CHECK(!g_is_timer_running, "Button timer is already running", ESP_ERR_INVALID_STATE);

esp_err_t err = esp_timer_start_periodic(g_button_timer_handle, TICKS_INTERVAL * 1000U);
BTN_CHECK(ESP_OK == err, "Button timer start failed", ESP_FAIL);
g_is_timer_running = true;
return ESP_OK;
}

esp_err_t iot_button_stop(void)
{
BTN_CHECK(g_button_timer_handle, "Button timer handle is invalid", ESP_ERR_INVALID_STATE);
BTN_CHECK(g_is_timer_running, "Button timer is not running", ESP_ERR_INVALID_STATE);

esp_err_t err = esp_timer_stop(g_button_timer_handle);
BTN_CHECK(ESP_OK == err, "Button timer stop failed", ESP_FAIL);
g_is_timer_running = false;
return ESP_OK;
}
91 changes: 62 additions & 29 deletions components/button/test_apps/main/button_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,40 @@ TEST_CASE("gpio button test", "[button][iot]")
iot_button_delete(g_btns[0]);
}

TEST_CASE("gpio button test power save", "[button][iot][power save]")
{
button_config_t cfg = {
.type = BUTTON_TYPE_GPIO,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.gpio_button_config = {
.gpio_num = 0,
.active_level = 0,
},
};
g_btns[0] = iot_button_create(&cfg);
TEST_ASSERT_NOT_NULL(g_btns[0]);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_press_down_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_press_up_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_press_repeat_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_single_click_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_double_click_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_long_press_start_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_long_press_hold_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_press_repeat_done_cb, NULL);

TEST_ASSERT_EQUAL(ESP_OK, iot_button_stop());
vTaskDelay(pdMS_TO_TICKS(1000));
TEST_ASSERT_EQUAL(ESP_OK, iot_button_resume());

while (1)
{
vTaskDelay(pdMS_TO_TICKS(1000));
}

iot_button_delete(g_btns[0]);
}

#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
TEST_CASE("adc button test", "[button][iot]")
{
Expand Down Expand Up @@ -445,35 +479,21 @@ TEST_CASE("gpio button auto-test", "[button][iot][auto]")
};
g_btns[0] = iot_button_create(&cfg);
TEST_ASSERT_NOT_NULL(g_btns[0]);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_DOWN, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_UP, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_SINGLE_CLICK, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_DOUBLE_CLICK, button_auto_check_cb, NULL);

button_event_config_t btn_cfg = {
.event = BUTTON_MULTIPLE_CLICK,
.event_data =
{
.multiple_clicks.clicks = 4,
},
};
iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb_1, NULL);
iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb, NULL);

iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_START, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_HOLD, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_UP, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_LONG_PRESS_UP, button_auto_check_cb, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], BUTTON_PRESS_REPEAT_DONE, button_auto_check_cb, NULL);

/* 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_config_t btn_cfg;
btn_cfg.event = i;
btn_cfg.event_data.multiple_clicks.clicks = 4;
iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb_1, NULL);
iot_button_register_event_cb(g_btns[0], btn_cfg, button_auto_check_cb, NULL);
} else {
iot_button_register_cb(g_btns[0], i, button_auto_check_cb_1, NULL);
iot_button_register_cb(g_btns[0], i, button_auto_check_cb, NULL);
}
}

TEST_ASSERT_EQUAL(ESP_OK, iot_button_set_param(g_btns[0], BUTTON_LONG_PRESS_TIME_MS, (void *)1500));

gpio_config_t io_conf = {
Expand All @@ -489,6 +509,19 @@ TEST_CASE("gpio button auto-test", "[button][iot][auto]")
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_config_t btn_cfg;
btn_cfg.event = i;
if (i == BUTTON_MULTIPLE_CLICK) {
btn_cfg.event_data.multiple_clicks.clicks = 4;
} else if ( i == BUTTON_LONG_PRESS_UP || i == BUTTON_LONG_PRESS_START) {
btn_cfg.event_data.long_press.press_time = 1500;
}
iot_button_unregister_event(g_btns[0], btn_cfg, button_auto_check_cb);
iot_button_unregister_event(g_btns[0], btn_cfg, button_auto_check_cb_1);
}

TEST_ASSERT_EQUAL(ESP_OK,iot_button_delete(g_btns[0]));
vEventGroupDelete(g_check);
vSemaphoreDelete(g_auto_check_pass);
Expand Down

0 comments on commit cec4efa

Please sign in to comment.