Button
Handles Hardware Buttons
Configuration
#define MAX_CONFIDENCE (100)
#define ON_CONFIDENCE (70)
#define OFF_CONFIDENCE (30)
#define MIN_CONFIDENCE (0)
#define CONFIDENCE_STEP (20)
MAX_CONFIDENCEthe maximum confidence valueON_CONFIDENCEthe confidence value at which the button is considered to be pressedOFF_CONFIDENCEthe confidence value at which the button is considered to be releasedMIN_CONFIDENCEthe minimum confidence valueCONFIDENCE_STEPthe amount by which the confidence value is incremented or decremented each tick
Public functions
button_init()
Initializes the button module
void button_init()
{
}
currently does nothing as the module is stateless, but may be used in the future
button_setup()
Registers a button handler, which will be called when the button state changes sets up the GPIO pin as an input with a pull-down resistor, and stores the handler information
void button_setup(gpio_num_t pin, gpio_int_type_t edge, gpio_isr_t callback, void* args)
{
gpio_config_t io_config = {
.intr_type = GPIO_INTR_DISABLE,
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = (1ULL << pin),
.pull_down_en = GPIO_PULLDOWN_ENABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
};
ESP_ERROR_CHECK(gpio_config(&io_config));
handlers[pin].enabled = true;
handlers[pin].callback = callback;
handlers[pin].edge = edge;
handlers[pin].args = args;
bool pinstate = getpin(pin);
handlers[pin].confidence = 255 * pinstate;
handlers[pin].current_state = pinstate;
}
button_tick()
Called every tick to update the button state machine
button state is determined by a confidence value, which is incremented or decremented by a fixed amount each tick based on the button's digital state
when the confidence value crosses a threshold, the button state is updated and the callback is called if the edge condition is met
there is a gap between the on and off thresholds to provide hysteresis and prevent chattering
void button_tick()
{
for (size_t n = 0; n < GPIO_NUM_MAX; n++)
{
handler_t* handle = &handlers[n];
if (handle->enabled && handle->callback != NULL)
{
// note: buttons are active low, hence using -CONFIDENCE_STEP when get_pin is true
if (getpin(n))
{
handle->confidence = add_clamped(handle->confidence, -CONFIDENCE_STEP);
}
else
{
handle->confidence = add_clamped(handle->confidence, CONFIDENCE_STEP);
}
if (handle->confidence >= ON_CONFIDENCE && !handle->current_state)
{
handle->current_state = true;
if (handle->edge == GPIO_INTR_POSEDGE || handle->edge == GPIO_INTR_ANYEDGE)
{
handle->callback(handle->args);
}
}
if (handle->confidence <= OFF_CONFIDENCE && handle->current_state)
{
handle->current_state = false;
if (handle->edge == GPIO_INTR_NEGEDGE || handle->edge == GPIO_INTR_ANYEDGE)
{
handle->callback(handle->args);
}
}
}
}
}
Internal types
handler_t
used to store information about a registerd button handler
typedef struct
{
bool enabled;
gpio_isr_t callback;
gpio_int_type_t edge;
void* args;
int confidence;
bool current_state;
} handler_t;
Internal variables
handlers
provides space to store a handler for each GPIO pin
static handler_t handlers[GPIO_NUM_MAX] = {0};
Internal functions
get_pin
helper to get the digital state of an arbitrary pin
inline bool getpin(gpio_num_t pin)
{
uint64_t state = (uint64_t)gpio_input_get() + ((uint64_t)gpio_input_get_high() << 32);
uint64_t bitmask = 1 << pin;
return state & bitmask;
}
add_clamped
helper to add two numbers, clamping the result to between the minimum and maximum confidence values
inline int add_clamped(int base, int to_add)
{
base = base + to_add;
if (base < MIN_CONFIDENCE)
base = MIN_CONFIDENCE;
if (base > MAX_CONFIDENCE)
base = MAX_CONFIDENCE;
return base;
}