]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/miniaxe/matrix.c
Replace serial.c of quantum/split_common/ (#4669)
[qmk_firmware.git] / keyboards / miniaxe / matrix.c
1 /*
2 Copyright 2012 Jun Wako <wakojun@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /*
19  * scan matrix
20  */
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <avr/io.h>
24 #include "wait.h"
25 #include "print.h"
26 #include "debug.h"
27 #include "util.h"
28 #include "matrix.h"
29 #include "split_util.h"
30 #include "pro_micro.h"
31 #include "config.h"
32 #include "timer.h"
33 #include "split_flags.h"
34
35 #ifdef BACKLIGHT_ENABLE
36 #   include "backlight.h"
37     extern backlight_config_t backlight_config;
38 #endif
39
40 #if defined(USE_I2C) || defined(EH)
41 #  include "i2c.h"
42 #else // USE_SERIAL
43 #  include "serial.h"
44 #endif
45
46 #ifndef DEBOUNCING_DELAY
47 #   define DEBOUNCING_DELAY 5
48 #endif
49
50 #if (DEBOUNCING_DELAY > 0)
51     static uint16_t debouncing_time;
52     static bool debouncing = false;
53 #endif
54
55 #if defined(USE_I2C) || defined(EH)
56
57 #if (MATRIX_COLS <= 8)
58 #    define print_matrix_header()  print("\nr/c 01234567\n")
59 #    define print_matrix_row(row)  print_bin_reverse8(matrix_get_row(row))
60 #    define matrix_bitpop(i)       bitpop(matrix[i])
61 #    define ROW_SHIFTER ((uint8_t)1)
62 #else
63 #    error "Currently only supports 8 COLS"
64 #endif
65
66 #else // USE_SERIAL
67
68 #if (MATRIX_COLS <= 8)
69 #    define print_matrix_header()  print("\nr/c 01234567\n")
70 #    define print_matrix_row(row)  print_bin_reverse8(matrix_get_row(row))
71 #    define matrix_bitpop(i)       bitpop(matrix[i])
72 #    define ROW_SHIFTER ((uint8_t)1)
73 #elif (MATRIX_COLS <= 16)
74 #    define print_matrix_header()  print("\nr/c 0123456789ABCDEF\n")
75 #    define print_matrix_row(row)  print_bin_reverse16(matrix_get_row(row))
76 #    define matrix_bitpop(i)       bitpop16(matrix[i])
77 #    define ROW_SHIFTER ((uint16_t)1)
78 #elif (MATRIX_COLS <= 32)
79 #    define print_matrix_header()  print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
80 #    define print_matrix_row(row)  print_bin_reverse32(matrix_get_row(row))
81 #    define matrix_bitpop(i)       bitpop32(matrix[i])
82 #    define ROW_SHIFTER  ((uint32_t)1)
83 #endif
84
85 #endif
86 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
87
88 #define ERROR_DISCONNECT_COUNT 5
89
90 #define ROWS_PER_HAND (MATRIX_ROWS/2)
91
92 static uint8_t error_count = 0;
93
94 #if ((DIODE_DIRECTION == COL2ROW) || (DIODE_DIRECTION == ROW2COL))
95 static uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
96 static uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
97 #elif (DIODE_DIRECTION == CUSTOM_MATRIX)
98 static uint8_t row_col_pins[MATRIX_ROWS][MATRIX_COLS] = MATRIX_ROW_COL_PINS;
99 #endif
100
101 /* matrix state(1:on, 0:off) */
102 static matrix_row_t matrix[MATRIX_ROWS];
103 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
104
105 #if (DIODE_DIRECTION == COL2ROW)
106     static void init_cols(void);
107     static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
108     static void unselect_rows(void);
109     static void select_row(uint8_t row);
110     static void unselect_row(uint8_t row);
111 #elif (DIODE_DIRECTION == ROW2COL)
112     static void init_rows(void);
113     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
114     static void unselect_cols(void);
115     static void unselect_col(uint8_t col);
116     static void select_col(uint8_t col);
117 #elif (DIODE_DIRECTION == CUSTOM_MATRIX)
118     static void init_cols_rows(void);
119     static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row);
120 #endif
121
122 __attribute__ ((weak))
123 void matrix_init_kb(void) {
124     matrix_init_user();
125 }
126
127 __attribute__ ((weak))
128 void matrix_scan_kb(void) {
129     matrix_scan_user();
130 }
131
132 __attribute__ ((weak))
133 void matrix_init_user(void) {
134 }
135
136 __attribute__ ((weak))
137 void matrix_scan_user(void) {
138 }
139
140 __attribute__ ((weak))
141 void matrix_slave_scan_user(void) {
142 }
143
144 inline
145 uint8_t matrix_rows(void)
146 {
147     return MATRIX_ROWS;
148 }
149
150 inline
151 uint8_t matrix_cols(void)
152 {
153     return MATRIX_COLS;
154 }
155
156 void matrix_init(void)
157 {
158 #ifdef DISABLE_JTAG
159   // JTAG disable for PORT F. write JTD bit twice within four cycles.
160   MCUCR |= (1<<JTD);
161   MCUCR |= (1<<JTD);
162 #endif
163
164     debug_enable = true;
165     debug_matrix = true;
166     debug_mouse = true;
167
168     // Set pinout for right half if pinout for that half is defined
169     if (!isLeftHand) {
170 #ifdef MATRIX_ROW_PINS_RIGHT
171         const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
172         for (uint8_t i = 0; i < MATRIX_ROWS; i++)
173             row_pins[i] = row_pins_right[i];
174 #endif
175 #ifdef MATRIX_COL_PINS_RIGHT
176         const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
177         for (uint8_t i = 0; i < MATRIX_COLS; i++)
178             col_pins[i] = col_pins_right[i];
179 #endif
180     }
181
182     // initialize row and col
183 #if (DIODE_DIRECTION == COL2ROW)
184     unselect_rows();
185     init_cols();
186 #elif (DIODE_DIRECTION == ROW2COL)
187     unselect_cols();
188     init_rows();
189 #elif (DIODE_DIRECTION == CUSTOM_MATRIX)
190     init_cols_rows();
191 #endif
192
193     // initialize matrix state: all keys off
194     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
195         matrix[i] = 0;
196         matrix_debouncing[i] = 0;
197     }
198     
199     matrix_init_quantum();
200     
201 }
202
203 uint8_t _matrix_scan(void)
204 {
205     int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
206 #if (DIODE_DIRECTION == COL2ROW)
207     // Set row, read cols
208     for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
209 #       if (DEBOUNCING_DELAY > 0)
210             bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
211
212             if (matrix_changed) {
213                 debouncing = true;
214                 debouncing_time = timer_read();
215             }
216
217 #       else
218             read_cols_on_row(matrix+offset, current_row);
219 #       endif
220
221     }
222
223 #elif (DIODE_DIRECTION == ROW2COL)
224     // Set col, read rows
225     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
226 #       if (DEBOUNCING_DELAY > 0)
227             bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
228             if (matrix_changed) {
229                 debouncing = true;
230                 debouncing_time = timer_read();
231             }
232 #       else
233              read_rows_on_col(matrix+offset, current_col);
234 #       endif
235
236     }
237
238 #elif (DIODE_DIRECTION == CUSTOM_MATRIX)
239     // Set row, read cols
240     for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
241 #       if (DEBOUNCING_DELAY > 0)
242             bool matrix_changed = read_cols(matrix_debouncing+offset, current_row);
243             if (matrix_changed) {
244                 debouncing = true;
245                 debouncing_time = timer_read();
246             }
247 #       else
248             read_cols(matrix+offset, current_row);
249 #       endif
250     }
251 #endif
252
253 #   if (DEBOUNCING_DELAY > 0)
254         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
255             for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
256                 matrix[i+offset] = matrix_debouncing[i+offset];
257             }
258             debouncing = false;
259         }
260 #   endif
261
262     return 1;
263 }
264
265 #if defined(USE_I2C) || defined(EH)
266
267 // Get rows from other half over i2c
268 int i2c_transaction(void) {
269     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
270     int err = 0;
271     
272     // write backlight info
273     #ifdef BACKLIGHT_ENABLE
274         if (BACKLIT_DIRTY) {
275             err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
276             if (err) goto i2c_error;
277             
278             // Backlight location
279             err = i2c_master_write(I2C_BACKLIT_START);
280             if (err) goto i2c_error;
281             
282             // Write backlight 
283             i2c_master_write(get_backlight_level());
284             
285             BACKLIT_DIRTY = false;
286         }
287     #endif
288
289     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
290     if (err) goto i2c_error;
291
292     // start of matrix stored at I2C_KEYMAP_START
293     err = i2c_master_write(I2C_KEYMAP_START);
294     if (err) goto i2c_error;
295
296     // Start read
297     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
298     if (err) goto i2c_error;
299
300     if (!err) {
301         int i;
302         for (i = 0; i < ROWS_PER_HAND-1; ++i) {
303             matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);
304         }
305         matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
306         i2c_master_stop();
307     } else {
308 i2c_error: // the cable is disconnceted, or something else went wrong
309         i2c_reset_state();
310         return err;
311     }
312     
313     #ifdef RGBLIGHT_ENABLE
314         if (RGB_DIRTY) {
315             err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
316             if (err) goto i2c_error;
317             
318             // RGB Location
319             err = i2c_master_write(I2C_RGB_START);
320             if (err) goto i2c_error;
321             
322             uint32_t dword = eeconfig_read_rgblight();
323             
324             // Write RGB
325             err = i2c_master_write_data(&dword, 4);
326             if (err) goto i2c_error;
327             
328             RGB_DIRTY = false;
329             i2c_master_stop();
330         }
331     #endif
332
333     return 0;
334 }
335
336 #else // USE_SERIAL
337
338
339 typedef struct _Serial_s2m_buffer_t {
340     // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
341     matrix_row_t smatrix[ROWS_PER_HAND];
342 } Serial_s2m_buffer_t;
343
344 volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
345 volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
346 uint8_t volatile status0 = 0;
347
348 SSTD_t transactions[] = {
349     { (uint8_t *)&status0,
350       sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
351       sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
352   }
353 };
354
355 void serial_master_init(void)
356 { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
357
358 void serial_slave_init(void)
359 { soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
360
361 int serial_transaction(void) {
362     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
363
364     if (soft_serial_transaction()) {
365         return 1;
366     }
367
368     // TODO:  if MATRIX_COLS > 8 change to unpack()
369     for (int i = 0; i < ROWS_PER_HAND; ++i) {
370         matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i];
371     }
372     
373     #ifdef RGBLIGHT_ENABLE
374         // Code to send RGB over serial goes here (not implemented yet)
375     #endif
376     
377     #ifdef BACKLIGHT_ENABLE
378         // Write backlight level for slave to read
379         serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
380     #endif
381
382     return 0;
383 }
384 #endif
385
386 uint8_t matrix_scan(void)
387 {
388     uint8_t ret = _matrix_scan();
389
390 #if defined(USE_I2C) || defined(EH)
391     if( i2c_transaction() ) {
392 #else // USE_SERIAL
393     if( serial_transaction() ) {
394 #endif
395
396         error_count++;
397
398         if (error_count > ERROR_DISCONNECT_COUNT) {
399             // reset other half if disconnected
400             int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
401             for (int i = 0; i < ROWS_PER_HAND; ++i) {
402                 matrix[slaveOffset+i] = 0;
403             }
404         }
405     } else {
406         error_count = 0;
407     }
408     matrix_scan_quantum();
409     return ret;
410 }
411
412 void matrix_slave_scan(void) {
413     _matrix_scan();
414
415     int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
416
417 #if defined(USE_I2C) || defined(EH)
418     for (int i = 0; i < ROWS_PER_HAND; ++i) {
419         i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i];
420     }   
421 #else // USE_SERIAL
422     // TODO: if MATRIX_COLS > 8 change to pack()
423     for (int i = 0; i < ROWS_PER_HAND; ++i) {
424         serial_s2m_buffer.smatrix[i] = matrix[offset+i];
425     }
426 #endif
427     matrix_slave_scan_user();
428 }
429
430 bool matrix_is_modified(void)
431 {
432     if (debouncing) return false;
433     return true;
434 }
435
436 inline
437 bool matrix_is_on(uint8_t row, uint8_t col)
438 {
439     return (matrix[row] & ((matrix_row_t)1<<col));
440 }
441
442 inline
443 matrix_row_t matrix_get_row(uint8_t row)
444 {
445     return matrix[row];
446 }
447
448 void matrix_print(void)
449 {
450     print("\nr/c 0123456789ABCDEF\n");
451     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
452         phex(row); print(": ");
453         pbin_reverse16(matrix_get_row(row));
454         print("\n");
455     }
456 }
457
458 uint8_t matrix_key_count(void)
459 {
460     uint8_t count = 0;
461     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
462         count += bitpop16(matrix[i]);
463     }
464     return count;
465 }
466
467 #if (DIODE_DIRECTION == COL2ROW)
468
469 static void init_cols(void)
470 {
471     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
472         uint8_t pin = col_pins[x];
473         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
474         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
475     }
476 }
477
478 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
479 {
480     // Store last value of row prior to reading
481     matrix_row_t last_row_value = current_matrix[current_row];
482
483     // Clear data in matrix row
484     current_matrix[current_row] = 0;
485
486     // Select row and wait for row selecton to stabilize
487     select_row(current_row);
488     wait_us(30);
489
490     // For each col...
491     for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
492
493         // Select the col pin to read (active low)
494         uint8_t pin = col_pins[col_index];
495         uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
496
497         // Populate the matrix row with the state of the col pin
498         current_matrix[current_row] |=  pin_state ? 0 : (ROW_SHIFTER << col_index);
499     }
500
501     // Unselect row
502     unselect_row(current_row);
503
504     return (last_row_value != current_matrix[current_row]);
505 }
506
507 static void select_row(uint8_t row)
508 {
509     uint8_t pin = row_pins[row];
510     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
511     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
512 }
513
514 static void unselect_row(uint8_t row)
515 {
516     uint8_t pin = row_pins[row];
517     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
518     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
519 }
520
521 static void unselect_rows(void)
522 {
523     for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
524         uint8_t pin = row_pins[x];
525         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
526         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
527     }
528 }
529
530 #elif (DIODE_DIRECTION == ROW2COL)
531
532 static void init_rows(void)
533 {
534     for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
535         uint8_t pin = row_pins[x];
536         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
537         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
538     }
539 }
540
541 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
542 {
543     bool matrix_changed = false;
544
545     // Select col and wait for col selecton to stabilize
546     select_col(current_col);
547     wait_us(30);
548
549     // For each row...
550     for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++)
551     {
552
553         // Store last value of row prior to reading
554         matrix_row_t last_row_value = current_matrix[row_index];
555
556         // Check row pin state
557         if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
558         {
559             // Pin LO, set col bit
560             current_matrix[row_index] |= (ROW_SHIFTER << current_col);
561         }
562         else
563         {
564             // Pin HI, clear col bit
565             current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
566         }
567
568         // Determine if the matrix changed state
569         if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
570         {
571             matrix_changed = true;
572         }
573     }
574
575     // Unselect col
576     unselect_col(current_col);
577
578     return matrix_changed;
579 }
580
581 static void select_col(uint8_t col)
582 {
583     uint8_t pin = col_pins[col];
584     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
585     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
586 }
587
588 static void unselect_col(uint8_t col)
589 {
590     uint8_t pin = col_pins[col];
591     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
592     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
593 }
594
595 static void unselect_cols(void)
596 {
597     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
598         uint8_t pin = col_pins[x];
599         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
600         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
601     }
602 }
603
604 #elif (DIODE_DIRECTION == CUSTOM_MATRIX)
605
606 static void init_cols_rows(void)
607 {
608     for(int row = 0; row < MATRIX_ROWS; row++) {
609         for(int col = 0; col < MATRIX_COLS; col++) {
610             uint8_t pin = row_col_pins[row][col];
611             if(pin == NO_PIN) {
612                 continue;
613             }
614             // DDxn set 0 for input
615             _SFR_IO8((pin >> 4) + 1) &=  ~_BV(pin & 0xF);
616             // PORTxn set 1 for input/pullup
617             _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
618         }
619     }
620 }
621
622 static bool read_cols(matrix_row_t current_matrix[], uint8_t current_row)
623 {
624     matrix_row_t last_row_value = current_matrix[current_row];
625     current_matrix[current_row] = 0;
626
627     for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
628         uint8_t pin = row_col_pins[current_row][col_index];
629         if(pin == NO_PIN) {
630             current_matrix[current_row] |= 0;
631         }
632         else {
633             uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
634             current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
635         }
636     }
637
638     return (last_row_value != current_matrix[current_row]);
639 }
640
641 #endif