sym_defer_pk.c (4867B)
1 // Copyright 2017 Alex Ong<the.onga@gmail.com> 2 // Copyright 2020 Andrei Purdea<andrei@purdea.ro> 3 // Copyright 2021 Simon Arlott 4 // SPDX-License-Identifier: GPL-2.0-or-later 5 // 6 // Basic symmetric per-key algorithm. Uses an 8-bit counter per key. 7 // When no state changes have occured for DEBOUNCE milliseconds, we push the state. 8 9 #include "debounce.h" 10 #include "timer.h" 11 #include "util.h" 12 13 #ifndef DEBOUNCE 14 # define DEBOUNCE 5 15 #endif 16 17 // Maximum debounce: 255ms 18 #if DEBOUNCE > UINT8_MAX 19 # undef DEBOUNCE 20 # define DEBOUNCE UINT8_MAX 21 #endif 22 23 #define DEBOUNCE_ELAPSED 0 24 25 #if DEBOUNCE > 0 26 typedef uint8_t debounce_counter_t; 27 // Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards 28 static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED}; 29 static bool counters_need_update; 30 static bool cooked_changed; 31 32 static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time); 33 static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]); 34 35 void debounce_init(void) {} 36 37 bool debounce(matrix_row_t raw[], matrix_row_t cooked[], bool changed) { 38 static fast_timer_t last_time; 39 bool updated_last = false; 40 cooked_changed = false; 41 42 if (counters_need_update) { 43 fast_timer_t now = timer_read_fast(); 44 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); 45 46 last_time = now; 47 updated_last = true; 48 49 if (elapsed_time > 0) { 50 // Update debounce counters with elapsed timer clamped to UINT8_MAX 51 update_debounce_counters_and_transfer_if_expired(raw, cooked, MIN(elapsed_time, UINT8_MAX)); 52 } 53 } 54 55 if (changed) { 56 if (!updated_last) { 57 last_time = timer_read_fast(); 58 } 59 60 start_debounce_counters(raw, cooked); 61 } 62 63 return cooked_changed; 64 } 65 66 /** 67 * @brief Updates debounce counters and transfers debounced key states if the debounce period has expired. 68 * 69 * Iterates through each key in the matrix and checks its debounce counter. If the debounce period has expired 70 * for a key, the debounced state is updated to match the raw state. Otherwise, the debounce counter is decremented 71 * by the elapsed time and marked for further updates. 72 * 73 * @param raw The current raw key state matrix. 74 * @param cooked The debounced key state matrix to be updated. 75 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. 76 */ 77 static inline void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t elapsed_time) { 78 counters_need_update = false; 79 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { 80 uint16_t row_offset = row * MATRIX_COLS; 81 82 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 83 uint16_t index = row_offset + col; 84 85 if (debounce_counters[index] != DEBOUNCE_ELAPSED) { 86 if (debounce_counters[index] <= elapsed_time) { 87 debounce_counters[index] = DEBOUNCE_ELAPSED; 88 matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col); 89 matrix_row_t cooked_next = (cooked[row] & ~col_mask) | (raw[row] & col_mask); 90 cooked_changed |= cooked[row] ^ cooked_next; 91 cooked[row] = cooked_next; 92 } else { 93 debounce_counters[index] -= elapsed_time; 94 counters_need_update = true; 95 } 96 } 97 } 98 } 99 } 100 101 /** 102 * @brief Initializes debounce counters for keys with changed states. 103 * 104 * For each key in the matrix, this function checks if the raw state differs from the debounced state. 105 * If a change is detected and the debounce counter has elapsed, the counter is set to the debounce period 106 * and marked for update. Otherwise, the counter is cleared. 107 * 108 * @param raw The current raw key state matrix. 109 * @param cooked The debounced key state matrix. 110 */ 111 static inline void start_debounce_counters(matrix_row_t raw[], matrix_row_t cooked[]) { 112 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { 113 uint16_t row_offset = row * MATRIX_COLS; 114 matrix_row_t delta = raw[row] ^ cooked[row]; 115 116 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 117 uint16_t index = row_offset + col; 118 119 if (delta & (MATRIX_ROW_SHIFTER << col)) { 120 if (debounce_counters[index] == DEBOUNCE_ELAPSED) { 121 debounce_counters[index] = DEBOUNCE; 122 counters_need_update = true; 123 } 124 } else { 125 debounce_counters[index] = DEBOUNCE_ELAPSED; 126 } 127 } 128 } 129 } 130 131 #else 132 # include "none.c" 133 #endif