summaryrefslogtreecommitdiff
path: root/app/drivers/kscan/debounce.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/drivers/kscan/debounce.c')
-rw-r--r--app/drivers/kscan/debounce.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/app/drivers/kscan/debounce.c b/app/drivers/kscan/debounce.c
new file mode 100644
index 0000000..b387822
--- /dev/null
+++ b/app/drivers/kscan/debounce.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2021 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "debounce.h"
+
+static uint32_t get_threshold(const struct debounce_state *state,
+ const struct debounce_config *config) {
+ return state->pressed ? config->debounce_release_ms : config->debounce_press_ms;
+}
+
+static void increment_counter(struct debounce_state *state, const int elapsed_ms) {
+ if (state->counter + elapsed_ms > DEBOUNCE_COUNTER_MAX) {
+ state->counter = DEBOUNCE_COUNTER_MAX;
+ } else {
+ state->counter += elapsed_ms;
+ }
+}
+
+static void decrement_counter(struct debounce_state *state, const int elapsed_ms) {
+ if (state->counter < elapsed_ms) {
+ state->counter = 0;
+ } else {
+ state->counter -= elapsed_ms;
+ }
+}
+
+void debounce_update(struct debounce_state *state, const bool active, const int elapsed_ms,
+ const struct debounce_config *config) {
+ // This uses a variation of the integrator debouncing described at
+ // https://www.kennethkuhn.com/electronics/debounce.c
+ // Every update where "active" does not match the current state, we increment
+ // a counter, otherwise we decrement it. When the counter reaches a
+ // threshold, the state flips and we reset the counter.
+ state->changed = false;
+
+ if (active == state->pressed) {
+ decrement_counter(state, elapsed_ms);
+ return;
+ }
+
+ const uint32_t flip_threshold = get_threshold(state, config);
+
+ if (state->counter < flip_threshold) {
+ increment_counter(state, elapsed_ms);
+ return;
+ }
+
+ state->pressed = !state->pressed;
+ state->counter = 0;
+ state->changed = true;
+}
+
+bool debounce_is_active(const struct debounce_state *state) {
+ return state->pressed || state->counter > 0;
+}
+
+bool debounce_is_pressed(const struct debounce_state *state) { return state->pressed; }
+
+bool debounce_get_changed(const struct debounce_state *state) { return state->changed; } \ No newline at end of file