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:
parent
c28ef1b61e
commit
0ca7f69b6d
12 changed files with 54 additions and 40 deletions
|
@ -1,3 +1,4 @@
|
||||||
zephyr_include_directories(include)
|
zephyr_include_directories(include)
|
||||||
|
|
||||||
add_subdirectory(drivers)
|
add_subdirectory(drivers)
|
||||||
|
add_subdirectory(lib)
|
|
@ -1,2 +1,3 @@
|
||||||
|
|
||||||
rsource "drivers/Kconfig"
|
rsource "drivers/Kconfig"
|
||||||
|
rsource "lib/Kconfig"
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,7 +183,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)];)) \
|
||||||
|
|
|
@ -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,7 +243,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)];)) \
|
||||||
|
|
|
@ -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);
|
2
app/module/lib/CMakeLists.txt
Normal file
2
app/module/lib/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
add_subdirectory_ifdef(CONFIG_ZMK_DEBOUNCE zmk_debounce)
|
2
app/module/lib/Kconfig
Normal file
2
app/module/lib/Kconfig
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
rsource "zmk_debounce/Kconfig"
|
3
app/module/lib/zmk_debounce/CMakeLists.txt
Normal file
3
app/module/lib/zmk_debounce/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
zephyr_library_sources(debounce.c)
|
3
app/module/lib/zmk_debounce/Kconfig
Normal file
3
app/module/lib/zmk_debounce/Kconfig
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
config ZMK_DEBOUNCE
|
||||||
|
bool "Debounce Support"
|
|
@ -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; }
|
Loading…
Add table
Reference in a new issue