From 28f2bc5b05a17b18f4ffd006fda3286298f3d49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=AB=E3=82=BF=E3=83=BC=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=83=91=E3=83=BC?= <76888457+filterpaper@users.noreply.github.com> Date: Thu, 24 Jul 2025 09:44:19 +0800 Subject: [PATCH 1/5] Refactor debounce counters with direct indexing * Refactor code to use array indexing for debounce_counters * Use global MATRIX_ROW_SHIFTER macro --- quantum/debounce/asym_eager_defer_pk.c | 40 +++++++++++------------- quantum/debounce/sym_defer_pk.c | 33 ++++++++++---------- quantum/debounce/sym_defer_pr.c | 42 ++++++++++++-------------- quantum/debounce/sym_eager_pk.c | 34 ++++++++++----------- quantum/debounce/sym_eager_pr.c | 24 ++++++--------- 5 files changed, 78 insertions(+), 95 deletions(-) diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c index b6fcdc3d4e7..78b34f8e39a 100644 --- a/quantum/debounce/asym_eager_defer_pk.c +++ b/quantum/debounce/asym_eager_defer_pk.c @@ -43,8 +43,6 @@ 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) - typedef struct { bool pressed : 1; uint8_t time : 7; @@ -109,67 +107,63 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool } 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); + uint16_t index = row * MATRIX_COLS + 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; - matrix_need_update = false; 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); + uint16_t index = row * MATRIX_COLS + 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/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c index 156535a3733..e4136a20e73 100644 --- a/quantum/debounce/sym_defer_pk.c +++ b/quantum/debounce/sym_defer_pk.c @@ -39,8 +39,6 @@ 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) - typedef uint8_t debounce_counter_t; #if DEBOUNCE > 0 @@ -101,40 +99,41 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool } 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; + counters_need_update = false; for (uint8_t row = 0; row < num_rows; row++) { 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 * MATRIX_COLS + 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]; 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 * MATRIX_COLS + 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 d6222af5b29..3ef98bb3634 100644 --- a/quantum/debounce/sym_defer_pr.c +++ b/quantum/debounce/sym_defer_pr.c @@ -19,32 +19,32 @@ DEBOUNCE milliseconds have elapsed since the last change. #include "debounce.h" #include "timer.h" -#include #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; +// Countdown timers for each matrix row, indexed by row. +static uint8_t countdowns[MATRIX_ROWS_PER_HAND] = {0}; +// Last raw state for each matrix row, indexed by row. +static matrix_row_t last_raw[MATRIX_ROWS_PER_HAND] = {0}; -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)); - - last_time = timer_read(); -} - -void debounce_free(void) { - free(countdowns); - countdowns = NULL; - free(last_raw); - last_raw = NULL; -} +void debounce_init(uint8_t num_rows) {} +/** + * @brief Debounces the raw matrix state and updates the cooked (debounced) state. + * + * For each row in the matrix, this function tracks changes and applies a debounce period. + * If a row's state changes, its countdown timer is reset. If the countdown timer expires, + * the debounced state is updated to match the raw state. + * + * @param raw The current raw key state matrix. + * @param cooked The debounced key state matrix to be updated. + * @param num_rows Number of rows in the matrix. + * @param changed True if the raw matrix has changed since the last call. + * @return true if the debounced matrix has new key changes, false otherwise. + */ 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); @@ -54,7 +54,7 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool uint8_t* countdown = countdowns; - for (uint8_t row = 0; row < num_rows; ++row, ++countdown) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; ++row, ++countdown) { matrix_row_t raw_row = raw[row]; if (raw_row != last_raw[row]) { @@ -71,7 +71,3 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool return cooked_changed; } - -bool debounce_active(void) { - return true; -} diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c index b359e79287e..f01aa9a5f41 100644 --- a/quantum/debounce/sym_eager_pk.c +++ b/quantum/debounce/sym_eager_pk.c @@ -39,8 +39,6 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. # define DEBOUNCE UINT8_MAX #endif -#define ROW_SHIFTER ((matrix_row_t)1) - typedef uint8_t debounce_counter_t; #if DEBOUNCE > 0 @@ -103,43 +101,43 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool // 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; + 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++) { - if (*debounce_pointer != DEBOUNCE_ELAPSED) { - if (*debounce_pointer <= elapsed_time) { - *debounce_pointer = DEBOUNCE_ELAPSED; - matrix_need_update = true; + uint16_t index = row * MATRIX_COLS + 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; + matrix_need_update = false; for (uint8_t row = 0; row < num_rows; row++) { 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 * MATRIX_COLS + 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 6cd9308affc..18a970366e5 100644 --- a/quantum/debounce/sym_eager_pr.c +++ b/quantum/debounce/sym_eager_pr.c @@ -99,41 +99,37 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool // 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; + counters_need_update = false; + matrix_need_update = false; 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; + 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; + matrix_need_update = false; for (uint8_t row = 0; row < num_rows; 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++; } } From 66193ec03e33019be2646fdb5e65913db7b99fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=AB=E3=82=BF=E3=83=BC=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=83=91=E3=83=BC?= <76888457+filterpaper@users.noreply.github.com> Date: Fri, 25 Jul 2025 12:07:30 +0800 Subject: [PATCH 2/5] 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() --- quantum/debounce.h | 2 - quantum/debounce/asym_eager_defer_pk.c | 71 ++++++++++--------- quantum/debounce/none.c | 4 +- quantum/debounce/sym_defer_g.c | 1 - quantum/debounce/sym_defer_pk.c | 68 ++++++++++-------- quantum/debounce/sym_defer_pr.c | 9 ++- quantum/debounce/sym_eager_pk.c | 70 +++++++++--------- quantum/debounce/sym_eager_pr.c | 68 +++++++++--------- .../debounce/tests/debounce_test_common.cpp | 2 - 9 files changed, 156 insertions(+), 139 deletions(-) diff --git a/quantum/debounce.h b/quantum/debounce.h index cea1f2b5260..30d2621d185 100644 --- a/quantum/debounce.h +++ b/quantum/debounce.h @@ -17,5 +17,3 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed); void debounce_init(uint8_t num_rows); - -void debounce_free(void); diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c index 78b34f8e39a..173c64beed1 100644 --- a/quantum/debounce/asym_eager_defer_pk.c +++ b/quantum/debounce/asym_eager_defer_pk.c @@ -25,7 +25,7 @@ releasing a key, that state is pushed after no changes occur for DEBOUNCE millis #include "debounce.h" #include "timer.h" -#include +#include "util.h" #ifdef PROTOCOL_CHIBIOS # if CH_CFG_USE_MEMCORE == FALSE @@ -49,32 +49,19 @@ typedef struct { } 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; +// 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] = {0}; +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); +static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time); +static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); -// 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_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; @@ -86,12 +73,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)); } } @@ -100,17 +85,28 @@ 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) { +/** + * @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 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++) { for (uint8_t col = 0; col < MATRIX_COLS; col++) { uint16_t index = row * MATRIX_COLS + col; @@ -137,10 +133,21 @@ static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], } } -static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { +/** + * @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 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++) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { matrix_row_t delta = raw[row] ^ cooked[row]; for (uint8_t col = 0; col < MATRIX_COLS; col++) { uint16_t index = row * MATRIX_COLS + col; diff --git a/quantum/debounce/none.c b/quantum/debounce/none.c index 0a8ccfc4eec..f996e478dbe 100644 --- a/quantum/debounce/none.c +++ b/quantum/debounce/none.c @@ -31,6 +31,4 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool } return cooked_changed; -} - -void debounce_free(void) {} +} \ No newline at end of file diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c index d96758fab35..a807e3e0bda 100644 --- a/quantum/debounce/sym_defer_g.c +++ b/quantum/debounce/sym_defer_g.c @@ -54,7 +54,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 e4136a20e73..9c1b57db9d8 100644 --- a/quantum/debounce/sym_defer_pk.c +++ b/quantum/debounce/sym_defer_pk.c @@ -21,7 +21,7 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state. #include "debounce.h" #include "timer.h" -#include +#include "util.h" #ifdef PROTOCOL_CHIBIOS # if CH_CFG_USE_MEMCORE == FALSE @@ -42,31 +42,18 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state. 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 cooked_changed; +// 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] = {0}; +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); +static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time); +static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]); -// 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; - } - } -} - -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; @@ -78,12 +65,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)); } } @@ -92,15 +77,26 @@ 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) { +/** + * @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 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 < num_rows; row++) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { for (uint8_t col = 0; col < MATRIX_COLS; col++) { uint16_t index = row * MATRIX_COLS + col; @@ -120,8 +116,18 @@ static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], } } -static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { - for (uint8_t row = 0; row < num_rows; 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 void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { matrix_row_t delta = raw[row] ^ cooked[row]; for (uint8_t col = 0; col < MATRIX_COLS; col++) { uint16_t index = row * MATRIX_COLS + col; diff --git a/quantum/debounce/sym_defer_pr.c b/quantum/debounce/sym_defer_pr.c index 3ef98bb3634..84437e03fa2 100644 --- a/quantum/debounce/sym_defer_pr.c +++ b/quantum/debounce/sym_defer_pr.c @@ -19,6 +19,8 @@ DEBOUNCE milliseconds have elapsed since the last change. #include "debounce.h" #include "timer.h" +#include "util.h" +#include #ifndef DEBOUNCE # define DEBOUNCE 5 @@ -30,7 +32,10 @@ static uint8_t countdowns[MATRIX_ROWS_PER_HAND] = {0}; // Last raw state for each matrix row, indexed by row. static matrix_row_t last_raw[MATRIX_ROWS_PER_HAND] = {0}; -void debounce_init(uint8_t num_rows) {} +void debounce_init(uint8_t num_rows) { + memset(countdowns, 0, sizeof(countdowns)); + memset(last_raw, 0, sizeof(last_raw)); +} /** * @brief Debounces the raw matrix state and updates the cooked (debounced) state. @@ -49,7 +54,7 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool uint16_t now = timer_read(); uint16_t elapsed16 = TIMER_DIFF_16(now, last_time); last_time = now; - uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16; + uint8_t elapsed = MIN(elapsed16, UINT8_MAX); bool cooked_changed = false; uint8_t* countdown = countdowns; diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c index f01aa9a5f41..b8cddd5c46e 100644 --- a/quantum/debounce/sym_eager_pk.c +++ b/quantum/debounce/sym_eager_pk.c @@ -21,7 +21,7 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. #include "debounce.h" #include "timer.h" -#include +#include "util.h" #ifdef PROTOCOL_CHIBIOS # if CH_CFG_USE_MEMCORE == FALSE @@ -42,32 +42,19 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. 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; -static bool cooked_changed; +// 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] = {0}; +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); +static void update_debounce_counters(uint8_t elapsed_time); +static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); -// 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; - } - } -} - -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; @@ -79,12 +66,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)); } } @@ -93,17 +78,25 @@ 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) { +/** + * @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 for a key, 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 void update_debounce_counters(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++) { for (uint8_t col = 0; col < MATRIX_COLS; col++) { uint16_t index = row * MATRIX_COLS + col; @@ -120,10 +113,19 @@ static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) { } } -// upload from raw_matrix to final matrix; -static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { +/** + * @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 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++) { + for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { matrix_row_t delta = raw[row] ^ cooked[row]; matrix_row_t existing_row = cooked[row]; for (uint8_t col = 0; col < MATRIX_COLS; col++) { diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c index 18a970366e5..d63da208c04 100644 --- a/quantum/debounce/sym_eager_pr.c +++ b/quantum/debounce/sym_eager_pr.c @@ -21,7 +21,7 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. #include "debounce.h" #include "timer.h" -#include +#include "util.h" #ifdef PROTOCOL_CHIBIOS # if CH_CFG_USE_MEMCORE == FALSE @@ -42,30 +42,19 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred. 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; -static bool cooked_changed; +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND] = {0}; +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); +static void update_debounce_counters(uint8_t elapsed_time); +static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); -// 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; - } -} - -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; @@ -77,12 +66,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,17 +78,25 @@ 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) { +/** + * @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 void update_debounce_counters(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++) { if (debounce_counters[row] != DEBOUNCE_ELAPSED) { if (debounce_counters[row] <= elapsed_time) { debounce_counters[row] = DEBOUNCE_ELAPSED; @@ -114,10 +109,19 @@ static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time) { } } -// upload from raw_matrix to final matrix; -static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) { +/** + * @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 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++) { + 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]; diff --git a/quantum/debounce/tests/debounce_test_common.cpp b/quantum/debounce/tests/debounce_test_common.cpp index fd4b6f01a62..3782f51411d 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) { From 54ece6abfa64e46a35f0bfde1ae1c11c50d1735e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=AB=E3=82=BF=E3=83=BC=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=83=91=E3=83=BC?= <76888457+filterpaper@users.noreply.github.com> Date: Sat, 26 Jul 2025 07:17:38 +0800 Subject: [PATCH 3/5] Rewrite sym_defer_pr * Modernise code using sym_defer_pk as template * Format consistency with other current algorithms --- quantum/debounce/sym_defer_pr.c | 144 ++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 43 deletions(-) diff --git a/quantum/debounce/sym_defer_pr.c b/quantum/debounce/sym_defer_pr.c index 84437e03fa2..e0dbd0dceee 100644 --- a/quantum/debounce/sym_defer_pr.c +++ b/quantum/debounce/sym_defer_pr.c @@ -1,5 +1,7 @@ /* -Copyright 2021 Chad Austin +Copyright 2017 Alex Ong +Copyright 2020 Andrei Purdea +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 @@ -13,66 +15,122 @@ along with this program. If not, see . */ /* -Symmetric per-row debounce algorithm. Changes only apply when -DEBOUNCE milliseconds have elapsed since the last change. +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 "util.h" -#include + +#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 -static uint16_t last_time; -// Countdown timers for each matrix row, indexed by row. -static uint8_t countdowns[MATRIX_ROWS_PER_HAND] = {0}; -// Last raw state for each matrix row, indexed by row. -static matrix_row_t last_raw[MATRIX_ROWS_PER_HAND] = {0}; +// Maximum debounce: 255ms +#if DEBOUNCE > UINT8_MAX +# undef DEBOUNCE +# define DEBOUNCE UINT8_MAX +#endif -void debounce_init(uint8_t num_rows) { - memset(countdowns, 0, sizeof(countdowns)); - memset(last_raw, 0, sizeof(last_raw)); -} +typedef uint8_t debounce_counter_t; + +#if DEBOUNCE > 0 +// Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards +static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND] = {0}; +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 elapsed_time); +static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]); + +void debounce_init(uint8_t num_rows) {} -/** - * @brief Debounces the raw matrix state and updates the cooked (debounced) state. - * - * For each row in the matrix, this function tracks changes and applies a debounce period. - * If a row's state changes, its countdown timer is reset. If the countdown timer expires, - * the debounced state is updated to match the raw state. - * - * @param raw The current raw key state matrix. - * @param cooked The debounced key state matrix to be updated. - * @param num_rows Number of rows in the matrix. - * @param changed True if the raw matrix has changed since the last call. - * @return true if the debounced matrix has new key changes, false otherwise. - */ 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 = MIN(elapsed16, UINT8_MAX); - bool cooked_changed = false; + bool updated_last = false; + cooked_changed = false; - uint8_t* countdown = countdowns; + if (counters_need_update) { + fast_timer_t now = timer_read_fast(); + fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); - for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; ++row, ++countdown) { - matrix_row_t raw_row = raw[row]; + last_time = now; + updated_last = true; - 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; + 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; } + +/** + * @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 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 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 \ No newline at end of file From bf6064d8887c924cfcea4c835cb6a349cbef7aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=AB=E3=82=BF=E3=83=BC=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=83=91=E3=83=BC?= <76888457+filterpaper@users.noreply.github.com> Date: Sat, 26 Jul 2025 07:46:40 +0800 Subject: [PATCH 4/5] Use shorter SPDX-License-Identifier --- quantum/debounce/asym_eager_defer_pk.c | 32 +++++++------------------- quantum/debounce/sym_defer_g.c | 24 +++++-------------- quantum/debounce/sym_defer_pk.c | 27 ++++++---------------- quantum/debounce/sym_defer_pr.c | 28 +++++++--------------- quantum/debounce/sym_eager_pk.c | 6 ++--- quantum/debounce/sym_eager_pr.c | 27 ++++++---------------- 6 files changed, 39 insertions(+), 105 deletions(-) diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c index 173c64beed1..88b860545c1 100644 --- a/quantum/debounce/asym_eager_defer_pk.c +++ b/quantum/debounce/asym_eager_defer_pk.c @@ -1,27 +1,11 @@ -/* - * Copyright 2017 Alex Ong - * Copyright 2020 Andrei Purdea - * 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 . - */ - -/* -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 +// Copyright 2020 Andrei Purdea +// 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" diff --git a/quantum/debounce/sym_defer_g.c b/quantum/debounce/sym_defer_g.c index a807e3e0bda..4dad528cd95 100644 --- a/quantum/debounce/sym_defer_g.c +++ b/quantum/debounce/sym_defer_g.c @@ -1,22 +1,10 @@ -/* -Copyright 2017 Alex Ong -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 . -*/ +// Copyright 2017 Alex Ong +// 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. -/* -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 diff --git a/quantum/debounce/sym_defer_pk.c b/quantum/debounce/sym_defer_pk.c index 9c1b57db9d8..ba23702c43f 100644 --- a/quantum/debounce/sym_defer_pk.c +++ b/quantum/debounce/sym_defer_pk.c @@ -1,23 +1,10 @@ -/* -Copyright 2017 Alex Ong -Copyright 2020 Andrei Purdea -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 . -*/ - -/* -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 +// Copyright 2020 Andrei Purdea +// 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" diff --git a/quantum/debounce/sym_defer_pr.c b/quantum/debounce/sym_defer_pr.c index e0dbd0dceee..98fa3125b77 100644 --- a/quantum/debounce/sym_defer_pr.c +++ b/quantum/debounce/sym_defer_pr.c @@ -1,23 +1,11 @@ -/* -Copyright 2017 Alex Ong -Copyright 2020 Andrei Purdea -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 . -*/ - -/* -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. -*/ +// Copyright 2017 Alex Ong +// Copyright 2020 Andrei Purdea +// 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" diff --git a/quantum/debounce/sym_eager_pk.c b/quantum/debounce/sym_eager_pk.c index b8cddd5c46e..17918fb3889 100644 --- a/quantum/debounce/sym_eager_pk.c +++ b/quantum/debounce/sym_eager_pk.c @@ -87,9 +87,9 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool /** * @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 for a key, 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. + * 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. */ diff --git a/quantum/debounce/sym_eager_pr.c b/quantum/debounce/sym_eager_pr.c index d63da208c04..d047acd1c5a 100644 --- a/quantum/debounce/sym_eager_pr.c +++ b/quantum/debounce/sym_eager_pr.c @@ -1,23 +1,10 @@ -/* -Copyright 2019 Alex Ong -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 . -*/ - -/* -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 +// 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" From 52a90587e49d07a1e37488ec1a6f3acd471113b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=95=E3=82=A3=E3=83=AB=E3=82=BF=E3=83=BC=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=83=91=E3=83=BC?= <76888457+filterpaper@users.noreply.github.com> Date: Sat, 26 Jul 2025 08:24:58 +0800 Subject: [PATCH 5/5] Add change log --- docs/ChangeLog/20250831/PR25515.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/ChangeLog/20250831/PR25515.md diff --git a/docs/ChangeLog/20250831/PR25515.md b/docs/ChangeLog/20250831/PR25515.md new file mode 100644 index 00000000000..ccc88e0c64c --- /dev/null +++ b/docs/ChangeLog/20250831/PR25515.md @@ -0,0 +1,3 @@ +# Refactor debounce algorithm with static allocation [#25515](https://github.com/qmk/qmk_firmware/pull/25515) + +Removed dynamic memory allocation (malloc, free) from all debounce implementations for improved efficiency on embedded systems and to avoid runtime allocation overhead. Refactored state arrays to use direct indexing, simplifying code and eliminating pointer arithmetic. Standardized usage of MATRIX_ROWS_PER_HAND throughout the codebase to ensure consistent support for split keyboards.