summaryrefslogtreecommitdiff
path: root/quantum/debounce
diff options
context:
space:
mode:
authorフィルターペーパー <76888457+filterpaper@users.noreply.github.com>2025-09-07 20:34:05 +0800
committerGitHub <noreply@github.com>2025-09-07 13:34:05 +0100
commit4bd5c033c3135576010baded53c44720d8030d32 (patch)
tree561a167570c79d39f62174d651d844a1c9cf2abc /quantum/debounce
parent5830b1b5e3323b7a491824bef2b5bdf223e5d50e (diff)
Refactor debounce algorithm with static allocation (#25515)
* Refactor debounce counters with direct indexing * Refactor code to use array indexing for debounce_counters * Use global MATRIX_ROW_SHIFTER macro * Refactor debounce algorithm with static allocation * Converted arrays to static allocation * Standardised use of MATRIX_ROWS_PER_HAND for array sizing * Added Doxygen comments for primary debounce functions * Removed debounce_free() * Rewrite sym_defer_pr * Modernise code using sym_defer_pk as template * Format consistency with other current algorithms * Use shorter SPDX-License-Identifier * Remove ChibiOS core memory manager guard * Keep type definition within DEBOUNCE guard * Add change log * Minor optimisation refactor * Pre-calculate row_offset in per-key matrix loops * Add inline compiler hints * Improve readability with blank lines * Limit elapsed time to the maximum debounce value * Apply suggestions from code review Declare counters with "DEBOUNCE_ELAPSED" Co-authored-by: Joel Challis <git@zvecr.com> * Update change log to new breaking change date --------- Co-authored-by: Joel Challis <git@zvecr.com>
Diffstat (limited to 'quantum/debounce')
-rw-r--r--quantum/debounce/asym_eager_defer_pk.c165
-rw-r--r--quantum/debounce/none.c2
-rw-r--r--quantum/debounce/sym_defer_g.c33
-rw-r--r--quantum/debounce/sym_defer_pk.c149
-rw-r--r--quantum/debounce/sym_defer_pr.c154
-rw-r--r--quantum/debounce/sym_eager_pk.c125
-rw-r--r--quantum/debounce/sym_eager_pr.c136
-rw-r--r--quantum/debounce/tests/debounce_test_common.cpp2
8 files changed, 371 insertions, 395 deletions
diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c
index b6fcdc3d4e..a385301c90 100644
--- a/quantum/debounce/asym_eager_defer_pk.c
+++ b/quantum/debounce/asym_eager_defer_pk.c
@@ -1,37 +1,15 @@
1/* 1// Copyright 2017 Alex Ong <the.onga@gmail.com>
2 * Copyright 2017 Alex Ong <the.onga@gmail.com> 2// Copyright 2020 Andrei Purdea <andrei@purdea.ro>
3 * Copyright 2020 Andrei Purdea <andrei@purdea.ro> 3// Copyright 2021 Simon Arlott
4 * Copyright 2021 Simon Arlott 4// SPDX-License-Identifier: GPL-2.0-or-later
5 * 5//
6 * This program is free software: you can redistribute it and/or modify 6// Asymetric per-key algorithm. After pressing a key, it immediately changes state,
7 * it under the terms of the GNU General Public License as published by 7// with no further inputs accepted until DEBOUNCE milliseconds have occurred. After
8 * the Free Software Foundation, either version 2 of the License, or 8// releasing a key, that state is pushed after no changes occur for DEBOUNCE milliseconds.
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21Asymetric per-key algorithm. After pressing a key, it immediately changes state,
22with no further inputs accepted until DEBOUNCE milliseconds have occurred. After
23releasing a key, that state is pushed after no changes occur for DEBOUNCE milliseconds.
24*/
25 9
26#include "debounce.h" 10#include "debounce.h"
27#include "timer.h" 11#include "timer.h"
28#include <stdlib.h> 12#include "util.h"
29
30#ifdef PROTOCOL_CHIBIOS
31# if CH_CFG_USE_MEMCORE == FALSE
32# 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.
33# endif
34#endif
35 13
36#ifndef DEBOUNCE 14#ifndef DEBOUNCE
37# define DEBOUNCE 5 15# define DEBOUNCE 5
@@ -43,44 +21,29 @@ releasing a key, that state is pushed after no changes occur for DEBOUNCE millis
43# define DEBOUNCE 127 21# define DEBOUNCE 127
44#endif 22#endif
45 23
46#define ROW_SHIFTER ((matrix_row_t)1) 24#define DEBOUNCE_ELAPSED 0
47 25
26#if DEBOUNCE > 0
48typedef struct { 27typedef struct {
49 bool pressed : 1; 28 bool pressed : 1;
50 uint8_t time : 7; 29 uint8_t time : 7;
51} debounce_counter_t; 30} debounce_counter_t;
52 31
53#if DEBOUNCE > 0 32// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards
54static debounce_counter_t *debounce_counters; 33static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED};
55static fast_timer_t last_time; 34static bool counters_need_update;
56static bool counters_need_update; 35static bool matrix_need_update;
57static bool matrix_need_update; 36static bool cooked_changed;
58static bool cooked_changed;
59
60# define DEBOUNCE_ELAPSED 0
61
62static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
63static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
64
65// we use num_rows rather than MATRIX_ROWS to support split keyboards
66void debounce_init(uint8_t num_rows) {
67 debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
68 int i = 0;
69 for (uint8_t r = 0; r < num_rows; r++) {
70 for (uint8_t c = 0; c < MATRIX_COLS; c++) {
71 debounce_counters[i++].time = DEBOUNCE_ELAPSED;
72 }
73 }
74}
75 37
76void debounce_free(void) { 38static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time);
77 free(debounce_counters); 39static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]);
78 debounce_counters = NULL; 40
79} 41void debounce_init(uint8_t num_rows) {}
80 42
81bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { 43bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
82 bool updated_last = false; 44 static fast_timer_t last_time;
83 cooked_changed = false; 45 bool updated_last = false;
46 cooked_changed = false;
84 47
85 if (counters_need_update) { 48 if (counters_need_update) {
86 fast_timer_t now = timer_read_fast(); 49 fast_timer_t now = timer_read_fast();
@@ -88,12 +51,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
88 51
89 last_time = now; 52 last_time = now;
90 updated_last = true; 53 updated_last = true;
91 if (elapsed_time > UINT8_MAX) {
92 elapsed_time = UINT8_MAX;
93 }
94 54
95 if (elapsed_time > 0) { 55 if (elapsed_time > 0) {
96 update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time); 56 // Update debounce counters with elapsed timer clamped to 127 (maximum debounce)
57 update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, 127));
97 } 58 }
98 } 59 }
99 60
@@ -102,74 +63,96 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
102 last_time = timer_read_fast(); 63 last_time = timer_read_fast();
103 } 64 }
104 65
105 transfer_matrix_values(raw, cooked, num_rows); 66 transfer_matrix_values(raw, cooked);
106 } 67 }
107 68
108 return cooked_changed; 69 return cooked_changed;
109} 70}
110 71
111static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) { 72/**
112 debounce_counter_t *debounce_pointer = debounce_counters; 73 * @brief Processes per-key debounce counters and updates the debounced matrix state.
113 74 *
75 * This function iterates through each key in the matrix and updates its debounce counter
76 * based on the elapsed time. If the debounce period has expired, the debounced state is
77 * updated accordingly for key-down (eager) and key-up (defer) events.
78 *
79 * @param raw The current raw key state matrix.
80 * @param cooked The debounced key state matrix to be updated.
81 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds.
82 */
83static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) {
114 counters_need_update = false; 84 counters_need_update = false;
115 matrix_need_update = false; 85 matrix_need_update = false;
116 86
117 for (uint8_t row = 0; row < num_rows; row++) { 87 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
88 uint16_t row_offset = row * MATRIX_COLS;
89
118 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 90 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
119 matrix_row_t col_mask = (ROW_SHIFTER << col); 91 uint16_t index = row_offset + col;
120 92
121 if (debounce_pointer->time != DEBOUNCE_ELAPSED) { 93 if (debounce_counters[index].time != DEBOUNCE_ELAPSED) {
122 if (debounce_pointer->time <= elapsed_time) { 94 if (debounce_counters[index].time <= elapsed_time) {
123 debounce_pointer->time = DEBOUNCE_ELAPSED; 95 debounce_counters[index].time = DEBOUNCE_ELAPSED;
124 96
125 if (debounce_pointer->pressed) { 97 if (debounce_counters[index].pressed) {
126 // key-down: eager 98 // key-down: eager
127 matrix_need_update = true; 99 matrix_need_update = true;
128 } else { 100 } else {
129 // key-up: defer 101 // key-up: defer
102 matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col);
130 matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask); 103 matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
131 cooked_changed |= cooked_next ^ cooked[row]; 104 cooked_changed |= cooked_next ^ cooked[row];
132 cooked[row] = cooked_next; 105 cooked[row] = cooked_next;
133 } 106 }
134 } else { 107 } else {
135 debounce_pointer->time -= elapsed_time; 108 debounce_counters[index].time -= elapsed_time;
136 counters_need_update = true; 109 counters_need_update = true;
137 } 110 }
138 } 111 }
139 debounce_pointer++;
140 } 112 }
141 } 113 }
142} 114}
143 115
144static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { 116/**
145 debounce_counter_t *debounce_pointer = debounce_counters; 117 * @brief Applies debounced changes to the matrix state based on per-key counters.
146 118 *
119 * This function compares the raw and cooked key state matrices to detect changes.
120 * For each key, it updates the debounce counter and the debounced state according
121 * to the debounce algorithm. Key-down events are handled eagerly, while key-up
122 * events are deferred until the debounce period has elapsed.
123 *
124 * @param raw The current raw key state matrix.
125 * @param cooked The debounced key state matrix to be updated.
126 */
127static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) {
147 matrix_need_update = false; 128 matrix_need_update = false;
148 129
149 for (uint8_t row = 0; row < num_rows; row++) { 130 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
150 matrix_row_t delta = raw[row] ^ cooked[row]; 131 uint16_t row_offset = row * MATRIX_COLS;
132 matrix_row_t delta = raw[row] ^ cooked[row];
133
151 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 134 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
152 matrix_row_t col_mask = (ROW_SHIFTER << col); 135 uint16_t index = row_offset + col;
136 matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col);
153 137
154 if (delta & col_mask) { 138 if (delta & col_mask) {
155 if (debounce_pointer->time == DEBOUNCE_ELAPSED) { 139 if (debounce_counters[index].time == DEBOUNCE_ELAPSED) {
156 debounce_pointer->pressed = (raw[row] & col_mask); 140 debounce_counters[index].pressed = (raw[row] & col_mask);
157 debounce_pointer->time = DEBOUNCE; 141 debounce_counters[index].time = DEBOUNCE;
158 counters_need_update = true; 142 counters_need_update = true;
159 143
160 if (debounce_pointer->pressed) { 144 if (debounce_counters[index].pressed) {
161 // key-down: eager 145 // key-down: eager
162 cooked[row] ^= col_mask; 146 cooked[row] ^= col_mask;
163 cooked_changed = true; 147 cooked_changed = true;
164 } 148 }
165 } 149 }
166 } else if (debounce_pointer->time != DEBOUNCE_ELAPSED) { 150 } else if (debounce_counters[index].time != DEBOUNCE_ELAPSED) {
167 if (!debounce_pointer->pressed) { 151 if (!debounce_counters[index].pressed) {
168 // key-up: defer 152 // key-up: defer
169 debounce_pointer->time = DEBOUNCE_ELAPSED; 153 debounce_counters[index].time = DEBOUNCE_ELAPSED;
170 } 154 }
171 } 155 }
172 debounce_pointer++;
173 } 156 }
174 } 157 }
175} 158}
diff --git a/quantum/debounce/none.c b/quantum/debounce/none.c
index 0a8ccfc4ee..0111dd6e31 100644
--- a/quantum/debounce/none.c
+++ b/quantum/debounce/none.c
@@ -32,5 +32,3 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
32 32
33 return cooked_changed; 33 return cooked_changed;
34} 34}
35
36void debounce_free(void) {}
diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c
index d96758fab3..81f351c126 100644
--- a/quantum/debounce/sym_defer_g.c
+++ b/quantum/debounce/sym_defer_g.c
@@ -1,22 +1,10 @@
1/* 1// Copyright 2017 Alex Ong<the.onga@gmail.com>
2Copyright 2017 Alex Ong<the.onga@gmail.com> 2// Copyright 2021 Simon Arlott
3Copyright 2021 Simon Arlott 3// SPDX-License-Identifier: GPL-2.0-or-later
4This program is free software: you can redistribute it and/or modify 4//
5it under the terms of the GNU General Public License as published by 5// Basic global debounce algorithm. Used in 99% of keyboards at time of implementation
6the Free Software Foundation, either version 2 of the License, or 6// When no state changes have occured for DEBOUNCE milliseconds, we push the state.
7(at your option) any later version. 7
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12You should have received a copy of the GNU General Public License
13along with this program. If not, see <http://www.gnu.org/licenses/>.
14*/
15
16/*
17Basic global debounce algorithm. Used in 99% of keyboards at time of implementation
18When no state changes have occured for DEBOUNCE milliseconds, we push the state.
19*/
20#include "debounce.h" 8#include "debounce.h"
21#include "timer.h" 9#include "timer.h"
22#include <string.h> 10#include <string.h>
@@ -31,13 +19,13 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
31#endif 19#endif
32 20
33#if DEBOUNCE > 0 21#if DEBOUNCE > 0
34static bool debouncing = false;
35static fast_timer_t debouncing_time;
36 22
37void debounce_init(uint8_t num_rows) {} 23void debounce_init(uint8_t num_rows) {}
38 24
39bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { 25bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
40 bool cooked_changed = false; 26 static fast_timer_t debouncing_time;
27 static bool debouncing = false;
28 bool cooked_changed = false;
41 29
42 if (changed) { 30 if (changed) {
43 debouncing = true; 31 debouncing = true;
@@ -54,7 +42,6 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
54 return cooked_changed; 42 return cooked_changed;
55} 43}
56 44
57void debounce_free(void) {}
58#else // no debouncing. 45#else // no debouncing.
59# include "none.c" 46# include "none.c"
60#endif 47#endif
diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c
index 156535a373..063094efe5 100644
--- a/quantum/debounce/sym_defer_pk.c
+++ b/quantum/debounce/sym_defer_pk.c
@@ -1,33 +1,14 @@
1/* 1// Copyright 2017 Alex Ong<the.onga@gmail.com>
2Copyright 2017 Alex Ong<the.onga@gmail.com> 2// Copyright 2020 Andrei Purdea<andrei@purdea.ro>
3Copyright 2020 Andrei Purdea<andrei@purdea.ro> 3// Copyright 2021 Simon Arlott
4Copyright 2021 Simon Arlott 4// SPDX-License-Identifier: GPL-2.0-or-later
5This program is free software: you can redistribute it and/or modify 5//
6it under the terms of the GNU General Public License as published by 6// Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
7the Free Software Foundation, either version 2 of the License, or 7// When no state changes have occured for DEBOUNCE milliseconds, we push the state.
8(at your option) any later version.
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13You should have received a copy of the GNU General Public License
14along with this program. If not, see <http://www.gnu.org/licenses/>.
15*/
16
17/*
18Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
19When no state changes have occured for DEBOUNCE milliseconds, we push the state.
20*/
21 8
22#include "debounce.h" 9#include "debounce.h"
23#include "timer.h" 10#include "timer.h"
24#include <stdlib.h> 11#include "util.h"
25
26#ifdef PROTOCOL_CHIBIOS
27# if CH_CFG_USE_MEMCORE == FALSE
28# 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.
29# endif
30#endif
31 12
32#ifndef DEBOUNCE 13#ifndef DEBOUNCE
33# define DEBOUNCE 5 14# define DEBOUNCE 5
@@ -39,40 +20,24 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
39# define DEBOUNCE UINT8_MAX 20# define DEBOUNCE UINT8_MAX
40#endif 21#endif
41 22
42#define ROW_SHIFTER ((matrix_row_t)1) 23#define DEBOUNCE_ELAPSED 0
43 24
25#if DEBOUNCE > 0
44typedef uint8_t debounce_counter_t; 26typedef uint8_t debounce_counter_t;
27// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards
28static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED};
29static bool counters_need_update;
30static bool cooked_changed;
45 31
46#if DEBOUNCE > 0 32static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time);
47static debounce_counter_t *debounce_counters; 33static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]);
48static fast_timer_t last_time;
49static bool counters_need_update;
50static bool cooked_changed;
51
52# define DEBOUNCE_ELAPSED 0
53
54static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
55static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
56
57// we use num_rows rather than MATRIX_ROWS to support split keyboards
58void debounce_init(uint8_t num_rows) {
59 debounce_counters = (debounce_counter_t *)malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
60 int i = 0;
61 for (uint8_t r = 0; r < num_rows; r++) {
62 for (uint8_t c = 0; c < MATRIX_COLS; c++) {
63 debounce_counters[i++] = DEBOUNCE_ELAPSED;
64 }
65 }
66}
67 34
68void debounce_free(void) { 35void debounce_init(uint8_t num_rows) {}
69 free(debounce_counters);
70 debounce_counters = NULL;
71}
72 36
73bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { 37bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
74 bool updated_last = false; 38 static fast_timer_t last_time;
75 cooked_changed = false; 39 bool updated_last = false;
40 cooked_changed = false;
76 41
77 if (counters_need_update) { 42 if (counters_need_update) {
78 fast_timer_t now = timer_read_fast(); 43 fast_timer_t now = timer_read_fast();
@@ -80,12 +45,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
80 45
81 last_time = now; 46 last_time = now;
82 updated_last = true; 47 updated_last = true;
83 if (elapsed_time > UINT8_MAX) {
84 elapsed_time = UINT8_MAX;
85 }
86 48
87 if (elapsed_time > 0) { 49 if (elapsed_time > 0) {
88 update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time); 50 // Update debounce counters with elapsed timer clamped to UINT8_MAX
51 update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, UINT8_MAX));
89 } 52 }
90 } 53 }
91 54
@@ -94,47 +57,73 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
94 last_time = timer_read_fast(); 57 last_time = timer_read_fast();
95 } 58 }
96 59
97 start_debounce_counters(raw, cooked, num_rows); 60 start_debounce_counters(raw, cooked);
98 } 61 }
99 62
100 return cooked_changed; 63 return cooked_changed;
101} 64}
102 65
103static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) { 66/**
104 counters_need_update = false; 67 * @brief Updates debounce counters and transfers debounced key states if the debounce period has expired.
105 debounce_counter_t *debounce_pointer = debounce_counters; 68 *
106 for (uint8_t row = 0; row < num_rows; row++) { 69 * Iterates through each key in the matrix and checks its debounce counter. If the debounce period has expired
70 * for a key, the debounced state is updated to match the raw state. Otherwise, the debounce counter is decremented
71 * by the elapsed time and marked for further updates.
72 *
73 * @param raw The current raw key state matrix.
74 * @param cooked The debounced key state matrix to be updated.
75 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds.
76 */
77static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) {
78 counters_need_update = false;
79 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
80 uint16_t row_offset = row * MATRIX_COLS;
81
107 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 82 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
108 if (*debounce_pointer != DEBOUNCE_ELAPSED) { 83 uint16_t index = row_offset + col;
109 if (*debounce_pointer <= elapsed_time) { 84
110 *debounce_pointer = DEBOUNCE_ELAPSED; 85 if (debounce_counters[index] != DEBOUNCE_ELAPSED) {
111 matrix_row_t cooked_next = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col)); 86 if (debounce_counters[index] <= elapsed_time) {
87 debounce_counters[index] = DEBOUNCE_ELAPSED;
88 matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col);
89 matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
112 cooked_changed |= cooked[row] ^ cooked_next; 90 cooked_changed |= cooked[row] ^ cooked_next;
113 cooked[row] = cooked_next; 91 cooked[row] = cooked_next;
114 } else { 92 } else {
115 *debounce_pointer -= elapsed_time; 93 debounce_counters[index] -= elapsed_time;
116 counters_need_update = true; 94 counters_need_update = true;
117 } 95 }
118 } 96 }
119 debounce_pointer++;
120 } 97 }
121 } 98 }
122} 99}
123 100
124static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { 101/**
125 debounce_counter_t *debounce_pointer = debounce_counters; 102 * @brief Initializes debounce counters for keys with changed states.
126 for (uint8_t row = 0; row < num_rows; row++) { 103 *
127 matrix_row_t delta = raw[row] ^ cooked[row]; 104 * For each key in the matrix, this function checks if the raw state differs from the debounced state.
105 * If a change is detected and the debounce counter has elapsed, the counter is set to the debounce period
106 * and marked for update. Otherwise, the counter is cleared.
107 *
108 * @param raw The current raw key state matrix.
109 * @param cooked The debounced key state matrix.
110 */
111static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]) {
112 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
113 uint16_t row_offset = row * MATRIX_COLS;
114 matrix_row_t delta = raw[row] ^ cooked[row];
115
128 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 116 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
129 if (delta & (ROW_SHIFTER << col)) { 117 uint16_t index = row_offset + col;
130 if (*debounce_pointer == DEBOUNCE_ELAPSED) { 118
131 *debounce_pointer = DEBOUNCE; 119 if (delta & (MATRIX_ROW_SHIFTER << col)) {
132 counters_need_update = true; 120 if (debounce_counters[index] == DEBOUNCE_ELAPSED) {
121 debounce_counters[index] = DEBOUNCE;
122 counters_need_update = true;
133 } 123 }
134 } else { 124 } else {
135 *debounce_pointer = DEBOUNCE_ELAPSED; 125 debounce_counters[index] = DEBOUNCE_ELAPSED;
136 } 126 }
137 debounce_pointer++;
138 } 127 }
139 } 128 }
140} 129}
diff --git a/quantum/debounce/sym_defer_pr.c b/quantum/debounce/sym_defer_pr.c
index d6222af5b2..2382fae898 100644
--- a/quantum/debounce/sym_defer_pr.c
+++ b/quantum/debounce/sym_defer_pr.c
@@ -1,77 +1,117 @@
1/* 1// Copyright 2017 Alex Ong<the.onga@gmail.com>
2Copyright 2021 Chad Austin <chad@chadaustin.me> 2// Copyright 2020 Andrei Purdea<andrei@purdea.ro>
3This program is free software: you can redistribute it and/or modify 3// Copyright 2021 Simon Arlott
4it under the terms of the GNU General Public License as published by 4// Copyright @filterpaper
5the Free Software Foundation, either version 2 of the License, or 5// SPDX-License-Identifier: GPL-2.0-or-later
6(at your option) any later version. 6//
7This program is distributed in the hope that it will be useful, 7// Basic symmetric per-row algorithm. Uses an 8-bit counter per row.
8but WITHOUT ANY WARRANTY; without even the implied warranty of 8// When no state changes have occured for DEBOUNCE milliseconds, we push the state.
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15/*
16Symmetric per-row debounce algorithm. Changes only apply when
17DEBOUNCE milliseconds have elapsed since the last change.
18*/
19 9
20#include "debounce.h" 10#include "debounce.h"
21#include "timer.h" 11#include "timer.h"
22#include <stdlib.h> 12#include "util.h"
23 13
24#ifndef DEBOUNCE 14#ifndef DEBOUNCE
25# define DEBOUNCE 5 15# define DEBOUNCE 5
26#endif 16#endif
27 17
28static uint16_t last_time; 18// Maximum debounce: 255ms
29// [row] milliseconds until key's state is considered debounced. 19#if DEBOUNCE > UINT8_MAX
30static uint8_t* countdowns; 20# undef DEBOUNCE
31// [row] 21# define DEBOUNCE UINT8_MAX
32static matrix_row_t* last_raw; 22#endif
33 23
34void debounce_init(uint8_t num_rows) { 24#define DEBOUNCE_ELAPSED 0
35 countdowns = (uint8_t*)calloc(num_rows, sizeof(uint8_t));
36 last_raw = (matrix_row_t*)calloc(num_rows, sizeof(matrix_row_t));
37 25
38 last_time = timer_read(); 26#if DEBOUNCE > 0
39} 27typedef uint8_t debounce_counter_t;
28// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards
29static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND] = {DEBOUNCE_ELAPSED};
30static bool counters_need_update;
31static bool cooked_changed;
40 32
41void debounce_free(void) { 33static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time);
42 free(countdowns); 34static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]);
43 countdowns = NULL; 35
44 free(last_raw); 36void debounce_init(uint8_t num_rows) {}
45 last_raw = NULL;
46}
47 37
48bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { 38bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
49 uint16_t now = timer_read(); 39 static fast_timer_t last_time;
50 uint16_t elapsed16 = TIMER_DIFF_16(now, last_time); 40 bool updated_last = false;
51 last_time = now; 41 cooked_changed = false;
52 uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16; 42
53 bool cooked_changed = false; 43 if (counters_need_update) {
54 44 fast_timer_t now = timer_read_fast();
55 uint8_t* countdown = countdowns; 45 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
56 46
57 for (uint8_t row = 0; row < num_rows; ++row, ++countdown) { 47 last_time = now;
58 matrix_row_t raw_row = raw[row]; 48 updated_last = true;
59 49
60 if (raw_row != last_raw[row]) { 50 if (elapsed_time > 0) {
61 *countdown = DEBOUNCE; 51 // Update debounce counters with elapsed timer clamped to UINT8_MAX
62 last_raw[row] = raw_row; 52 update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, UINT8_MAX));
63 } else if (*countdown > elapsed) {
64 *countdown -= elapsed;
65 } else if (*countdown) {
66 cooked_changed |= cooked[row] ^ raw_row;
67 cooked[row] = raw_row;
68 *countdown = 0;
69 } 53 }
70 } 54 }
71 55
56 if (changed) {
57 if (!updated_last) {
58 last_time = timer_read_fast();
59 }
60
61 start_debounce_counters(raw, cooked);
62 }
63
72 return cooked_changed; 64 return cooked_changed;
73} 65}
74 66
75bool debounce_active(void) { 67/**
76 return true; 68 * @brief Updates debounce counters and transfers debounced row states if the debounce period has expired.
69 *
70 * Iterates through each row in the matrix and checks its debounce counter. If the debounce period has expired
71 * for a row, the debounced state is updated to match the raw state. Otherwise, the debounce counter is decremented
72 * by the elapsed time and marked for further updates.
73 *
74 * @param raw The current raw key state matrix.
75 * @param cooked The debounced key state matrix to be updated.
76 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds.
77 */
78static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) {
79 counters_need_update = false;
80 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
81 if (debounce_counters[row] != DEBOUNCE_ELAPSED) {
82 if (debounce_counters[row] <= elapsed_time) {
83 debounce_counters[row] = DEBOUNCE_ELAPSED;
84 cooked_changed |= cooked[row] ^ raw[row];
85 cooked[row] = raw[row];
86 } else {
87 debounce_counters[row] -= elapsed_time;
88 counters_need_update = true;
89 }
90 }
91 }
77} 92}
93
94/**
95 * @brief Initializes debounce counters for rows with changed states.
96 *
97 * For each row in the matrix, this function checks if the raw state differs from the debounced state.
98 * If a change is detected and the debounce counter has elapsed, the counter is set to the debounce period
99 * and marked for update. Otherwise, the counter is cleared.
100 *
101 * @param raw The current raw key state matrix.
102 * @param cooked The debounced key state matrix.
103 */
104static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]) {
105 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
106 if (raw[row] != cooked[row]) {
107 debounce_counters[row] = DEBOUNCE;
108 counters_need_update = true;
109 } else {
110 debounce_counters[row] = DEBOUNCE_ELAPSED;
111 }
112 }
113}
114
115#else
116# include "none.c"
117#endif
diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c
index b359e79287..c3a7afde24 100644
--- a/quantum/debounce/sym_eager_pk.c
+++ b/quantum/debounce/sym_eager_pk.c
@@ -21,13 +21,7 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
21 21
22#include "debounce.h" 22#include "debounce.h"
23#include "timer.h" 23#include "timer.h"
24#include <stdlib.h> 24#include "util.h"
25
26#ifdef PROTOCOL_CHIBIOS
27# if CH_CFG_USE_MEMCORE == FALSE
28# 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.
29# endif
30#endif
31 25
32#ifndef DEBOUNCE 26#ifndef DEBOUNCE
33# define DEBOUNCE 5 27# define DEBOUNCE 5
@@ -39,41 +33,25 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
39# define DEBOUNCE UINT8_MAX 33# define DEBOUNCE UINT8_MAX
40#endif 34#endif
41 35
42#define ROW_SHIFTER ((matrix_row_t)1) 36#define DEBOUNCE_ELAPSED 0
43 37
38#if DEBOUNCE > 0
44typedef uint8_t debounce_counter_t; 39typedef uint8_t debounce_counter_t;
40// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards
41static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED};
42static bool counters_need_update;
43static bool matrix_need_update;
44static bool cooked_changed;
45 45
46#if DEBOUNCE > 0 46static inline void update_debounce_counters(uint8_t elapsed_time);
47static debounce_counter_t *debounce_counters; 47static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]);
48static fast_timer_t last_time;
49static bool counters_need_update;
50static bool matrix_need_update;
51static bool cooked_changed;
52
53# define DEBOUNCE_ELAPSED 0
54
55static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
56static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
57
58// we use num_rows rather than MATRIX_ROWS to support split keyboards
59void debounce_init(uint8_t num_rows) {
60 debounce_counters = (debounce_counter_t *)malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
61 int i = 0;
62 for (uint8_t r = 0; r < num_rows; r++) {
63 for (uint8_t c = 0; c < MATRIX_COLS; c++) {
64 debounce_counters[i++] = DEBOUNCE_ELAPSED;
65 }
66 }
67}
68 48
69void debounce_free(void) { 49void debounce_init(uint8_t num_rows) {}
70 free(debounce_counters);
71 debounce_counters = NULL;
72}
73 50
74bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { 51bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
75 bool updated_last = false; 52 static fast_timer_t last_time;
76 cooked_changed = false; 53 bool updated_last = false;
54 cooked_changed = false;
77 55
78 if (counters_need_update) { 56 if (counters_need_update) {
79 fast_timer_t now = timer_read_fast(); 57 fast_timer_t now = timer_read_fast();
@@ -81,12 +59,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
81 59
82 last_time = now; 60 last_time = now;
83 updated_last = true; 61 updated_last = true;
84 if (elapsed_time > UINT8_MAX) {
85 elapsed_time = UINT8_MAX;
86 }
87 62
88 if (elapsed_time > 0) { 63 if (elapsed_time > 0) {
89 update_debounce_counters(num_rows, elapsed_time); 64 // Update debounce counters with elapsed timer clamped to UINT8_MAX
65 update_debounce_counters(MIN(elapsed_time, UINT8_MAX));
90 } 66 }
91 } 67 }
92 68
@@ -95,51 +71,74 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
95 last_time = timer_read_fast(); 71 last_time = timer_read_fast();
96 } 72 }
97 73
98 transfer_matrix_values(raw, cooked, num_rows); 74 transfer_matrix_values(raw, cooked);
99 } 75 }
100 76
101 return cooked_changed; 77 return cooked_changed;
102} 78}
103 79
104// If the current time is > debounce counter, set the counter to enable input. 80/**
105static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) { 81 * @brief Updates per-key debounce counters and determines if matrix needs updating.
106 counters_need_update = false; 82 *
107 matrix_need_update = false; 83 * Iterates through each key in the matrix and checks its debounce counter. If the debounce
108 debounce_counter_t *debounce_pointer = debounce_counters; 84 * period has elapsed, the counter is reset and the matrix is marked for update. Otherwise,
109 for (uint8_t row = 0; row < num_rows; row++) { 85 * the counter is decremented by the elapsed time and marked for further updates if needed.
86 *
87 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds.
88 */
89static inline void update_debounce_counters(uint8_t elapsed_time) {
90 counters_need_update = false;
91 matrix_need_update = false;
92
93 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
94 uint16_t row_offset = row * MATRIX_COLS;
95
110 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 96 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
111 if (*debounce_pointer != DEBOUNCE_ELAPSED) { 97 uint16_t index = row_offset + col;
112 if (*debounce_pointer <= elapsed_time) { 98
113 *debounce_pointer = DEBOUNCE_ELAPSED; 99 if (debounce_counters[index] != DEBOUNCE_ELAPSED) {
114 matrix_need_update = true; 100 if (debounce_counters[index] <= elapsed_time) {
101 debounce_counters[index] = DEBOUNCE_ELAPSED;
102 matrix_need_update = true;
115 } else { 103 } else {
116 *debounce_pointer -= elapsed_time; 104 debounce_counters[index] -= elapsed_time;
117 counters_need_update = true; 105 counters_need_update = true;
118 } 106 }
119 } 107 }
120 debounce_pointer++;
121 } 108 }
122 } 109 }
123} 110}
124 111
125// upload from raw_matrix to final matrix; 112/**
126static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { 113 * @brief Transfers debounced key states from the raw matrix to the cooked matrix.
127 matrix_need_update = false; 114 *
128 debounce_counter_t *debounce_pointer = debounce_counters; 115 * For each key in the matrix, this function checks if its state has changed and if its
129 for (uint8_t row = 0; row < num_rows; row++) { 116 * debounce counter has elapsed. If so, the debounce counter is reset, the cooked matrix
117 * is updated to reflect the new state, and the matrix is marked for further updates.
118 *
119 * @param raw The current raw key state matrix.
120 * @param cooked The debounced key state matrix to be updated.
121 */
122static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) {
123 matrix_need_update = false;
124
125 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
126 uint16_t row_offset = row * MATRIX_COLS;
130 matrix_row_t delta = raw[row] ^ cooked[row]; 127 matrix_row_t delta = raw[row] ^ cooked[row];
131 matrix_row_t existing_row = cooked[row]; 128 matrix_row_t existing_row = cooked[row];
129
132 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 130 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
133 matrix_row_t col_mask = (ROW_SHIFTER << col); 131 uint16_t index = row_offset + col;
132
133 matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col);
134 if (delta & col_mask) { 134 if (delta & col_mask) {
135 if (*debounce_pointer == DEBOUNCE_ELAPSED) { 135 if (debounce_counters[index] == DEBOUNCE_ELAPSED) {
136 *debounce_pointer = DEBOUNCE; 136 debounce_counters[index] = DEBOUNCE;
137 counters_need_update = true; 137 counters_need_update = true;
138 existing_row ^= col_mask; // flip the bit. 138 existing_row ^= col_mask; // flip the bit.
139 cooked_changed = true; 139 cooked_changed = true;
140 } 140 }
141 } 141 }
142 debounce_pointer++;
143 } 142 }
144 cooked[row] = existing_row; 143 cooked[row] = existing_row;
145 } 144 }
diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c
index 6cd9308aff..5a1e3a1bda 100644
--- a/quantum/debounce/sym_eager_pr.c
+++ b/quantum/debounce/sym_eager_pr.c
@@ -1,33 +1,14 @@
1/* 1// Copyright 2017 Alex Ong<the.onga@gmail.com>
2Copyright 2019 Alex Ong<the.onga@gmail.com> 2// Copyright 2021 Simon Arlott
3Copyright 2021 Simon Arlott 3// SPDX-License-Identifier: GPL-2.0-or-later
4This program is free software: you can redistribute it and/or modify 4//
5it under the terms of the GNU General Public License as published by 5// Basic per-row algorithm. Uses an 8-bit counter per key.
6the Free Software Foundation, either version 2 of the License, or 6// After pressing a key, it immediately changes state, and sets a counter.
7(at your option) any later version. 7// No further inputs are accepted until DEBOUNCE milliseconds have occurred.
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12You should have received a copy of the GNU General Public License
13along with this program. If not, see <http://www.gnu.org/licenses/>.
14*/
15
16/*
17Basic per-row algorithm. Uses an 8-bit counter per row.
18After pressing a key, it immediately changes state, and sets a counter.
19No further inputs are accepted until DEBOUNCE milliseconds have occurred.
20*/
21 8
22#include "debounce.h" 9#include "debounce.h"
23#include "timer.h" 10#include "timer.h"
24#include <stdlib.h> 11#include "util.h"
25
26#ifdef PROTOCOL_CHIBIOS
27# if CH_CFG_USE_MEMCORE == FALSE
28# 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.
29# endif
30#endif
31 12
32#ifndef DEBOUNCE 13#ifndef DEBOUNCE
33# define DEBOUNCE 5 14# define DEBOUNCE 5
@@ -39,37 +20,25 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
39# define DEBOUNCE UINT8_MAX 20# define DEBOUNCE UINT8_MAX
40#endif 21#endif
41 22
42typedef uint8_t debounce_counter_t; 23#define DEBOUNCE_ELAPSED 0
43 24
44#if DEBOUNCE > 0 25#if DEBOUNCE > 0
45static bool matrix_need_update; 26typedef uint8_t debounce_counter_t;
46 27// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards
47static debounce_counter_t *debounce_counters; 28static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND] = {DEBOUNCE_ELAPSED};
48static fast_timer_t last_time; 29static bool counters_need_update;
49static bool counters_need_update; 30static bool matrix_need_update;
50static bool cooked_changed; 31static bool cooked_changed;
51
52# define DEBOUNCE_ELAPSED 0
53
54static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
55static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
56 32
57// we use num_rows rather than MATRIX_ROWS to support split keyboards 33static inline void update_debounce_counters(uint8_t elapsed_time);
58void debounce_init(uint8_t num_rows) { 34static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]);
59 debounce_counters = (debounce_counter_t *)malloc(num_rows * sizeof(debounce_counter_t));
60 for (uint8_t r = 0; r < num_rows; r++) {
61 debounce_counters[r] = DEBOUNCE_ELAPSED;
62 }
63}
64 35
65void debounce_free(void) { 36void debounce_init(uint8_t num_rows) {}
66 free(debounce_counters);
67 debounce_counters = NULL;
68}
69 37
70bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { 38bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
71 bool updated_last = false; 39 static fast_timer_t last_time;
72 cooked_changed = false; 40 bool updated_last = false;
41 cooked_changed = false;
73 42
74 if (counters_need_update) { 43 if (counters_need_update) {
75 fast_timer_t now = timer_read_fast(); 44 fast_timer_t now = timer_read_fast();
@@ -77,12 +46,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
77 46
78 last_time = now; 47 last_time = now;
79 updated_last = true; 48 updated_last = true;
80 if (elapsed_time > UINT8_MAX) {
81 elapsed_time = UINT8_MAX;
82 }
83 49
84 if (elapsed_time > 0) { 50 if (elapsed_time > 0) {
85 update_debounce_counters(num_rows, elapsed_time); 51 // Update debounce counters with elapsed timer clamped to UINT8_MAX
52 update_debounce_counters(MIN(elapsed_time, UINT8_MAX));
86 } 53 }
87 } 54 }
88 55
@@ -91,49 +58,64 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
91 last_time = timer_read_fast(); 58 last_time = timer_read_fast();
92 } 59 }
93 60
94 transfer_matrix_values(raw, cooked, num_rows); 61 transfer_matrix_values(raw, cooked);
95 } 62 }
96 63
97 return cooked_changed; 64 return cooked_changed;
98} 65}
99 66
100// If the current time is > debounce counter, set the counter to enable input. 67/**
101static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) { 68 * @brief Updates per-row debounce counters and determines if matrix needs updating.
102 counters_need_update = false; 69 *
103 matrix_need_update = false; 70 * Iterates through each row in the matrix and checks its debounce counter. If the debounce
104 debounce_counter_t *debounce_pointer = debounce_counters; 71 * period has elapsed, the counter is reset and the matrix is marked for update. Otherwise,
105 for (uint8_t row = 0; row < num_rows; row++) { 72 * the counter is decremented by the elapsed time and marked for further updates if needed.
106 if (*debounce_pointer != DEBOUNCE_ELAPSED) { 73 *
107 if (*debounce_pointer <= elapsed_time) { 74 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds.
108 *debounce_pointer = DEBOUNCE_ELAPSED; 75 */
109 matrix_need_update = true; 76static inline void update_debounce_counters(uint8_t elapsed_time) {
77 counters_need_update = false;
78 matrix_need_update = false;
79
80 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
81 if (debounce_counters[row] != DEBOUNCE_ELAPSED) {
82 if (debounce_counters[row] <= elapsed_time) {
83 debounce_counters[row] = DEBOUNCE_ELAPSED;
84 matrix_need_update = true;
110 } else { 85 } else {
111 *debounce_pointer -= elapsed_time; 86 debounce_counters[row] -= elapsed_time;
112 counters_need_update = true; 87 counters_need_update = true;
113 } 88 }
114 } 89 }
115 debounce_pointer++;
116 } 90 }
117} 91}
118 92
119// upload from raw_matrix to final matrix; 93/**
120static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { 94 * @brief Transfers debounced key states from the raw matrix to the cooked matrix.
121 matrix_need_update = false; 95 *
122 debounce_counter_t *debounce_pointer = debounce_counters; 96 * For each row in the matrix, this function checks if its state has changed and if its
123 for (uint8_t row = 0; row < num_rows; row++) { 97 * debounce counter has elapsed. If so, the debounce counter is reset, the cooked matrix
98 * is updated to reflect the new state, and the matrix is marked for further updates.
99 *
100 * @param raw The current raw key state matrix.
101 * @param cooked The debounced key state matrix
102 */
103static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) {
104 matrix_need_update = false;
105
106 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
124 matrix_row_t existing_row = cooked[row]; 107 matrix_row_t existing_row = cooked[row];
125 matrix_row_t raw_row = raw[row]; 108 matrix_row_t raw_row = raw[row];
126 109
127 // determine new value basd on debounce pointer + raw value 110 // determine new value basd on debounce pointer + raw value
128 if (existing_row != raw_row) { 111 if (existing_row != raw_row) {
129 if (*debounce_pointer == DEBOUNCE_ELAPSED) { 112 if (debounce_counters[row] == DEBOUNCE_ELAPSED) {
130 *debounce_pointer = DEBOUNCE; 113 debounce_counters[row] = DEBOUNCE;
131 cooked_changed |= cooked[row] ^ raw_row; 114 cooked_changed |= cooked[row] ^ raw_row;
132 cooked[row] = raw_row; 115 cooked[row] = raw_row;
133 counters_need_update = true; 116 counters_need_update = true;
134 } 117 }
135 } 118 }
136 debounce_pointer++;
137 } 119 }
138} 120}
139 121
diff --git a/quantum/debounce/tests/debounce_test_common.cpp b/quantum/debounce/tests/debounce_test_common.cpp
index fd4b6f01a6..3782f51411 100644
--- a/quantum/debounce/tests/debounce_test_common.cpp
+++ b/quantum/debounce/tests/debounce_test_common.cpp
@@ -121,8 +121,6 @@ void DebounceTest::runEventsInternal() {
121 checkCookedMatrix(false, "debounce() modified cooked matrix"); 121 checkCookedMatrix(false, "debounce() modified cooked matrix");
122 advance_time(1); 122 advance_time(1);
123 } 123 }
124
125 debounce_free();
126} 124}
127 125
128void DebounceTest::runDebounce(bool changed) { 126void DebounceTest::runDebounce(bool changed) {