diff options
Diffstat (limited to 'quantum/debounce')
-rw-r--r-- | quantum/debounce/asym_eager_defer_pk.c | 165 | ||||
-rw-r--r-- | quantum/debounce/none.c | 2 | ||||
-rw-r--r-- | quantum/debounce/sym_defer_g.c | 33 | ||||
-rw-r--r-- | quantum/debounce/sym_defer_pk.c | 149 | ||||
-rw-r--r-- | quantum/debounce/sym_defer_pr.c | 154 | ||||
-rw-r--r-- | quantum/debounce/sym_eager_pk.c | 125 | ||||
-rw-r--r-- | quantum/debounce/sym_eager_pr.c | 136 | ||||
-rw-r--r-- | quantum/debounce/tests/debounce_test_common.cpp | 2 |
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 @@ -/* - * Copyright 2017 Alex Ong <[email protected]> - * Copyright 2020 Andrei Purdea <[email protected]> - * 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/>. - */ - -/* -Asymetric per-key algorithm. After pressing a key, it immediately changes state, -with no further inputs accepted until DEBOUNCE milliseconds have occurred. After -releasing a key, that state is pushed after no changes occur for DEBOUNCE milliseconds. -*/ +// Copyright 2017 Alex Ong <[email protected]> +// Copyright 2020 Andrei Purdea <[email protected]> +// Copyright 2021 Simon Arlott +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Asymetric per-key algorithm. After pressing a key, it immediately changes state, +// with no further inputs accepted until DEBOUNCE milliseconds have occurred. After +// releasing a key, that state is pushed after no changes occur for DEBOUNCE milliseconds. #include "debounce.h" #include "timer.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 +#include "util.h" #ifndef DEBOUNCE # define DEBOUNCE 5 @@ -43,44 +21,29 @@ releasing a key, that state is pushed after no changes occur for DEBOUNCE millis # define DEBOUNCE 127 #endif -#define ROW_SHIFTER ((matrix_row_t)1) +#define DEBOUNCE_ELAPSED 0 +#if DEBOUNCE > 0 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; -static bool cooked_changed; - -# 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; - } - } -} +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED}; +static bool counters_need_update; +static bool matrix_need_update; +static bool cooked_changed; -void debounce_free(void) { - free(debounce_counters); - debounce_counters = NULL; -} +static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time); +static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); + +void debounce_init(uint8_t num_rows) {} bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - bool updated_last = false; - cooked_changed = false; + static fast_timer_t last_time; + bool updated_last = false; + cooked_changed = false; if (counters_need_update) { 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 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); + // Update debounce counters with elapsed timer clamped to 127 (maximum debounce) + update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, 127)); } } @@ -102,74 +63,96 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool last_time = timer_read_fast(); } - transfer_matrix_values(raw, cooked, num_rows); + transfer_matrix_values(raw, cooked); } return cooked_changed; } -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; - +/** + * @brief Processes per-key debounce counters and updates the debounced matrix state. + * + * This function iterates through each key in the matrix and updates its debounce counter + * based on the elapsed time. If the debounce period has expired, the debounced state is + * updated accordingly for key-down (eager) and key-up (defer) events. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix to be updated. + * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. + */ +static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) { counters_need_update = false; matrix_need_update = false; - for (uint8_t row = 0; row < num_rows; row++) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + uint16_t row_offset = row * MATRIX_COLS; + for (uint8_t col = 0; col < MATRIX_COLS; col++) { - matrix_row_t col_mask = (ROW_SHIFTER << col); + uint16_t index = row_offset + col; - if (debounce_pointer->time != DEBOUNCE_ELAPSED) { - if (debounce_pointer->time <= elapsed_time) { - debounce_pointer->time = DEBOUNCE_ELAPSED; + if (debounce_counters[index].time != DEBOUNCE_ELAPSED) { + if (debounce_counters[index].time <= elapsed_time) { + debounce_counters[index].time = DEBOUNCE_ELAPSED; - if (debounce_pointer->pressed) { + if (debounce_counters[index].pressed) { // key-down: eager matrix_need_update = true; } else { // key-up: defer + matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col); matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask); cooked_changed |= cooked_next ^ cooked[row]; cooked[row] = cooked_next; } } else { - debounce_pointer->time -= elapsed_time; + debounce_counters[index].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; - +/** + * @brief Applies debounced changes to the matrix state based on per-key counters. + * + * This function compares the raw and cooked key state matrices to detect changes. + * For each key, it updates the debounce counter and the debounced state according + * to the debounce algorithm. Key-down events are handled eagerly, while key-up + * events are deferred until the debounce period has elapsed. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix to be updated. + */ +static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) { matrix_need_update = false; - for (uint8_t row = 0; row < num_rows; row++) { - matrix_row_t delta = raw[row] ^ cooked[row]; + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + uint16_t row_offset = row * MATRIX_COLS; + 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); + uint16_t index = row_offset + col; + matrix_row_t col_mask = (MATRIX_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_counters[index].time == DEBOUNCE_ELAPSED) { + debounce_counters[index].pressed = (raw[row] & col_mask); + debounce_counters[index].time = DEBOUNCE; + counters_need_update = true; - if (debounce_pointer->pressed) { + if (debounce_counters[index].pressed) { // key-down: eager cooked[row] ^= col_mask; cooked_changed = true; } } - } else if (debounce_pointer->time != DEBOUNCE_ELAPSED) { - if (!debounce_pointer->pressed) { + } else if (debounce_counters[index].time != DEBOUNCE_ELAPSED) { + if (!debounce_counters[index].pressed) { // key-up: defer - debounce_pointer->time = DEBOUNCE_ELAPSED; + debounce_counters[index].time = DEBOUNCE_ELAPSED; } } - debounce_pointer++; } } } 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 return cooked_changed; } - -void 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 @@ -/* -Copyright 2017 Alex Ong<[email protected]> -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 global debounce algorithm. Used in 99% of keyboards at time of implementation -When no state changes have occured for DEBOUNCE milliseconds, we push the state. -*/ +// Copyright 2017 Alex Ong<[email protected]> +// Copyright 2021 Simon Arlott +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Basic global debounce algorithm. Used in 99% of keyboards at time of implementation +// When no state changes have occured for DEBOUNCE milliseconds, we push the state. + #include "debounce.h" #include "timer.h" #include <string.h> @@ -31,13 +19,13 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state. #endif #if DEBOUNCE > 0 -static bool debouncing = false; -static fast_timer_t debouncing_time; void debounce_init(uint8_t num_rows) {} bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - bool cooked_changed = false; + static fast_timer_t debouncing_time; + static bool debouncing = false; + bool cooked_changed = false; if (changed) { debouncing = true; @@ -54,7 +42,6 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool return cooked_changed; } -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 156535a373..063094efe5 100644 --- a/quantum/debounce/sym_defer_pk.c +++ b/quantum/debounce/sym_defer_pk.c @@ -1,33 +1,14 @@ -/* -Copyright 2017 Alex Ong<[email protected]> -Copyright 2020 Andrei Purdea<[email protected]> -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. -*/ +// Copyright 2017 Alex Ong<[email protected]> +// Copyright 2020 Andrei Purdea<[email protected]> +// Copyright 2021 Simon Arlott +// SPDX-License-Identifier: GPL-2.0-or-later +// +// 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 "debounce.h" #include "timer.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 +#include "util.h" #ifndef DEBOUNCE # define DEBOUNCE 5 @@ -39,40 +20,24 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state. # define DEBOUNCE UINT8_MAX #endif -#define ROW_SHIFTER ((matrix_row_t)1) +#define DEBOUNCE_ELAPSED 0 +#if DEBOUNCE > 0 typedef uint8_t debounce_counter_t; +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED}; +static bool counters_need_update; +static bool cooked_changed; -#if DEBOUNCE > 0 -static debounce_counter_t *debounce_counters; -static fast_timer_t last_time; -static bool counters_need_update; -static bool cooked_changed; - -# 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 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) { - debounce_counters = (debounce_counter_t *)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++] = DEBOUNCE_ELAPSED; - } - } -} +static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time); +static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]); -void debounce_free(void) { - free(debounce_counters); - debounce_counters = NULL; -} +void debounce_init(uint8_t num_rows) {} bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - bool updated_last = false; - cooked_changed = false; + static fast_timer_t last_time; + bool updated_last = false; + cooked_changed = false; if (counters_need_update) { 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 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); + // Update debounce counters with elapsed timer clamped to UINT8_MAX + update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, UINT8_MAX)); } } @@ -94,47 +57,73 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool last_time = timer_read_fast(); } - start_debounce_counters(raw, cooked, num_rows); + start_debounce_counters(raw, cooked); } return cooked_changed; } -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++) { +/** + * @brief Updates debounce counters and transfers debounced key states if the debounce period has expired. + * + * Iterates through each key in the matrix and checks its debounce counter. If the debounce period has expired + * for a key, the debounced state is updated to match the raw state. Otherwise, the debounce counter is decremented + * by the elapsed time and marked for further updates. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix to be updated. + * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. + */ +static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) { + counters_need_update = false; + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + uint16_t row_offset = row * MATRIX_COLS; + for (uint8_t col = 0; col < MATRIX_COLS; col++) { - if (*debounce_pointer != DEBOUNCE_ELAPSED) { - if (*debounce_pointer <= elapsed_time) { - *debounce_pointer = DEBOUNCE_ELAPSED; - matrix_row_t cooked_next = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col)); + uint16_t index = row_offset + col; + + if (debounce_counters[index] != DEBOUNCE_ELAPSED) { + if (debounce_counters[index] <= elapsed_time) { + debounce_counters[index] = DEBOUNCE_ELAPSED; + matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col); + matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask); cooked_changed |= cooked[row] ^ cooked_next; cooked[row] = cooked_next; } else { - *debounce_pointer -= elapsed_time; + debounce_counters[index] -= elapsed_time; counters_need_update = true; } } - debounce_pointer++; } } } -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]; +/** + * @brief Initializes debounce counters for keys with changed states. + * + * For each key in the matrix, this function checks if the raw state differs from the debounced state. + * If a change is detected and the debounce counter has elapsed, the counter is set to the debounce period + * and marked for update. Otherwise, the counter is cleared. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix. + */ +static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + uint16_t row_offset = row * MATRIX_COLS; + 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 = DEBOUNCE; - counters_need_update = true; + uint16_t index = row_offset + col; + + if (delta & (MATRIX_ROW_SHIFTER << col)) { + if (debounce_counters[index] == DEBOUNCE_ELAPSED) { + debounce_counters[index] = DEBOUNCE; + counters_need_update = true; } } else { - *debounce_pointer = DEBOUNCE_ELAPSED; + debounce_counters[index] = DEBOUNCE_ELAPSED; } - debounce_pointer++; } } } 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 @@ -/* -Copyright 2021 Chad Austin <[email protected]> -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/>. -*/ - -/* -Symmetric per-row debounce algorithm. Changes only apply when -DEBOUNCE milliseconds have elapsed since the last change. -*/ +// Copyright 2017 Alex Ong<[email protected]> +// Copyright 2020 Andrei Purdea<[email protected]> +// Copyright 2021 Simon Arlott +// Copyright @filterpaper +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Basic symmetric per-row algorithm. Uses an 8-bit counter per row. +// When no state changes have occured for DEBOUNCE milliseconds, we push the state. #include "debounce.h" #include "timer.h" -#include <stdlib.h> +#include "util.h" #ifndef DEBOUNCE # define DEBOUNCE 5 #endif -static uint16_t last_time; -// [row] milliseconds until key's state is considered debounced. -static uint8_t* countdowns; -// [row] -static matrix_row_t* last_raw; +// Maximum debounce: 255ms +#if DEBOUNCE > UINT8_MAX +# undef DEBOUNCE +# define DEBOUNCE UINT8_MAX +#endif -void debounce_init(uint8_t num_rows) { - countdowns = (uint8_t*)calloc(num_rows, sizeof(uint8_t)); - last_raw = (matrix_row_t*)calloc(num_rows, sizeof(matrix_row_t)); +#define DEBOUNCE_ELAPSED 0 - last_time = timer_read(); -} +#if DEBOUNCE > 0 +typedef uint8_t debounce_counter_t; +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND] = {DEBOUNCE_ELAPSED}; +static bool counters_need_update; +static bool cooked_changed; -void debounce_free(void) { - free(countdowns); - countdowns = NULL; - free(last_raw); - last_raw = NULL; -} +static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time); +static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]); + +void debounce_init(uint8_t num_rows) {} bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - uint16_t now = timer_read(); - uint16_t elapsed16 = TIMER_DIFF_16(now, last_time); - last_time = now; - uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16; - bool cooked_changed = false; - - uint8_t* countdown = countdowns; - - for (uint8_t row = 0; row < num_rows; ++row, ++countdown) { - matrix_row_t raw_row = raw[row]; - - if (raw_row != last_raw[row]) { - *countdown = DEBOUNCE; - last_raw[row] = raw_row; - } else if (*countdown > elapsed) { - *countdown -= elapsed; - } else if (*countdown) { - cooked_changed |= cooked[row] ^ raw_row; - cooked[row] = raw_row; - *countdown = 0; + static fast_timer_t last_time; + bool updated_last = false; + cooked_changed = 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 > 0) { + // Update debounce counters with elapsed timer clamped to UINT8_MAX + update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, UINT8_MAX)); } } + if (changed) { + if (!updated_last) { + last_time = timer_read_fast(); + } + + start_debounce_counters(raw, cooked); + } + return cooked_changed; } -bool debounce_active(void) { - return true; +/** + * @brief Updates debounce counters and transfers debounced row states if the debounce period has expired. + * + * Iterates through each row in the matrix and checks its debounce counter. If the debounce period has expired + * for a row, the debounced state is updated to match the raw state. Otherwise, the debounce counter is decremented + * by the elapsed time and marked for further updates. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix to be updated. + * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. + */ +static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) { + counters_need_update = false; + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + if (debounce_counters[row] != DEBOUNCE_ELAPSED) { + if (debounce_counters[row] <= elapsed_time) { + debounce_counters[row] = DEBOUNCE_ELAPSED; + cooked_changed |= cooked[row] ^ raw[row]; + cooked[row] = raw[row]; + } else { + debounce_counters[row] -= elapsed_time; + counters_need_update = true; + } + } + } } + +/** + * @brief Initializes debounce counters for rows with changed states. + * + * For each row in the matrix, this function checks if the raw state differs from the debounced state. + * If a change is detected and the debounce counter has elapsed, the counter is set to the debounce period + * and marked for update. Otherwise, the counter is cleared. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix. + */ +static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + if (raw[row] != cooked[row]) { + debounce_counters[row] = DEBOUNCE; + counters_need_update = true; + } else { + debounce_counters[row] = DEBOUNCE_ELAPSED; + } + } +} + +#else +# include "none.c" +#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. #include "debounce.h" #include "timer.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 +#include "util.h" #ifndef DEBOUNCE # define DEBOUNCE 5 @@ -39,41 +33,25 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. # define DEBOUNCE UINT8_MAX #endif -#define ROW_SHIFTER ((matrix_row_t)1) +#define DEBOUNCE_ELAPSED 0 +#if DEBOUNCE > 0 typedef uint8_t debounce_counter_t; +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED}; +static bool counters_need_update; +static bool matrix_need_update; +static bool cooked_changed; -#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; -static bool cooked_changed; - -# define DEBOUNCE_ELAPSED 0 - -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) { - debounce_counters = (debounce_counter_t *)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++] = DEBOUNCE_ELAPSED; - } - } -} +static inline void update_debounce_counters(uint8_t elapsed_time); +static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); -void debounce_free(void) { - free(debounce_counters); - debounce_counters = NULL; -} +void debounce_init(uint8_t num_rows) {} bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - bool updated_last = false; - cooked_changed = false; + static fast_timer_t last_time; + bool updated_last = false; + cooked_changed = false; if (counters_need_update) { 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 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); + // Update debounce counters with elapsed timer clamped to UINT8_MAX + update_debounce_counters(MIN(elapsed_time, UINT8_MAX)); } } @@ -95,51 +71,74 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool last_time = timer_read_fast(); } - transfer_matrix_values(raw, cooked, num_rows); + transfer_matrix_values(raw, cooked); } return cooked_changed; } -// If the current time is > debounce counter, set the counter to enable input. -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++) { +/** + * @brief Updates per-key debounce counters and determines if matrix needs updating. + * + * Iterates through each key in the matrix and checks its debounce counter. If the debounce + * period has elapsed, the counter is reset and the matrix is marked for update. Otherwise, + * the counter is decremented by the elapsed time and marked for further updates if needed. + * + * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. + */ +static inline void update_debounce_counters(uint8_t elapsed_time) { + counters_need_update = false; + matrix_need_update = false; + + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + uint16_t row_offset = row * MATRIX_COLS; + for (uint8_t col = 0; col < MATRIX_COLS; col++) { - if (*debounce_pointer != DEBOUNCE_ELAPSED) { - if (*debounce_pointer <= elapsed_time) { - *debounce_pointer = DEBOUNCE_ELAPSED; - matrix_need_update = true; + uint16_t index = row_offset + col; + + if (debounce_counters[index] != DEBOUNCE_ELAPSED) { + if (debounce_counters[index] <= elapsed_time) { + debounce_counters[index] = DEBOUNCE_ELAPSED; + matrix_need_update = true; } else { - *debounce_pointer -= elapsed_time; + debounce_counters[index] -= elapsed_time; counters_need_update = true; } } - debounce_pointer++; } } } -// upload from raw_matrix to final matrix; -static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { - matrix_need_update = false; - debounce_counter_t *debounce_pointer = debounce_counters; - for (uint8_t row = 0; row < num_rows; row++) { +/** + * @brief Transfers debounced key states from the raw matrix to the cooked matrix. + * + * For each key in the matrix, this function checks if its state has changed and if its + * debounce counter has elapsed. If so, the debounce counter is reset, the cooked matrix + * is updated to reflect the new state, and the matrix is marked for further updates. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix to be updated. + */ +static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) { + matrix_need_update = false; + + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + uint16_t row_offset = row * MATRIX_COLS; matrix_row_t delta = raw[row] ^ cooked[row]; matrix_row_t existing_row = cooked[row]; + for (uint8_t col = 0; col < MATRIX_COLS; col++) { - matrix_row_t col_mask = (ROW_SHIFTER << col); + uint16_t index = row_offset + col; + + matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col); if (delta & col_mask) { - if (*debounce_pointer == DEBOUNCE_ELAPSED) { - *debounce_pointer = DEBOUNCE; - counters_need_update = true; + if (debounce_counters[index] == DEBOUNCE_ELAPSED) { + debounce_counters[index] = DEBOUNCE; + counters_need_update = true; existing_row ^= col_mask; // flip the bit. cooked_changed = true; } } - debounce_pointer++; } cooked[row] = existing_row; } 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 @@ -/* -Copyright 2019 Alex Ong<[email protected]> -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 per-row algorithm. Uses an 8-bit counter per row. -After pressing a key, it immediately changes state, and sets a counter. -No further inputs are accepted until DEBOUNCE milliseconds have occurred. -*/ +// Copyright 2017 Alex Ong<[email protected]> +// Copyright 2021 Simon Arlott +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Basic per-row algorithm. Uses an 8-bit counter per key. +// After pressing a key, it immediately changes state, and sets a counter. +// No further inputs are accepted until DEBOUNCE milliseconds have occurred. #include "debounce.h" #include "timer.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 +#include "util.h" #ifndef DEBOUNCE # define DEBOUNCE 5 @@ -39,37 +20,25 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. # define DEBOUNCE UINT8_MAX #endif -typedef uint8_t debounce_counter_t; +#define DEBOUNCE_ELAPSED 0 #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; -static bool cooked_changed; - -# define DEBOUNCE_ELAPSED 0 - -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); +typedef uint8_t debounce_counter_t; +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND] = {DEBOUNCE_ELAPSED}; +static bool counters_need_update; +static bool matrix_need_update; +static bool cooked_changed; -// we use num_rows rather than MATRIX_ROWS to support split keyboards -void debounce_init(uint8_t num_rows) { - debounce_counters = (debounce_counter_t *)malloc(num_rows * sizeof(debounce_counter_t)); - for (uint8_t r = 0; r < num_rows; r++) { - debounce_counters[r] = DEBOUNCE_ELAPSED; - } -} +static inline void update_debounce_counters(uint8_t elapsed_time); +static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); -void debounce_free(void) { - free(debounce_counters); - debounce_counters = NULL; -} +void debounce_init(uint8_t num_rows) {} bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) { - bool updated_last = false; - cooked_changed = false; + static fast_timer_t last_time; + bool updated_last = false; + cooked_changed = false; if (counters_need_update) { 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 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); + // Update debounce counters with elapsed timer clamped to UINT8_MAX + update_debounce_counters(MIN(elapsed_time, UINT8_MAX)); } } @@ -91,49 +58,64 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool last_time = timer_read_fast(); } - transfer_matrix_values(raw, cooked, num_rows); + transfer_matrix_values(raw, cooked); } return cooked_changed; } -// If the current time is > debounce counter, set the counter to enable input. -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 (*debounce_pointer <= elapsed_time) { - *debounce_pointer = DEBOUNCE_ELAPSED; - matrix_need_update = true; +/** + * @brief Updates per-row debounce counters and determines if matrix needs updating. + * + * Iterates through each row in the matrix and checks its debounce counter. If the debounce + * period has elapsed, the counter is reset and the matrix is marked for update. Otherwise, + * the counter is decremented by the elapsed time and marked for further updates if needed. + * + * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. + */ +static inline void update_debounce_counters(uint8_t elapsed_time) { + counters_need_update = false; + matrix_need_update = false; + + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { + if (debounce_counters[row] != DEBOUNCE_ELAPSED) { + if (debounce_counters[row] <= elapsed_time) { + debounce_counters[row] = DEBOUNCE_ELAPSED; + matrix_need_update = true; } else { - *debounce_pointer -= elapsed_time; + debounce_counters[row] -= elapsed_time; counters_need_update = true; } } - debounce_pointer++; } } -// upload from raw_matrix to final matrix; -static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { - matrix_need_update = false; - debounce_counter_t *debounce_pointer = debounce_counters; - for (uint8_t row = 0; row < num_rows; row++) { +/** + * @brief Transfers debounced key states from the raw matrix to the cooked matrix. + * + * For each row in the matrix, this function checks if its state has changed and if its + * debounce counter has elapsed. If so, the debounce counter is reset, the cooked matrix + * is updated to reflect the new state, and the matrix is marked for further updates. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix + */ +static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) { + matrix_need_update = false; + + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { matrix_row_t existing_row = cooked[row]; matrix_row_t raw_row = raw[row]; // determine new value basd on debounce pointer + raw value if (existing_row != raw_row) { - if (*debounce_pointer == DEBOUNCE_ELAPSED) { - *debounce_pointer = DEBOUNCE; + if (debounce_counters[row] == DEBOUNCE_ELAPSED) { + debounce_counters[row] = DEBOUNCE; cooked_changed |= cooked[row] ^ raw_row; cooked[row] = raw_row; counters_need_update = true; } } - debounce_pointer++; } } 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() { checkCookedMatrix(false, "debounce() modified cooked matrix"); advance_time(1); } - - debounce_free(); } void DebounceTest::runDebounce(bool changed) { |