sym_eager_pk.c (5203B)
1 /* 2 Copyright 2017 Alex Ong<the.onga@gmail.com> 3 Copyright 2021 Simon Arlott 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 2 of the License, or 7 (at your option) any later version. 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 You should have received a copy of the GNU General Public License 13 along with this program. If not, see <http://www.gnu.org/licenses/>. 14 */ 15 16 /* 17 Basic per-key algorithm. Uses an 8-bit counter per key. 18 After pressing a key, it immediately changes state, and sets a counter. 19 No further inputs are accepted until DEBOUNCE milliseconds have occurred. 20 */ 21 22 #include "debounce.h" 23 #include "timer.h" 24 #include "util.h" 25 26 #ifndef DEBOUNCE 27 # define DEBOUNCE 5 28 #endif 29 30 // Maximum debounce: 255ms 31 #if DEBOUNCE > UINT8_MAX 32 # undef DEBOUNCE 33 # define DEBOUNCE UINT8_MAX 34 #endif 35 36 #define DEBOUNCE_ELAPSED 0 37 38 #if DEBOUNCE > 0 39 typedef uint8_t debounce_counter_t; 40 // Uses MATRIX_ROWS_PER_HAND instead of MATRIX_ROWS to support split keyboards 41 static debounce_counter_t debounce_counters[MATRIX_ROWS_PER_HAND * MATRIX_COLS] = {DEBOUNCE_ELAPSED}; 42 static bool counters_need_update; 43 static bool matrix_need_update; 44 static bool cooked_changed; 45 46 static inline void update_debounce_counters(uint8_t elapsed_time); 47 static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]); 48 49 void debounce_init(void) {} 50 51 bool debounce(matrix_row_t raw[], matrix_row_t cooked[], bool changed) { 52 static fast_timer_t last_time; 53 bool updated_last = false; 54 cooked_changed = false; 55 56 if (counters_need_update) { 57 fast_timer_t now = timer_read_fast(); 58 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time); 59 60 last_time = now; 61 updated_last = true; 62 63 if (elapsed_time > 0) { 64 // Update debounce counters with elapsed timer clamped to UINT8_MAX 65 update_debounce_counters(MIN(elapsed_time, UINT8_MAX)); 66 } 67 } 68 69 if (changed || matrix_need_update) { 70 if (!updated_last) { 71 last_time = timer_read_fast(); 72 } 73 74 transfer_matrix_values(raw, cooked); 75 } 76 77 return cooked_changed; 78 } 79 80 /** 81 * @brief Updates per-key debounce counters and determines if matrix needs updating. 82 * 83 * Iterates through each key in the matrix and checks its debounce counter. If the debounce 84 * period has elapsed, the counter is reset and the matrix is marked for update. Otherwise, 85 * the counter is decremented by the elapsed time and marked for further updates if needed. 86 * 87 * @param elapsed_time The time elapsed since the last debounce update, in milliseconds. 88 */ 89 static inline void update_debounce_counters(uint8_t elapsed_time) { 90 counters_need_update = false; 91 matrix_need_update = false; 92 93 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { 94 uint16_t row_offset = row * MATRIX_COLS; 95 96 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 97 uint16_t index = row_offset + col; 98 99 if (debounce_counters[index] != DEBOUNCE_ELAPSED) { 100 if (debounce_counters[index] <= elapsed_time) { 101 debounce_counters[index] = DEBOUNCE_ELAPSED; 102 matrix_need_update = true; 103 } else { 104 debounce_counters[index] -= elapsed_time; 105 counters_need_update = true; 106 } 107 } 108 } 109 } 110 } 111 112 /** 113 * @brief Transfers debounced key states from the raw matrix to the cooked matrix. 114 * 115 * For each key in the matrix, this function checks if its state has changed and if its 116 * debounce counter has elapsed. If so, the debounce counter is reset, the cooked matrix 117 * is updated to reflect the new state, and the matrix is marked for further updates. 118 * 119 * @param raw The current raw key state matrix. 120 * @param cooked The debounced key state matrix to be updated. 121 */ 122 static inline void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[]) { 123 matrix_need_update = false; 124 125 for (uint8_t row = 0; row < MATRIX_ROWS_PER_HAND; row++) { 126 uint16_t row_offset = row * MATRIX_COLS; 127 matrix_row_t delta = raw[row] ^ cooked[row]; 128 matrix_row_t existing_row = cooked[row]; 129 130 for (uint8_t col = 0; col < MATRIX_COLS; col++) { 131 uint16_t index = row_offset + col; 132 133 matrix_row_t col_mask = (MATRIX_ROW_SHIFTER << col); 134 if (delta & col_mask) { 135 if (debounce_counters[index] == DEBOUNCE_ELAPSED) { 136 debounce_counters[index] = DEBOUNCE; 137 counters_need_update = true; 138 existing_row ^= col_mask; // flip the bit. 139 cooked_changed = true; 140 } 141 } 142 } 143 cooked[row] = existing_row; 144 } 145 } 146 147 #else 148 # include "none.c" 149 #endif