mirror of
https://github.com/qmk/qmk_firmware.git
synced 2025-07-27 11:31:13 +00:00
Merge 52a90587e4
into 542440eac5
This commit is contained in:
commit
9fc72569a0
3
docs/ChangeLog/20250831/PR25515.md
Normal file
3
docs/ChangeLog/20250831/PR25515.md
Normal file
@ -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.
|
@ -17,5 +17,3 @@
|
|||||||
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed);
|
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_init(uint8_t num_rows);
|
||||||
|
|
||||||
void debounce_free(void);
|
|
||||||
|
@ -1,31 +1,15 @@
|
|||||||
/*
|
// Copyright 2017 Alex Ong <the.onga@gmail.com>
|
||||||
* Copyright 2017 Alex Ong <the.onga@gmail.com>
|
// Copyright 2020 Andrei Purdea <andrei@purdea.ro>
|
||||||
* Copyright 2020 Andrei Purdea <andrei@purdea.ro>
|
// Copyright 2021 Simon Arlott
|
||||||
* Copyright 2021 Simon Arlott
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*
|
//
|
||||||
* This program is free software: you can redistribute it and/or modify
|
// Asymetric per-key algorithm. After pressing a key, it immediately changes state,
|
||||||
* it under the terms of the GNU General Public License as published by
|
// with no further inputs accepted until DEBOUNCE milliseconds have occurred. After
|
||||||
* the Free Software Foundation, either version 2 of the License, or
|
// releasing a key, that state is pushed after no changes occur for DEBOUNCE milliseconds.
|
||||||
* (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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <stdlib.h>
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef PROTOCOL_CHIBIOS
|
#ifdef PROTOCOL_CHIBIOS
|
||||||
# if CH_CFG_USE_MEMCORE == FALSE
|
# if CH_CFG_USE_MEMCORE == FALSE
|
||||||
@ -43,15 +27,14 @@ releasing a key, that state is pushed after no changes occur for DEBOUNCE millis
|
|||||||
# define DEBOUNCE 127
|
# define DEBOUNCE 127
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ROW_SHIFTER ((matrix_row_t)1)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool pressed : 1;
|
bool pressed : 1;
|
||||||
uint8_t time : 7;
|
uint8_t time : 7;
|
||||||
} debounce_counter_t;
|
} debounce_counter_t;
|
||||||
|
|
||||||
#if DEBOUNCE > 0
|
#if DEBOUNCE > 0
|
||||||
static debounce_counter_t *debounce_counters;
|
// 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 fast_timer_t last_time;
|
||||||
static bool counters_need_update;
|
static bool counters_need_update;
|
||||||
static bool matrix_need_update;
|
static bool matrix_need_update;
|
||||||
@ -59,24 +42,10 @@ static bool cooked_changed;
|
|||||||
|
|
||||||
# define DEBOUNCE_ELAPSED 0
|
# 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 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[], uint8_t num_rows);
|
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) {}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
bool updated_last = false;
|
bool updated_last = false;
|
||||||
@ -88,12 +57,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
|
|
||||||
last_time = now;
|
last_time = now;
|
||||||
updated_last = true;
|
updated_last = true;
|
||||||
if (elapsed_time > UINT8_MAX) {
|
|
||||||
elapsed_time = UINT8_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elapsed_time > 0) {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,74 +69,92 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
last_time = timer_read_fast();
|
last_time = timer_read_fast();
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer_matrix_values(raw, cooked, num_rows);
|
transfer_matrix_values(raw, cooked);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cooked_changed;
|
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 void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) {
|
||||||
counters_need_update = false;
|
counters_need_update = false;
|
||||||
matrix_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++) {
|
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_counters[index].time != DEBOUNCE_ELAPSED) {
|
||||||
if (debounce_pointer->time <= elapsed_time) {
|
if (debounce_counters[index].time <= elapsed_time) {
|
||||||
debounce_pointer->time = DEBOUNCE_ELAPSED;
|
debounce_counters[index].time = DEBOUNCE_ELAPSED;
|
||||||
|
|
||||||
if (debounce_pointer->pressed) {
|
if (debounce_counters[index].pressed) {
|
||||||
// key-down: eager
|
// key-down: eager
|
||||||
matrix_need_update = true;
|
matrix_need_update = true;
|
||||||
} else {
|
} else {
|
||||||
// key-up: defer
|
// 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);
|
matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
|
||||||
cooked_changed |= cooked_next ^ cooked[row];
|
cooked_changed |= cooked_next ^ cooked[row];
|
||||||
cooked[row] = cooked_next;
|
cooked[row] = cooked_next;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debounce_pointer->time -= elapsed_time;
|
debounce_counters[index].time -= elapsed_time;
|
||||||
counters_need_update = true;
|
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 void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) {
|
||||||
matrix_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++) {
|
||||||
matrix_row_t delta = raw[row] ^ cooked[row];
|
matrix_row_t delta = raw[row] ^ cooked[row];
|
||||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
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 (delta & col_mask) {
|
||||||
if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
|
if (debounce_counters[index].time == DEBOUNCE_ELAPSED) {
|
||||||
debounce_pointer->pressed = (raw[row] & col_mask);
|
debounce_counters[index].pressed = (raw[row] & col_mask);
|
||||||
debounce_pointer->time = DEBOUNCE;
|
debounce_counters[index].time = DEBOUNCE;
|
||||||
counters_need_update = true;
|
counters_need_update = true;
|
||||||
|
|
||||||
if (debounce_pointer->pressed) {
|
if (debounce_counters[index].pressed) {
|
||||||
// key-down: eager
|
// key-down: eager
|
||||||
cooked[row] ^= col_mask;
|
cooked[row] ^= col_mask;
|
||||||
cooked_changed = true;
|
cooked_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
|
} else if (debounce_counters[index].time != DEBOUNCE_ELAPSED) {
|
||||||
if (!debounce_pointer->pressed) {
|
if (!debounce_counters[index].pressed) {
|
||||||
// key-up: defer
|
// key-up: defer
|
||||||
debounce_pointer->time = DEBOUNCE_ELAPSED;
|
debounce_counters[index].time = DEBOUNCE_ELAPSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debounce_pointer++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,5 +32,3 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
|
|
||||||
return cooked_changed;
|
return cooked_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void debounce_free(void) {}
|
|
||||||
|
@ -1,22 +1,10 @@
|
|||||||
/*
|
// Copyright 2017 Alex Ong<the.onga@gmail.com>
|
||||||
Copyright 2017 Alex Ong<the.onga@gmail.com>
|
// Copyright 2021 Simon Arlott
|
||||||
Copyright 2021 Simon Arlott
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
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
|
// Basic global debounce algorithm. Used in 99% of keyboards at time of implementation
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
// When no state changes have occured for DEBOUNCE milliseconds, we push the state.
|
||||||
(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.
|
|
||||||
*/
|
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -54,7 +42,6 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
return cooked_changed;
|
return cooked_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void debounce_free(void) {}
|
|
||||||
#else // no debouncing.
|
#else // no debouncing.
|
||||||
# include "none.c"
|
# include "none.c"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,27 +1,14 @@
|
|||||||
/*
|
// Copyright 2017 Alex Ong<the.onga@gmail.com>
|
||||||
Copyright 2017 Alex Ong<the.onga@gmail.com>
|
// Copyright 2020 Andrei Purdea<andrei@purdea.ro>
|
||||||
Copyright 2020 Andrei Purdea<andrei@purdea.ro>
|
// Copyright 2021 Simon Arlott
|
||||||
Copyright 2021 Simon Arlott
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
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
|
// Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
// When no state changes have occured for DEBOUNCE milliseconds, we push the state.
|
||||||
(at your option) any later version.
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
|
|
||||||
When no state changes have occured for DEBOUNCE milliseconds, we push the state.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <stdlib.h>
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef PROTOCOL_CHIBIOS
|
#ifdef PROTOCOL_CHIBIOS
|
||||||
# if CH_CFG_USE_MEMCORE == FALSE
|
# if CH_CFG_USE_MEMCORE == FALSE
|
||||||
@ -39,36 +26,21 @@ When no state changes have occured for DEBOUNCE milliseconds, we push the state.
|
|||||||
# define DEBOUNCE UINT8_MAX
|
# define DEBOUNCE UINT8_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ROW_SHIFTER ((matrix_row_t)1)
|
|
||||||
|
|
||||||
typedef uint8_t debounce_counter_t;
|
typedef uint8_t debounce_counter_t;
|
||||||
|
|
||||||
#if DEBOUNCE > 0
|
#if DEBOUNCE > 0
|
||||||
static debounce_counter_t *debounce_counters;
|
// 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 fast_timer_t last_time;
|
||||||
static bool counters_need_update;
|
static bool counters_need_update;
|
||||||
static bool cooked_changed;
|
static bool cooked_changed;
|
||||||
|
|
||||||
# define DEBOUNCE_ELAPSED 0
|
# 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 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[], uint8_t num_rows);
|
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) {}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
bool updated_last = false;
|
bool updated_last = false;
|
||||||
@ -80,12 +52,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
|
|
||||||
last_time = now;
|
last_time = now;
|
||||||
updated_last = true;
|
updated_last = true;
|
||||||
if (elapsed_time > UINT8_MAX) {
|
|
||||||
elapsed_time = UINT8_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elapsed_time > 0) {
|
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 +64,69 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
last_time = timer_read_fast();
|
last_time = timer_read_fast();
|
||||||
}
|
}
|
||||||
|
|
||||||
start_debounce_counters(raw, cooked, num_rows);
|
start_debounce_counters(raw, cooked);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cooked_changed;
|
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;
|
counters_need_update = false;
|
||||||
debounce_counter_t *debounce_pointer = debounce_counters;
|
for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
|
||||||
for (uint8_t row = 0; row < num_rows; row++) {
|
|
||||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
||||||
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
|
uint16_t index = row * MATRIX_COLS + col;
|
||||||
if (*debounce_pointer <= elapsed_time) {
|
|
||||||
*debounce_pointer = DEBOUNCE_ELAPSED;
|
if (debounce_counters[index] != DEBOUNCE_ELAPSED) {
|
||||||
matrix_row_t cooked_next = (cooked[row] & ~(ROW_SHIFTER << col)) | (raw[row] & (ROW_SHIFTER << col));
|
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_changed |= cooked[row] ^ cooked_next;
|
||||||
cooked[row] = cooked_next;
|
cooked[row] = cooked_next;
|
||||||
} else {
|
} else {
|
||||||
*debounce_pointer -= elapsed_time;
|
debounce_counters[index] -= elapsed_time;
|
||||||
counters_need_update = true;
|
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;
|
* @brief Initializes debounce counters for keys with changed states.
|
||||||
for (uint8_t row = 0; row < num_rows; row++) {
|
*
|
||||||
|
* 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];
|
matrix_row_t delta = raw[row] ^ cooked[row];
|
||||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
||||||
if (delta & (ROW_SHIFTER << col)) {
|
uint16_t index = row * MATRIX_COLS + col;
|
||||||
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
|
|
||||||
*debounce_pointer = DEBOUNCE;
|
if (delta & (MATRIX_ROW_SHIFTER << col)) {
|
||||||
|
if (debounce_counters[index] == DEBOUNCE_ELAPSED) {
|
||||||
|
debounce_counters[index] = DEBOUNCE;
|
||||||
counters_need_update = true;
|
counters_need_update = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*debounce_pointer = DEBOUNCE_ELAPSED;
|
debounce_counters[index] = DEBOUNCE_ELAPSED;
|
||||||
}
|
}
|
||||||
debounce_pointer++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,77 +1,124 @@
|
|||||||
/*
|
// Copyright 2017 Alex Ong<the.onga@gmail.com>
|
||||||
Copyright 2021 Chad Austin <chad@chadaustin.me>
|
// Copyright 2020 Andrei Purdea<andrei@purdea.ro>
|
||||||
This program is free software: you can redistribute it and/or modify
|
// Copyright 2021 Simon Arlott
|
||||||
it under the terms of the GNU General Public License as published by
|
// Copyright @filterpaper
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
(at your option) any later version.
|
//
|
||||||
This program is distributed in the hope that it will be useful,
|
// Basic symmetric per-row algorithm. Uses an 8-bit counter per row.
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// When no state changes have occured for DEBOUNCE milliseconds, we push the state.
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <stdlib.h>
|
#include "util.h"
|
||||||
|
|
||||||
|
#ifdef PROTOCOL_CHIBIOS
|
||||||
|
# if CH_CFG_USE_MEMCORE == FALSE
|
||||||
|
# error ChibiOS is configured without a memory allocator. Your keyboard may have set `#define CH_CFG_USE_MEMCORE FALSE`, which is incompatible with this debounce algorithm.
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DEBOUNCE
|
#ifndef DEBOUNCE
|
||||||
# define DEBOUNCE 5
|
# define DEBOUNCE 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint16_t last_time;
|
// Maximum debounce: 255ms
|
||||||
// [row] milliseconds until key's state is considered debounced.
|
#if DEBOUNCE > UINT8_MAX
|
||||||
static uint8_t* countdowns;
|
# undef DEBOUNCE
|
||||||
// [row]
|
# define DEBOUNCE UINT8_MAX
|
||||||
static matrix_row_t* last_raw;
|
#endif
|
||||||
|
|
||||||
void debounce_init(uint8_t num_rows) {
|
typedef uint8_t debounce_counter_t;
|
||||||
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();
|
#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;
|
||||||
|
|
||||||
void debounce_free(void) {
|
# define DEBOUNCE_ELAPSED 0
|
||||||
free(countdowns);
|
|
||||||
countdowns = NULL;
|
static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time);
|
||||||
free(last_raw);
|
static void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]);
|
||||||
last_raw = 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 debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
uint16_t now = timer_read();
|
bool updated_last = false;
|
||||||
uint16_t elapsed16 = TIMER_DIFF_16(now, last_time);
|
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;
|
last_time = now;
|
||||||
uint8_t elapsed = (elapsed16 > 255) ? 255 : elapsed16;
|
updated_last = true;
|
||||||
bool cooked_changed = false;
|
|
||||||
|
|
||||||
uint8_t* countdown = countdowns;
|
if (elapsed_time > 0) {
|
||||||
|
// Update debounce counters with elapsed timer clamped to UINT8_MAX
|
||||||
for (uint8_t row = 0; row < num_rows; ++row, ++countdown) {
|
update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, UINT8_MAX));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
if (!updated_last) {
|
||||||
|
last_time = timer_read_fast();
|
||||||
|
}
|
||||||
|
|
||||||
|
start_debounce_counters(raw, cooked);
|
||||||
|
}
|
||||||
|
|
||||||
return cooked_changed;
|
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 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
|
@ -21,7 +21,7 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
|
|||||||
|
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <stdlib.h>
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef PROTOCOL_CHIBIOS
|
#ifdef PROTOCOL_CHIBIOS
|
||||||
# if CH_CFG_USE_MEMCORE == FALSE
|
# if CH_CFG_USE_MEMCORE == FALSE
|
||||||
@ -39,12 +39,11 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
|
|||||||
# define DEBOUNCE UINT8_MAX
|
# define DEBOUNCE UINT8_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ROW_SHIFTER ((matrix_row_t)1)
|
|
||||||
|
|
||||||
typedef uint8_t debounce_counter_t;
|
typedef uint8_t debounce_counter_t;
|
||||||
|
|
||||||
#if DEBOUNCE > 0
|
#if DEBOUNCE > 0
|
||||||
static debounce_counter_t *debounce_counters;
|
// 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 fast_timer_t last_time;
|
||||||
static bool counters_need_update;
|
static bool counters_need_update;
|
||||||
static bool matrix_need_update;
|
static bool matrix_need_update;
|
||||||
@ -52,24 +51,10 @@ static bool cooked_changed;
|
|||||||
|
|
||||||
# define DEBOUNCE_ELAPSED 0
|
# define DEBOUNCE_ELAPSED 0
|
||||||
|
|
||||||
static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
|
static void update_debounce_counters(uint8_t elapsed_time);
|
||||||
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
|
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) {}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
bool updated_last = false;
|
bool updated_last = false;
|
||||||
@ -81,12 +66,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
|
|
||||||
last_time = now;
|
last_time = now;
|
||||||
updated_last = true;
|
updated_last = true;
|
||||||
if (elapsed_time > UINT8_MAX) {
|
|
||||||
elapsed_time = UINT8_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elapsed_time > 0) {
|
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 +78,68 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
last_time = timer_read_fast();
|
last_time = timer_read_fast();
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer_matrix_values(raw, cooked, num_rows);
|
transfer_matrix_values(raw, cooked);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cooked_changed;
|
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, 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;
|
counters_need_update = false;
|
||||||
matrix_need_update = false;
|
matrix_need_update = false;
|
||||||
debounce_counter_t *debounce_pointer = debounce_counters;
|
for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
|
||||||
for (uint8_t row = 0; row < num_rows; row++) {
|
|
||||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
||||||
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
|
uint16_t index = row * MATRIX_COLS + col;
|
||||||
if (*debounce_pointer <= elapsed_time) {
|
|
||||||
*debounce_pointer = DEBOUNCE_ELAPSED;
|
if (debounce_counters[index] != DEBOUNCE_ELAPSED) {
|
||||||
|
if (debounce_counters[index] <= elapsed_time) {
|
||||||
|
debounce_counters[index] = DEBOUNCE_ELAPSED;
|
||||||
matrix_need_update = true;
|
matrix_need_update = true;
|
||||||
} else {
|
} else {
|
||||||
*debounce_pointer -= elapsed_time;
|
debounce_counters[index] -= elapsed_time;
|
||||||
counters_need_update = true;
|
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) {
|
* @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;
|
matrix_need_update = false;
|
||||||
debounce_counter_t *debounce_pointer = debounce_counters;
|
for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
|
||||||
for (uint8_t row = 0; row < num_rows; row++) {
|
|
||||||
matrix_row_t delta = raw[row] ^ cooked[row];
|
matrix_row_t delta = raw[row] ^ cooked[row];
|
||||||
matrix_row_t existing_row = cooked[row];
|
matrix_row_t existing_row = cooked[row];
|
||||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
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 (delta & col_mask) {
|
||||||
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
|
if (debounce_counters[index] == DEBOUNCE_ELAPSED) {
|
||||||
*debounce_pointer = DEBOUNCE;
|
debounce_counters[index] = DEBOUNCE;
|
||||||
counters_need_update = true;
|
counters_need_update = true;
|
||||||
existing_row ^= col_mask; // flip the bit.
|
existing_row ^= col_mask; // flip the bit.
|
||||||
cooked_changed = true;
|
cooked_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debounce_pointer++;
|
|
||||||
}
|
}
|
||||||
cooked[row] = existing_row;
|
cooked[row] = existing_row;
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,14 @@
|
|||||||
/*
|
// Copyright 2017 Alex Ong<the.onga@gmail.com>
|
||||||
Copyright 2019 Alex Ong<the.onga@gmail.com>
|
// Copyright 2021 Simon Arlott
|
||||||
Copyright 2021 Simon Arlott
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
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
|
// Basic per-row algorithm. Uses an 8-bit counter per key.
|
||||||
the Free Software Foundation, either version 2 of the License, or
|
// After pressing a key, it immediately changes state, and sets a counter.
|
||||||
(at your option) any later version.
|
// No further inputs are accepted until DEBOUNCE milliseconds have occurred.
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "debounce.h"
|
#include "debounce.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <stdlib.h>
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef PROTOCOL_CHIBIOS
|
#ifdef PROTOCOL_CHIBIOS
|
||||||
# if CH_CFG_USE_MEMCORE == FALSE
|
# if CH_CFG_USE_MEMCORE == FALSE
|
||||||
@ -42,30 +29,19 @@ No further inputs are accepted until DEBOUNCE milliseconds have occurred.
|
|||||||
typedef uint8_t debounce_counter_t;
|
typedef uint8_t debounce_counter_t;
|
||||||
|
|
||||||
#if DEBOUNCE > 0
|
#if DEBOUNCE > 0
|
||||||
static bool matrix_need_update;
|
// 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 debounce_counter_t *debounce_counters;
|
|
||||||
static fast_timer_t last_time;
|
static fast_timer_t last_time;
|
||||||
static bool counters_need_update;
|
static bool counters_need_update;
|
||||||
|
static bool matrix_need_update;
|
||||||
static bool cooked_changed;
|
static bool cooked_changed;
|
||||||
|
|
||||||
# define DEBOUNCE_ELAPSED 0
|
# define DEBOUNCE_ELAPSED 0
|
||||||
|
|
||||||
static void update_debounce_counters(uint8_t num_rows, uint8_t elapsed_time);
|
static void update_debounce_counters(uint8_t elapsed_time);
|
||||||
static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
|
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) {}
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
|
||||||
bool updated_last = false;
|
bool updated_last = false;
|
||||||
@ -77,12 +53,10 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
|
|
||||||
last_time = now;
|
last_time = now;
|
||||||
updated_last = true;
|
updated_last = true;
|
||||||
if (elapsed_time > UINT8_MAX) {
|
|
||||||
elapsed_time = UINT8_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elapsed_time > 0) {
|
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 +65,62 @@ bool debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool
|
|||||||
last_time = timer_read_fast();
|
last_time = timer_read_fast();
|
||||||
}
|
}
|
||||||
|
|
||||||
transfer_matrix_values(raw, cooked, num_rows);
|
transfer_matrix_values(raw, cooked);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cooked_changed;
|
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;
|
counters_need_update = false;
|
||||||
matrix_need_update = false;
|
matrix_need_update = false;
|
||||||
debounce_counter_t *debounce_pointer = debounce_counters;
|
for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
|
||||||
for (uint8_t row = 0; row < num_rows; row++) {
|
if (debounce_counters[row] != DEBOUNCE_ELAPSED) {
|
||||||
if (*debounce_pointer != DEBOUNCE_ELAPSED) {
|
if (debounce_counters[row] <= elapsed_time) {
|
||||||
if (*debounce_pointer <= elapsed_time) {
|
debounce_counters[row] = DEBOUNCE_ELAPSED;
|
||||||
*debounce_pointer = DEBOUNCE_ELAPSED;
|
|
||||||
matrix_need_update = true;
|
matrix_need_update = true;
|
||||||
} else {
|
} else {
|
||||||
*debounce_pointer -= elapsed_time;
|
debounce_counters[row] -= elapsed_time;
|
||||||
counters_need_update = true;
|
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) {
|
* @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;
|
matrix_need_update = false;
|
||||||
debounce_counter_t *debounce_pointer = debounce_counters;
|
for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) {
|
||||||
for (uint8_t row = 0; row < num_rows; row++) {
|
|
||||||
matrix_row_t existing_row = cooked[row];
|
matrix_row_t existing_row = cooked[row];
|
||||||
matrix_row_t raw_row = raw[row];
|
matrix_row_t raw_row = raw[row];
|
||||||
|
|
||||||
// determine new value basd on debounce pointer + raw value
|
// determine new value basd on debounce pointer + raw value
|
||||||
if (existing_row != raw_row) {
|
if (existing_row != raw_row) {
|
||||||
if (*debounce_pointer == DEBOUNCE_ELAPSED) {
|
if (debounce_counters[row] == DEBOUNCE_ELAPSED) {
|
||||||
*debounce_pointer = DEBOUNCE;
|
debounce_counters[row] = DEBOUNCE;
|
||||||
cooked_changed |= cooked[row] ^ raw_row;
|
cooked_changed |= cooked[row] ^ raw_row;
|
||||||
cooked[row] = raw_row;
|
cooked[row] = raw_row;
|
||||||
counters_need_update = true;
|
counters_need_update = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debounce_pointer++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,8 +121,6 @@ void DebounceTest::runEventsInternal() {
|
|||||||
checkCookedMatrix(false, "debounce() modified cooked matrix");
|
checkCookedMatrix(false, "debounce() modified cooked matrix");
|
||||||
advance_time(1);
|
advance_time(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
debounce_free();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebounceTest::runDebounce(bool changed) {
|
void DebounceTest::runDebounce(bool changed) {
|
||||||
|
Loading…
Reference in New Issue
Block a user