added feature to help debugging control signals
[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
61cf2ea0 144void shift_data(uint32_t data, int data_idle, int shcp_idle, int stcp_idle)
773b7610
PA
145{
146 int i;
61cf2ea0
PA
147 writePin(CAPSENSE_SHIFT_SHCP, 0);
148 writePin(CAPSENSE_SHIFT_STCP, 0);
773b7610
PA
149 for (i=SHIFT_BITS-1; i>=0; i--)
150 {
151 writePin(CAPSENSE_SHIFT_DIN, (data >> (SHIFT_BITS - 1)) & 1);
152 writePin(CAPSENSE_SHIFT_SHCP, 1);
61cf2ea0
PA
153 if (!((i == 0) && (shcp_idle))) {
154 writePin(CAPSENSE_SHIFT_SHCP, 0);
155 }
773b7610
PA
156 data <<= 1;
157 }
158 writePin(CAPSENSE_SHIFT_STCP, 1);
61cf2ea0
PA
159 if (!stcp_idle) {
160 writePin(CAPSENSE_SHIFT_STCP, 0);
161 }
162 writePin(CAPSENSE_SHIFT_DIN, !!data_idle);
773b7610
PA
163}
164
31b3f2de 165void shift_select_col_no_strobe(uint8_t col)
405cc8cf
PA
166{
167 int i;
f4270f7d 168 for (i=SHIFT_BITS-1; i>=0; i--)
405cc8cf 169 {
3e1298e4
PA
170 writePin(CAPSENSE_SHIFT_DIN, !!(col == i));
171 writePin(CAPSENSE_SHIFT_SHCP, 1);
172 writePin(CAPSENSE_SHIFT_SHCP, 0);
405cc8cf 173 }
405cc8cf
PA
174}
175
31b3f2de
PA
176static inline void shift_select_col(uint8_t col)
177{
178 shift_select_col_no_strobe(col);
3e1298e4
PA
179 writePin(CAPSENSE_SHIFT_STCP, 1);
180 writePin(CAPSENSE_SHIFT_STCP, 0);
31b3f2de
PA
181}
182
405cc8cf
PA
183void shift_init(void)
184{
3e1298e4
PA
185 setPinOutput(CAPSENSE_SHIFT_DIN);
186 setPinOutput(CAPSENSE_SHIFT_OE);
187 setPinOutput(CAPSENSE_SHIFT_STCP);
188 setPinOutput(CAPSENSE_SHIFT_SHCP);
e999475d 189 writePin(CAPSENSE_SHIFT_OE, 0);
3e1298e4
PA
190 writePin(CAPSENSE_SHIFT_STCP, 0);
191 writePin(CAPSENSE_SHIFT_SHCP, 0);
405cc8cf 192 shift_select_nothing();
3e1298e4 193 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
405cc8cf
PA
194}
195
f3d8013a
PA
196// Timing:
197// IN instructions (1 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE)
198// Store to array instructions (2 * number of bytes)
199// adiw: 1 cycle
200// cp: 1 cycle
201// cpc: 1 cycle
202// brlo: 2 cycles (when jumping)
203// --- Total loop length:
204// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 cycles
205// first sample elements will be taken after [1..CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
206// second sample elements will be taken after
207// [3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + 1..
208// 3 * CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 5 + CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE-1] cycles
209
210// the following function requires storage for CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE * (time + 1) bytes
31b3f2de
PA
211// but returns valid data only in the first (time + 1) bytes
212void test_multiple(uint8_t col, uint16_t time, uint8_t *array)
213{
214 shift_select_col_no_strobe(col);
215 uint16_t index;
3e1298e4 216 CAPSENSE_READ_ROWS_LOCAL_VARS;
31b3f2de
PA
217 uint8_t *arrayp = array;
218 asm volatile (
219 "ldi %A[index], 0" "\n\t"
220 "ldi %B[index], 0" "\n\t"
221 "cli" "\n\t"
222 "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
f3d8013a
PA
223 "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
224 CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\n\t"
31b3f2de
PA
225 "adiw %A[index], 0x01" "\n\t"
226 "cp %A[index], %A[time]" "\n\t"
227 "cpc %B[index], %B[time]" "\n\t"
228 "brlo 1b" "\n\t"
229 "sei" "\n\t"
230 "cbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
231 : [arr] "=e" (arrayp),
232 [index] "=&w" (index),
3e1298e4 233 CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS
31b3f2de 234 : [time] "r" (time + 1),
3e1298e4
PA
235 [stcp_regaddr] "I" (CAPSENSE_SHIFT_STCP_IO),
236 [stcp_bit] "I" (CAPSENSE_SHIFT_STCP_BIT),
237 CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS,
31b3f2de
PA
238 "0" (arrayp)
239 : "memory" );
240 uint16_t i, p0, p1;
241 p0 = p1 = 0;
242 for (i=0; i<=time; i++)
243 {
f3d8013a 244 CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
3e1298e4 245 array[p1++] = CAPSENSE_READ_ROWS_VALUE;
31b3f2de 246 }
f2a03868 247 shift_select_nothing();
3e1298e4 248 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
31b3f2de
PA
249}
250
23d3309b 251uint8_t test_single(uint8_t col, uint16_t time, uint8_t *interference_ptr)
31b3f2de
PA
252{
253 shift_select_col_no_strobe(col);
254 uint16_t index;
3e1298e4 255 CAPSENSE_READ_ROWS_LOCAL_VARS;
23d3309b
PA
256 uint8_t array[CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE + 1]; // one sample before triggering, and one dummy byte
257 uint8_t *arrayp = array;
31b3f2de
PA
258 asm volatile (
259 "ldi %A[index], 0" "\n\t"
260 "ldi %B[index], 0" "\n\t"
261 "cli" "\n\t"
23d3309b
PA
262 CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
263 CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS "\n\t"
31b3f2de 264 "sbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
f3d8013a
PA
265 "1:" CAPSENSE_READ_ROWS_ASM_INSTRUCTIONS "\n\t"
266 CAPSENSE_READ_ROWS_STORE_TO_ARRAY_INSTRUCTIONS_FAKE "\n\t"
31b3f2de
PA
267 "adiw %A[index], 0x01" "\n\t"
268 "cp %A[index], %A[time]" "\n\t"
269 "cpc %B[index], %B[time]" "\n\t"
270 "brlo 1b" "\n\t"
271 "sei" "\n\t"
272 "cbi %[stcp_regaddr], %[stcp_bit]" "\n\t"
273 : [arr] "=e" (arrayp),
274 [index] "=&w" (index),
3e1298e4 275 CAPSENSE_READ_ROWS_OUTPUT_CONSTRAINTS
31b3f2de 276 : [time] "r" (time + 1),
3e1298e4
PA
277 [stcp_regaddr] "I" (CAPSENSE_SHIFT_STCP_IO),
278 [stcp_bit] "I" (CAPSENSE_SHIFT_STCP_BIT),
279 CAPSENSE_READ_ROWS_INPUT_CONSTRAINTS,
31b3f2de
PA
280 "0" (arrayp)
281 : "memory" );
f2a03868 282 shift_select_nothing();
3e1298e4 283 wait_us(CAPSENSE_KEYBOARD_SETTLE_TIME_US);
23d3309b
PA
284 uint8_t value_at_time = CAPSENSE_READ_ROWS_VALUE;
285 if (interference_ptr)
286 {
287 uint16_t p0 = 0;
288 CAPSENSE_READ_ROWS_EXTRACT_FROM_ARRAY;
289 uint8_t interference = CAPSENSE_READ_ROWS_VALUE;
290 *interference_ptr = interference;
291 }
292 return value_at_time;
31b3f2de 293}
405cc8cf 294
38e6feca 295#ifndef NO_PRINT
ced94ac4 296#define NRTIMES 64
f2a03868
PA
297#define TESTATONCE 8
298#define REPS_V2 15
299void test_col_print_data_v2(uint8_t col)
300{
301 uprintf("%d: ", col);
f3d8013a 302 static uint8_t data[NRTIMES*CAPSENSE_READ_ROWS_NUMBER_OF_BYTES_PER_SAMPLE];
4addcae8 303 static uint8_t sums[(TESTATONCE+1) * MATRIX_ROWS];
f2a03868
PA
304 uint8_t to_time = NRTIMES-1;
305 uint8_t from_time = 0;
306 while (from_time<NRTIMES-1)
307 {
308 if (to_time - from_time + 1 > TESTATONCE)
309 {
310 to_time = from_time + TESTATONCE - 1;
311 }
312 uint8_t curr_TESTATONCE = to_time - from_time + 1;
313 uint8_t i;
314 for (i=0;i<(sizeof(sums)/sizeof(sums[0]));i++)
315 {
316 sums[i] = 0;
317 }
318 for (i=0;i<REPS_V2;i++)
319 {
320 uint8_t st = read_rows();
321 test_multiple(col, to_time, data);
322 uint8_t j;
323 uint8_t ii = 0;
324 uint8_t k;
325 for (j=0;j<curr_TESTATONCE;j++)
326 {
327 uint8_t dataj = data[j + from_time];
4addcae8 328 for (k=0; k<MATRIX_ROWS;k++)
f2a03868
PA
329 {
330 sums[ii] += (dataj & 1);
331 dataj >>= 1;
332 ii += 1;
333 }
334 }
335 if (from_time == 0) {
4addcae8
PA
336 ii = TESTATONCE * MATRIX_ROWS;
337 for (k=0; k<MATRIX_ROWS;k++)
f2a03868
PA
338 {
339 sums[ii] += (st & 1);
340 st >>= 1;
341 ii += 1;
342 }
343 }
344 }
345 if (from_time == 0) {
4addcae8 346 for (i=TESTATONCE*MATRIX_ROWS;i<(TESTATONCE+1)*MATRIX_ROWS;i++) {
f2a03868
PA
347 if (sums[i] > 0xf) {
348 print("?");
349 } else {
350 uprintf("%X", sums[i]);
351 }
352 }
353 print(":");
354 }
4addcae8 355 for (i=0;i<curr_TESTATONCE*MATRIX_ROWS;i++)
f2a03868
PA
356 {
357 if (sums[i] > 0xf) {
358 print("?");
359 } else {
360 uprintf("%X", sums[i]);
361 }
362 }
363 from_time = to_time + 1;
364 to_time = NRTIMES - 1;
365 }
366 print("\n");
367}
38e6feca 368#endif
f2a03868 369
38e6feca 370#ifndef NO_PRINT
f2a03868
PA
371void test_v2(void) {
372 int i;
373 for (i=7;i>0;i--) {
374 uprintf("Starting test in %d\n", i);
375 wait_ms(1000);
376 }
377 uprintf("shift_init()");
378 shift_init();
379 uprintf(" DONE\n");
380 uprintf("dac_init()");
381 dac_init();
382 uprintf(" DONE\n");
383 int d;
384 for (d=90;d<=260;d++)
385 {
386 uprintf("Testing threshold: %d\n", d);
387 dac_write_threshold(d);
388 #if 1
389 int c;
4addcae8 390 for (c=0; c<MATRIX_COLS;c++)
f2a03868 391 {
4addcae8 392 test_col_print_data_v2(CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(c));
f2a03868 393 }
f2a03868
PA
394 #else
395 test_col_print_data_v2(0);
396 test_col_print_data_v2(2);
397 test_col_print_data_v2(6);
398 test_col_print_data_v2(7);
399 test_col_print_data_v2(15);
400 #endif
401 }
402 uprintf("TEST DONE\n");
403 while(1);
404}
38e6feca 405#endif
f2a03868 406
1e57a998
PA
407#define TRACKING_TEST_TIME 4
408// Key 1 is the always non-pressed key under the space bar to the right.
409#define TRACKING_KEY_1_COL 6
410#define TRACKING_KEY_1_ROW 4
411// Key 2 is the always-pressed calibration pad to the far right-bottom of the keyboard. (both on F62 and F77)
412#define TRACKING_KEY_2_COL 15
413#define TRACKING_KEY_2_ROW 6
414// Key 3 is the F key
415#define TRACKING_KEY_3_COL 2
416#define TRACKING_KEY_3_ROW 5
417// Key 4 is the half of the split backspace that is unused if the user has a normal backspace.
418#define TRACKING_KEY_4_COL 7
419#define TRACKING_KEY_4_ROW 3
420// Key 5 is hidden key next to the left shift, which is only used in ISO layouts.
421#define TRACKING_KEY_5_COL 0
422#define TRACKING_KEY_5_ROW 7
423
424#define TRACKING_REPS 16
425
38e6feca 426uint16_t measure_middle(uint8_t col, uint8_t row, uint8_t time, uint8_t reps)
1e57a998 427{
f3f721b9 428 uint8_t reps_div2 = reps / 2;
05ffaaf5 429 uint16_t min = 0, max = CAPSENSE_DAC_MAX;
1e57a998
PA
430 while (min < max)
431 {
432 uint16_t mid = (min + max) / 2;
433 dac_write_threshold(mid);
434 uint8_t sum = 0;
435 uint8_t i;
f3f721b9 436 for (i=0;i<reps;i++)
1e57a998 437 {
23d3309b 438 sum += (test_single(col, time, NULL) >> row) & 1;
1e57a998 439 }
f3f721b9 440 if (sum < reps_div2)
1e57a998
PA
441 {
442 max = mid - 1;
f3f721b9 443 } else if (sum > reps_div2) {
1e57a998
PA
444 min = mid + 1;
445 } else return mid;
446 }
447 return min;
448}
449
e8583e26
PA
450uint16_t measure_middle_keymap_coords(uint8_t col, uint8_t row, uint8_t time, uint8_t reps)
451{
452 return measure_middle(CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col), CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), time, reps);
453}
454
38e6feca 455uint16_t measure_middle_settled(uint8_t col, uint8_t row, uint8_t reps)
123c07cf
PA
456{
457 uint8_t reps_div2 = reps / 2;
05ffaaf5 458 uint16_t min = 0, max = CAPSENSE_DAC_MAX;
123c07cf
PA
459 while (min < max)
460 {
461 uint16_t mid = (min + max) / 2;
462 dac_write_threshold(mid);
463 uint8_t sum = 0;
464 uint8_t i;
465 for (i=0;i<reps;i++)
466 {
467 sum += (read_rows() >> row) & 1;
468 }
469 if (sum < reps_div2)
470 {
471 max = mid - 1;
472 } else if (sum > reps_div2) {
473 min = mid + 1;
474 } else return mid;
475 }
476 return min;
477}
478
38e6feca 479#ifndef NO_PRINT
1e57a998
PA
480void tracking_test(void)
481{
482 int i;
483 for (i=7;i>0;i--) {
484 uprintf("Starting test in %d\n", i);
485 wait_ms(1000);
486 }
487 uprintf("shift_init()");
488 shift_init();
489 uprintf(" DONE\n");
490 uprintf("dac_init()");
491 dac_init();
492 uprintf(" DONE\n");
493 while (1) {
1e527cc7 494 uint32_t tt = timer_read32();
f3f721b9
PA
495 uint16_t key1 = measure_middle(TRACKING_KEY_1_COL, TRACKING_KEY_1_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
496 uint16_t key2 = measure_middle(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
497 uint16_t key3 = measure_middle(TRACKING_KEY_3_COL, TRACKING_KEY_3_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
498 uint16_t key4 = measure_middle(TRACKING_KEY_4_COL, TRACKING_KEY_4_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
499 uint16_t key5 = measure_middle(TRACKING_KEY_5_COL, TRACKING_KEY_5_ROW, TRACKING_TEST_TIME, TRACKING_REPS);
123c07cf
PA
500 uint16_t sett = measure_middle_settled(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_REPS);
501 uint16_t key1l = measure_middle(TRACKING_KEY_1_COL, TRACKING_KEY_1_ROW, TRACKING_TEST_TIME*2, TRACKING_REPS);
502 uint16_t key2l = measure_middle(TRACKING_KEY_2_COL, TRACKING_KEY_2_ROW, TRACKING_TEST_TIME*2, TRACKING_REPS);
503 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
504 }
505}
38e6feca 506#endif
f2a03868 507
f3f721b9
PA
508uint16_t calibration_measure_all_valid_keys(uint8_t time, uint8_t reps, bool looking_for_all_zero)
509{
05ffaaf5 510 uint16_t min = 0, max = CAPSENSE_DAC_MAX;
f3f721b9
PA
511 while (min < max)
512 {
513 uint16_t mid = (min + max) / 2;
514 if (!looking_for_all_zero) {
515 mid = (min + max + 1) / 2;
516 }
517 dac_write_threshold(mid);
518 uint8_t col;
519 for (col = 0; col < MATRIX_COLS; col++)
520 {
521 uint8_t valid_physical_rows = 0;
522 uint8_t row;
523 for (row=0; row < MATRIX_ROWS; row++)
524 {
fe505403 525 if (pgm_read_word(&keymaps[0][row][col]) != KC_NO)
f3f721b9 526 {
3ee273a4 527 valid_physical_rows |= (((matrix_row_t)1) << CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row)); // convert keymap row to physical row
f3f721b9
PA
528 }
529 }
f4270f7d 530 uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
f3f721b9
PA
531 uint8_t i;
532 for (i=0;i<reps;i++) {
533 if (looking_for_all_zero)
534 {
23d3309b 535 uint8_t all_zero = (test_single(physical_col, time, NULL) & valid_physical_rows) == 0;
f3f721b9
PA
536 if (!all_zero) {
537 min = mid + 1;
538 goto next_binary_search;
539 }
540 } else {
23d3309b 541 uint8_t all_ones = (test_single(physical_col, time, NULL) & valid_physical_rows) == valid_physical_rows;
f3f721b9
PA
542 if (!all_ones) {
543 max = mid - 1;
544 goto next_binary_search;
545 }
546 }
547 }
548 }
549 if (looking_for_all_zero) {
550 max = mid;
551 } else {
552 min = mid;
553 }
554 next_binary_search:;
555 }
556 return min;
557}
558
f4270f7d 559#if CAPSENSE_CAL_ENABLED
c737e37a
PA
560#if defined(BOOTMAGIC_ENABLE) || defined(BOOTMAGIC_LITE)
561#error "Calibration is not supported in conjunction with BOOTMAGIC, because calibration requires that no keys are pressed while the keyboard is plugged in"
562#endif
563#endif
564
3e1298e4
PA
565uint16_t cal_thresholds[CAPSENSE_CAL_BINS];
566matrix_row_t assigned_to_threshold[CAPSENSE_CAL_BINS][MATRIX_ROWS];
f3f721b9
PA
567uint16_t cal_tr_allzero;
568uint16_t cal_tr_allone;
f3f721b9
PA
569void calibration(void)
570{
94b5327f
PA
571 uint16_t cal_thresholds_max[CAPSENSE_CAL_BINS];
572 uint16_t cal_thresholds_min[CAPSENSE_CAL_BINS];
573 memset(cal_thresholds_max, 0xff, sizeof(cal_thresholds_max));
574 memset(cal_thresholds_min, 0xff, sizeof(cal_thresholds_min));
3e1298e4
PA
575 cal_tr_allzero = calibration_measure_all_valid_keys(CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_INIT_REPS, true);
576 cal_tr_allone = calibration_measure_all_valid_keys(CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_INIT_REPS, false);
f3f721b9
PA
577 uint16_t max = (cal_tr_allzero == 0) ? 0 : (cal_tr_allzero - 1);
578 uint16_t min = cal_tr_allone + 1;
579 if (max < min) max = min;
580 uint16_t d = max - min;
581 uint8_t i;
3e1298e4
PA
582 for (i=0;i<CAPSENSE_CAL_BINS;i++) {
583 cal_thresholds[i] = min + (d * (2 * i + 1)) / 2 / CAPSENSE_CAL_BINS;
f3f721b9
PA
584 }
585 uint8_t col;
586 for (col = 0; col < MATRIX_COLS; col++) {
f4270f7d 587 uint8_t physical_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
f3f721b9
PA
588 uint8_t row;
589 for (row = 0; row < MATRIX_ROWS; row++) {
fe505403 590 if (pgm_read_word(&keymaps[0][row][col]) != KC_NO) {
f4270f7d 591 uint16_t threshold = measure_middle(physical_col, CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row), CAPSENSE_HARDCODED_SAMPLE_TIME, CAPSENSE_CAL_EACHKEY_REPS);
f3f721b9
PA
592 uint8_t besti = 0;
593 uint16_t best_diff = (uint16_t)abs(threshold - cal_thresholds[besti]);
3e1298e4 594 for (i=1;i<CAPSENSE_CAL_BINS;i++) {
f3f721b9
PA
595 uint16_t this_diff = (uint16_t)abs(threshold - cal_thresholds[i]);
596 if (this_diff < best_diff)
597 {
598 best_diff = this_diff;
599 besti = i;
600 }
601 }
3ee273a4 602 assigned_to_threshold[besti][row] |= (((matrix_row_t)1) << col);
94b5327f
PA
603 if ((cal_thresholds_max[besti] == 0xFFFFU) || (cal_thresholds_max[besti] < threshold)) cal_thresholds_max[besti] = threshold;
604 if ((cal_thresholds_min[besti] == 0xFFFFU) || (cal_thresholds_min[besti] > threshold)) cal_thresholds_min[besti] = threshold;
f3f721b9
PA
605 }
606 }
607 }
3e1298e4 608 for (i=0;i<CAPSENSE_CAL_BINS;i++) {
2ec3972f 609 uint16_t bin_signal_level;
3f49a80b 610 if ((cal_thresholds_max[i] == 0xFFFFU) || (cal_thresholds_min[i] == 0xFFFFU)) {
2ec3972f 611 bin_signal_level = cal_thresholds[i];
3f49a80b 612 } else {
2ec3972f 613 bin_signal_level = (cal_thresholds_max[i] + cal_thresholds_min[i]) / 2;
3f49a80b 614 }
2ec3972f
PA
615 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PUSHED_DOWN_ON_KEYPRESS
616 if ((bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET) > CAPSENSE_DAC_MAX)
617 {
618 cal_thresholds[i] = CAPSENSE_DAC_MAX;
619 } else {
620 cal_thresholds[i] = bin_signal_level + CAPSENSE_CAL_THRESHOLD_OFFSET;
621 }
622 #else
623 if (bin_signal_level < CAPSENSE_CAL_THRESHOLD_OFFSET)
624 {
625 cal_thresholds[i] = 0;
626 } else {
627 cal_thresholds[i] = bin_signal_level - CAPSENSE_CAL_THRESHOLD_OFFSET;
628 }
629 #endif
f3f721b9
PA
630 }
631}
632
03a454e1
PA
633void set_leds(int num_lock, int caps_lock, int scroll_lock)
634{
635 #if defined(LED_NUM_LOCK_PIN)
636 #if defined(LED_NUM_LOCK_ACTIVE_LOW)
637 writePin(LED_NUM_LOCK_PIN, !num_lock);
638 #else
639 writePin(LED_NUM_LOCK_PIN, num_lock);
640 #endif
641 #endif
642 #if defined(LED_CAPS_LOCK_PIN)
643 #if defined(LED_CAPS_LOCK_ACTIVE_LOW)
644 writePin(LED_CAPS_LOCK_PIN, !caps_lock);
645 #else
646 writePin(LED_CAPS_LOCK_PIN, caps_lock);
647 #endif
648 #endif
649 #if defined(LED_SCROLL_LOCK_PIN)
650 #if defined(LED_SCROLL_LOCK_ACTIVE_LOW)
651 writePin(LED_SCROLL_LOCK_PIN, !scroll_lock);
652 #else
653 writePin(LED_SCROLL_LOCK_PIN, scroll_lock);
654 #endif
655 #endif
656}
657
09c2b24e
PA
658void real_keyboard_init_basic(void)
659{
12d658b8 660 SETUP_UNUSED_PINS();
03a454e1
PA
661
662 #if defined(LED_NUM_LOCK_PIN)
663 setPinOutput(LED_NUM_LOCK_PIN);
664 #endif
665 #if defined(LED_CAPS_LOCK_PIN)
666 setPinOutput(LED_CAPS_LOCK_PIN);
667 #endif
668 #if defined(LED_SCROLL_LOCK_PIN)
669 setPinOutput(LED_SCROLL_LOCK_PIN);
670 #endif
671 set_leds(0, 0, 0);
672
38e6feca 673 #ifndef NO_PRINT
09c2b24e 674 uprintf("shift_init()");
38e6feca 675 #endif
09c2b24e 676 shift_init();
38e6feca 677 #ifndef NO_PRINT
09c2b24e
PA
678 uprintf(" DONE\n");
679 uprintf("dac_init()");
38e6feca 680 #endif
09c2b24e 681 dac_init();
38e6feca 682 #ifndef NO_PRINT
09c2b24e 683 uprintf(" DONE\n");
38e6feca 684 #endif
c5657b7d 685 SETUP_ROW_GPIOS();
f4270f7d 686 #if CAPSENSE_CAL_ENABLED
f3f721b9
PA
687 calibration();
688 #else
38e6feca
PA
689 dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
690 dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
691 dac_write_threshold(CAPSENSE_HARDCODED_THRESHOLD);
f3f721b9 692 #endif
330e4867 693 #if defined(CONTROLLER_IS_THROUGH_HOLE_BEAMSPRING) || defined(CONTROLLER_IS_THROUGH_HOLE_MODEL_F)
b6bb4370
PA
694 // Disable on-board leds.
695 setPinOutput(D5);
696 writePin(D5, 1);
697 setPinOutput(B0);
698 writePin(B0, 1);
699 #endif
a03d56f8
PA
700 #ifdef USING_SOLENOID_ENABLE_PIN
701 // ^^ this must be defined in config.h if you are using and xwhatsit type solenoid
702 setPinOutput(USING_SOLENOID_ENABLE_PIN);
703 writePin(USING_SOLENOID_ENABLE_PIN, 1);
704 #endif
09c2b24e
PA
705}
706
03a454e1
PA
707
708bool led_update_kb(led_t led_state) {
709 bool res = led_update_user(led_state);
710 if(res) {
711 set_leds(led_state.num_lock, led_state.caps_lock, led_state.scroll_lock);
712 }
713 return res;
714}
715
06b963f3 716void matrix_init_custom(void) {
03a454e1
PA
717
718
9d9305db 719 //test_v2();
1e57a998 720 //tracking_test();
09c2b24e 721 real_keyboard_init_basic();
06b963f3
PA
722}
723
f3f721b9 724matrix_row_t previous_matrix[MATRIX_ROWS];
38e6feca
PA
725
726bool matrix_has_it_changed(const matrix_row_t current_matrix[]) {
727 uint8_t row;
728 bool changed = false;
729 for (row=0;row<MATRIX_ROWS;row++)
730 {
731 if (previous_matrix[row] != current_matrix[row]) changed = true;
732 previous_matrix[row] = current_matrix[row];
733 }
734 return changed;
735}
736
f4270f7d 737#if CAPSENSE_CAL_ENABLED && CAPSENSE_CAL_DEBUG
f3f721b9
PA
738bool cal_stats_printed = false;
739#endif
dabf024c 740
38e6feca
PA
741bool keyboard_scan_enabled = 1;
742
743#ifndef NO_PRINT
744void matrix_print_stats(void)
745{
746 uint8_t row, cal;
f4270f7d 747 #if CAPSENSE_CAL_ENABLED && CAPSENSE_CAL_DEBUG
f3f721b9
PA
748 if (!cal_stats_printed)
749 {
750 uint32_t time = timer_read32();
751 if (time >= 10 * 1000UL) { // after 10 seconds
752 uprintf("Cal All Zero = %u, Cal All Ones = %u\n", cal_tr_allzero, cal_tr_allone);
3e1298e4 753 for (cal=0;cal<CAPSENSE_CAL_BINS;cal++)
f3f721b9
PA
754 {
755 uprintf("Cal bin %u, Threshold=%u Assignments:\n", cal, cal_thresholds[cal]);
756 for (row=0;row<MATRIX_ROWS;row++)
757 {
758 uprintf("0x%02X\n", assigned_to_threshold[cal][row]);
759 }
760 }
761 cal_stats_printed = true;
762 }
763 }
764 #endif
38e6feca
PA
765}
766#endif
767
768void matrix_scan_raw(matrix_row_t current_matrix[]) {
02743d4c 769 uint8_t col, row;
38e6feca 770 memset(current_matrix, 0, sizeof(matrix_row_t) * MATRIX_ROWS);
f4270f7d 771 #if CAPSENSE_CAL_ENABLED
02743d4c 772 uint8_t cal;
3e1298e4 773 for (cal=0;cal<CAPSENSE_CAL_BINS;cal++) {
f3f721b9
PA
774 dac_write_threshold(cal_thresholds[cal]);
775 for (col=0;col<MATRIX_COLS;col++) {
f4270f7d 776 uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
23d3309b 777 uint8_t d, interference;
f3f721b9
PA
778 uint8_t d_tested = 0;
779 for (row=0;row<MATRIX_ROWS;row++) {
3ee273a4 780 if (assigned_to_threshold[cal][row] & (((matrix_row_t)1) << col))
f3f721b9
PA
781 {
782 if (!d_tested)
783 {
23d3309b 784 d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME, &interference);
f4270f7d
PA
785 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
786 d = ~d;
787 #endif
f3f721b9
PA
788 d_tested = 1;
789 }
f4270f7d 790 uint8_t physical_row = CAPSENSE_KEYMAP_ROW_TO_PHYSICAL_ROW(row);
23d3309b
PA
791 if (!((interference >> physical_row) & 1))
792 {
793 current_matrix[row] |= ((matrix_row_t)((d >> physical_row) & 1)) << col;
794 }
f3f721b9
PA
795 }
796 }
797 }
798 }
799 #else
800 for (col=0;col<MATRIX_COLS;col++)
09c2b24e 801 {
f4270f7d 802 uint8_t real_col = CAPSENSE_KEYMAP_COL_TO_PHYSICAL_COL(col);
23d3309b
PA
803 uint8_t interference;
804 uint8_t d = test_single(real_col, CAPSENSE_HARDCODED_SAMPLE_TIME, &interference);
f4270f7d
PA
805 #ifdef CAPSENSE_CONDUCTIVE_PLASTIC_IS_PULLED_UP_ON_KEYPRESS
806 d = ~d;
807 #endif
f3f721b9 808 for (row=0;row<MATRIX_ROWS;row++)
09c2b24e 809 {
a6b3e4e5 810 current_matrix[CAPSENSE_PHYSICAL_ROW_TO_KEYMAP_ROW(row)] |= (((matrix_row_t)(d & 1)) << col);
09c2b24e
PA
811 d >>= 1;
812 }
813 }
f3f721b9 814 #endif
38e6feca
PA
815}
816
817bool matrix_scan_custom(matrix_row_t current_matrix[]) {
818#ifndef NO_PRINT
819 matrix_print_stats();
820#endif
821 if (keyboard_scan_enabled) {
822 matrix_scan_raw(current_matrix);
823 } else {
824 memset(current_matrix, 0, sizeof(matrix_row_t) * MATRIX_ROWS);
f3f721b9 825 }
38e6feca 826 return matrix_has_it_changed(current_matrix);
332fa7c4 827}