summaryrefslogtreecommitdiffstats
path: root/quantum/debounce
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/debounce')
-rw-r--r--quantum/debounce/asym_eager_defer_pk.c171
-rw-r--r--quantum/debounce/none.c31
-rw-r--r--quantum/debounce/sym_defer_g.c26
-rw-r--r--quantum/debounce/sym_defer_pk.c67
-rw-r--r--quantum/debounce/sym_eager_pk.c72
-rw-r--r--quantum/debounce/sym_eager_pr.c76
-rw-r--r--quantum/debounce/tests/asym_eager_defer_pk_tests.cpp374
-rw-r--r--quantum/debounce/tests/debounce_test_common.cpp229
-rw-r--r--quantum/debounce/tests/debounce_test_common.h83
-rw-r--r--quantum/debounce/tests/rules.mk44
-rw-r--r--quantum/debounce/tests/sym_defer_g_tests.cpp223
-rw-r--r--quantum/debounce/tests/sym_defer_pk_tests.cpp225
-rw-r--r--quantum/debounce/tests/sym_eager_pk_tests.cpp237
-rw-r--r--quantum/debounce/tests/sym_eager_pr_tests.cpp280
-rw-r--r--quantum/debounce/tests/testlist.mk6
15 files changed, 2057 insertions, 87 deletions
diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c
new file mode 100644
index 0000000000..24380dc5e5
--- /dev/null
+++ b/quantum/debounce/asym_eager_defer_pk.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2017 Alex Ong <the.onga@gmail.com>
+ * Copyright 2020 Andrei Purdea <andrei@purdea.ro>
+ * Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
+When no state changes have occured for DEBOUNCE milliseconds, we push the state.
+*/
+
+#include "matrix.h"
+#include "timer.h"
+#include "quantum.h"
+#include <stdlib.h>
+
+#ifdef PROTOCOL_CHIBIOS
+# if CH_CFG_USE_MEMCORE == FALSE
+# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
+# endif
+#endif
+
+#ifndef DEBOUNCE
+# define DEBOUNCE 5
+#endif
+
+// Maximum debounce: 127ms
+#if DEBOUNCE > 127
+# undef DEBOUNCE
+# define DEBOUNCE 127
+#endif
+
+#define ROW_SHIFTER ((matrix_row_t)1)
+
+typedef struct {
+ bool pressed : 1;
+ uint8_t time : 7;
+} debounce_counter_t;
+
+#if DEBOUNCE > 0
+static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
+static bool counters_need_update;
+static bool matrix_need_update;
+
+#define DEBOUNCE_ELAPSED 0
+
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
+
+// we use num_rows rather than MATRIX_ROWS to support split keyboards
+void debounce_init(uint8_t num_rows) {
+ debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
+ int i = 0;
+ for (uint8_t r = 0; r < num_rows; r++) {
+ for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+ debounce_counters[i++].time = DEBOUNCE_ELAPSED;
+ }
+ }
+}
+
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
+ bool updated_last = false;
+
+ if (counters_need_update) {
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
+ }
+ }
+
+ if (changed || matrix_need_update) {
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ transfer_matrix_values(raw, cooked, num_rows);
+ }
+}
+
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
+ debounce_counter_t *debounce_pointer = debounce_counters;
+
+ counters_need_update = false;
+ matrix_need_update = false;
+
+ for (uint8_t row = 0; row < num_rows; row++) {
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ matrix_row_t col_mask = (ROW_SHIFTER << col);
+
+ if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
+ if (debounce_pointer->time <= elapsed_time) {
+ debounce_pointer->time = DEBOUNCE_ELAPSED;
+
+ if (debounce_pointer->pressed) {
+ // key-down: eager
+ matrix_need_update = true;
+ } else {
+ // key-up: defer
+ cooked[row] = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
+ }
+ } else {
+ debounce_pointer->time -= elapsed_time;
+ counters_need_update = true;
+ }
+ }
+ debounce_pointer++;
+ }
+ }
+}
+
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
+ debounce_counter_t *debounce_pointer = debounce_counters;
+
+ for (uint8_t row = 0; row < num_rows; row++) {
+ matrix_row_t delta = raw[row] ^ cooked[row];
+ for (uint8_t col = 0; col < MATRIX_COLS; col++) {
+ matrix_row_t col_mask = (ROW_SHIFTER << col);
+
+ if (delta & col_mask) {
+ if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
+ debounce_pointer->pressed = (raw[row] & col_mask);
+ debounce_pointer->time = DEBOUNCE;
+ counters_need_update = true;
+
+ if (debounce_pointer->pressed) {
+ // key-down: eager
+ cooked[row] ^= col_mask;
+ }
+ }
+ } else if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
+ if (!debounce_pointer->pressed) {
+ // key-up: defer
+ debounce_pointer->time = DEBOUNCE_ELAPSED;
+ }
+ }
+ debounce_pointer++;
+ }
+ }
+}
+
+bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/none.c b/quantum/debounce/none.c
new file mode 100644
index 0000000000..b03892bc5b
--- /dev/null
+++ b/quantum/debounce/none.c
@@ -0,0 +1,31 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "matrix.h"
+#include "quantum.h"
+#include <stdlib.h>
+
+void debounce_init(uint8_t num_rows) {}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
+ for (int i = 0; i < num_rows; i++) {
+ cooked[i] = raw[i];
+ }
+}
+
+bool debounce_active(void) { return false; }
+
+void debounce_free(void) {}
diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c
index 3ed9055d2a..fbefd55ede 100644
--- a/quantum/debounce/sym_defer_g.c
+++ b/quantum/debounce/sym_defer_g.c
@@ -1,5 +1,6 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
+Copyright 2021 Simon Arlott
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
@@ -23,30 +24,29 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
# define DEBOUNCE 5
#endif
-void debounce_init(uint8_t num_rows) {}
+#if DEBOUNCE > 0
static bool debouncing = false;
+static fast_timer_t debouncing_time;
-#if DEBOUNCE > 0
-static uint16_t debouncing_time;
-void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
+void debounce_init(uint8_t num_rows) {}
+
+void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
if (changed) {
debouncing = true;
- debouncing_time = timer_read();
+ debouncing_time = timer_read_fast();
}
- if (debouncing && timer_elapsed(debouncing_time) > DEBOUNCE) {
+ if (debouncing && timer_elapsed_fast(debouncing_time) >= DEBOUNCE) {
for (int i = 0; i < num_rows; i++) {
cooked[i] = raw[i];
}
debouncing = false;
}
}
-#else // no debouncing.
-void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- for (int i = 0; i < num_rows; i++) {
- cooked[i] = raw[i];
- }
-}
-#endif
bool debounce_active(void) { return debouncing; }
+
+void debounce_free(void) {}
+#else // no debouncing.
+# include "none.c"
+#endif
diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c
index 60513f98e1..626a9be841 100644
--- a/quantum/debounce/sym_defer_pk.c
+++ b/quantum/debounce/sym_defer_pk.c
@@ -1,6 +1,7 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
Copyright 2020 Andrei Purdea<andrei@purdea.ro>
+Copyright 2021 Simon Arlott
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
@@ -33,28 +34,25 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
# define DEBOUNCE 5
#endif
+// Maximum debounce: 255ms
+#if DEBOUNCE > UINT8_MAX
+# undef DEBOUNCE
+# define DEBOUNCE UINT8_MAX
+#endif
+
#define ROW_SHIFTER ((matrix_row_t)1)
-#define debounce_counter_t uint8_t
+typedef uint8_t debounce_counter_t;
+#if DEBOUNCE > 0
static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
static bool counters_need_update;
-#define DEBOUNCE_ELAPSED 251
-#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
-
-static uint8_t wrapping_timer_read(void) {
- static uint16_t time = 0;
- static uint8_t last_result = 0;
- uint16_t new_time = timer_read();
- uint16_t diff = new_time - time;
- time = new_time;
- last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
- return last_result;
-}
+#define DEBOUNCE_ELAPSED 0
-void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
-void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
+static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
@@ -67,27 +65,49 @@ void debounce_init(uint8_t num_rows) {
}
}
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- uint8_t current_time = wrapping_timer_read();
+ bool updated_last = false;
+
if (counters_need_update) {
- update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, current_time);
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
+ }
}
if (changed) {
- start_debounce_counters(raw, cooked, num_rows, current_time);
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ start_debounce_counters(raw, cooked, num_rows);
}
}
-void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
+static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
- if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+ if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
cooked[row] = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col));
} else {
+ *debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
@@ -96,14 +116,14 @@ void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix
}
}
-void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
+static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (delta & (ROW_SHIFTER << col)) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
- *debounce_pointer = current_time;
+ *debounce_pointer = DEBOUNCE;
counters_need_update = true;
}
} else {
@@ -115,3 +135,6 @@ void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t
}
bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c
index e66cf92d79..15a3242e68 100644
--- a/quantum/debounce/sym_eager_pk.c
+++ b/quantum/debounce/sym_eager_pk.c
@@ -1,5 +1,6 @@
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
+Copyright 2021 Simon Arlott
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
@@ -33,29 +34,26 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
# define DEBOUNCE 5
#endif
+// Maximum debounce: 255ms
+#if DEBOUNCE > UINT8_MAX
+# undef DEBOUNCE
+# define DEBOUNCE UINT8_MAX
+#endif
+
#define ROW_SHIFTER ((matrix_row_t)1)
-#define debounce_counter_t uint8_t
+typedef uint8_t debounce_counter_t;
+#if DEBOUNCE > 0
static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
static bool counters_need_update;
static bool matrix_need_update;
-#define DEBOUNCE_ELAPSED 251
-#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
-
-static uint8_t wrapping_timer_read(void) {
- static uint16_t time = 0;
- static uint8_t last_result = 0;
- uint16_t new_time = timer_read();
- uint16_t diff = new_time - time;
- time = new_time;
- last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
- return last_result;
-}
+#define DEBOUNCE_ELAPSED 0
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time);
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
@@ -68,27 +66,51 @@ void debounce_init(uint8_t num_rows) {
}
}
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- uint8_t current_time = wrapping_timer_read();
+ bool updated_last = false;
+
if (counters_need_update) {
- update_debounce_counters(num_rows, current_time);
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters(num_rows, elapsed_time);
+ }
}
if (changed || matrix_need_update) {
- transfer_matrix_values(raw, cooked, num_rows, current_time);
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ transfer_matrix_values(raw, cooked, num_rows);
}
}
// If the current time is > debounce counter, set the counter to enable input.
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
+ matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
- if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+ if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
+ matrix_need_update = true;
} else {
+ *debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
@@ -98,8 +120,7 @@ void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
}
// upload from raw_matrix to final matrix;
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
- matrix_need_update = false;
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t delta = raw[row] ^ cooked[row];
@@ -108,11 +129,9 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
matrix_row_t col_mask = (ROW_SHIFTER << col);
if (delta & col_mask) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
- *debounce_pointer = current_time;
+ *debounce_pointer = DEBOUNCE;
counters_need_update = true;
existing_row ^= col_mask; // flip the bit.
- } else {
- matrix_need_update = true;
}
}
debounce_pointer++;
@@ -122,3 +141,6 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
}
bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c
index 20ccb46f1d..2ad592c5a6 100644
--- a/quantum/debounce/sym_eager_pr.c
+++ b/quantum/debounce/sym_eager_pr.c
@@ -1,5 +1,6 @@
/*
Copyright 2019 Alex Ong<the.onga@gmail.com>
+Copyright 2021 Simon Arlott
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
@@ -33,27 +34,25 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
# define DEBOUNCE 5
#endif
-#define debounce_counter_t uint8_t
+// Maximum debounce: 255ms
+#if DEBOUNCE > UINT8_MAX
+# undef DEBOUNCE
+# define DEBOUNCE UINT8_MAX
+#endif
+
+typedef uint8_t debounce_counter_t;
+
+#if DEBOUNCE > 0
static bool matrix_need_update;
static debounce_counter_t *debounce_counters;
+static fast_timer_t last_time;
static bool counters_need_update;
-#define DEBOUNCE_ELAPSED 251
-#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
-
-static uint8_t wrapping_timer_read(void) {
- static uint16_t time = 0;
- static uint8_t last_result = 0;
- uint16_t new_time = timer_read();
- uint16_t diff = new_time - time;
- time = new_time;
- last_result = (last_result + diff) % (MAX_DEBOUNCE + 1);
- return last_result;
-}
+#define DEBOUNCE_ELAPSED 0
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time);
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time);
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init(uint8_t num_rows) {
@@ -63,27 +62,50 @@ void debounce_init(uint8_t num_rows) {
}
}
+void debounce_free(void) {
+ free(debounce_counters);
+ debounce_counters = NULL;
+}
+
void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
- uint8_t current_time = wrapping_timer_read();
- bool needed_update = counters_need_update;
+ bool updated_last = false;
+
if (counters_need_update) {
- update_debounce_counters(num_rows, current_time);
+ fast_timer_t now = timer_read_fast();
+ fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
+
+ last_time = now;
+ updated_last = true;
+ if (elapsed_time > UINT8_MAX) {
+ elapsed_time = UINT8_MAX;
+ }
+
+ if (elapsed_time > 0) {
+ update_debounce_counters(num_rows, elapsed_time);
+ }
}
- if (changed || (needed_update && !counters_need_update) || matrix_need_update) {
- transfer_matrix_values(raw, cooked, num_rows, current_time);
+ if (changed || matrix_need_update) {
+ if (!updated_last) {
+ last_time = timer_read_fast();
+ }
+
+ transfer_matrix_values(raw, cooked, num_rows);
}
}
// If the current time is > debounce counter, set the counter to enable input.
-void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
+static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) {
counters_need_update = false;
+ matrix_need_update = false;
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
- if (TIMER_DIFF(current_time, *debounce_pointer, MAX_DEBOUNCE) >= DEBOUNCE) {
+ if (*debounce_pointer <= elapsed_time) {
*debounce_pointer = DEBOUNCE_ELAPSED;
+ matrix_need_update = true;
} else {
+ *debounce_pointer -= elapsed_time;
counters_need_update = true;
}
}
@@ -92,8 +114,7 @@ void update_debounce_counters(uint8_t num_rows, uint8_t current_time) {
}
// upload from raw_matrix to final matrix;
-void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t current_time) {
- matrix_need_update = false;
+static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
debounce_counter_t *debounce_pointer = debounce_counters;
for (uint8_t row = 0; row < num_rows; row++) {
matrix_row_t existing_row = cooked[row];
@@ -102,11 +123,9 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
// determine new value basd on debounce pointer + raw value
if (existing_row != raw_row) {
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
- *debounce_pointer = current_time;
+ *debounce_pointer = DEBOUNCE;
cooked[row] = raw_row;
counters_need_update = true;
- } else {
- matrix_need_update = true;
}
}
debounce_pointer++;
@@ -114,3 +133,6 @@ void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t n
}
bool debounce_active(void) { return true; }
+#else
+# include "none.c"
+#endif
diff --git a/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp b/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
new file mode 100644
index 0000000000..fe374c3dfa
--- /dev/null
+++ b/quantum/debounce/tests/asym_eager_defer_pk_tests.cpp
@@ -0,0 +1,374 @@
+/* Copyright 2021 Simon Arlott
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "gtest/gtest.h"
+
+#include "debounce_test_common.h"
+
+TEST_F(DebounceTest, OneKeyShort1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 1ms delay */
+ {1, {{0, 1, UP}}, {}},
+
+ /*
+ * Until the eager timer on DOWN is observed to finish, the defer timer
+ * on UP can't start. There's no workaround for this because it's not
+ * possible to debounce an event that isn't being tracked.
+ *
+ * sym_defer_pk has the same problem but the test has to track that the
+ * key changed state so the DOWN timer is always allowed to finish
+ * before starting the UP timer.
+ */
+ {5, {}, {}},
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 2ms delay */
+ {2, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort3) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 3ms delay */
+ {3, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort4) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 4ms delay */
+ {4, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort5) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Release key after 5ms delay */
+ {5, {{0, 1, UP}}, {}},
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms+5ms after DOWN at time 0 */
+ /* Press key again after 1ms delay */
+ {11, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort6) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Release key after 6ms delay */
+ {6, {{0, 1, UP}}, {}},
+
+ {11, {}, {{0, 1, UP}}}, /* 5ms after UP at time 6 */
+ /* Press key again after 1ms delay */
+ {12, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort7) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+
+ /* Release key after 7ms delay */
+ {7, {{0, 1, UP}}, {}},
+
+ {12, {}, {{0, 1, UP}}}, /* 5ms after UP at time 7 */
+ /* Press key again after 1ms delay */
+ {13, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort8) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 1ms delay */
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ {10, {}, {{0, 1, UP}}}, /* 5ms after UP at time 7 */
+ /* Press key again after 0ms delay (scan 2) */
+ {10, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyShort9) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Release key after 1ms delay */
+ {1, {{0, 1, UP}}, {}},
+
+ {5, {}, {}}, /* See OneKeyShort1 */
+
+ /* Press key again after 0ms delay (same scan) before debounce finishes */
+ {10, {{0, 1, DOWN}}, {}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing1) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ {1, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {3, {{0, 1, UP}}, {}},
+ {4, {{0, 1, DOWN}}, {}},
+ {5, {{0, 1, UP}}, {}},
+ {6, {{0, 1, DOWN}}, {}},
+ {7, {{0, 1, UP}}, {}},
+ {8, {{0, 1, DOWN}}, {}},
+ {9, {{0, 1, UP}}, {}},
+ {10, {{0, 1, DOWN}}, {}},
+ {11, {{0, 1, UP}}, {}},
+ {12, {{0, 1, DOWN}}, {}},
+ {13, {{0, 1, UP}}, {}},
+ {14, {{0, 1, DOWN}}, {}},
+ {15, {{0, 1, UP}}, {}},
+
+ {20, {}, {{0, 1, UP}}},
+ /* Press key again after 1ms delay */
+ {21, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ });
+ runEvents();
+}
+
+TEST_F(DebounceTest, OneKeyBouncing2) {
+ addEvents({ /* Time, Inputs, Outputs */
+ {0, {{0, 1, DOWN}}, {{0, 1, DOWN}}},
+ /* Change twice in the same time period */
+ {1, {{0, 1, UP}}, {}},
+ {1, {{0, 1, DOWN}}, {}},
+ /* Change three times in the same time period */
+ {2, {{0, 1, UP}}, {}},
+ {2, {{0, 1, DOWN}}, {}},
+ {2, {{0, 1, UP}}, {}},
+ /* Change twice in the same time period */
+ {6, {{0, 1, DOWN}}, {}},
+ {6, {{0, 1, UP}}, {}},
+ /* Change three times in the same time period */
+ {7, {{0, 1, DOWN}}, {}