]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/split_common/matrix.c
Replace serial.c of quantum/split_common/ (#4669)
[qmk_firmware.git] / quantum / split_common / 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 static uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
95 static uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
96
97 /* matrix state(1:on, 0:off) */
98 static matrix_row_t matrix[MATRIX_ROWS];
99 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
100
101 #if (DIODE_DIRECTION == COL2ROW)
102     static void init_cols(void);
103     static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
104     static void unselect_rows(void);
105     static void select_row(uint8_t row);
106     static void unselect_row(uint8_t row);
107 #elif (DIODE_DIRECTION == ROW2COL)
108     static void init_rows(void);
109     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
110     static void unselect_cols(void);
111     static void unselect_col(uint8_t col);
112     static void select_col(uint8_t col);
113 #endif
114
115 __attribute__ ((weak))
116 void matrix_init_kb(void) {
117     matrix_init_user();
118 }
119
120 __attribute__ ((weak))
121 void matrix_scan_kb(void) {
122     matrix_scan_user();
123 }
124
125 __attribute__ ((weak))
126 void matrix_init_user(void) {
127 }
128
129 __attribute__ ((weak))
130 void matrix_scan_user(void) {
131 }
132
133 __attribute__ ((weak))
134 void matrix_slave_scan_user(void) {
135 }
136
137 inline
138 uint8_t matrix_rows(void)
139 {
140     return MATRIX_ROWS;
141 }
142
143 inline
144 uint8_t matrix_cols(void)
145 {
146     return MATRIX_COLS;
147 }
148
149 void matrix_init(void)
150 {
151     debug_enable = true;
152     debug_matrix = true;
153     debug_mouse = true;
154
155     // Set pinout for right half if pinout for that half is defined
156     if (!isLeftHand) {
157 #ifdef MATRIX_ROW_PINS_RIGHT
158         const uint8_t row_pins_right[MATRIX_ROWS] = MATRIX_ROW_PINS_RIGHT;
159         for (uint8_t i = 0; i < MATRIX_ROWS; i++)
160             row_pins[i] = row_pins_right[i];
161 #endif
162 #ifdef MATRIX_COL_PINS_RIGHT
163         const uint8_t col_pins_right[MATRIX_COLS] = MATRIX_COL_PINS_RIGHT;
164         for (uint8_t i = 0; i < MATRIX_COLS; i++)
165             col_pins[i] = col_pins_right[i];
166 #endif
167     }
168
169     // initialize row and col
170 #if (DIODE_DIRECTION == COL2ROW)
171     unselect_rows();
172     init_cols();
173 #elif (DIODE_DIRECTION == ROW2COL)
174     unselect_cols();
175     init_rows();
176 #endif
177
178     // initialize matrix state: all keys off
179     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
180         matrix[i] = 0;
181         matrix_debouncing[i] = 0;
182     }
183     
184     matrix_init_quantum();
185     
186 }
187
188 uint8_t _matrix_scan(void)
189 {
190     int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
191 #if (DIODE_DIRECTION == COL2ROW)
192     // Set row, read cols
193     for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
194 #       if (DEBOUNCING_DELAY > 0)
195             bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
196
197             if (matrix_changed) {
198                 debouncing = true;
199                 debouncing_time = timer_read();
200             }
201
202 #       else
203             read_cols_on_row(matrix+offset, current_row);
204 #       endif
205
206     }
207
208 #elif (DIODE_DIRECTION == ROW2COL)
209     // Set col, read rows
210     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
211 #       if (DEBOUNCING_DELAY > 0)
212             bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
213             if (matrix_changed) {
214                 debouncing = true;
215                 debouncing_time = timer_read();
216             }
217 #       else
218              read_rows_on_col(matrix+offset, current_col);
219 #       endif
220
221     }
222 #endif
223
224 #   if (DEBOUNCING_DELAY > 0)
225         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
226             for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
227                 matrix[i+offset] = matrix_debouncing[i+offset];
228             }
229             debouncing = false;
230         }
231 #   endif
232
233     return 1;
234 }
235
236 #if defined(USE_I2C) || defined(EH)
237
238 // Get rows from other half over i2c
239 int i2c_transaction(void) {
240     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
241     int err = 0;
242     
243     // write backlight info
244     #ifdef BACKLIGHT_ENABLE
245         if (BACKLIT_DIRTY) {
246             err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
247             if (err) goto i2c_error;
248             
249             // Backlight location
250             err = i2c_master_write(I2C_BACKLIT_START);
251             if (err) goto i2c_error;
252             
253             // Write backlight 
254             i2c_master_write(get_backlight_level());
255             
256             BACKLIT_DIRTY = false;
257         }
258     #endif
259
260     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
261     if (err) goto i2c_error;
262
263     // start of matrix stored at I2C_KEYMAP_START
264     err = i2c_master_write(I2C_KEYMAP_START);
265     if (err) goto i2c_error;
266
267     // Start read
268     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
269     if (err) goto i2c_error;
270
271     if (!err) {
272         int i;
273         for (i = 0; i < ROWS_PER_HAND-1; ++i) {
274             matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);
275         }
276         matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
277         i2c_master_stop();
278     } else {
279 i2c_error: // the cable is disconnceted, or something else went wrong
280         i2c_reset_state();
281         return err;
282     }
283     
284     #ifdef RGBLIGHT_ENABLE
285         if (RGB_DIRTY) {
286             err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
287             if (err) goto i2c_error;
288             
289             // RGB Location
290             err = i2c_master_write(I2C_RGB_START);
291             if (err) goto i2c_error;
292             
293             uint32_t dword = eeconfig_read_rgblight();
294             
295             // Write RGB
296             err = i2c_master_write_data(&dword, 4);
297             if (err) goto i2c_error;
298             
299             RGB_DIRTY = false;
300             i2c_master_stop();
301         }
302     #endif
303
304     return 0;
305 }
306
307 #else // USE_SERIAL
308
309
310 typedef struct _Serial_s2m_buffer_t {
311     // TODO: if MATRIX_COLS > 8 change to uint8_t packed_matrix[] for pack/unpack
312     matrix_row_t smatrix[ROWS_PER_HAND];
313 } Serial_s2m_buffer_t;
314
315 volatile Serial_s2m_buffer_t serial_s2m_buffer = {};
316 volatile Serial_m2s_buffer_t serial_m2s_buffer = {};
317 uint8_t volatile status0 = 0;
318
319 SSTD_t transactions[] = {
320     { (uint8_t *)&status0,
321       sizeof(serial_m2s_buffer), (uint8_t *)&serial_m2s_buffer,
322       sizeof(serial_s2m_buffer), (uint8_t *)&serial_s2m_buffer
323   }
324 };
325
326 void serial_master_init(void)
327 { soft_serial_initiator_init(transactions, TID_LIMIT(transactions)); }
328
329 void serial_slave_init(void)
330 { soft_serial_target_init(transactions, TID_LIMIT(transactions)); }
331
332 int serial_transaction(void) {
333     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
334
335     if (soft_serial_transaction()) {
336         return 1;
337     }
338
339     // TODO:  if MATRIX_COLS > 8 change to unpack()
340     for (int i = 0; i < ROWS_PER_HAND; ++i) {
341         matrix[slaveOffset+i] = serial_s2m_buffer.smatrix[i];
342     }
343     
344     #if defined(RGBLIGHT_ENABLE) && defined(RGBLIGHT_SPLIT)
345         // Code to send RGB over serial goes here (not implemented yet)
346     #endif
347     
348     #ifdef BACKLIGHT_ENABLE
349         // Write backlight level for slave to read
350         serial_m2s_buffer.backlight_level = backlight_config.enable ? backlight_config.level : 0;
351     #endif
352
353     return 0;
354 }
355 #endif
356
357 uint8_t matrix_scan(void)
358 {
359     uint8_t ret = _matrix_scan();
360
361 #if defined(USE_I2C) || defined(EH)
362     if( i2c_transaction() ) {
363 #else // USE_SERIAL
364     if( serial_transaction() ) {
365 #endif
366
367         error_count++;
368
369         if (error_count > ERROR_DISCONNECT_COUNT) {
370             // reset other half if disconnected
371             int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
372             for (int i = 0; i < ROWS_PER_HAND; ++i) {
373                 matrix[slaveOffset+i] = 0;
374             }
375         }
376     } else {
377         error_count = 0;
378     }
379     matrix_scan_quantum();
380     return ret;
381 }
382
383 void matrix_slave_scan(void) {
384     _matrix_scan();
385
386     int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
387
388 #if defined(USE_I2C) || defined(EH)
389     for (int i = 0; i < ROWS_PER_HAND; ++i) {
390         i2c_slave_buffer[I2C_KEYMAP_START+i] = matrix[offset+i];
391     }   
392 #else // USE_SERIAL
393     // TODO: if MATRIX_COLS > 8 change to pack()
394     for (int i = 0; i < ROWS_PER_HAND; ++i) {
395         serial_s2m_buffer.smatrix[i] = matrix[offset+i];
396     }
397 #endif
398     matrix_slave_scan_user();
399 }
400
401 bool matrix_is_modified(void)
402 {
403     if (debouncing) return false;
404     return true;
405 }
406
407 inline
408 bool matrix_is_on(uint8_t row, uint8_t col)
409 {
410     return (matrix[row] & ((matrix_row_t)1<<col));
411 }
412
413 inline
414 matrix_row_t matrix_get_row(uint8_t row)
415 {
416     return matrix[row];
417 }
418
419 void matrix_print(void)
420 {
421     print("\nr/c 0123456789ABCDEF\n");
422     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
423         phex(row); print(": ");
424         pbin_reverse16(matrix_get_row(row));
425         print("\n");
426     }
427 }
428
429 uint8_t matrix_key_count(void)
430 {
431     uint8_t count = 0;
432     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
433         count += bitpop16(matrix[i]);
434     }
435     return count;
436 }
437
438 #if (DIODE_DIRECTION == COL2ROW)
439
440 static void init_cols(void)
441 {
442     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
443         uint8_t pin = col_pins[x];
444         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
445         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
446     }
447 }
448
449 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
450 {
451     // Store last value of row prior to reading
452     matrix_row_t last_row_value = current_matrix[current_row];
453
454     // Clear data in matrix row
455     current_matrix[current_row] = 0;
456
457     // Select row and wait for row selecton to stabilize
458     select_row(current_row);
459     wait_us(30);
460
461     // For each col...
462     for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
463
464         // Select the col pin to read (active low)
465         uint8_t pin = col_pins[col_index];
466         uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
467
468         // Populate the matrix row with the state of the col pin
469         current_matrix[current_row] |=  pin_state ? 0 : (ROW_SHIFTER << col_index);
470     }
471
472     // Unselect row
473     unselect_row(current_row);
474
475     return (last_row_value != current_matrix[current_row]);
476 }
477
478 static void select_row(uint8_t row)
479 {
480     uint8_t pin = row_pins[row];
481     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
482     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
483 }
484
485 static void unselect_row(uint8_t row)
486 {
487     uint8_t pin = row_pins[row];
488     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
489     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
490 }
491
492 static void unselect_rows(void)
493 {
494     for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
495         uint8_t pin = row_pins[x];
496         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
497         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
498     }
499 }
500
501 #elif (DIODE_DIRECTION == ROW2COL)
502
503 static void init_rows(void)
504 {
505     for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
506         uint8_t pin = row_pins[x];
507         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
508         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
509     }
510 }
511
512 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
513 {
514     bool matrix_changed = false;
515
516     // Select col and wait for col selecton to stabilize
517     select_col(current_col);
518     wait_us(30);
519
520     // For each row...
521     for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++)
522     {
523
524         // Store last value of row prior to reading
525         matrix_row_t last_row_value = current_matrix[row_index];
526
527         // Check row pin state
528         if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
529         {
530             // Pin LO, set col bit
531             current_matrix[row_index] |= (ROW_SHIFTER << current_col);
532         }
533         else
534         {
535             // Pin HI, clear col bit
536             current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
537         }
538
539         // Determine if the matrix changed state
540         if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
541         {
542             matrix_changed = true;
543         }
544     }
545
546     // Unselect col
547     unselect_col(current_col);
548
549     return matrix_changed;
550 }
551
552 static void select_col(uint8_t col)
553 {
554     uint8_t pin = col_pins[col];
555     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
556     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
557 }
558
559 static void unselect_col(uint8_t col)
560 {
561     uint8_t pin = col_pins[col];
562     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
563     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
564 }
565
566 static void unselect_cols(void)
567 {
568     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
569         uint8_t pin = col_pins[x];
570         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
571         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
572     }
573 }
574
575 #endif