util: added keyboard defs for at wcass and original xwhatsit controller variants
[jackhill/qmk/firmware.git] / keyboards / xwhatsit / matrix.c
CommitLineData
332fa7c4
PA
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"
38e6feca
PA
18#include "matrix_manipulate.h"
19#include <string.h>
332fa7c4 20
1e61ab07
PA
21/* Notes on Expansion Header:
22
23Pinout:
24--1--O O--2--
25--3--O O--4--
26--5--O O--6--
27
28Pin 1 is always VCC
29Pin 6 in always GND
30
31When using xwhatsit's solenoid controller board,
32pin 2 is connected to the ENABLE input of the current
33limiter, and pin 4 drives the solenoid.
34
35On original xwhatsit controllers:
36pin 2 = PB7
37pin 3 = PB4
38pin 4 = PB6
39pin 5 = PB5
40
41On the TH xwhatsit controller:
42pin 2 = HEADER3 = TXO = PD3
43pin 3 = HEADER1 = D(igital)6 = PD7
44pin 4 = HEADER4 = RXI = PD2
45pin 5 = HEADER2 = D(igital)7 = PE6
46*/
47
38f3278e 48// USING_SOLENOID_ENABLE_PIN must be defined in config.h if you are using and xwhatsit type solenoid
1e61ab07 49
0162369b 50static inline uint8_t read_rows(void)
405cc8cf 51{
3e1298e4
PA
52 CAPSENSE_READ_ROWS_LOCAL_VARS;
53 asm volatile (CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS : CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS : CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS);
54 return CAPSENSE_READ_ROWS_VALUE;
405cc8cf
PA
55}
56
d22c0016
PA
57#if defined(CAPSENSE_DAC_MCP4921)
58
59void dac_init(void)
60{
61 writePin(CAPSENSE_DAC_NCS, 1);
62 setPinOutput(CAPSENSE_DAC_NCS);
63 setPinOutput(CAPSENSE_DAC_SCK);
64 setPinOutput(CAPSENSE_DAC_SDI);
65 writePin(CAPSENSE_DAC_NCS, 1);
66 writePin(CAPSENSE_DAC_SCK, 0);
67 writePin(CAPSENSE_DAC_SDI, 0);
68}
69
70void dac_write_threshold(uint16_t value)
71{
72 const uint16_t buffered = 0;
73 #define nSHDN_BIT 12
74 value |= 1 << nSHDN_BIT; // nSHDN = 0 -- make sure output is not floating.
75 #define MCP_DAC_GAIN_2X 0
76 #define MCP_DAC_GAIN_1X 1
77 #define nGA_BIT 13
78 value |= MCP_DAC_GAIN_1X << nGA_BIT;
79 #define BUF_BIT 14;
80 value |= buffered << BUF_BIT;
81
82 writePin(CAPSENSE_DAC_NCS, 0);
83 int i;
84 for (i=0;i<16;i++)
85 {
86 writePin(CAPSENSE_DAC_SDI, (value >> 15) & 1);
87 value <<= 1;
88 writePin(CAPSENSE_DAC_SCK, 1);
89 writePin(CAPSENSE_DAC_SCK, 0);
90 }
91 writePin(CAPSENSE_DAC_NCS, 1);
92 wait_us(CAPSENSE_DAC_SETTLE_TIME_US);
93}
94
95#else
96
405cc8cf
PA
97void dac_init(void)
98{
3e1298e4
PA
99 setPinOutput(CAPSENSE_DAC_SCLK);
100 setPinOutput(CAPSENSE_DAC_DIN);
101 setPinOutput(CAPSENSE_DAC_SYNC_N);
102 writePin(CAPSENSE_DAC_SYNC_N, 1);
103 writePin(CAPSENSE_DAC_SCLK, 0);
104 writePin(CAPSENSE_DAC_SCLK, 1);
105 writePin(CAPSENSE_DAC_SCLK, 0);
405cc8cf
PA
106}
107
108void dac_write_threshold(uint16_t value)
109{
c733dd82 110 value <<= 2; // The two LSB bits of this DAC are don't care.
3e1298e4 111 writePin(CAPSENSE_DAC_SYNC_N, 0);
405cc8cf
PA
112 int i;
113 for (i=0;i<16;i++)
114 {
3e1298e4 115 writePin(CAPSENSE_DAC_DIN, (value >> 15) & 1);
405cc8cf 116 value <<= 1;
3e1298e4
PA
117 writePin(CAPSENSE_DAC_SCLK, 1);
118 writePin(CAPSENSE_DAC_SCLK, 0);
405cc8cf 119 }
3e1298e4
PA
120 writePin(CAPSENSE_DAC_SYNC_N, 1);
121 writePin(CAPSENSE_DAC_SCLK, 1);
122 writePin(CAPSENSE_DAC_SCLK, 0);
123 wait_us(CAPSENSE_DAC_SETTLE_TIME_US);
405cc8cf
PA
124}
125
d22c0016
PA
126#endif
127
aa63771d
PA
128#define SHIFT_BITS (((CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(MATRIX_COLS - 1) >= 16) || \
129 (CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(0) >= 16)) ? 24 : 16)
f4270f7d 130
405cc8cf
PA
131void shift_select_nothing(void)
132{
3e1298e4 133 writePin(CAPSENSE_SHIFT_DIN, 0);
405cc8cf 134 int i;
f4270f7d 135 for (i=0;i<SHIFT_BITS;i++)
405cc8cf 136 {
3e1298e4
PA
137 writePin(CAPSENSE_SHIFT_SHCP, 1);
138 writePin(CAPSENSE_SHIFT_SHCP, 0);
405cc8cf 139 }
3e1298e4
PA
140 writePin(CAPSENSE_SHIFT_STCP, 1);
141 writePin(CAPSENSE_SHIFT_STCP, 0);
405cc8cf
PA
142}
143
773b7610
PA
144void shift_data(uint32_t data)
145{
146 int i;
147 for (i=SHIFT_BITS-1; i>=0; i--)
148 {
149 writePin(CAPSENSE_SHIFT_DIN, (data >> (SHIFT_BITS - 1)) & 1);
150 writePin(CAPSENSE_SHIFT_SHCP, 1);
151 writePin(CAPSENSE_SHIFT_SHCP, 0);
152 data <<= 1;
153 }
154 writePin(CAPSENSE_SHIFT_STCP, 1);
155 writePin(CAPSENSE_SHIFT_STCP, 0);
156}
157
31b3f2de 158void shift_select_col_no_strobe(uint8_t col)
405cc8cf
PA
159{
160 int i;
f4270f7d 161 for (i=SHIFT_BITS-1; i>=0; i--)
405cc8cf 162 {
3e1298e4
PA
163 writePin(CAPSENSE_SHIFT_DIN, !!(col == i));
164 writePin(CAPSENSE_SHIFT_SHCP, 1);
165 writePin(CAPSENSE_SHIFT_SHCP, 0);
405cc8cf 166 }
405cc8cf
PA
167}
168
31b3f2de
PA
169static inline void shift_select_col(uint8_t col)
170{
171 shift_select_col_no_strobe(col);
3e1298e4
PA
172 writePin(CAPSENSE_SHIFT_STCP, 1);
173 writePin(CAPSENSE_SHIFT_STCP, 0);
31b3f2de
PA
174}
175
405cc8cf
PA
176void shift_init(void)
177{
3e1298e4
PA
178 setPinOutput(CAPSENSE_SHIFT_DIN);
179 setPinOutput(CAPSENSE_SHIFT_OE);
180 setPinOutput(CAPSENSE_SHIFT_STCP);
181 setPinOutput(CAPSENSE_SHIFT_SHCP);
182 writePin(CAPSENSE_SHIFT_STCP, 0);
183 writePin(CAPSENSE_SHIFT_SHCP, 0);
405cc8cf 184 shift_select_nothing();
3e1298e4 185 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
405cc8cf
PA
186}
187
f3d8013a
PA
188// Timing:
189// IN instructions (1 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE)
190// Store to array instructions (2 * number of bytes)
191// adiw: 1 cycle
192// cp: 1 cycle
193// cpc: 1 cycle
194// brlo: 2 cycles (when jumping)
195// --- Total loop length:
196// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 cycles
197// first sample elements will be taken after [1..CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
198// second sample elements will be taken after
199// [3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + 1..
200// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
201
202// the following function requires storage for CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE * (time + 1) bytes
31b3f2de
PA
203// but returns valid data only in the first (time + 1) bytes
204void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
205{
206 shift_select_col_no_strobe(col);
207 uint16_t index;
3e1298e4 208 CAPSENSE_READ_ROWS_LOCAL_VARS;
31b3f2de
PA
209 uint8_t *arrayp = array;
210 asm volatile (
211 "ldi %A[index], 0" "\n\t"
212 "ldi %B[index], 0" "\n\t"
213 "cli" "\n\t"
214 "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
f3d8013a
PA
215 "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
216 CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\n\t"
31b3f2de
PA
217 "adiw %A[index], 0x01" "\n\t"
218 "cp %A[index], %A[time]" "\n\t"
219 "cpc %B[index], %B[time]" "\n\t"
220 "brlo 1b" "\n\t"
221 "sei" "\n\t"
222 "cbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
223 : [arr] "=e" (arrayp),
224 [index] "=&w" (index),
3e1298e4 225 CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS
31b3f2de 226 : [time] "r" (time + 1),
3e1298e4
PA
227 [stcp_regaddr] "I" (CAPSENSE_SHIFT_STCP_IO),
228 [stcp_bit] "I" (CAPSENSE_SHIFT_STCP_BIT),
229 CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS,
31b3f2de
PA
230 "0" (arrayp)
231 : "memory" );
232 uint16_t i, p0, p1;
233 p0 = p1 = 0;
234 for (i=0; i<=time; i++)
235 {
f3d8013a 236 CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
3e1298e4 237 array[p1++] = CAPSENSE_READ_ROWS_VALUE;
31b3f2de 238 }
f2a03868 239 shift_select_nothing();
3e1298e4 240 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
31b3f2de
PA
241}
242
23d3309b 243uint8_t test_single(uint8_t col, uint16_t time, uint8_t *interference_ptr)
31b3f2de
PA
244{
245 shift_select_col_no_strobe(col);
246 uint16_t index;
3e1298e4 247 CAPSENSE_READ_ROWS_LOCAL_VARS;
23d3309b
PA
248 uint8_t array[CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 1]; // one sample before triggering, and one dummy byte
249 uint8_t *arrayp = array;
31b3f2de
PA
250 asm volatile (
251 "ldi %A[index], 0" "\n\t"
252 "ldi %B[index], 0" "\n\t"
253 "cli" "\n\t"
23d3309b
PA
254 CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
255 CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\n\t"
31b3f2de 256 "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
f3d8013a
PA
257 "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
258 CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE "\n\t"
31b3f2de
PA
259 "adiw %A[index], 0x01" "\n\t"
260 "cp %A[index], %A[time]" "\n\t"
261 "cpc %B[index], %B[time]" "\n\t"
262 "brlo 1b" "\n\t"
263 "sei" "\n\t"
264 "cbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
265 : [arr] "=e" (arrayp),
266 [index] "=&w" (index),
3e1298e4 267 CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS
31b3f2de 268 : [time] "r" (time + 1),
3e1298e4
PA
269 [stcp_regaddr] "I" (CAPSENSE_SHIFT_STCP_IO),
270 [stcp_bit] "I" (CAPSENSE_SHIFT_STCP_BIT),
271 CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS,
31b3f2de
PA
272 "0" (arrayp)
273 : "memory" );
f2a03868 274 shift_select_nothing();
3e1298e4 275 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
23d3309b
PA
276 uint8_t value_at_time = CAPSENSE_READ_ROWS_VALUE;
277 if (interference_ptr)
278 {
279 uint16_t p0 = 0;
280 CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
281 uint8_t interference = CAPSENSE_READ_ROWS_VALUE;
282 *interference_ptr = interference;
283 }
284 return value_at_time;
31b3f2de 285}
405cc8cf 286
38e6feca 287#ifndef NO_PRINT
ced94ac4 288#define NRTIMES 64
f2a03868
PA
289#define TESTATONCE 8
290#define REPS_V2 15
291void test_col_print_data_v2(uint8_t col)
292{
293 uprintf("%d: ", col);
f3d8013a 294 static uint8_t data[NRTIMES*CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE];
4addcae8 295 static uint8_t sums[(TESTATONCE+1) * MATRIX_ROWS];
f2a03868
PA
296 uint8_t to_time = NRTIMES-1;
297 uint8_t from_time = 0;
298 while (from_time<NRTIMES-1)
299 {
300 if (to_time - from_time + 1 > TESTATONCE)
301 {
302 to_time = from_time + TESTATONCE - 1;
303 }
304 uint8_t curr_TESTATONCE = to_time - from_time + 1;
305 uint8_t i;
306 for (i=0;i<(sizeof(sums)/sizeof(sums[0]));i++)
307 {
308 sums[i] = 0;
309 }
310 for (i=0;i<REPS_V2;i++)
311 {
312 uint8_t st = read_rows();
313 test_multiple(col, to_time, data);
314 uint8_t j;
315 uint8_t ii = 0;
316 uint8_t k;
317 for (j=0;j<curr_TESTATONCE;j++)
318 {
319 uint8_t dataj = data[j + from_time];
4addcae8 320 for (k=0; k<MATRIX_ROWS;k++)
f2a03868
PA
321 {
322 sums[ii] += (dataj & 1);
323 dataj >>= 1;
324 ii += 1;
325 }
326 }
327 if (from_time == 0) {
4addcae8
PA
328 ii = TESTATONCE * MATRIX_ROWS;
329 for (k=0; k<MATRIX_ROWS;k++)
f2a03868
PA
330 {
331 sums[ii] += (st & 1);
332 st >>= 1;
333 ii += 1;
334 }
335 }
336 }
337 if (from_time == 0) {
4addcae8 338 for (i=TESTATONCE*MATRIX_ROWS;i<(TESTATONCE+1)*MATRIX_ROWS;i++) {
f2a03868
PA
339 if (sums[i] > 0xf) {
340 print("?");
341 } else {
342 uprintf("%X", sums[i]);
343 }
344 }
345 print(":");
346 }
4addcae8 347 for (i=0;i<curr_TESTATONCE*MATRIX_ROWS;i++)
f2a03868
PA
348 {
349 if (sums[i] > 0xf) {
350 print("?");
351 } else {
352 uprintf("%X", sums[i]);
353 }
354 }
355 from_time = to_time + 1;
356 to_time = NRTIMES - 1;
357 }
358 print("\n");
359}
38e6feca 360#endif
f2a03868 361
38e6feca 362#ifndef NO_PRINT
f2a03868
PA
363void test_v2(void) {
364 int i;
365 for (i=7;i>0;i--) {
366 uprintf("Starting test in %d\n", i);
367 wait_ms(1000);
368 }
369 uprintf("shift_init()");
370 shift_init();
371 uprintf(" DONE\n");
372 uprintf("dac_init()");
373 dac_init();
374 uprintf(" DONE\n");
375 int d;
376 for (d=90;d<=260;d++)
377 {
378 uprintf("Testing threshold: %d\n", d);
379 dac_write_threshold(d);
380 #if 1
381 int c;
4addcae8 382 for (c=0; c<MATRIX_COLS;c++)
f2a03868 383 {
4addcae8 384 test_col_print_data_v2(CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(c));
f2a03868 385 }
f2a03868
PA
386 #else
387 test_col_print_data_v2(0);
388 test_col_print_data_v2(2);
389 test_col_print_data_v2(6);
390 test_col_print_data_v2(7);
391 test_col_print_data_v2(15);
392 #endif
393 }
394 uprintf("TEST DONE\n");
395 while(1);
396}
38e6feca 397#endif
f2a03868 398
1e57a998
PA
399#define TRACKING_TEST_TIME 4
400// Key 1 is the always non-pressed key under the space bar to the right.
401#define TRACKING_KEY_1_COL 6
402#define TRACKING_KEY_1_ROW 4
403// Key 2 is the always-pressed calibration pad to the far right-bottom of the keyboard. (both on F62 and F77)
404#define TRACKING_KEY_2_COL 15
405#define TRACKING_KEY_2_ROW 6
406// Key 3 is the F key
407#define TRACKING_KEY_3_COL 2
408#define TRACKING_KEY_3_ROW 5
409// Key 4 is the half of the split backspace that is unused if the user has a normal backspace.
410#define TRACKING_KEY_4_COL 7
411#define TRACKING_KEY_4_ROW 3
412// Key 5 is hidden key next to the left shift, which is only used in ISO layouts.
413#define TRACKING_KEY_5_COL 0
414#define TRACKING_KEY_5_ROW 7
415
416#define TRACKING_REPS 16
417
38e6feca 418uint16_t measure_middle(uint8_t col, uint8_t row, uint8_t time, uint8_t reps)
1e57a998 419{
f3f721b9 420 uint8_t reps_div2 = reps / 2;
05ffaaf5 421 uint16_t min = 0, max = CAPSENSE_DAC_MAX;
1e57a998
PA
422 while (min < max)
423 {
424 uint16_t mid = (min + max) / 2;
425 dac_write_threshold(mid);
426 uint8_t sum = 0;
427 uint8_t i;
f3f721b9 428 for (i=0;i<reps;i++)
1e57a998 429 {
23d3309b 430 sum += (test_single(col, time, NULL) >> row) & 1;
1e57a998 431 }
f3f721b9 432 if (sum < reps_div2)
1e57a998
PA
433 {
434 max = mid - 1;
f3f721b9 435 } else if (sum > reps_div2) {
1e57a998
PA
436 min = mid + 1;
437 } else return mid;
438 }
439 return min;
440}
441
e8583e26
PA
442uint16_t measure_middle_keymap_coords(uint8_t col, uint8_t row, uint8_t time, uint8_t reps)
443{
444 return measure_middle(CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col), CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), time, reps);
445}
446
38e6feca 447uint16_t measure_middle_settled(uint8_t col, uint8_t row, uint8_t reps)
123c07cf
PA
448{
449 uint8_t reps_div2 = reps / 2;
05ffaaf5 450 uint16_t min = 0, max = CAPSENSE_DAC_MAX;
123c07cf
PA
451 while (min < max)
452 {
453 uint16_t mid = (min + max) / 2;
454 dac_write_threshold(mid);
455 uint8_t sum = 0;
456 uint8_t i;
457 for (i=0;i<reps;i++)
458 {
459 sum += (read_rows() >> row) & 1;
460 }
461 if (sum < reps_div2)
462 {
463 max = mid - 1;
464 } else if (sum > reps_div2) {
465 min = mid + 1;
466 } else return mid;
467 }
468 return min;
469}
470
38e6feca 471#ifndef NO_PRINT
1e57a998
PA
472void tracking_test(void)
473{
474 int i;
475 for (i=7;i>0;i--) {
476 uprintf("Starting test in %d\n", i);
477 wait_ms(1000);
478 }
479 uprintf("shift_init()");
480 shift_init();
481 uprintf(" DONE\n");
482 uprintf("dac_init()");
483 dac_init();
484 uprintf(" DONE\n");
485 while (1) {
1e527cc7 486 uint32_t tt = timer_read32();
f3f721b9
PA
487 uint16_t key1 = measure_middle(TRACKING_KEY_1_COL, TRACKING_KEY_1_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
488 uint16_t key2 = measure_middle(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
489 uint16_t key3 = measure_middle(TRACKING_KEY_3_COL, TRACKING_KEY_3_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
490 uint16_t key4 = measure_middle(TRACKING_KEY_4_COL, TRACKING_KEY_4_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
491 uint16_t key5 = measure_middle(TRACKING_KEY_5_COL, TRACKING_KEY_5_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
123c07cf
PA
492 uint16_t sett = measure_middle_settled(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_REPS);
493 uint16_t key1l = measure_middle(TRACKING_KEY_1_COL, TRACKING_KEY_1_ROW, TRACKING_TEST_TIME*2, TRACKING_REPS);
494 uint16_t key2l = measure_middle(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_TEST_TIME*2, TRACKING_REPS);
495 uprintf("%5lu.%03u, %u, %u, %u, %u, %u, %u, %u, %u\n", tt/1000, (uint16_t)(tt%1000), key1, key2, key3, key4, key5, sett, key1l, key2l);
1e57a998
PA
496 }
497}
38e6feca 498#endif
f2a03868 499
f3f721b9
PA
500uint16_t calibration_measure_all_valid_keys(uint8_t time, uint8_t reps, bool looking_for_all_zero)
501{
05ffaaf5 502 uint16_t min = 0, max = CAPSENSE_DAC_MAX;
f3f721b9
PA
503 while (min < max)
504 {
505 uint16_t mid = (min + max) / 2;
506 if (!looking_for_all_zero) {
507 mid = (min + max + 1) / 2;
508 }
509 dac_write_threshold(mid);
510 uint8_t col;
511 for (col = 0; col < MATRIX_COLS; col++)
512 {
513 uint8_t valid_physical_rows = 0;
514 uint8_t row;
515 for (row=0; row < MATRIX_ROWS; row++)
516 {
fe505403 517 if (pgm_read_word(&keymaps[0][row][col]) != KC_NO)
f3f721b9 518 {
3ee273a4 519 valid_physical_rows |= (((matrix_row_t)1) << CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row)); // convert keymap row to physical row
f3f721b9
PA
520 }
521 }
f4270f7d 522 uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
f3f721b9
PA
523 uint8_t i;
524 for (i=0;i<reps;i++) {
525 if (looking_for_all_zero)
526 {
23d3309b 527 uint8_t all_zero = (test_single(physical_col, time, NULL) & valid_physical_rows) == 0;
f3f721b9
PA
528 if (!all_zero) {
529 min = mid + 1;
530 goto next_binary_search;
531 }
532 } else {
23d3309b 533 uint8_t all_ones = (test_single(physical_col, time, NULL) & valid_physical_rows) == valid_physical_rows;
f3f721b9
PA
534 if (!all_ones) {
535 max = mid - 1;
536 goto next_binary_search;
537 }
538 }
539 }
540 }
541 if (looking_for_all_zero) {
542 max = mid;
543 } else {
544 min = mid;
545 }
546 next_binary_search:;
547 }
548 return min;
549}
550
f4270f7d 551#if CAPSENSE_CAL_ENABLED
c737e37a
PA
552#if defined(BOOTMAGIC_ENABLE) || defined(BOOTMAGIC_LITE)
553#error "Calibration is not supported in conjunction with BOOTMAGIC, because calibration requires that no keys are pressed while the keyboard is plugged in"
554#endif
555#endif
556
3e1298e4
PA
557uint16_t cal_thresholds[CAPSENSE_CAL_BINS];
558matrix_row_t assigned_to_threshold[CAPSENSE_CAL_BINS][MATRIX_ROWS];
f3f721b9
PA
559uint16_t cal_tr_allzero;
560uint16_t cal_tr_allone;
f3f721b9
PA
561void calibration(void)
562{
94b5327f
PA
563 uint16_t cal_thresholds_max[CAPSENSE_CAL_BINS];
564 uint16_t cal_thresholds_min[CAPSENSE_CAL_BINS];
565 memset(cal_thresholds_max, 0xff, sizeof(cal_thresholds_max));
566 memset(cal_thresholds_min, 0xff, sizeof(cal_thresholds_min));
3e1298e4
PA
567 cal_tr_allzero = calibration_measure_all_valid_keys(CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_INIT_REPS, true);
568 cal_tr_allone = calibration_measure_all_valid_keys(CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_INIT_REPS, false);
f3f721b9
PA
569 uint16_t max = (cal_tr_allzero == 0) ? 0 : (cal_tr_allzero - 1);
570 uint16_t min = cal_tr_allone + 1;
571 if (max < min) max = min;
572 uint16_t d = max - min;
573 uint8_t i;
3e1298e4
PA
574 for (i=0;i<CAPSENSE_CAL_BINS;i++) {
575 cal_thresholds[i] = min + (d * (2 * i + 1)) / 2 / CAPSENSE_CAL_BINS;
f3f721b9
PA
576 }
577 uint8_t col;
578 for (col = 0; col < MATRIX_COLS; col++) {
f4270f7d 579 uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
f3f721b9
PA
580 uint8_t row;
581 for (row = 0; row < MATRIX_ROWS; row++) {
fe505403 582 if (pgm_read_word(&keymaps[0][row][col]) != KC_NO) {
f4270f7d 583 uint16_t threshold = measure_middle(physical_col, CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_EACHKEY_REPS);
f3f721b9
PA
584 uint8_t besti = 0;
585 uint16_t best_diff = (uint16_t)abs(threshold - cal_thresholds[besti]);
3e1298e4 586 for (i=1;i<CAPSENSE_CAL_BINS;i++) {
f3f721b9
PA
587 uint16_t this_diff = (uint16_t)abs(threshold - cal_thresholds[i]);
588 if (this_diff < best_diff)
589 {
590 best_diff = this_diff;
591 besti = i;
592 }
593 }
3ee273a4 594 assigned_to_threshold[besti][row] |= (((matrix_row_t)1) << col);
94b5327f
PA
595 if ((cal_thresholds_max[besti] == 0xFFFFU) || (cal_thresholds_max[besti] < threshold)) cal_thresholds_max[besti] = threshold;
596 if ((cal_thresholds_min[besti] == 0xFFFFU) || (cal_thresholds_min[besti] > threshold)) cal_thresholds_min[besti] = threshold;
f3f721b9
PA
597 }
598 }
599 }
3e1298e4 600 for (i=0;i<CAPSENSE_CAL_BINS;i++) {
2ec3972f 601 uint16_t bin_signal_level;
3f49a80b 602 if ((cal_thresholds_max[i] == 0xFFFFU) || (cal_thresholds_min[i] == 0xFFFFU)) {
2ec3972f 603 bin_signal_level = cal_thresholds[i];
3f49a80b 604 } else {
2ec3972f 605 bin_signal_level = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2;
3f49a80b 606 }
2ec3972f
PA
607 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
608 if ((bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET) > CAPSENSE_DAC_MAX)
609 {
610 cal_thresholds[i] = CAPSENSE_DAC_MAX;
611 } else {
612 cal_thresholds[i] = bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET;
613 }
614 #else
615 if (bin_signal_level < CAPSENSE_CAL_THRESHOLD_OFFSET)
616 {
617 cal_thresholds[i] = 0;
618 } else {
619 cal_thresholds[i] = bin_signal_level - CAPSENSE_CAL_THRESHOLD_OFFSET;
620 }
621 #endif
f3f721b9
PA
622 }
623}
624
09c2b24e
PA
625void real_keyboard_init_basic(void)
626{
38e6feca 627 #ifndef NO_PRINT
09c2b24e 628 uprintf("shift_init()");
38e6feca 629 #endif
09c2b24e 630 shift_init();
38e6feca 631 #ifndef NO_PRINT
09c2b24e
PA
632 uprintf(" DONE\n");
633 uprintf("dac_init()");
38e6feca 634 #endif
09c2b24e 635 dac_init();
38e6feca 636 #ifndef NO_PRINT
09c2b24e 637 uprintf(" DONE\n");
38e6feca 638 #endif
f4270f7d 639 #if CAPSENSE_CAL_ENABLED
f3f721b9
PA
640 calibration();
641 #else
38e6feca
PA
642 dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
643 dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
644 dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
f3f721b9 645 #endif
330e4867 646 #if defined(CONTROLLER_IS_THROUGH_HOLE_BEAMSPRING) || defined(CONTROLLER_IS_THROUGH_HOLE_MODEL_F)
b6bb4370
PA
647 // Disable on-board leds.
648 setPinOutput(D5);
649 writePin(D5, 1);
650 setPinOutput(B0);
651 writePin(B0, 1);
652 #endif
a03d56f8
PA
653 #ifdef USING_SOLENOID_ENABLE_PIN
654 // ^^ this must be defined in config.h if you are using and xwhatsit type solenoid
655 setPinOutput(USING_SOLENOID_ENABLE_PIN);
656 writePin(USING_SOLENOID_ENABLE_PIN, 1);
657 #endif
09c2b24e
PA
658}
659
06b963f3 660void matrix_init_custom(void) {
9d9305db 661 //test_v2();
1e57a998 662 //tracking_test();
09c2b24e 663 real_keyboard_init_basic();
06b963f3
PA
664}
665
f3f721b9 666matrix_row_t previous_matrix[MATRIX_ROWS];
38e6feca
PA
667
668bool matrix_has_it_changed(const matrix_row_t current_matrix[]) {
669 uint8_t row;
670 bool changed = false;
671 for (row=0;row<MATRIX_ROWS;row++)
672 {
673 if (previous_matrix[row] != current_matrix[row]) changed = true;
674 previous_matrix[row] = current_matrix[row];
675 }
676 return changed;
677}
678
f4270f7d 679#if CAPSENSE_CAL_ENABLED && CAPSENSE_CAL_DEBUG
f3f721b9
PA
680bool cal_stats_printed = false;
681#endif
dabf024c 682
38e6feca
PA
683bool keyboard_scan_enabled = 1;
684
685#ifndef NO_PRINT
686void matrix_print_stats(void)
687{
688 uint8_t row, cal;
f4270f7d 689 #if CAPSENSE_CAL_ENABLED && CAPSENSE_CAL_DEBUG
f3f721b9
PA
690 if (!cal_stats_printed)
691 {
692 uint32_t time = timer_read32();
693 if (time >= 10 * 1000UL) { // after 10 seconds
694 uprintf("Cal All Zero = %u, Cal All Ones = %u\n", cal_tr_allzero, cal_tr_allone);
3e1298e4 695 for (cal=0;cal<CAPSENSE_CAL_BINS;cal++)
f3f721b9
PA
696 {
697 uprintf("Cal bin %u, Threshold=%u Assignments:\n", cal, cal_thresholds[cal]);
698 for (row=0;row<MATRIX_ROWS;row++)
699 {
700 uprintf("0x%02X\n", assigned_to_threshold[cal][row]);
701 }
702 }
703 cal_stats_printed = true;
704 }
705 }
706 #endif
38e6feca
PA
707}
708#endif
709
710void matrix_scan_raw(matrix_row_t current_matrix[]) {
02743d4c 711 uint8_t col, row;
38e6feca 712 memset(current_matrix, 0, sizeof(matrix_row_t) * MATRIX_ROWS);
f4270f7d 713 #if CAPSENSE_CAL_ENABLED
02743d4c 714 uint8_t cal;
3e1298e4 715 for (cal=0;cal<CAPSENSE_CAL_BINS;cal++) {
f3f721b9
PA
716 dac_write_threshold(cal_thresholds[cal]);
717 for (col=0;col<MATRIX_COLS;col++) {
f4270f7d 718 uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
23d3309b 719 uint8_t d, interference;
f3f721b9
PA
720 uint8_t d_tested = 0;
721 for (row=0;row<MATRIX_ROWS;row++) {
3ee273a4 722 if (assigned_to_threshold[cal][row] & (((matrix_row_t)1) << col))
f3f721b9
PA
723 {
724 if (!d_tested)
725 {
23d3309b 726 d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME, &interference);
f4270f7d
PA
727 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
728 d = ~d;
729 #endif
f3f721b9
PA
730 d_tested = 1;
731 }
f4270f7d 732 uint8_t physical_row = CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row);
23d3309b
PA
733 if (!((interference >> physical_row) & 1))
734 {
735 current_matrix[row] |= ((matrix_row_t)((d >> physical_row) & 1)) << col;
736 }
f3f721b9
PA
737 }
738 }
739 }
740 }
741 #else
742 for (col=0;col<MATRIX_COLS;col++)
09c2b24e 743 {
f4270f7d 744 uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
23d3309b
PA
745 uint8_t interference;
746 uint8_t d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME, &interference);
f4270f7d
PA
747 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
748 d = ~d;
749 #endif
f3f721b9 750 for (row=0;row<MATRIX_ROWS;row++)
09c2b24e 751 {
a6b3e4e5 752 current_matrix[CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row)] |= (((matrix_row_t)(d & 1)) << col);
09c2b24e
PA
753 d >>= 1;
754 }
755 }
f3f721b9 756 #endif
38e6feca
PA
757}
758
759bool matrix_scan_custom(matrix_row_t current_matrix[]) {
760#ifndef NO_PRINT
761 matrix_print_stats();
762#endif
763 if (keyboard_scan_enabled) {
764 matrix_scan_raw(current_matrix);
765 } else {
766 memset(current_matrix, 0, sizeof(matrix_row_t) * MATRIX_ROWS);
f3f721b9 767 }
38e6feca 768 return matrix_has_it_changed(current_matrix);
332fa7c4 769}