refactor: Promote debounce to exposed mod lib.

* Promote previously local debounce code from kscan drivers to exposed
  module lib, for use with other drivers as needed.
* Refactor existing kscan driver to new "public" API.
This commit is contained in:
Peter Johanson 2023-09-11 21:56:37 -07:00 committed by Pete Johanson
parent c28ef1b61e
commit 0ca7f69b6d
12 changed files with 54 additions and 40 deletions

View file

@ -1,3 +1,4 @@
zephyr_include_directories(include) zephyr_include_directories(include)
add_subdirectory(drivers) add_subdirectory(drivers)
add_subdirectory(lib)

View file

@ -1,2 +1,3 @@
rsource "drivers/Kconfig" rsource "drivers/Kconfig"
rsource "lib/Kconfig"

View file

@ -3,7 +3,6 @@
zephyr_library_amend() zephyr_library_amend()
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER debounce.c)
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DRIVER kscan_gpio.c)
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_MATRIX kscan_gpio_matrix.c)
zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c) zephyr_library_sources_ifdef(CONFIG_ZMK_KSCAN_GPIO_DIRECT kscan_gpio_direct.c)

View file

@ -16,6 +16,7 @@ config ZMK_KSCAN_COMPOSITE_DRIVER
config ZMK_KSCAN_GPIO_DRIVER config ZMK_KSCAN_GPIO_DRIVER
bool bool
select GPIO select GPIO
select ZMK_DEBOUNCE
config ZMK_KSCAN_GPIO_DEMUX config ZMK_KSCAN_GPIO_DEMUX
bool bool

View file

