]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/ergotravel/matrix.c
Merge branch 'master' of github.com:qmk/qmk_firmware into hf/shinydox
[qmk_firmware.git] / keyboards / ergotravel / matrix.c
1 /*
2 Copyright 2018 Pierre Constantineau
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 "backlight.h"
34
35 #ifdef USE_I2C
36 #  include "i2c.h"
37 #else // USE_SERIAL
38 #  include "serial.h"
39 #endif
40
41 #ifndef DEBOUNCING_DELAY
42 #   define DEBOUNCING_DELAY 5
43 #endif
44
45 #if (DEBOUNCING_DELAY > 0)
46     static uint16_t debouncing_time;
47     static bool debouncing = false;
48 #endif
49
50 #if (MATRIX_COLS <= 8)
51 #    define print_matrix_header()  print("\nr/c 01234567\n")
52 #    define print_matrix_row(row)  print_bin_reverse8(matrix_get_row(row))
53 #    define matrix_bitpop(i)       bitpop(matrix[i])
54 #    define ROW_SHIFTER ((uint8_t)1)
55 #else
56 #    error "Currently only supports 8 COLS"
57 #endif
58 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
59
60 #define ERROR_DISCONNECT_COUNT 5
61
62 #define SERIAL_LED_ADDR 0x00
63
64 #define ROWS_PER_HAND (MATRIX_ROWS/2)
65
66 static uint8_t error_count = 0;
67
68 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
69 static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
70
71 /* matrix state(1:on, 0:off) */
72 static matrix_row_t matrix[MATRIX_ROWS];
73 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
74
75 #if (DIODE_DIRECTION == COL2ROW)
76     static void init_cols(void);
77     static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
78     static void unselect_rows(void);
79     static void select_row(uint8_t row);
80     static void unselect_row(uint8_t row);
81 #elif (DIODE_DIRECTION == ROW2COL)
82     static void init_rows(void);
83     static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
84     static void unselect_cols(void);
85     static void unselect_col(uint8_t col);
86     static void select_col(uint8_t col);
87 #endif
88
89
90 __attribute__ ((weak))
91 void matrix_init_kb(void) {
92     matrix_init_user();
93 }
94
95 __attribute__ ((weak))
96 void matrix_scan_kb(void) {
97     matrix_scan_user();
98 }
99
100 __attribute__ ((weak))
101 void matrix_init_user(void) {
102 }
103
104 __attribute__ ((weak))
105 void matrix_scan_user(void) {
106 }
107
108 inline
109 uint8_t matrix_rows(void)
110 {
111     return MATRIX_ROWS;
112 }
113
114 inline
115 uint8_t matrix_cols(void)
116 {
117     return MATRIX_COLS;
118 }
119
120 void matrix_init(void)
121 {
122     debug_enable = true;
123     debug_matrix = true;
124     debug_mouse = true;
125     // initialize row and col
126     unselect_rows();
127     init_cols();
128
129     TX_RX_LED_INIT;
130
131     // initialize matrix state: all keys off
132     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
133         matrix[i] = 0;
134         matrix_debouncing[i] = 0;
135     }
136
137     matrix_init_quantum();
138
139 }
140
141 uint8_t _matrix_scan(void)
142 {
143     int offset = isLeftHand ? 0 : (ROWS_PER_HAND);
144 #if (DIODE_DIRECTION == COL2ROW)
145     // Set row, read cols
146     for (uint8_t current_row = 0; current_row < ROWS_PER_HAND; current_row++) {
147 #       if (DEBOUNCING_DELAY > 0)
148             bool matrix_changed = read_cols_on_row(matrix_debouncing+offset, current_row);
149
150             if (matrix_changed) {
151                 debouncing = true;
152                 debouncing_time = timer_read();
153                 PORTD ^= (1 << 2);
154             }
155
156 #       else
157             read_cols_on_row(matrix+offset, current_row);
158 #       endif
159
160     }
161
162 #elif (DIODE_DIRECTION == ROW2COL)
163     // Set col, read rows
164     for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
165 #       if (DEBOUNCING_DELAY > 0)
166             bool matrix_changed = read_rows_on_col(matrix_debouncing+offset, current_col);
167             if (matrix_changed) {
168                 debouncing = true;
169                 debouncing_time = timer_read();
170             }
171 #       else
172              read_rows_on_col(matrix+offset, current_col);
173 #       endif
174
175     }
176 #endif
177
178 #   if (DEBOUNCING_DELAY > 0)
179         if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
180             for (uint8_t i = 0; i < ROWS_PER_HAND; i++) {
181                 matrix[i+offset] = matrix_debouncing[i+offset];
182             }
183             debouncing = false;
184         }
185 #   endif
186
187     return 1;
188 }
189
190 #ifdef USE_I2C
191
192 // Get rows from other half over i2c
193 int i2c_transaction(void) {
194     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
195
196     int err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_WRITE);
197     if (err) goto i2c_error;
198
199     // start of matrix stored at 0x00
200     err = i2c_master_write(0x00);
201     if (err) goto i2c_error;
202
203 #ifdef BACKLIGHT_ENABLE
204     // Write backlight level for slave to read
205     err = i2c_master_write(get_backlight_level());
206 #else
207     // Write zero, so our byte index is the same
208     err = i2c_master_write(0x00);
209 #endif
210     if (err) goto i2c_error;
211
212     // Start read
213     err = i2c_master_start(SLAVE_I2C_ADDRESS + I2C_READ);
214     if (err) goto i2c_error;
215
216     if (!err) {
217         int i;
218         for (i = 0; i < ROWS_PER_HAND-1; ++i) {
219             matrix[slaveOffset+i] = i2c_master_read(I2C_ACK);
220         }
221         matrix[slaveOffset+i] = i2c_master_read(I2C_NACK);
222         i2c_master_stop();
223     } else {
224 i2c_error: // the cable is disconnceted, or something else went wrong
225         i2c_reset_state();
226         return err;
227     }
228
229     return 0;
230 }
231
232 #else // USE_SERIAL
233
234 int serial_transaction(void) {
235     int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
236
237     if (serial_update_buffers()) {
238         return 1;
239     }
240
241     for (int i = 0; i < ROWS_PER_HAND; ++i) {
242         matrix[slaveOffset+i] = serial_slave_buffer[i];
243     }
244
245 #ifdef BACKLIGHT_ENABLE
246     // Write backlight level for slave to read
247     serial_master_buffer[SERIAL_LED_ADDR] = get_backlight_level();
248 #endif
249     return 0;
250 }
251 #endif
252
253 uint8_t matrix_scan(void)
254 {
255     uint8_t ret = _matrix_scan();
256
257 #ifdef USE_I2C
258     if( i2c_transaction() ) {
259 #else // USE_SERIAL
260     if( serial_transaction() ) {
261 #endif
262         // turn on the indicator led when halves are disconnected
263         TXLED1;
264
265         error_count++;
266
267         if (error_count > ERROR_DISCONNECT_COUNT) {
268             // reset other half if disconnected
269             int slaveOffset = (isLeftHand) ? (ROWS_PER_HAND) : 0;
270             for (int i = 0; i < ROWS_PER_HAND; ++i) {
271                 matrix[slaveOffset+i] = 0;
272             }
273         }
274     } else {
275         // turn off the indicator led on no error
276         TXLED0;
277         error_count = 0;
278     }
279     matrix_scan_quantum();
280     return ret;
281 }
282
283 void matrix_slave_scan(void) {
284     _matrix_scan();
285
286     int offset = (isLeftHand) ? 0 : ROWS_PER_HAND;
287
288 #ifdef USE_I2C
289 #ifdef BACKLIGHT_ENABLE
290     // Read backlight level sent from master and update level on slave
291     backlight_set(i2c_slave_buffer[0]);
292 #endif
293     for (int i = 0; i < ROWS_PER_HAND; ++i) {
294         i2c_slave_buffer[i+1] = matrix[offset+i];
295     }
296 #else // USE_SERIAL
297     for (int i = 0; i < ROWS_PER_HAND; ++i) {
298         serial_slave_buffer[i] = matrix[offset+i];
299     }
300
301 #ifdef BACKLIGHT_ENABLE
302     // Read backlight level sent from master and update level on slave
303     backlight_set(serial_master_buffer[SERIAL_LED_ADDR]);
304 #endif
305 #endif
306 }
307
308 bool matrix_is_modified(void)
309 {
310     if (debouncing) return false;
311     return true;
312 }
313
314 inline
315 bool matrix_is_on(uint8_t row, uint8_t col)
316 {
317     return (matrix[row] & ((matrix_row_t)1<<col));
318 }
319
320 inline
321 matrix_row_t matrix_get_row(uint8_t row)
322 {
323     return matrix[row];
324 }
325
326 void matrix_print(void)
327 {
328     print("\nr/c 0123456789ABCDEF\n");
329     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
330         phex(row); print(": ");
331         pbin_reverse16(matrix_get_row(row));
332         print("\n");
333     }
334 }
335
336 uint8_t matrix_key_count(void)
337 {
338     uint8_t count = 0;
339     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
340         count += bitpop16(matrix[i]);
341     }
342     return count;
343 }
344
345 #if (DIODE_DIRECTION == COL2ROW)
346
347 static void init_cols(void)
348 {
349     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
350         uint8_t pin = col_pins[x];
351         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
352         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
353     }
354 }
355
356 static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
357 {
358     // Store last value of row prior to reading
359     matrix_row_t last_row_value = current_matrix[current_row];
360
361     // Clear data in matrix row
362     current_matrix[current_row] = 0;
363
364     // Select row and wait for row selecton to stabilize
365     select_row(current_row);
366     wait_us(30);
367
368     // For each col...
369     for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
370
371         // Select the col pin to read (active low)
372         uint8_t pin = col_pins[col_index];
373         uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
374
375         // Populate the matrix row with the state of the col pin
376         current_matrix[current_row] |=  pin_state ? 0 : (ROW_SHIFTER << col_index);
377     }
378
379     // Unselect row
380     unselect_row(current_row);
381
382     return (last_row_value != current_matrix[current_row]);
383 }
384
385 static void select_row(uint8_t row)
386 {
387     uint8_t pin = row_pins[row];
388     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
389     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
390 }
391
392 static void unselect_row(uint8_t row)
393 {
394     uint8_t pin = row_pins[row];
395     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
396     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
397 }
398
399 static void unselect_rows(void)
400 {
401     for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
402         uint8_t pin = row_pins[x];
403         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
404         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
405     }
406 }
407
408 #elif (DIODE_DIRECTION == ROW2COL)
409
410 static void init_rows(void)
411 {
412     for(uint8_t x = 0; x < ROWS_PER_HAND; x++) {
413         uint8_t pin = row_pins[x];
414         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
415         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
416     }
417 }
418
419 static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
420 {
421     bool matrix_changed = false;
422
423     // Select col and wait for col selecton to stabilize
424     select_col(current_col);
425     wait_us(30);
426
427     // For each row...
428     for(uint8_t row_index = 0; row_index < ROWS_PER_HAND; row_index++)
429     {
430
431         // Store last value of row prior to reading
432         matrix_row_t last_row_value = current_matrix[row_index];
433
434         // Check row pin state
435         if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
436         {
437             // Pin LO, set col bit
438             current_matrix[row_index] |= (ROW_SHIFTER << current_col);
439         }
440         else
441         {
442             // Pin HI, clear col bit
443             current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
444         }
445
446         // Determine if the matrix changed state
447         if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
448         {
449             matrix_changed = true;
450         }
451     }
452
453     // Unselect col
454     unselect_col(current_col);
455
456     return matrix_changed;
457 }
458
459 static void select_col(uint8_t col)
460 {
461     uint8_t pin = col_pins[col];
462     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF); // OUT
463     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
464 }
465
466 static void unselect_col(uint8_t col)
467 {
468     uint8_t pin = col_pins[col];
469     _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
470     _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
471 }
472
473 static void unselect_cols(void)
474 {
475     for(uint8_t x = 0; x < MATRIX_COLS; x++) {
476         uint8_t pin = col_pins[x];
477         _SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
478         _SFR_IO8((pin >> 4) + 2) |=  _BV(pin & 0xF); // HI
479     }
480 }
481
482 #endif