aboutsummaryrefslogtreecommitdiff
path: root/quantum/debounce/asym_eager_defer_pk.c
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/debounce/asym_eager_defer_pk.c')
-rw-r--r--quantum/debounce/asym_eager_defer_pk.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/quantum/debounce/asym_eager_defer_pk.c b/quantum/debounce/asym_eager_defer_pk.c
new file mode 100644
index 000000000..24380dc5e
--- /dev/null
+++ b/quantum/debounce/asym_eager_defer_pk.c
@@ -0,0 +1,171 @@
1/*
2 * Copyright 2017 Alex Ong <the.onga@gmail.com>
3 * Copyright 2020 Andrei Purdea <andrei@purdea.ro>
4 * Copyright 2021 Simon Arlott
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21Basic symmetric per-key algorithm. Uses an 8-bit counter per key.
22When no state changes have occured for DEBOUNCE milliseconds, we push the state.
23*/
24
25#include "matrix.h"
26#include "timer.h"
27#include "quantum.h"
28#include <stdlib.h>
29
30#ifdef PROTOCOL_CHIBIOS
31# if CH_CFG_USE_MEMCORE == FALSE
32# 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.
33# endif
34#endif
35
36#ifndef DEBOUNCE
37# define DEBOUNCE 5
38#endif
39
40// Maximum debounce: 127ms
41#if DEBOUNCE > 127
42# undef DEBOUNCE
43# define DEBOUNCE 127
44#endif
45
46#define ROW_SHIFTER ((matrix_row_t)1)
47
48typedef struct {
49 bool pressed : 1;
50 uint8_t time : 7;
51} debounce_counter_t;
52
53#if DEBOUNCE > 0
54static debounce_counter_t *debounce_counters;
55static fast_timer_t last_time;
56static bool counters_need_update;
57static bool matrix_need_update;
58
59#define DEBOUNCE_ELAPSED 0
60
61static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time);
62static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows);
63
64// we use num_rows rather than MATRIX_ROWS to support split keyboards
65void debounce_init(uint8_t num_rows) {
66 debounce_counters = malloc(num_rows * MATRIX_COLS * sizeof(debounce_counter_t));
67 int i = 0;
68 for (uint8_t r = 0; r < num_rows; r++) {
69 for (uint8_t c = 0; c < MATRIX_COLS; c++) {
70 debounce_counters[i++].time = DEBOUNCE_ELAPSED;
71 }
72 }
73}
74
75void debounce_free(void) {
76 free(debounce_counters);
77 debounce_counters = NULL;
78}
79
80void debounce(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, bool changed) {
81 bool updated_last = false;
82
83 if (counters_need_update) {
84 fast_timer_t now = timer_read_fast();
85 fast_timer_t elapsed_time = TIMER_DIFF_FAST(now, last_time);
86
87 last_time = now;
88 updated_last = true;
89 if (elapsed_time > UINT8_MAX) {
90 elapsed_time = UINT8_MAX;
91 }
92
93 if (elapsed_time > 0) {
94 update_debounce_counters_and_transfer_if_expired(raw, cooked, num_rows, elapsed_time);
95 }
96 }
97
98 if (changed || matrix_need_update) {
99 if (!updated_last) {
100 last_time = timer_read_fast();
101 }
102
103 transfer_matrix_values(raw, cooked, num_rows);
104 }
105}
106
107static void update_debounce_counters_and_transfer_if_expired(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows, uint8_t elapsed_time) {
108 debounce_counter_t *debounce_pointer = debounce_counters;
109
110 counters_need_update = false;
111 matrix_need_update = false;
112
113 for (uint8_t row = 0; row < num_rows; row++) {
114 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
115 matrix_row_t col_mask = (ROW_SHIFTER << col);
116
117 if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
118 if (debounce_pointer->time <= elapsed_time) {
119 debounce_pointer->time = DEBOUNCE_ELAPSED;
120
121 if (debounce_pointer->pressed) {
122 // key-down: eager
123 matrix_need_update = true;
124 } else {
125 // key-up: defer
126 cooked[row] = (cooked[row] & ~col_mask) | (raw[row] & col_mask);
127 }
128 } else {
129 debounce_pointer->time -= elapsed_time;
130 counters_need_update = true;
131 }
132 }
133 debounce_pointer++;
134 }
135 }
136}
137
138static void transfer_matrix_values(matrix_row_t raw[], matrix_row_t cooked[], uint8_t num_rows) {
139 debounce_counter_t *debounce_pointer = debounce_counters;
140
141 for (uint8_t row = 0; row < num_rows; row++) {
142 matrix_row_t delta = raw[row] ^ cooked[row];
143 for (uint8_t col = 0; col < MATRIX_COLS; col++) {
144 matrix_row_t col_mask = (ROW_SHIFTER << col);
145
146 if (delta & col_mask) {
147 if (debounce_pointer->time == DEBOUNCE_ELAPSED) {
148 debounce_pointer->pressed = (raw[row] & col_mask);
149 debounce_pointer->time = DEBOUNCE;
150 counters_need_update = true;
151
152 if (debounce_pointer->pressed) {
153 // key-down: eager
154 cooked[row] ^= col_mask;
155 }
156 }
157 } else if (debounce_pointer->time != DEBOUNCE_ELAPSED) {
158 if (!debounce_pointer->pressed) {
159 // key-up: defer
160 debounce_pointer->time = DEBOUNCE_ELAPSED;
161 }
162 }
163 debounce_pointer++;
164 }
165 }
166}
167
168bool debounce_active(void) { return true; }
169#else
170# include "none.c"
171#endif