@ -4,7 +4,6 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include "debounce.h"
#include "kscan_gpio.h" #include "kscan_gpio.h"
#include <zephyr/device.h> #include <zephyr/device.h>
@ -15,6 +14,8 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
#include <zmk/debounce.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#define DT_DRV_COMPAT zmk_kscan_gpio_direct #define DT_DRV_COMPAT zmk_kscan_gpio_direct
@ -61,11 +62,11 @@ struct kscan_direct_data {
/** Timestamp of the current or scheduled scan. */ /** Timestamp of the current or scheduled scan. */
int64_t scan_time; int64_t scan_time;
/** Current state of the inputs as an array of length config->inputs.len */ /** Current state of the inputs as an array of length config->inputs.len */
struct debounce_state *pin_state; struct zmk_debounce_state *pin_state;
}; };
struct kscan_direct_config { struct kscan_direct_config {
struct debounce_config debounce_config; struct zmk_debounce_config debounce_config;
int32_t debounce_scan_period_ms; int32_t debounce_scan_period_ms;
int32_t poll_period_ms; int32_t poll_period_ms;
bool toggle_mode; bool toggle_mode;
@ -182,8 +183,8 @@ static int kscan_direct_read(const struct device *dev) {
return active; return active;
} }
debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms, zmk_debounce_update(&data->pin_state[gpio->index], active, config->debounce_scan_period_ms,
&config->debounce_config); &config->debounce_config);
} }
// Process the new state. // Process the new state.
@ -191,10 +192,10 @@ static int kscan_direct_read(const struct device *dev) {
for (int i = 0; i < data->inputs.len; i++) { for (int i = 0; i < data->inputs.len; i++) {
const struct kscan_gpio *gpio = &data->inputs.gpios[i]; const struct kscan_gpio *gpio = &data->inputs.gpios[i];
struct debounce_state *state = &data->pin_state[gpio->index]; struct zmk_debounce_state *state = &data->pin_state[gpio->index];
if (debounce_get_changed(state)) { if (zmk_debounce_get_changed(state)) {
const bool pressed = debounce_is_pressed(state); const bool pressed = zmk_debounce_is_pressed(state);
LOG_DBG("Sending event at 0,%i state %s", gpio->index, pressed ? "on" : "off"); LOG_DBG("Sending event at 0,%i state %s", gpio->index, pressed ? "on" : "off");
data->callback(dev, 0, gpio->index, pressed); data->callback(dev, 0, gpio->index, pressed);
@ -203,7 +204,7 @@ static int kscan_direct_read(const struct device *dev) {
} }
} }
continue_scan = continue_scan || debounce_is_active(state); continue_scan = continue_scan || zmk_debounce_is_active(state);
} }
if (continue_scan) { if (continue_scan) {
@ -332,7 +333,7 @@ static const struct kscan_driver_api kscan_direct_api = {
static struct kscan_gpio kscan_direct_inputs_##n[] = { \ static struct kscan_gpio kscan_direct_inputs_##n[] = { \
LISTIFY(INST_INPUTS_LEN(n), KSCAN_DIRECT_INPUT_CFG_INIT, (, ), n)}; \ LISTIFY(INST_INPUTS_LEN(n), KSCAN_DIRECT_INPUT_CFG_INIT, (, ), n)}; \
\ \
static struct debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \ static struct zmk_debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \
\ \
COND_INTERRUPTS( \ COND_INTERRUPTS( \
(static struct kscan_direct_irq_callback kscan_direct_irqs_##n[INST_INPUTS_LEN(n)];)) \ (static struct kscan_direct_irq_callback kscan_direct_irqs_##n[INST_INPUTS_LEN(n)];)) \

View file

@ -4,7 +4,6 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include "debounce.h"
#include "kscan_gpio.h" #include "kscan_gpio.h"
#include <zephyr/device.h> #include <zephyr/device.h>
@ -16,6 +15,8 @@
#include <zephyr/sys/__assert.h> #include <zephyr/sys/__assert.h>
#include <zephyr/sys/util.h> #include <zephyr/sys/util.h>
#include <zmk/debounce.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#define DT_DRV_COMPAT zmk_kscan_gpio_matrix #define DT_DRV_COMPAT zmk_kscan_gpio_matrix
@ -80,12 +81,12 @@ struct kscan_matrix_data {
* Current state of the matrix as a flattened 2D array of length * Current state of the matrix as a flattened 2D array of length
* (config->rows * config->cols) * (config->rows * config->cols)
*/ */
struct debounce_state *matrix_state; struct zmk_debounce_state *matrix_state;
}; };
struct kscan_matrix_config { struct kscan_matrix_config {
struct kscan_gpio_list outputs; struct kscan_gpio_list outputs;
struct debounce_config debounce_config; struct zmk_debounce_config debounce_config;
size_t rows; size_t rows;
size_t cols; size_t cols;
int32_t debounce_scan_period_ms; int32_t debounce_scan_period_ms;
@ -242,8 +243,8 @@ static int kscan_matrix_read(const struct device *dev) {
return active; return active;
} }
debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms, zmk_debounce_update(&data->matrix_state[index], active, config->debounce_scan_period_ms,
&config->debounce_config); &config->debounce_config);
} }
err = gpio_pin_set_dt(&out_gpio->spec, 0); err = gpio_pin_set_dt(&out_gpio->spec, 0);
@ -263,16 +264,16 @@ static int kscan_matrix_read(const struct device *dev) {
for (int r = 0; r < config->rows; r++) { for (int r = 0; r < config->rows; r++) {
for (int c = 0; c < config->cols; c++) { for (int c = 0; c < config->cols; c++) {
const int index = state_index_rc(config, r, c); const int index = state_index_rc(config, r, c);
struct debounce_state *state = &data->matrix_state[index]; struct zmk_debounce_state *state = &data->matrix_state[index];
if (debounce_get_changed(state)) { if (zmk_debounce_get_changed(state)) {
const bool pressed = debounce_is_pressed(state); const bool pressed = zmk_debounce_is_pressed(state);
LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off"); LOG_DBG("Sending event at %i,%i state %s", r, c, pressed ? "on" : "off");
data->callback(dev, r, c, pressed); data->callback(dev, r, c, pressed);
} }
continue_scan = continue_scan || debounce_is_active(state); continue_scan = continue_scan || zmk_debounce_is_active(state);
} }
} }
@ -438,7 +439,7 @@ static const struct kscan_driver_api kscan_matrix_api = {
static struct kscan_gpio kscan_matrix_cols_##n[] = { \ static struct kscan_gpio kscan_matrix_cols_##n[] = { \
LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, (, ), n)}; \ LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, (, ), n)}; \
\ \
static struct debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \ static struct zmk_debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \
\ \
COND_INTERRUPTS( \ COND_INTERRUPTS( \
(static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \ (static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \

View file

@ -13,13 +13,13 @@
#define DEBOUNCE_COUNTER_BITS 14 #define DEBOUNCE_COUNTER_BITS 14
#define DEBOUNCE_COUNTER_MAX BIT_MASK(DEBOUNCE_COUNTER_BITS) #define DEBOUNCE_COUNTER_MAX BIT_MASK(DEBOUNCE_COUNTER_BITS)
struct debounce_state { struct zmk_debounce_state {
bool pressed : 1; bool pressed : 1;
bool changed : 1; bool changed : 1;
uint16_t counter : DEBOUNCE_COUNTER_BITS; uint16_t counter : DEBOUNCE_COUNTER_BITS;
}; };
struct debounce_config { struct zmk_debounce_config {
/** Duration a switch must be pressed to latch as pressed. */ /** Duration a switch must be pressed to latch as pressed. */
uint32_t debounce_press_ms; uint32_t debounce_press_ms;
/** Duration a switch must be released to latch as released. */ /** Duration a switch must be released to latch as released. */
@ -34,23 +34,23 @@ struct debounce_config {
* @param elapsed_ms Time elapsed since the previous update in milliseconds. * @param elapsed_ms Time elapsed since the previous update in milliseconds.
* @param config Debounce settings. * @param config Debounce settings.
*/ */
void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms, void zmk_debounce_update(struct zmk_debounce_state *state, const bool active, const int elapsed_ms,
const struct debounce_config *config); const struct zmk_debounce_config *config);
/** /**
* @returns whether the switch is either latched as pressed or it is potentially * @returns whether the switch is either latched as pressed or it is potentially
* pressed but the debouncer has not yet made a decision. If this returns true, * pressed but the debouncer has not yet made a decision. If this returns true,
* the kscan driver should continue to poll quickly. * the kscan driver should continue to poll quickly.
*/ */
bool debounce_is_active(const struct debounce_state *state); bool zmk_debounce_is_active(const struct zmk_debounce_state *state);
/** /**
* @returns whether the switch is latched as pressed. * @returns whether the switch is latched as pressed.
*/ */
bool debounce_is_pressed(const struct debounce_state *state); bool zmk_debounce_is_pressed(const struct zmk_debounce_state *state);
/** /**
* @returns whether the pressed state of the switch changed in the last call to * @returns whether the pressed state of the switch changed in the last call to
* debounce_update. * debounce_update.
*/ */
bool debounce_get_changed(const struct debounce_state *state); bool zmk_debounce_get_changed(const struct zmk_debounce_state *state);

View file

@ -0,0 +1,2 @@
add_subdirectory_ifdef(CONFIG_ZMK_DEBOUNCE zmk_debounce)

2
app/module/lib/Kconfig Normal file
View file

@ -0,0 +1,2 @@
rsource "zmk_debounce/Kconfig"

View file

@ -0,0 +1,3 @@
zephyr_library()
zephyr_library_sources(debounce.c)

View file

@ -0,0 +1,3 @@
config ZMK_DEBOUNCE
bool "Debounce Support"

View file

@ -4,14 +4,14 @@
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
#include "debounce.h" #include <zmk/debounce.h>
static uint32_t get_threshold(const struct debounce_state *state, static uint32_t get_threshold(const struct zmk_debounce_state *state,
const struct debounce_config *config) { const struct zmk_debounce_config *config) {
return state->pressed ? config->debounce_release_ms : config->debounce_press_ms; return state->pressed ? config->debounce_release_ms : config->debounce_press_ms;
} }
static void increment_counter(struct debounce_state *state, const int elapsed_ms) { static void increment_counter(struct zmk_debounce_state *state, const int elapsed_ms) {
if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) { if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) {
state->counter = DEBOUNCE_COUNTER_MAX; state->counter = DEBOUNCE_COUNTER_MAX;
} else { } else {
@ -19,7 +19,7 @@ static void increment_counter(struct debounce_state *state, const int elapsed_ms
} }
} }
static void decrement_counter(struct debounce_state *state, const int elapsed_ms) { static void decrement_counter(struct zmk_debounce_state *state, const int elapsed_ms) {
if (state->counter < elapsed_ms) { if (state->counter < elapsed_ms) {
state->counter = 0; state->counter = 0;
} else { } else {
@ -27,8 +27,8 @@ static void decrement_counter(struct debounce_state *state, const int elapsed_ms
} }
} }
void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms, void zmk_debounce_update(struct zmk_debounce_state *state, const bool active, const int elapsed_ms,
const struct debounce_config *config) { const struct zmk_debounce_config *config) {
// This uses a variation of the integrator debouncing described at // This uses a variation of the integrator debouncing described at
// https://www.kennethkuhn.com/electronics/debounce.c // https://www.kennethkuhn.com/electronics/debounce.c
// Every update where "active" does not match the current state, we increment // Every update where "active" does not match the current state, we increment
@ -53,10 +53,10 @@ void debounce_update(struct debounce_state *state, const bool active, const int
state->changed = true; state->changed = true;
} }
bool debounce_is_active(const struct debounce_state *state) { bool zmk_debounce_is_active(const struct zmk_debounce_state *state) {
return state->pressed || state->counter > 0; return state->pressed || state->counter > 0;
} }
bool debounce_is_pressed(const struct debounce_state *state) { return state->pressed; } bool zmk_debounce_is_pressed(const struct zmk_debounce_state *state) { return state->pressed; }
bool debounce_get_changed(const struct debounce_state *state) { return state->changed; } bool zmk_debounce_get_changed(const struct zmk_debounce_state *state) { return state->changed; }