keyboards/xwhatsit: get rid of some magic numbers
[jackhill/qmk/firmware.git] / keyboards / xwhatsit / matrix.c
1 /* Copyright 2020 Purdea Andrei
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
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 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include "quantum.h"
18
19 #if defined(CONTROLLER_IS_XWHATSIT_BEAMSPRING_REV_4)
20 #define CAPSENSE_DAC_SCLK B1
21 #define CAPSENSE_DAC_DIN B2
22 #define CAPSENSE_DAC_SYNC_N B0
23
24 #define CAPSENSE_SHIFT_DIN C4
25 #define CAPSENSE_SHIFT_OE C6
26 #define CAPSENSE_SHIFT_SHCP C5
27 #define CAPSENSE_SHIFT_STCP C7
28 #define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTC)
29 #define CAPSENSE_SHIFT_STCP_BIT 7
30
31 #define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PIND)
32 #define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
33 #define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
34 #define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
35 #define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
36 #define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
37 #define CAPSENSE_READ_ROWS_VALUE (dest_row_1 & 0xf)
38 // Note: for now Beamspring reads PIND twice to match model F timings. We might change that in the future
39
40 #define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (row)
41 #define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (row)
42 #ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
43 #define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
44 #endif
45 #define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
46 #elif defined(CONTROLLER_IS_XWHATSIT_MODEL_F_OR_WCASS_MODEL_F)
47 #define CAPSENSE_DAC_SCLK B1
48 #define CAPSENSE_DAC_DIN B2
49 #define CAPSENSE_DAC_SYNC_N B0
50
51 #define CAPSENSE_SHIFT_DIN D4
52 #define CAPSENSE_SHIFT_OE D5
53 #define CAPSENSE_SHIFT_SHCP D7
54 #define CAPSENSE_SHIFT_STCP D6
55 #define CAPSENSE_SHIFT_STCP_IO _SFR_IO_ADDR(PORTD)
56 #define CAPSENSE_SHIFT_STCP_BIT 6
57
58 #define CAPSENSE_READ_ROWS_PIN_1 _SFR_IO_ADDR(PINC)
59 #define CAPSENSE_READ_ROWS_PIN_2 _SFR_IO_ADDR(PIND)
60 #define CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "in %[dest_row_1], %[ioreg_row_1]\n\tin %[dest_row_2], %[ioreg_row_2]"
61 #define CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS [dest_row_1] "=&r" (dest_row_1), [dest_row_2] "=&r" (dest_row_2)
62 #define CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS [ioreg_row_1] "I" (CAPSENSE_READ_ROWS_PIN_1), [ioreg_row_2] "I" (CAPSENSE_READ_ROWS_PIN_2)
63 #define CAPSENSE_READ_ROWS_LOCAL_VARS uint8_t dest_row_1, dest_row_2
64 #define CAPSENSE_READ_ROWS_VALUE ((dest_row_1 >> 4) | (dest_row_2 << 4))
65
66 #define CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row) (7-(row))
67 #define CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row) (7-(row))
68 #ifndef CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL
69 #define CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col) (col)
70 #endif
71 #define CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
72 #else
73 #ifndef CAPSENSE_DAC_SCLK
74 #error "Please select controller type in config.h, or please define each macro that is defined when selecting a particular macro type in matrix.c"
75 #endif
76 #endif
77
78 #ifndef CAPSENSE_KEYBOARD_SETTLE_TIME_US
79 #error "Please define CAPSENSE_KEYBOARD_SETTLE_TIME_US in config.h"
80 #endif
81 #ifndef CAPSENSE_DAC_SETTLE_TIME_US
82 #error "Please define CAPSENSE_DAC_SETTLE_TIME_US in config.h"
83 #endif
84 #ifndef CAPSENSE_HARDCODED_SAMPLE_TIME
85 #error "Please define CAPSENSE_HARDCODED_SAMPLE_TIME in config.h"
86 #endif
87
88 #ifndef CAPSENSE_CAL_ENABLED
89 #error "Please define CAPSENSE_CAL_ENABLED as 1/0 in config.h"
90 #endif
91 #ifndef CAPSENSE_CAL_DEBUG
92 #error "Please define CAPSENSE_CAL_DEBUG as 1/0 in config.h"
93 #endif
94 #ifndef CAPSENSE_CAL_INIT_REPS
95 #define CAPSENSE_CAL_INIT_REPS 16
96 #endif
97 #ifndef CAPSENSE_CAL_EACHKEY_REPS
98 #define CAPSENSE_CAL_EACHKEY_REPS 16
99 #endif
100 #ifndef CAPSENSE_CAL_BINS
101 #error "Please define CAPSENSE_CAL_BINS in config.h"
102 #endif
103 #ifndef CAPSENSE_CAL_THRESHOLD_OFFSET
104 #error "Please define CAPSENSE_CAL_THRESHOLD_OFFSET in config.h"
105 #endif
106
107 #if (!defined(CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS)) && (!defined(CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS))
108 #error "Please specify whether the flyplate is pushed down or pulled up on keypress!"
109 #endif
110
111 static inline uint8_t read_rows(void)
112 {
113 CAPSENSE_READ_ROWS_LOCAL_VARS;
114 asm volatile (CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS : CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS : CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS);
115 return CAPSENSE_READ_ROWS_VALUE;
116 }
117
118 void dac_init(void)
119 {
120 setPinOutput(CAPSENSE_DAC_SCLK);
121 setPinOutput(CAPSENSE_DAC_DIN);
122 setPinOutput(CAPSENSE_DAC_SYNC_N);
123 writePin(CAPSENSE_DAC_SYNC_N, 1);
124 writePin(CAPSENSE_DAC_SCLK, 0);
125 writePin(CAPSENSE_DAC_SCLK, 1);
126 writePin(CAPSENSE_DAC_SCLK, 0);
127 }
128
129 void dac_write_threshold(uint16_t value)
130 {
131 value <<= 2; // The two LSB bits of this DAC are don't care.
132 writePin(CAPSENSE_DAC_SYNC_N, 0);
133 int i;
134 for (i=0;i<16;i++)
135 {
136 writePin(CAPSENSE_DAC_DIN, (value >> 15) & 1);
137 value <<= 1;
138 writePin(CAPSENSE_DAC_SCLK, 1);
139 writePin(CAPSENSE_DAC_SCLK, 0);
140 }
141 writePin(CAPSENSE_DAC_SYNC_N, 1);
142 writePin(CAPSENSE_DAC_SCLK, 1);
143 writePin(CAPSENSE_DAC_SCLK, 0);
144 wait_us(CAPSENSE_DAC_SETTLE_TIME_US);
145 }
146
147 #define SHIFT_BITS ((MATRIX_COLS > 16) ? 24 : 16)
148
149 void shift_select_nothing(void)
150 {
151 writePin(CAPSENSE_SHIFT_DIN, 0);
152 int i;
153 for (i=0;i<SHIFT_BITS;i++)
154 {
155 writePin(CAPSENSE_SHIFT_SHCP, 1);
156 writePin(CAPSENSE_SHIFT_SHCP, 0);
157 }
158 writePin(CAPSENSE_SHIFT_STCP, 1);
159 writePin(CAPSENSE_SHIFT_STCP, 0);
160 }
161
162 void shift_select_col_no_strobe(uint8_t col)
163 {
164 int i;
165 for (i=SHIFT_BITS-1; i>=0; i--)
166 {
167 writePin(CAPSENSE_SHIFT_DIN, !!(col == i));
168 writePin(CAPSENSE_SHIFT_SHCP, 1);
169 writePin(CAPSENSE_SHIFT_SHCP, 0);
170 }
171 }
172
173 static inline void shift_select_col(uint8_t col)
174 {
175 shift_select_col_no_strobe(col);
176 writePin(CAPSENSE_SHIFT_STCP, 1);
177 writePin(CAPSENSE_SHIFT_STCP, 0);
178 }
179
180 void shift_init(void)
181 {
182 setPinOutput(CAPSENSE_SHIFT_DIN);
183 setPinOutput(CAPSENSE_SHIFT_OE);
184 setPinOutput(CAPSENSE_SHIFT_STCP);
185 setPinOutput(CAPSENSE_SHIFT_SHCP);
186 writePin(CAPSENSE_SHIFT_STCP, 0);
187 writePin(CAPSENSE_SHIFT_SHCP, 0);
188 shift_select_nothing();
189 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
190 }
191
192 // the following function requires storage for 2 * (time + 1) bytes
193 // but returns valid data only in the first (time + 1) bytes
194 void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
195 {
196 shift_select_col_no_strobe(col);
197 uint16_t index;
198 CAPSENSE_READ_ROWS_LOCAL_VARS;
199 uint8_t *arrayp = array;
200 asm volatile (
201 "ldi %A[index], 0" "\n\t"
202 "ldi %B[index], 0" "\n\t"
203 "cli" "\n\t"
204 "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
205 "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
206 "st %a[arr]+, %[dest_row_1]" "\n\t"
207 "st %a[arr]+, %[dest_row_2]" "\n\t"
208 "adiw %A[index], 0x01" "\n\t"
209 "cp %A[index], %A[time]" "\n\t"
210 "cpc %B[index], %B[time]" "\n\t"
211 "brlo 1b" "\n\t"
212 "sei" "\n\t"
213 "cbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
214 : [arr] "=e" (arrayp),
215 [index] "=&w" (index),
216 CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS
217 : [time] "r" (time + 1),
218 [stcp_regaddr] "I" (CAPSENSE_SHIFT_STCP_IO),
219 [stcp_bit] "I" (CAPSENSE_SHIFT_STCP_BIT),
220 CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS,
221 "0" (arrayp)
222 : "memory" );
223 uint16_t i, p0, p1;
224 p0 = p1 = 0;
225 for (i=0; i<=time; i++)
226 {
227 dest_row_1 = array[p0++];
228 dest_row_2 = array[p0++];
229 array[p1++] = CAPSENSE_READ_ROWS_VALUE;
230 }
231 shift_select_nothing();
232 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
233 }
234
235 uint8_t test_single(uint8_t col, uint16_t time)
236 {
237 shift_select_col_no_strobe(col);
238 uint16_t index;
239 CAPSENSE_READ_ROWS_LOCAL_VARS;
240 uint8_t dummy_data;
241 uint8_t *arrayp = &dummy_data;
242 asm volatile (
243 "ldi %A[index], 0" "\n\t"
244 "ldi %B[index], 0" "\n\t"
245 "cli" "\n\t"
246 "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
247 "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
248 "st %a[arr], %[dest_row_1]" "\n\t"
249 "st %a[arr], %[dest_row_2]" "\n\t"
250 "adiw %A[index], 0x01" "\n\t"
251 "cp %A[index], %A[time]" "\n\t"
252 "cpc %B[index], %B[time]" "\n\t"
253 "brlo 1b" "\n\t"
254 "sei" "\n\t"
255 "cbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
256 : [arr] "=e" (arrayp),
257 [index] "=&w" (index),
258 CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS
259 : [time] "r" (time + 1),
260 [stcp_regaddr] "I" (CAPSENSE_SHIFT_STCP_IO),
261 [stcp_bit] "I" (CAPSENSE_SHIFT_STCP_BIT),
262 CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS,
263 "0" (arrayp)
264 : "memory" );
265 shift_select_nothing();
266 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
267 return CAPSENSE_READ_ROWS_VALUE;
268 }
269
270 #define NRTIMES 64
271 #define TESTATONCE 8
272 #define REPS_V2 15
273 void test_col_print_data_v2(uint8_t col)
274 {
275 uprintf("%d: ", col);
276 static uint8_t data[NRTIMES*2];
277 static uint8_t sums[(TESTATONCE+1) * MATRIX_ROWS];
278 uint8_t to_time = NRTIMES-1;
279 uint8_t from_time = 0;
280 while (from_time<NRTIMES-1)
281 {
282 if (to_time - from_time + 1 > TESTATONCE)
283 {
284 to_time = from_time + TESTATONCE - 1;
285 }
286 uint8_t curr_TESTATONCE = to_time - from_time + 1;
287 uint8_t i;
288 for (i=0;i<(sizeof(sums)/sizeof(sums[0]));i++)
289 {
290 sums[i] = 0;
291 }
292 for (i=0;i<REPS_V2;i++)
293 {
294 uint8_t st = read_rows();
295 test_multiple(col, to_time, data);
296 uint8_t j;
297 uint8_t ii = 0;
298 uint8_t k;
299 for (j=0;j<curr_TESTATONCE;j++)
300 {
301 uint8_t dataj = data[j + from_time];
302 for (k=0; k<MATRIX_ROWS;k++)
303 {
304 sums[ii] += (dataj & 1);
305 dataj >>= 1;
306 ii += 1;
307 }
308 }
309 if (from_time == 0) {
310 ii = TESTATONCE * MATRIX_ROWS;
311 for (k=0; k<MATRIX_ROWS;k++)
312 {
313 sums[ii] += (st & 1);
314 st >>= 1;
315 ii += 1;
316 }
317 }
318 }
319 if (from_time == 0) {
320 for (i=TESTATONCE*MATRIX_ROWS;i<(TESTATONCE+1)*MATRIX_ROWS;i++) {
321 if (sums[i] > 0xf) {
322 print("?");
323 } else {
324 uprintf("%X", sums[i]);
325 }
326 }
327 print(":");
328 }
329 for (i=0;i<curr_TESTATONCE*MATRIX_ROWS;i++)
330 {
331 if (sums[i] > 0xf) {
332 print("?");
333 } else {
334 uprintf("%X", sums[i]);
335 }
336 }
337 from_time = to_time + 1;
338 to_time = NRTIMES - 1;
339 }
340 print("\n");
341 }
342
343 void test_v2(void) {
344 int i;
345 for (i=7;i>0;i--) {
346 uprintf("Starting test in %d\n", i);
347 wait_ms(1000);
348 }
349 uprintf("shift_init()");
350 shift_init();
351 uprintf(" DONE\n");
352 uprintf("dac_init()");
353 dac_init();
354 uprintf(" DONE\n");
355 int d;
356 for (d=90;d<=260;d++)
357 {
358 uprintf("Testing threshold: %d\n", d);
359 dac_write_threshold(d);
360 #if 1
361 int c;
362 for (c=0; c<MATRIX_COLS;c++)
363 {
364 test_col_print_data_v2(CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(c));
365 }
366 #else
367 test_col_print_data_v2(0);
368 test_col_print_data_v2(2);
369 test_col_print_data_v2(6);
370 test_col_print_data_v2(7);
371 test_col_print_data_v2(15);
372 #endif
373 }
374 uprintf("TEST DONE\n");
375 while(1);
376 }
377
378 #define TRACKING_TEST_TIME 4
379 // Key 1 is the always non-pressed key under the space bar to the right.
380 #define TRACKING_KEY_1_COL 6
381 #define TRACKING_KEY_1_ROW 4
382 // Key 2 is the always-pressed calibration pad to the far right-bottom of the keyboard. (both on F62 and F77)
383 #define TRACKING_KEY_2_COL 15
384 #define TRACKING_KEY_2_ROW 6
385 // Key 3 is the F key
386 #define TRACKING_KEY_3_COL 2
387 #define TRACKING_KEY_3_ROW 5
388 // Key 4 is the half of the split backspace that is unused if the user has a normal backspace.
389 #define TRACKING_KEY_4_COL 7
390 #define TRACKING_KEY_4_ROW 3
391 // Key 5 is hidden key next to the left shift, which is only used in ISO layouts.
392 #define TRACKING_KEY_5_COL 0
393 #define TRACKING_KEY_5_ROW 7
394
395 #define TRACKING_REPS 16
396
397 static uint16_t measure_middle(uint8_t col, uint8_t row, uint8_t time, uint8_t reps)
398 {
399 uint8_t reps_div2 = reps / 2;
400 uint16_t min = 0, max = 1023;
401 while (min < max)
402 {
403 uint16_t mid = (min + max) / 2;
404 dac_write_threshold(mid);
405 uint8_t sum = 0;
406 uint8_t i;
407 for (i=0;i<reps;i++)
408 {
409 sum += (test_single(col, time) >> row) & 1;
410 }
411 if (sum < reps_div2)
412 {
413 max = mid - 1;
414 } else if (sum > reps_div2) {
415 min = mid + 1;
416 } else return mid;
417 }
418 return min;
419 }
420
421 void tracking_test(void)
422 {
423 int i;
424 for (i=7;i>0;i--) {
425 uprintf("Starting test in %d\n", i);
426 wait_ms(1000);
427 }
428 uprintf("shift_init()");
429 shift_init();
430 uprintf(" DONE\n");
431 uprintf("dac_init()");
432 dac_init();
433 uprintf(" DONE\n");
434 while (1) {
435 uint32_t tt = timer_read32();
436 uint16_t key1 = measure_middle(TRACKING_KEY_1_COL, TRACKING_KEY_1_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
437 uint16_t key2 = measure_middle(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
438 uint16_t key3 = measure_middle(TRACKING_KEY_3_COL, TRACKING_KEY_3_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
439 uint16_t key4 = measure_middle(TRACKING_KEY_4_COL, TRACKING_KEY_4_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
440 uint16_t key5 = measure_middle(TRACKING_KEY_5_COL, TRACKING_KEY_5_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
441 uprintf("%5lu.%03u, %u, %u, %u, %u, %u\n", tt/1000, (uint16_t)(tt%1000), key1, key2, key3, key4, key5);
442 }
443 }
444
445 uint16_t calibration_measure_all_valid_keys(uint8_t time, uint8_t reps, bool looking_for_all_zero)
446 {
447 uint16_t min = 0, max = 1023;
448 while (min < max)
449 {
450 uint16_t mid = (min + max) / 2;
451 if (!looking_for_all_zero) {
452 mid = (min + max + 1) / 2;
453 }
454 dac_write_threshold(mid);
455 uint8_t col;
456 for (col = 0; col < MATRIX_COLS; col++)
457 {
458 uint8_t valid_physical_rows = 0;
459 uint8_t row;
460 for (row=0; row < MATRIX_ROWS; row++)
461 {
462 if (pgm_read_byte(&keymaps[0][row][col]) != KC_NO)
463 {
464 valid_physical_rows |= (1 << CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row)); // convert keymap row to physical row
465 }
466 }
467 uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
468 uint8_t i;
469 for (i=0;i<reps;i++) {
470 if (looking_for_all_zero)
471 {
472 uint8_t all_zero = (test_single(physical_col, time) & valid_physical_rows) == 0;
473 if (!all_zero) {
474 min = mid + 1;
475 goto next_binary_search;
476 }
477 } else {
478 uint8_t all_ones = (test_single(physical_col, time) & valid_physical_rows) == valid_physical_rows;
479 if (!all_ones) {
480 max = mid - 1;
481 goto next_binary_search;
482 }
483 }
484 }
485 }
486 if (looking_for_all_zero) {
487 max = mid;
488 } else {
489 min = mid;
490 }
491 next_binary_search:;
492 }
493 return min;
494 }
495
496 #if CAPSENSE_CAL_ENABLED
497 #if defined(BOOTMAGIC_ENABLE) || defined(BOOTMAGIC_LITE)
498 #error "Calibration is not supported in conjunction with BOOTMAGIC, because calibration requires that no keys are pressed while the keyboard is plugged in"
499 #endif
500 #endif
501
502 uint16_t cal_thresholds[CAPSENSE_CAL_BINS];
503 matrix_row_t assigned_to_threshold[CAPSENSE_CAL_BINS][MATRIX_ROWS];
504 uint16_t cal_tr_allzero;
505 uint16_t cal_tr_allone;
506 void calibration(void)
507 {
508 uint16_t cal_thresholds_max[CAPSENSE_CAL_BINS]={0xFFFFU,0xFFFFU,0xFFFFU};
509 uint16_t cal_thresholds_min[CAPSENSE_CAL_BINS]={0xFFFFU,0xFFFFU,0xFFFFU};
510 cal_tr_allzero = calibration_measure_all_valid_keys(CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_INIT_REPS, true);
511 cal_tr_allone = calibration_measure_all_valid_keys(CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_INIT_REPS, false);
512 uint16_t max = (cal_tr_allzero == 0) ? 0 : (cal_tr_allzero - 1);
513 uint16_t min = cal_tr_allone + 1;
514 if (max < min) max = min;
515 uint16_t d = max - min;
516 uint8_t i;
517 for (i=0;i<CAPSENSE_CAL_BINS;i++) {
518 cal_thresholds[i] = min + (d * (2 * i + 1)) / 2 / CAPSENSE_CAL_BINS;
519 }
520 uint8_t col;
521 for (col = 0; col < MATRIX_COLS; col++) {
522 uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
523 uint8_t row;
524 for (row = 0; row < MATRIX_ROWS; row++) {
525 if (pgm_read_byte(&keymaps[0][row][col]) != KC_NO) {
526 uint16_t threshold = measure_middle(physical_col, CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_EACHKEY_REPS);
527 uint8_t besti = 0;
528 uint16_t best_diff = (uint16_t)abs(threshold - cal_thresholds[besti]);
529 for (i=1;i<CAPSENSE_CAL_BINS;i++) {
530 uint16_t this_diff = (uint16_t)abs(threshold - cal_thresholds[i]);
531 if (this_diff < best_diff)
532 {
533 best_diff = this_diff;
534 besti = i;
535 }
536 }
537 assigned_to_threshold[besti][row] |= (1 << col);
538 if ((cal_thresholds_max[besti] = 0xFFFFU) || (cal_thresholds_max[besti] < threshold)) cal_thresholds_max[besti] = threshold;
539 if ((cal_thresholds_min[besti] = 0xFFFFU) || (cal_thresholds_min[besti] > threshold)) cal_thresholds_min[besti] = threshold;
540 }
541 }
542 }
543 for (i=0;i<CAPSENSE_CAL_BINS;i++) {
544 if ((cal_thresholds_max[i] == 0xFFFFU) || (cal_thresholds_min[i] == 0xFFFFU)) {
545 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
546 cal_thresholds[i] += CAPSENSE_CAL_THRESHOLD_OFFSET;
547 #else
548 cal_thresholds[i] -= CAPSENSE_CAL_THRESHOLD_OFFSET;
549 #endif
550 } else {
551 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
552 cal_thresholds[i] = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2 + CAPSENSE_CAL_THRESHOLD_OFFSET;
553 #else
554 cal_thresholds[i] = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2 - CAPSENSE_CAL_THRESHOLD_OFFSET;
555 #endif
556 }
557 }
558 }
559
560 void real_keyboard_init_basic(void)
561 {
562 uprintf("shift_init()");
563 shift_init();
564 uprintf(" DONE\n");
565 uprintf("dac_init()");
566 dac_init();
567 uprintf(" DONE\n");
568 #if CAPSENSE_CAL_ENABLED
569 calibration();
570 #else
571 dac_write_threshold(142);
572 dac_write_threshold(142);
573 dac_write_threshold(142);
574 #endif
575 }
576
577 void matrix_init_custom(void) {
578 //test_v2();
579 //tracking_test();
580 real_keyboard_init_basic();
581 }
582
583 matrix_row_t previous_matrix[MATRIX_ROWS];
584 #if CAPSENSE_CAL_ENABLED && CAPSENSE_CAL_DEBUG
585 bool cal_stats_printed = false;
586 #endif
587
588 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
589 uint8_t col, row, cal;
590 #if CAPSENSE_CAL_ENABLED && CAPSENSE_CAL_DEBUG
591 if (!cal_stats_printed)
592 {
593 uint32_t time = timer_read32();
594 if (time >= 10 * 1000UL) { // after 10 seconds
595 uprintf("Cal All Zero = %u, Cal All Ones = %u\n", cal_tr_allzero, cal_tr_allone);
596 for (cal=0;cal<CAPSENSE_CAL_BINS;cal++)
597 {
598 uprintf("Cal bin %u, Threshold=%u Assignments:\n", cal, cal_thresholds[cal]);
599 for (row=0;row<MATRIX_ROWS;row++)
600 {
601 uprintf("0x%02X\n", assigned_to_threshold[cal][row]);
602 }
603 }
604 cal_stats_printed = true;
605 }
606 }
607 #endif
608 for (row=0;row<MATRIX_ROWS;row++)
609 {
610 current_matrix[row] = 0;
611 }
612 #if CAPSENSE_CAL_ENABLED
613 for (cal=0;cal<CAPSENSE_CAL_BINS;cal++) {
614 dac_write_threshold(cal_thresholds[cal]);
615 for (col=0;col<MATRIX_COLS;col++) {
616 uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
617 uint8_t d;
618 uint8_t d_tested = 0;
619 for (row=0;row<MATRIX_ROWS;row++) {
620 if (assigned_to_threshold[cal][row] & (1 << col))
621 {
622 if (!d_tested)
623 {
624 d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME);
625 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
626 d = ~d;
627 #endif
628 d_tested = 1;
629 }
630 uint8_t physical_row = CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row);
631 current_matrix[row] |= ((d >> physical_row) & 1) << col;
632 }
633 }
634 }
635 }
636 #else
637 for (col=0;col<MATRIX_COLS;col++)
638 {
639 uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
640 uint8_t d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME);
641 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
642 d = ~d;
643 #endif
644 for (row=0;row<MATRIX_ROWS;row++)
645 {
646 current_matrix[CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row)] |= (((uint16_t)(d & 1)) << col);
647 d >>= 1;
648 }
649 }
650 #endif
651 bool changed = false;
652 for (row=0;row<MATRIX_ROWS;row++)
653 {
654 if (previous_matrix[row] != current_matrix[row]) changed = true;
655 previous_matrix[row] = current_matrix[row];
656 }
657 return changed;
658 }