2019-01-26 17:03:46 +11:00
/*
Copyright 2017 Alex Ong<the.onga@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Basic per-key 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 "matrix.h"
#include "timer.h"
2019-01-27 00:10:14 +11:00
#include "quantum.h"
2019-01-26 23:18:24 +11:00
#include <stdlib.h>
2019-01-26 17:03:46 +11:00
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
2019-01-26 17:03:46 +11:00
#ifndef DEBOUNCE
2019-08-30 11:19:03 -07:00
# define DEBOUNCE 5
2019-01-26 17:03:46 +11:00
#endif
2020-04-11 14:29:48 +03:00
#define ROW_SHIFTER ((matrix_row_t)1)
2019-01-26 17:03:46 +11:00
#define debounce_counter_t uint8_t
2019-01-26 23:18:24 +11:00
static debounce_counter_t * debounce_counters ;
2019-04-16 05:58:03 +10:00
static bool counters_need_update ;
2019-07-09 11:09:54 -07:00
static bool matrix_need_update ;
2019-01-26 17:03:46 +11:00
#define DEBOUNCE_ELAPSED 251
#define MAX_DEBOUNCE (DEBOUNCE_ELAPSED - 1)
2020-04-11 03:14:28 +03:00
static uint8_t wrapping_timer_read ( void ) {
2020-04-11 00:48:16 +00:00
static uint16_t time = 0 ;
2020-04-11 03:14:28 +03:00
static uint8_t last_result = 0 ;
2020-04-11 00:48:16 +00:00
uint16_t new_time = timer_read ();
uint16_t diff = new_time - time ;
time = new_time ;
last_result = ( last_result + diff ) % ( MAX_DEBOUNCE + 1 );
2020-04-11 03:14:28 +03:00
return last_result ;
}
2019-01-26 17:29:02 +11:00
void update_debounce_counters ( uint8_t num_rows , uint8_t current_time );
void transfer_matrix_values ( matrix_row_t raw [], matrix_row_t cooked [], uint8_t num_rows , uint8_t current_time );
2019-01-26 17:03:46 +11:00
2019-04-16 05:58:03 +10:00
// we use num_rows rather than MATRIX_ROWS to support split keyboards
void debounce_init ( uint8_t num_rows ) {
2019-08-30 11:19:03 -07:00
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 ;
}
2019-01-26 17:03:46 +11:00
}
}
2019-04-16 05:58:03 +10:00
void debounce ( matrix_row_t raw [], matrix_row_t cooked [], uint8_t num_rows , bool changed ) {
2020-04-11 03:14:28 +03:00
uint8_t current_time = wrapping_timer_read ();
2019-08-30 11:19:03 -07:00
if ( counters_need_update ) {
update_debounce_counters ( num_rows , current_time );
}
2019-04-16 05:58:03 +10:00
2019-08-30 11:19:03 -07:00
if ( changed || matrix_need_update ) {
transfer_matrix_values ( raw , cooked , num_rows , current_time );
}
2019-01-26 17:03:46 +11:00
}
2019-04-16 05:58:03 +10:00
// If the current time is > debounce counter, set the counter to enable input.
void update_debounce_counters ( uint8_t num_rows , uint8_t current_time ) {
2019-08-30 11:19:03 -07: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 ) {
if ( TIMER_DIFF ( current_time , * debounce_pointer , MAX_DEBOUNCE ) >= DEBOUNCE ) {
* debounce_pointer = DEBOUNCE_ELAPSED ;
} else {
counters_need_update = true ;
}
}
debounce_pointer ++ ;
2019-01-26 17:03:46 +11:00
}
}
}
// upload from raw_matrix to final matrix;
2019-04-16 05:58:03 +10:00
void transfer_matrix_values ( matrix_row_t raw [], matrix_row_t cooked [], uint8_t num_rows , uint8_t current_time ) {
2019-08-30 11:19:03 -07:00
matrix_need_update = false ;
debounce_counter_t * debounce_pointer = debounce_counters ;
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 );
if ( delta & col_mask ) {
if ( * debounce_pointer == DEBOUNCE_ELAPSED ) {
* debounce_pointer = current_time ;
counters_need_update = true ;
existing_row ^= col_mask ; // flip the bit.
} else {
matrix_need_update = true ;
}
}
debounce_pointer ++ ;
2019-07-09 11:09:54 -07:00
}
2019-08-30 11:19:03 -07:00
cooked [ row ] = existing_row ;
2019-01-26 17:03:46 +11:00
}
2019-01-26 17:29:02 +11:00
}
2019-01-26 17:03:46 +11:00
2019-04-16 05:58:03 +10:00
bool debounce_active ( void ) { return true ; }