]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/handwired/dactyl/matrix.c
Remove/migrate action_get_macro()s from default keymaps (#5625)
[qmk_firmware.git] / keyboards / handwired / dactyl / matrix.c
1 /*
2 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
3 Copyright 2017 Erin Call <hello@erincall.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <avr/io.h>
21 #include "wait.h"
22 #include "action_layer.h"
23 #include "print.h"
24 #include "debug.h"
25 #include "util.h"
26 #include "matrix.h"
27 #include "dactyl.h"
28 #include "i2cmaster.h"
29 #include "timer.h"
30
31
32 /* Set 0 if debouncing isn't needed */
33
34 #ifndef DEBOUNCE
35 #   define DEBOUNCE 5
36 #endif
37
38 #if (DEBOUNCE > 0)
39     static uint16_t debouncing_time;
40     static bool debouncing = false;
41 #endif
42
43 #ifdef MATRIX_MASKED
44     extern const matrix_row_t matrix_mask[];
45 #endif
46
47 #if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
48 static const uint8_t onboard_row_pins[MATRIX_ROWS] = MATRIX_ONBOARD_ROW_PINS;
49 static const uint8_t onboard_col_pins[MATRIX_COLS] = MATRIX_ONBOARD_COL_PINS;
50 static const bool col_expanded[MATRIX_COLS] = COL_EXPANDED;
51 #endif
52
53 /* matrix state(1:on, 0:off) */
54 static matrix_row_t matrix[MATRIX_ROWS];
55
56 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
57
58 #if (DIODE_DIRECTION == COL2ROW)
59     static const uint8_t expander_col_pins[MATRIX_COLS] = MATRIX_EXPANDER_COL_PINS;
60     static void init_cols(void);
61     static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
62     static void unselect_rows(void);
63     static void select_row(uint8_t row);
64     static void unselect_row(uint8_t row);
65 #elif (DIODE_DIRECTION == ROW2COL)
66     static const uint8_t expander_row_pins[MATRIX_ROWS] = MATRIX_EXPANDER_ROW_PINS;
67     static void init_rows(void);
68     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
69     static void unselect_cols(void);
70     static void select_col(uint8_t col);
71     static void unselect_col(uint8_t col);
72 #endif
73
74 static uint8_t expander_reset_loop;
75 uint8_t expander_status;
76 uint8_t expander_input_pin_mask;
77 bool i2c_initialized = false;
78
79 #ifdef DEBUG_MATRIX_SCAN_RATE
80 uint32_t matrix_timer;
81 uint32_t matrix_scan_count;
82 #endif
83
84 #define ROW_SHIFTER ((matrix_row_t)1)
85
86 __attribute__ ((weak))
87 void matrix_init_user(void) {}
88
89 __attribute__ ((weak))
90 void matrix_scan_user(void) {}
91
92 __attribute__ ((weak))
93 void matrix_init_kb(void) {
94   matrix_init_user();
95 }
96
97 __attribute__ ((weak))
98 void matrix_scan_kb(void) {
99   matrix_scan_user();
100 }
101
102 inline
103 uint8_t matrix_rows(void)
104 {
105     return MATRIX_ROWS;
106 }
107
108 inline
109 uint8_t matrix_cols(void)
110 {
111     return MATRIX_COLS;
112 }
113
114 void matrix_init(void)
115 {
116     init_expander();
117
118 #if (DIODE_DIRECTION == COL2ROW)
119     unselect_rows();
120     init_cols();
121 #elif (DIODE_DIRECTION == ROW2COL)
122     unselect_cols();
123     init_rows();
124 #endif
125
126     // initialize matrix state: all keys off
127     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
128         matrix[i] = 0;
129         matrix_debouncing[i] = 0;
130     }
131
132 #ifdef DEBUG_MATRIX_SCAN_RATE
133     matrix_timer = timer_read32();
134     matrix_scan_count = 0;
135 #endif
136
137     matrix_init_quantum();
138 }
139
140 void init_expander(void) {
141     if (! i2c_initialized) {
142         i2c_init();
143         wait_us(1000000);
144     }
145
146     if (! expander_input_pin_mask) {
147 #if (DIODE_DIRECTION == COL2ROW)
148         for (int col = 0; col < MATRIX_COLS; col++) {
149             if (col_expanded[col]) {
150                 expander_input_pin_mask |= (1 << expander_col_pins[col]);
151             }
152         }
153 #elif (DIODE_DIRECTION == ROW2COL)
154         for (int row = 0; row < MATRIX_ROWS; row++) {
155             expander_input_pin_mask |= (1 << expander_row_pins[row]);
156         }
157 #endif
158     }
159
160     expander_status = i2c_start(I2C_ADDR_WRITE); if (expander_status) goto out;
161     expander_status = i2c_write(IODIRA);         if (expander_status) goto out;
162
163     /*
164     Pin direction and pull-up depends on both the diode direction
165     and on whether the column register is GPIOA or GPIOB
166     +-------+---------------+---------------+
167     |       | ROW2COL       | COL2ROW       |
168     +-------+---------------+---------------+
169     | GPIOA | input, output | output, input |
170     +-------+---------------+---------------+
171     | GPIOB | output, input | input, output |
172     +-------+---------------+---------------+
173     */
174
175 #if (EXPANDER_COL_REGISTER == GPIOA)
176 #   if (DIODE_DIRECTION == COL2ROW)
177         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
178         expander_status = i2c_write(0);                       if (expander_status) goto out;
179 #   elif (DIODE_DIRECTION == ROW2COL)
180         expander_status = i2c_write(0);                       if (expander_status) goto out;
181         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
182 #   endif
183 #elif (EXPANDER_COL_REGISTER == GPIOB)
184 #   if (DIODE_DIRECTION == COL2ROW)
185         expander_status = i2c_write(0);                       if (expander_status) goto out;
186         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
187 #   elif (DIODE_DIRECTION == ROW2COL)
188         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
189         expander_status = i2c_write(0);                       if (expander_status) goto out;
190 #   endif
191 #endif
192
193     i2c_stop();
194
195     // set pull-up
196     // - unused  : off : 0
197     // - input   : on  : 1
198     // - driving : off : 0
199     expander_status = i2c_start(I2C_ADDR_WRITE);              if (expander_status) goto out;
200     expander_status = i2c_write(GPPUA);                       if (expander_status) goto out;
201 #if (EXPANDER_COL_REGISTER == GPIOA)
202 #   if (DIODE_DIRECTION == COL2ROW)
203         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
204         expander_status = i2c_write(0);                       if (expander_status) goto out;
205 #   elif (DIODE_DIRECTION == ROW2COL)
206         expander_status = i2c_write(0);                       if (expander_status) goto out;
207         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
208 #   endif
209 #elif (EXPANDER_COL_REGISTER == GPIOB)
210 #   if (DIODE_DIRECTION == COL2ROW)
211         expander_status = i2c_write(0);                       if (expander_status) goto out;
212         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
213 #   elif (DIODE_DIRECTION == ROW2COL)
214         expander_status = i2c_write(expander_input_pin_mask); if (expander_status) goto out;
215         expander_status = i2c_write(0);                       if (expander_status) goto out;
216 #   endif
217 #endif
218
219 out:
220     i2c_stop();
221 }
222
223 uint8_t matrix_scan(void)
224 {
225     if (expander_status) { // if there was an error
226         if (++expander_reset_loop == 0) {
227             // since expander_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
228             // this will be approx bit more frequent than once per second
229             print("trying to reset expander\n");
230             init_expander();
231             if (expander_status) {
232                 print("left side not responding\n");
233             } else {
234                 print("left side attached\n");
235             }
236         }
237     }
238
239 #ifdef DEBUG_MATRIX_SCAN_RATE
240     matrix_scan_count++;
241
242     uint32_t timer_now = timer_read32();
243     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
244         print("matrix scan frequency: ");
245         pdec(matrix_scan_count);
246         print("\n");
247
248         matrix_timer = timer_now;
249         matrix_scan_count = 0;
250     }
251 #endif
252
253 #if (DIODE_DIRECTION == COL2ROW)
254     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
255 #       if (DEBOUNCE > 0)
256             bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
257
258             if (matrix_changed) {
259                 debouncing = true;
260                 debouncing_time = timer_read();
261             }
262 #       else
263             read_cols_on_row(matrix, current_row);
264 #       endif
265     }
266
267 #elif (DIODE_DIRECTION == ROW2COL)
268     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
269 #       if (DEBOUNCE > 0)
270             bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
271
272             if (matrix_changed) {
273                 debouncing = true;
274                 debouncing_time = timer_read();
275             }
276 #       else
277             read_rows_on_col(matrix, current_col);
278 #       endif
279
280     }
281 #endif
282
283 #   if (DEBOUNCE > 0)
284         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCE)) {
285             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
286                 matrix[i] = matrix_debouncing[i];
287             }
288             debouncing = false;
289         }
290 #   endif
291
292     matrix_scan_quantum();
293     return 1;
294 }
295
296 bool matrix_is_modified(void) // deprecated and evidently not called.
297 {
298 #if (DEBOUNCE > 0)
299     if (debouncing) return false;
300 #endif
301     return true;
302 }
303
304 inline
305 bool matrix_is_on(uint8_t row, uint8_t col)
306 {
307     return (matrix[row] & (ROW_SHIFTER << col));
308 }
309
310 inline
311 matrix_row_t matrix_get_row(uint8_t row)
312 {
313 #ifdef MATRIX_MASKED
314     return matrix[row] & matrix_mask[row];
315 #else
316     return matrix[row];
317 #endif
318 }
319
320 void matrix_print(void)
321 {
322     print("\nr/c 0123456789ABCDEF\n");
323     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
324         phex(row); print(": ");
325         pbin_reverse16(matrix_get_row(row));
326         print("\n");
327     }
328 }
329
330 uint8_t matrix_key_count(void)
331 {
332     uint8_t count = 0;
333     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
334         count += bitpop16(matrix[i]);
335     }
336     return count;
337 }
338
339 #if (DIODE_DIRECTION == COL2ROW)
340
341 static void init_cols(void) {
342     for (uint8_t x = 0; x < MATRIX_COLS; x++) {
343         if (! col_expanded[x]) {
344             uint8_t pin = onboard_col_pins[x];
345             _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
346             _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
347         }
348     }
349 }
350
351 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
352     // Store last value of row prior to reading
353     matrix_row_t last_row_value = current_matrix[current_row];
354
355     // Clear data in matrix row
356     current_matrix[current_row] = 0;
357
358     // Select row and wait for row selection to stabilize
359     select_row(current_row);
360     wait_us(30);
361
362     // Read columns from expander, unless it's in an error state
363     if (! expander_status) {
364         expander_status = i2c_start(I2C_ADDR_WRITE);           if (expander_status) goto out;
365         expander_status = i2c_write(EXPANDER_COL_REGISTER);    if (expander_status) goto out;
366         expander_status = i2c_start(I2C_ADDR_READ);            if (expander_status) goto out;
367
368         current_matrix[current_row] |= (~i2c_readNak()) & expander_input_pin_mask;
369
370         out:
371             i2c_stop();
372     }
373
374     // Read columns from onboard pins
375     for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
376         if (! col_expanded[col_index]) {
377             uint8_t pin = onboard_col_pins[col_index];
378             uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
379             current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
380         }
381     }
382
383     unselect_row(current_row);
384
385     return (last_row_value != current_matrix[current_row]);
386 }
387
388 static void select_row(uint8_t row) {
389     // select on expander, unless it's in an error state
390     if (! expander_status) {
391         // set active row low  : 0
392         // set other rows hi-Z : 1
393         expander_status = i2c_start(I2C_ADDR_WRITE);           if (expander_status) goto out;
394         expander_status = i2c_write(EXPANDER_ROW_REGISTER);    if (expander_status) goto out;
395         expander_status = i2c_write(0xFF & ~(1<<row));         if (expander_status) goto out;
396     out:
397         i2c_stop();
398     }
399
400     // select on teensy
401     uint8_t pin = onboard_row_pins[row];
402     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
403     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
404 }
405
406 static void unselect_row(uint8_t row)
407 {
408     // No need to explicitly unselect expander pins--their I/O state is
409     // set simultaneously, with a single bitmask sent to i2c_write. When
410     // select_row selects a single pin, it implicitly unselects all the
411     // other ones.
412
413     // unselect on teensy
414     uint8_t pin = onboard_row_pins[row];
415     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // OUT
416     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // LOW
417 }
418
419 static void unselect_rows(void) {
420     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
421         unselect_row(x);
422     }
423 }
424
425 #elif (DIODE_DIRECTION == ROW2COL)
426
427 static void init_rows(void)
428 {
429     for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
430         uint8_t pin = onboard_row_pins[x];
431         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
432         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
433     }
434 }
435
436 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
437 {
438     bool matrix_changed = false;
439
440     uint8_t column_state = 0;
441
442     //select col and wait for selection to stabilize
443     select_col(current_col);
444     wait_us(30);
445
446     if (current_col < 6) {
447         // read rows from expander
448         if (expander_status) {
449             // it's already in an error state; nothing we can do
450             return false;
451         }
452
453         expander_status = i2c_start(I2C_ADDR_WRITE);           if (expander_status) goto out;
454         expander_status = i2c_write(EXPANDER_ROW_REGISTER);    if (expander_status) goto out;
455         expander_status = i2c_start(I2C_ADDR_READ);            if (expander_status) goto out;
456         column_state = i2c_readNak();
457
458         out:
459             i2c_stop();
460
461         column_state = ~column_state;
462     } else {
463         for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
464             if ((_SFR_IO8(onboard_row_pins[current_row] >> 4) & _BV(onboard_row_pins[current_row] & 0xF)) == 0) {
465                 column_state |= (1 << current_row);
466             }
467         }
468     }
469
470     for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
471         // Store last value of row prior to reading
472         matrix_row_t last_row_value = current_matrix[current_row];
473
474         if (column_state & (1 << current_row)) {
475             // key closed; set state bit in matrix
476             current_matrix[current_row] |= (ROW_SHIFTER << current_col);
477         } else {
478             // key open; clear state bit in matrix
479             current_matrix[current_row] &= ~(ROW_SHIFTER << current_col);
480         }
481
482         // Determine whether the matrix changed state
483         if ((last_row_value != current_matrix[current_row]) && !(matrix_changed))
484         {
485             matrix_changed = true;
486         }
487     }
488
489     unselect_col(current_col);
490
491     return matrix_changed;
492 }
493
494 static void select_col(uint8_t col)
495 {
496     if (col_expanded[col]) {
497         // select on expander
498         if (expander_status) { // if there was an error
499             // do nothing
500         } else {
501             // set active col low  : 0
502             // set other cols hi-Z : 1
503             expander_status = i2c_start(I2C_ADDR_WRITE);          if (expander_status) goto out;
504             expander_status = i2c_write(EXPANDER_COL_REGISTER);   if (expander_status) goto out;
505             expander_status = i2c_write(0xFF & ~(1<<col));        if (expander_status) goto out;
506         out:
507             i2c_stop();
508         }
509     } else {
510         // select on teensy
511         uint8_t pin = onboard_col_pins[col];
512         _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
513         _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
514     }
515 }
516
517 static void unselect_col(uint8_t col)
518 {
519     if (col_expanded[col]) {
520         // No need to explicitly unselect expander pins--their I/O state is
521         // set simultaneously, with a single bitmask sent to i2c_write. When
522         // select_col selects a single pin, it implicitly unselects all the
523         // other ones.
524     } else {
525         // unselect on teensy
526         uint8_t pin = onboard_col_pins[col];
527         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
528         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
529     }
530 }
531
532 static void unselect_cols(void)
533 {
534     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
535         unselect_col(x);
536     }
537 }
538 #endif