2020-04-11 14:29:48 +03:00
/*
Copyright 2017 Alex Ong < the . onga @ gmail . com >
Copyright 2020 Andrei Purdea < andrei @ purdea . ro >
2021-06-09 08:23:21 +01:00
Copyright 2021 Simon Arlott
2020-04-11 14:29:48 +03:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
Basic symmetric per - key algorithm . Uses an 8 - bit counter per key .
When no state changes have occured for DEBOUNCE milliseconds , we push the state .
*/
2023-07-09 11:05:20 +10:00
# include "debounce.h"
2020-04-11 14:29:48 +03:00
# include "timer.h"
# include <stdlib.h>
2021-01-30 15:13:56 +11:00
# 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
2020-04-11 14:29:48 +03:00
# ifndef DEBOUNCE
# define DEBOUNCE 5
# endif
2021-06-09 08:23:21 +01:00
// Maximum debounce: 255ms
# if DEBOUNCE > UINT8_MAX
# undef DEBOUNCE
# define DEBOUNCE UINT8_MAX
# endif
2020-04-11 14:29:48 +03:00
# define ROW_SHIFTER ((matrix_row_t)1)
2021-06-09 08:23:21 +01:00
typedef uint8_t debounce_counter_t ;
2020-04-11 14:29:48 +03:00
2021-06-09 08:23:21 +01:00
# if DEBOUNCE > 0
2020-04-11 14:29:48 +03:00
static debounce_counter_t * debounce_counters ;
2021-06-09 08:23:21 +01:00
static fast_timer_t last_time ;
2020-04-11 14:29:48 +03:00
static bool counters_need_update ;
2022-07-07 10:00:40 +02:00
static bool cooked_changed ;
2020-04-11 14:29:48 +03:00
2021-11-01 19:18:33 +00:00
# define DEBOUNCE_ELAPSED 0
2020-04-11 14:29:48 +03:00
2021-06-09 08:23:21 +01:00
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 ) ;
2020-04-11 14:29:48 +03:00
// 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 ;
}
}
}
2021-06-09 08:23:21 +01:00
void debounce_free ( void ) {
free ( debounce_counters ) ;
debounce_counters = NULL ;
}
2022-07-07 10:00:40 +02:00
bool debounce ( matrix_row_t raw [ ] , matrix_row_t cooked [ ] , uint8_t num_rows , bool changed ) {
2021-06-09 08:23:21 +01:00
bool updated_last = false ;
2022-07-07 10:00:40 +02:00
cooked_changed = false ;
2021-06-09 08:23:21 +01:00
2020-04-11 14:29:48 +03:00
if ( counters_need_update ) {
2021-11-01 19:18:33 +00:00
fast_timer_t now = timer_read_fast ( ) ;
2021-06-09 08:23:21 +01:00
fast_timer_t elapsed_time = TIMER_DIFF_FAST ( now , last_time ) ;
2021-11-01 19:18:33 +00:00
last_time = now ;
2021-06-09 08:23:21 +01:00
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 ) ;
}
2020-04-11 14:29:48 +03:00
}
if ( changed ) {
2021-06-09 08:23:21 +01:00
if ( ! updated_last ) {
last_time = timer_read_fast ( ) ;
}
start_debounce_counters ( raw , cooked , num_rows ) ;
2020-04-11 14:29:48 +03:00
}
2022-07-07 10:00:40 +02:00
return cooked_changed ;
2020-04-11 14:29:48 +03:00
}
2021-06-09 08:23:21 +01:00
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 ) {
2020-04-11 14:29:48 +03:00
counters_need_update = false ;
debounce_counter_t * debounce_pointer = debounce_counters ;
for ( uint8_t row = 0 ; row < num_rows ; row + + ) {
for ( uint8_t col = 0 ; col < MATRIX_COLS ; col + + ) {
if ( * debounce_pointer ! = DEBOUNCE_ELAPSED ) {
2021-06-09 08:23:21 +01:00
if ( * debounce_pointer < = elapsed_time ) {
2022-07-07 10:00:40 +02:00
* debounce_pointer = DEBOUNCE_ELAPSED ;
matrix_row_t cooked_next = ( cooked [ row ] & ~ ( ROW_SHIFTER < < col ) ) | ( raw [ row ] & ( ROW_SHIFTER < < col ) ) ;
cooked_changed | = cooked [ row ] ^ cooked_next ;
cooked [ row ] = cooked_next ;
2020-04-11 14:29:48 +03:00
} else {
2021-06-09 08:23:21 +01:00
* debounce_pointer - = elapsed_time ;
2020-04-11 14:29:48 +03:00
counters_need_update = true ;
}
}
debounce_pointer + + ;
}
}
}
2021-06-09 08:23:21 +01:00
static void start_debounce_counters ( matrix_row_t raw [ ] , matrix_row_t cooked [ ] , uint8_t num_rows ) {
2020-04-11 14:29:48 +03:00
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 ) {
2021-06-09 08:23:21 +01:00
* debounce_pointer = DEBOUNCE ;
2020-04-11 14:29:48 +03:00
counters_need_update = true ;
}
} else {
* debounce_pointer = DEBOUNCE_ELAPSED ;
}
debounce_pointer + + ;
}
}
}
2021-06-09 08:23:21 +01:00
# else
# include "none.c"
# endif