replace esp-iot-solution button driver

This commit is contained in:
0x1abin
2018-06-26 12:02:23 +08:00
parent bbd447a412
commit 6230376ca0
14 changed files with 889 additions and 120 deletions
+6
View File
@@ -0,0 +1,6 @@
menu "Button"
config IO_GLITCH_FILTER_TIME_MS
int "IO glitch filter timer ms (10~100)"
range 10 100
default 50
endmenu
+47
View File
@@ -0,0 +1,47 @@
# Component: Button
* This component defines a button as a well encapsulated object.
* A button device is defined by:
* GPIO number on which the button is attached.
* Active level which decided by peripheral hardware.
* Trigger mode which decides whether to call serial trigger callback during pressing
* Serial threshold seconds which decides that serial trigger callback will be called after how many seconds' pressing
* A button device can provide:
* One push event callback
* One release event callback
* One short-time tap event callback
* One serial trigger event callback
* Several long-time press event callback
We can set different jitter filters for all the events.
Once any of the long press callback is triggered, the short tap event will not be triggered.
This components are based on GPIO provided by idf and soft timer provided by FreeRTOS.
* To use the button device, you need to :
* create a button object returned by iot_button_create().
* Then hook different event callbacks to the button object.
* To free the object, you can call iot_button_delete to delete the button object and free the memory that used.
* Todo:
* Add hardware timer mode(because sometimes soft-timer callback function is limited)
### NOTE:
> All the event callback function are realized by FreeRTOS soft timer APIs, the callback must follow the rule:
```
Button callback functions execute in the context of the timer service task.
It is therefore essential that button callback functions never attempt to block.
For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(), or specify a non zero block time when accessing a queue or a semaphore.
```
> In addition:
> You can adjust the following macros within FreeRTOS to adjust the stack depth/queue length/task priority of the timer service.
```
#define configUSE_TIMERS //enable soft-timer
#define configTIMER_TASK_PRIORITY // priority of the timers service task
#define configQueue_LENGTH // length of timer command queue
#define configTIMER_TASK_STACK_DEPTH // stack depth of the soft-timer
```
+315
View File
@@ -0,0 +1,315 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "iot_button.h"
#define IOT_CHECK(tag, a, ret) if(!(a)) { \
ESP_LOGE(tag,"%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__); \
return (ret); \
}
#define ERR_ASSERT(tag, param) IOT_CHECK(tag, (param) == ESP_OK, ESP_FAIL)
#define POINT_ASSERT(tag, param, ret) IOT_CHECK(tag, (param) != NULL, (ret))
typedef enum {
BUTTON_STATE_IDLE = 0,
BUTTON_STATE_PUSH,
BUTTON_STATE_PRESSED,
} button_status_t;
typedef struct button_dev button_dev_t;
typedef struct btn_cb button_cb_t;
struct btn_cb{
TickType_t interval;
button_cb cb;
void* arg;
TimerHandle_t tmr;
button_dev_t *pbtn;
button_cb_t *next_cb;
};
struct button_dev{
uint8_t io_num;
uint8_t active_level;
uint32_t serial_thres_sec;
button_status_t state;
button_cb_t tap_short_cb;
button_cb_t tap_psh_cb;
button_cb_t tap_rls_cb;
button_cb_t press_serial_cb;
button_cb_t* cb_head;
};
// #define BUTTON_GLITCH_FILTER_TIME_MS CONFIG_IO_GLITCH_FILTER_TIME_MS
#define BUTTON_GLITCH_FILTER_TIME_MS 50
static const char* TAG = "button";
static void button_press_cb(xTimerHandle tmr)
{
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
button_dev_t* btn = btn_cb->pbtn;
// low, then restart
if (btn->active_level == gpio_get_level(btn->io_num)) {
btn->state = BUTTON_STATE_PRESSED;
if (btn_cb->cb) {
btn_cb->cb(btn_cb->arg);
}
}
}
static void button_tap_psh_cb(xTimerHandle tmr)
{
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
button_dev_t* btn = btn_cb->pbtn;
xTimerStop(btn->tap_rls_cb.tmr, portMAX_DELAY);
int lv = gpio_get_level(btn->io_num);
if (btn->active_level == lv) {
// high, then key is up
btn->state = BUTTON_STATE_PUSH;
if (btn->press_serial_cb.tmr) {
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
}
if (btn->tap_psh_cb.cb) {
btn->tap_psh_cb.cb(btn->tap_psh_cb.arg);
}
} else {
// 50ms, check if this is a real key up
if (btn->tap_rls_cb.tmr) {
xTimerStop(btn->tap_rls_cb.tmr, portMAX_DELAY);
xTimerReset(btn->tap_rls_cb.tmr, portMAX_DELAY);
}
}
}
static void button_tap_rls_cb(xTimerHandle tmr)
{
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
button_dev_t* btn = btn_cb->pbtn;
xTimerStop(btn->tap_rls_cb.tmr, portMAX_DELAY);
if (btn->active_level == gpio_get_level(btn->io_num)) {
} else {
// high, then key is up
button_cb_t *pcb = btn->cb_head;
while (pcb != NULL) {
if (pcb->tmr != NULL) {
xTimerStop(pcb->tmr, portMAX_DELAY);
}
pcb = pcb->next_cb;
}
if (btn->press_serial_cb.tmr && btn->press_serial_cb.tmr != NULL) {
xTimerStop(btn->press_serial_cb.tmr, portMAX_DELAY);
}
if (btn->tap_short_cb.cb && btn->state == BUTTON_STATE_PUSH) {
btn->tap_short_cb.cb(btn->tap_short_cb.arg);
}
if(btn->tap_rls_cb.cb && btn->state != BUTTON_STATE_IDLE) {
btn->tap_rls_cb.cb(btn->tap_rls_cb.arg);
}
btn->state = BUTTON_STATE_IDLE;
}
}
static void button_press_serial_cb(xTimerHandle tmr)
{
button_dev_t* btn = (button_dev_t*) pvTimerGetTimerID(tmr);
if (btn->press_serial_cb.cb) {
btn->press_serial_cb.cb(btn->press_serial_cb.arg);
}
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->press_serial_cb.interval, portMAX_DELAY);
xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
}
static void button_gpio_isr_handler(void* arg)
{
button_dev_t* btn = (button_dev_t*) arg;
portBASE_TYPE HPTaskAwoken = pdFALSE;
int level = gpio_get_level(btn->io_num);
if (level == btn->active_level) {
if (btn->tap_psh_cb.tmr) {
xTimerStopFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
xTimerResetFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
}
button_cb_t *pcb = btn->cb_head;
while (pcb != NULL) {
if (pcb->tmr != NULL) {
xTimerStopFromISR(pcb->tmr, &HPTaskAwoken);
xTimerResetFromISR(pcb->tmr, &HPTaskAwoken);
}
pcb = pcb->next_cb;
}
} else {
// 50ms, check if this is a real key up
if (btn->tap_rls_cb.tmr) {
xTimerStopFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
xTimerResetFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
}
}
if(HPTaskAwoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
static void button_free_tmr(xTimerHandle* tmr)
{
if (tmr && *tmr) {
xTimerStop(*tmr, portMAX_DELAY);
xTimerDelete(*tmr, portMAX_DELAY);
*tmr = NULL;
}
}
esp_err_t iot_button_delete(button_handle_t btn_handle)
{
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
button_dev_t* btn = (button_dev_t*) btn_handle;
gpio_set_intr_type(btn->io_num, GPIO_INTR_DISABLE);
gpio_isr_handler_remove(btn->io_num);
button_free_tmr(&btn->tap_rls_cb.tmr);
button_free_tmr(&btn->tap_psh_cb.tmr);
button_free_tmr(&btn->tap_short_cb.tmr);
button_free_tmr(&btn->press_serial_cb.tmr);
button_cb_t *pcb = btn->cb_head;
while (pcb != NULL) {
button_cb_t *cb_next = pcb->next_cb;
button_free_tmr(&pcb->tmr);
free(pcb);
pcb = cb_next;
}
free(btn);
return ESP_OK;
}
button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level)
{
IOT_CHECK(TAG, gpio_num < GPIO_NUM_MAX, NULL);
button_dev_t* btn = (button_dev_t*) calloc(1, sizeof(button_dev_t));
POINT_ASSERT(TAG, btn, NULL);
btn->active_level = active_level;
btn->io_num = gpio_num;
btn->state = BUTTON_STATE_IDLE;
btn->tap_rls_cb.arg = NULL;
btn->tap_rls_cb.cb = NULL;
btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
btn->tap_rls_cb.pbtn = btn;
btn->tap_rls_cb.tmr = xTimerCreate("btn_rls_tmr", btn->tap_rls_cb.interval, pdFALSE,
&btn->tap_rls_cb, button_tap_rls_cb);
btn->tap_psh_cb.arg = NULL;
btn->tap_psh_cb.cb = NULL;
btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
btn->tap_psh_cb.pbtn = btn;
btn->tap_psh_cb.tmr = xTimerCreate("btn_psh_tmr", btn->tap_psh_cb.interval, pdFALSE,
&btn->tap_psh_cb, button_tap_psh_cb);
gpio_install_isr_service(0);
gpio_config_t gpio_conf;
gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
gpio_conf.mode = GPIO_MODE_INPUT;
gpio_conf.pin_bit_mask = (1ULL << gpio_num);
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
gpio_config(&gpio_conf);
gpio_isr_handler_add(gpio_num, button_gpio_isr_handler, btn);
return (button_handle_t) btn;
}
esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type)
{
button_dev_t* btn = (button_dev_t*) btn_handle;
button_cb_t* btn_cb = NULL;
if (type == BUTTON_CB_PUSH) {
btn_cb = &btn->tap_psh_cb;
} else if (type == BUTTON_CB_RELEASE) {
btn_cb = &btn->tap_rls_cb;
} else if (type == BUTTON_CB_TAP) {
btn_cb = &btn->tap_short_cb;
} else if (type == BUTTON_CB_SERIAL) {
btn_cb = &btn->press_serial_cb;
}
btn_cb->cb = NULL;
btn_cb->arg = NULL;
btn_cb->pbtn = btn;
button_free_tmr(&btn_cb->tmr);
return ESP_OK;
}
esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg)
{
button_dev_t* btn = (button_dev_t*) btn_handle;
btn->serial_thres_sec = start_after_sec;
if (btn->press_serial_cb.tmr == NULL) {
btn->press_serial_cb.tmr = xTimerCreate("btn_serial_tmr", btn->serial_thres_sec*1000 / portTICK_PERIOD_MS,
pdFALSE, btn, button_press_serial_cb);
}
btn->press_serial_cb.arg = arg;
btn->press_serial_cb.cb = cb;
btn->press_serial_cb.interval = interval_tick;
btn->press_serial_cb.pbtn = btn;
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
return ESP_OK;
}
esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg)
{
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
button_dev_t* btn = (button_dev_t*) btn_handle;
if (type == BUTTON_CB_PUSH) {
btn->tap_psh_cb.arg = arg;
btn->tap_psh_cb.cb = cb;
btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
btn->tap_psh_cb.pbtn = btn;
xTimerChangePeriod(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
} else if (type == BUTTON_CB_RELEASE) {
btn->tap_rls_cb.arg = arg;
btn->tap_rls_cb.cb = cb;
btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
btn->tap_rls_cb.pbtn = btn;
xTimerChangePeriod(btn->tap_rls_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
} else if (type == BUTTON_CB_TAP) {
btn->tap_short_cb.arg = arg;
btn->tap_short_cb.cb = cb;
btn->tap_short_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
btn->tap_short_cb.pbtn = btn;
} else if (type == BUTTON_CB_SERIAL) {
iot_button_set_serial_cb(btn_handle, 1, 1000 / portTICK_RATE_MS, cb, arg);
}
return ESP_OK;
}
esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg)
{
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
IOT_CHECK(TAG, press_sec != 0, ESP_ERR_INVALID_ARG);
button_dev_t* btn = (button_dev_t*) btn_handle;
button_cb_t* cb_new = (button_cb_t*) calloc(1, sizeof(button_cb_t));
POINT_ASSERT(TAG, cb_new, ESP_FAIL);
cb_new->arg = arg;
cb_new->cb = cb;
cb_new->interval = press_sec * 1000 / portTICK_PERIOD_MS;
cb_new->pbtn = btn;
cb_new->tmr = xTimerCreate("btn_press_tmr", cb_new->interval, pdFALSE, cb_new, button_press_cb);
cb_new->next_cb = btn->cb_head;
btn->cb_head = cb_new;
return ESP_OK;
}
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "iot_button.h"
CButton::CButton(gpio_num_t gpio_num, button_active_t active_level)
{
m_btn_handle = iot_button_create(gpio_num, active_level);
}
CButton::~CButton()
{
iot_button_delete(m_btn_handle);
m_btn_handle = NULL;
}
esp_err_t CButton::set_evt_cb(button_cb_type_t type, button_cb cb, void* arg)
{
return iot_button_set_evt_cb(m_btn_handle, type, cb, arg);
}
esp_err_t CButton::set_serial_cb(button_cb cb, void* arg, TickType_t interval_tick, uint32_t start_after_sec)
{
return iot_button_set_serial_cb(m_btn_handle, start_after_sec, interval_tick, cb, arg);
}
esp_err_t CButton::add_custom_cb(uint32_t press_sec, button_cb cb, void* arg)
{
return iot_button_add_custom_cb(m_btn_handle, press_sec, cb, arg);
}
esp_err_t CButton::rm_cb(button_cb_type_t type)
{
return iot_button_rm_cb(m_btn_handle, type);
}
+4
View File
@@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
@@ -0,0 +1,230 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _IOT_BUTTON_H_
#define _IOT_BUTTON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "driver/gpio.h"
#include "freertos/portmacro.h"
typedef void (* button_cb)(void*);
typedef void* button_handle_t;
typedef enum {
BUTTON_ACTIVE_HIGH = 1, /*!<button active level: high level*/
BUTTON_ACTIVE_LOW = 0, /*!<button active level: low level*/
} button_active_t;
typedef enum {
BUTTON_CB_PUSH = 0, /*!<button push callback event */
BUTTON_CB_RELEASE, /*!<button release callback event */
BUTTON_CB_TAP, /*!<button quick tap callback event(will not trigger if there already is a "PRESS" event) */
BUTTON_CB_SERIAL, /*!<button serial trigger callback event */
} button_cb_type_t;
/**
* @brief Init button functions
*
* @param gpio_num GPIO index of the pin that the button uses
* @param active_level button hardware active level.
* For "BUTTON_ACTIVE_LOW" it means when the button pressed, the GPIO will read low level.
*
* @return A button_handle_t handle to the created button object, or NULL in case of error.
*/
button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level);
/**
* @brief Register a callback function for a serial trigger event.
*
* @param btn_handle handle of the button object
* @start_after_sec define the time after which to start serial trigger action
* @interval_tick serial trigger interval
* @cb callback function for "TAP" action.
* @arg Parameter for callback function
* @note
* Button callback functions execute in the context of the timer service task.
* It is therefore essential that button callback functions never attempt to block.
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
* or specify a non zero block time when accessing a queue or a semaphore.
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg);
/**
* @brief Register a callback function for a button_cb_type_t action.
*
* @param btn_handle handle of the button object
* @param type callback function type
* @param cb callback function for "TAP" action.
* @param arg Parameter for callback function
* @note
* Button callback functions execute in the context of the timer service task.
* It is therefore essential that button callback functions never attempt to block.
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
* or specify a non zero block time when accessing a queue or a semaphore.
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg);
/**
* @brief
*
* @param btn_handle handle of the button object
* @param press_sec the callback function would be called if you press the button for a specified period of time
* @param cb callback function for "PRESS" action.
* @param arg Parameter for callback function
*
* @note
* Button callback functions execute in the context of the timer service task.
* It is therefore essential that button callback functions never attempt to block.
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
* or specify a non zero block time when accessing a queue or a semaphore.
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg);
/**
* @brief Delete button object and free memory
* @param btn_handle handle of the button object
*
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t iot_button_delete(button_handle_t btn_handle);
/**
* @brief Remove callback
*
* @param btn_handle The handle of the button object
* @param type callback function event type
*
* @return
* - ESP_OK Success
*/
esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
/**
* class of button
* simple usage:
* CButton* btn = new CButton(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL, BUTTON_SERIAL_TRIGGER, 3);
* btn->add_cb(BUTTON_CB_PUSH, button_tap_cb, (void*) push, 50 / portTICK_PERIOD_MS);
* btn->add_custom_cb(5, button_press_5s_cb, NULL);
* ......
* delete btn;
*/
class CButton
{
private:
button_handle_t m_btn_handle;
/**
* prevent copy constructing
*/
CButton(const CButton&);
CButton& operator = (const CButton&);
public:
/**
* @brief constructor of CButton
*
* @param gpio_num GPIO index of the pin that the button uses
* @param active_level button hardware active level.
* For "BUTTON_ACTIVE_LOW" it means when the button pressed, the GPIO will read low level.
*/
CButton(gpio_num_t gpio_num, button_active_t active_level = BUTTON_ACTIVE_LOW);
~CButton();
/**
* @brief Register a callback function for a button_cb_type_t action.
*
* @param type callback function type
* @param cb callback function for "TAP" action.
* @param arg Parameter for callback function
* @note
* Button callback functions execute in the context of the timer service task.
* It is therefore essential that button callback functions never attempt to block.
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
* or specify a non zero block time when accessing a queue or a semaphore.
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t set_evt_cb(button_cb_type_t type, button_cb cb, void* arg);
/**
* @brief Register a callback function for a serial trigger event.
*
* @param btn_handle handle of the button object
* @start_after_sec define the time after which to start serial trigger action
* @interval_tick serial trigger interval
* @cb callback function for "TAP" action.
* @arg Parameter for callback function
* @note
* Button callback functions execute in the context of the timer service task.
* It is therefore essential that button callback functions never attempt to block.
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
* or specify a non zero block time when accessing a queue or a semaphore.
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t set_serial_cb(button_cb cb, void* arg, TickType_t interval_tick, uint32_t start_after_sec);
/**
* @brief
*
* @param press_sec the callback function would be called if you press the button for a specified period of time
* @param cb callback function for "PRESS" action.
* @param arg Parameter for callback function
*
* @note
* Button callback functions execute in the context of the timer service task.
* It is therefore essential that button callback functions never attempt to block.
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
* or specify a non zero block time when accessing a queue or a semaphore.
* @return
* - ESP_OK Success
* - ESP_FAIL Parameter error
*/
esp_err_t add_custom_cb(uint32_t press_sec, button_cb cb, void* arg);
/**
* @brief Remove callback
*
* @param type callback function event type
*
* @return
* - ESP_OK Success
*/
esp_err_t rm_cb(button_cb_type_t type);
};
#endif
#endif
+24
View File
@@ -0,0 +1,24 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# componet standalone mode
ifndef CONFIG_IOT_SOLUTION_EMBED
COMPONENT_ADD_INCLUDEDIRS := ./button/include
COMPONENT_SRCDIRS := ./button
else
ifdef CONFIG_IOT_BUTTON_ENABLE
COMPONENT_ADD_INCLUDEDIRS := ./button/include
COMPONENT_SRCDIRS := ./button
else
# Disable component
COMPONENT_ADD_INCLUDEDIRS :=
COMPONENT_ADD_LDFLAGS :=
COMPONENT_SRCDIRS :=
endif
endif
@@ -0,0 +1,64 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "unity.h"
#include "iot_button.h"
#include "esp_log.h"
#define BUTTON_IO_NUM GPIO_NUM_39
#define BUTTON_ACTIVE_LEVEL BUTTON_ACTIVE_LOW
static const char* TAG_BTN = "BTN_TEST";
static void button_tap_cb(void* arg)
{
char* pstr = (char*) arg;
ESP_EARLY_LOGI(TAG_BTN, "tap cb (%s), heap: %d\n", pstr, esp_get_free_heap_size());
}
static void button_press_2s_cb(void* arg)
{
ESP_EARLY_LOGI(TAG_BTN, "press 2s, heap: %d\n", esp_get_free_heap_size());
}
static void button_press_5s_cb(void* arg)
{
ESP_EARLY_LOGI(TAG_BTN, "press 5s, heap: %d\n", esp_get_free_heap_size());
}
extern "C" void button_obj_test()
{
const char *push = "PUSH";
const char *release = "RELEASE";
const char *tap = "TAP";
const char *serial = "SERIAL";
CButton* btn = new CButton(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL);
btn->set_evt_cb(BUTTON_CB_PUSH, button_tap_cb, (void*) push);
btn->set_evt_cb(BUTTON_CB_RELEASE, button_tap_cb, (void*) release);
btn->set_evt_cb(BUTTON_CB_TAP, button_tap_cb, (void*) tap);
btn->set_evt_cb(BUTTON_CB_SERIAL, button_tap_cb, (void*) serial);
btn->add_custom_cb(2, button_press_2s_cb, NULL);
btn->add_custom_cb(5, button_press_5s_cb, NULL);
vTaskDelay(10000 / portTICK_PERIOD_MS);
delete btn;
ESP_LOGI(TAG_BTN, "button is deleted");
}
TEST_CASE("Button cpp test", "[button_cpp][iot]")
{
button_obj_test();
}
+67
View File
@@ -0,0 +1,67 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#define BUTTON_IO_NUM GPIO_NUM_37
#define BUTTON_ACTIVE_LEVEL BUTTON_ACTIVE_LOW
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
#include "unity.h"
#include "iot_button.h"
#include "esp_system.h"
#include "esp_log.h"
static const char* TAG_BTN = "BTN_TEST";
void button_tap_cb(void* arg)
{
char* pstr = (char*) arg;
ESP_EARLY_LOGI(TAG_BTN, "tap cb (%s), heap: %d\n", pstr, esp_get_free_heap_size());
}
void button_press_2s_cb(void* arg)
{
ESP_EARLY_LOGI(TAG_BTN, "press 2s, heap: %d\n", esp_get_free_heap_size());
}
void button_press_5s_cb(void* arg)
{
ESP_EARLY_LOGI(TAG_BTN, "press 5s, heap: %d\n", esp_get_free_heap_size());
}
void button_test()
{
printf("before btn init, heap: %d\n", esp_get_free_heap_size());
button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL);
iot_button_set_evt_cb(btn_handle, BUTTON_CB_PUSH, button_tap_cb, "PUSH");
iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE");
iot_button_set_evt_cb(btn_handle, BUTTON_CB_TAP, button_tap_cb, "TAP");
iot_button_set_serial_cb(btn_handle, 2, 1000/portTICK_RATE_MS, button_tap_cb, "SERIAL");
iot_button_add_custom_cb(btn_handle, 2, button_press_2s_cb, NULL);
iot_button_add_custom_cb(btn_handle, 5, button_press_5s_cb, NULL);
printf("after btn init, heap: %d\n", esp_get_free_heap_size());
vTaskDelay(10000 / portTICK_PERIOD_MS);
printf("free btn: heap:%d\n", esp_get_free_heap_size());
iot_button_delete(btn_handle);
printf("after free btn: heap:%d\n", esp_get_free_heap_size());
}
TEST_CASE("Button test", "[button][iot]")
{
button_test();
}
+5
View File
@@ -0,0 +1,5 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
-3
View File
@@ -6,6 +6,3 @@
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_SRCDIRS :=
+67
View File
@@ -0,0 +1,67 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#define BUTTON_IO_NUM GPIO_NUM_37
#define BUTTON_ACTIVE_LEVEL BUTTON_ACTIVE_LOW
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/timers.h"
// #include "unity.h"
#include "iot_button.h"
#include "esp_system.h"
#include "esp_log.h"
static const char* TAG_BTN = "BTN_TEST";
void button_tap_cb(void* arg)
{
char* pstr = (char*) arg;
ESP_EARLY_LOGI(TAG_BTN, "tap cb (%s), heap: %d\n", pstr, esp_get_free_heap_size());
}
void button_press_2s_cb(void* arg)
{
ESP_EARLY_LOGI(TAG_BTN, "press 2s, heap: %d\n", esp_get_free_heap_size());
}
void button_press_5s_cb(void* arg)
{
ESP_EARLY_LOGI(TAG_BTN, "press 5s, heap: %d\n", esp_get_free_heap_size());
}
void button_test()
{
printf("before btn init, heap: %d\n", esp_get_free_heap_size());
button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL);
iot_button_set_evt_cb(btn_handle, BUTTON_CB_PUSH, button_tap_cb, "PUSH");
iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE");
iot_button_set_evt_cb(btn_handle, BUTTON_CB_TAP, button_tap_cb, "TAP");
iot_button_set_serial_cb(btn_handle, 2, 1000/portTICK_RATE_MS, button_tap_cb, "SERIAL");
iot_button_add_custom_cb(btn_handle, 2, button_press_2s_cb, NULL);
iot_button_add_custom_cb(btn_handle, 5, button_press_5s_cb, NULL);
printf("after btn init, heap: %d\n", esp_get_free_heap_size());
// vTaskDelay(10000 / portTICK_PERIOD_MS);
// printf("free btn: heap:%d\n", esp_get_free_heap_size());
// iot_button_delete(btn_handle);
// printf("after free btn: heap:%d\n", esp_get_free_heap_size());
}
void app_main()
{
button_test();
}
@@ -1,114 +0,0 @@
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/gpio.h"
#include "multi_button.h"
struct Button btn1;
struct Button btn2;
uint8_t read_button1_GPIO()
{
return (uint8_t)gpio_get_level(GPIO_NUM_39);
}
uint8_t read_button2_GPIO()
{
return (uint8_t)gpio_get_level(GPIO_NUM_38);
}
void BTN1_PRESS_DOWN_Handler(void* btn)
{
//do something...
printf("BTN1_PRESS_DOWN_Handler\n");
}
void BTN1_PRESS_UP_Handler(void* btn)
{
//do something...
printf("BTN1_PRESS_UP_Handler\n");
}
void BTN1_PRESS_REPEAT_Handler(void* btn)
{
printf("BTN1_PRESS_REPEAT_Handler\n");
}
void BTN1_SINGLE_Click_Handler(void* btn)
{
printf("BTN1_SINGLE_Click_Handler\n");
}
void BTN1_DOUBLE_Click_Handler(void* btn)
{
printf("BTN1_DOUBLE_Click_Handler\n");
}
void BTN2_PRESS_DOWN_Handler(void* btn)
{
//do something...
printf("BTN2_PRESS_DOWN_Handler\n");
}
void button_test(void *param)
{
// gpio_config_t gpio_conf;
// gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
// gpio_conf.mode = GPIO_MODE_INPUT;
// gpio_conf.pin_bit_mask = (1 << 39);
// gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
// gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
// gpio_config(&gpio_conf);
gpio_set_direction(GPIO_NUM_39, GPIO_MODE_INPUT);
gpio_set_direction(GPIO_NUM_38, GPIO_MODE_INPUT);
button_init(&btn1, read_button1_GPIO, 0);
button_init(&btn2, read_button2_GPIO, 0);
// button_attach(&btn1, PRESS_DOWN, BTN1_PRESS_DOWN_Handler);
// button_attach(&btn1, PRESS_UP, BTN1_PRESS_UP_Handler);
button_attach(&btn1, PRESS_REPEAT, BTN1_PRESS_REPEAT_Handler);
button_attach(&btn1, SINGLE_CLICK, BTN1_SINGLE_Click_Handler);
button_attach(&btn1, DOUBLE_CLICK, BTN1_DOUBLE_Click_Handler);
// button_attach(&btn1, LONG_RRESS_START, BTN1_LONG_RRESS_START_Handler);
// button_attach(&btn1, LONG_PRESS_HOLD, BTN1_LONG_PRESS_HOLD_Handler);
button_attach(&btn2, PRESS_DOWN, BTN2_PRESS_DOWN_Handler);
// button_attach(&btn2, PRESS_UP, BTN2_PRESS_UP_Handler);
// button_attach(&btn2, PRESS_REPEAT, BTN2_PRESS_REPEAT_Handler);
// button_attach(&btn2, SINGLE_CLICK, BTN2_SINGLE_Click_Handler);
// button_attach(&btn2, DOUBLE_CLICK, BTN2_DOUBLE_Click_Handler);
// button_attach(&btn2, LONG_RRESS_START, BTN2_LONG_RRESS_START_Handler);
// button_attach(&btn2, LONG_PRESS_HOLD, BTN2_LONG_PRESS_HOLD_Handler);
button_start(&btn1);
button_start(&btn2);
//make the timer invoking the button_ticks() interval 5ms.
//This function is implemented by yourself.
// __timer_start(button_ticks, 0, 5);
while(1)
{
button_ticks();
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void app_main()
{
xTaskCreate(&button_test, "button_test", 4096, NULL, 5, NULL);
}
+12 -3
View File
@@ -83,9 +83,8 @@ CONFIG_PARTITION_TABLE_SINGLE_APP=y
CONFIG_PARTITION_TABLE_TWO_OTA=
CONFIG_PARTITION_TABLE_CUSTOM=
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
CONFIG_APP_OFFSET=0x10000
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
#
@@ -124,12 +123,22 @@ CONFIG_BT_ENABLED=
CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
CONFIG_BT_RESERVE_DRAM=0
#
# Driver configurations
#
#
# ADC configuration
#
CONFIG_ADC_FORCE_XPD_FSM=
CONFIG_ADC2_DISABLE_DAC=y
#
# SPI master configuration
#
CONFIG_SPI_MASTER_IN_IRAM=
CONFIG_SPI_MASTER_ISR_IN_IRAM=y
#
# ESP32-specific
#
@@ -143,7 +152,7 @@ CONFIG_SPIRAM_SUPPORT=y
# SPI RAM config
#
CONFIG_SPIRAM_BOOT_INIT=y
CONFIG_SPIRAM_IGNORE_NOTFOUND=
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
CONFIG_SPIRAM_USE_MEMMAP=
CONFIG_SPIRAM_USE_CAPS_ALLOC=
CONFIG_SPIRAM_USE_MALLOC=y