]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/ergodox_ez/matrix.c
Make python a required build dependency (#5784)
[qmk_firmware.git] / keyboards / ergodox_ez / matrix.c
1 /*
2
3 Note for ErgoDox EZ customizers: Here be dragons!
4 This is not a file you want to be messing with.
5 All of the interesting stuff for you is under keymaps/ :)
6 Love, Erez
7
8 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com>
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  * scan matrix
26  */
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <avr/io.h>
30 #include "wait.h"
31 #include "action_layer.h"
32 #include "print.h"
33 #include "debug.h"
34 #include "util.h"
35 #include "matrix.h"
36 #include "debounce.h"
37 #include QMK_KEYBOARD_H
38 #ifdef DEBUG_MATRIX_SCAN_RATE
39 #  include "timer.h"
40 #endif
41
42 /*
43  * This constant define not debouncing time in msecs, assuming eager_pr.
44  *
45  * On Ergodox matrix scan rate is relatively low, because of slow I2C.
46  * Now it's only 317 scans/second, or about 3.15 msec/scan.
47  * According to Cherry specs, debouncing time is 5 msec.
48  *
49  * However, some switches seem to have higher debouncing requirements, or
50  * something else might be wrong. (Also, the scan speed has improved since
51  * that comment was written.)
52  */
53
54 #ifndef DEBOUNCE
55 #  define DEBOUNCE 5
56 #endif
57
58 /* matrix state(1:on, 0:off) */
59 static matrix_row_t raw_matrix[MATRIX_ROWS];  // raw values
60 static matrix_row_t matrix[MATRIX_ROWS];      // debounced values
61
62 static matrix_row_t read_cols(uint8_t row);
63 static void         init_cols(void);
64 static void         unselect_rows(void);
65 static void         select_row(uint8_t row);
66
67 static uint8_t mcp23018_reset_loop;
68 // static uint16_t mcp23018_reset_loop;
69
70 #ifdef DEBUG_MATRIX_SCAN_RATE
71 uint32_t matrix_timer;
72 uint32_t matrix_scan_count;
73 #endif
74
75 __attribute__((weak)) void matrix_init_user(void) {}
76
77 __attribute__((weak)) void matrix_scan_user(void) {}
78
79 __attribute__((weak)) void matrix_init_kb(void) { matrix_init_user(); }
80
81 __attribute__((weak)) void matrix_scan_kb(void) { matrix_scan_user(); }
82
83 inline uint8_t matrix_rows(void) { return MATRIX_ROWS; }
84
85 inline uint8_t matrix_cols(void) { return MATRIX_COLS; }
86
87 void matrix_init(void) {
88   // initialize row and col
89
90   mcp23018_status = init_mcp23018();
91
92   unselect_rows();
93   init_cols();
94
95   // initialize matrix state: all keys off
96   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
97     matrix[i]     = 0;
98     raw_matrix[i] = 0;    
99   }
100
101 #ifdef DEBUG_MATRIX_SCAN_RATE
102   matrix_timer      = timer_read32();
103   matrix_scan_count = 0;
104 #endif
105   debounce_init(MATRIX_ROWS);
106   matrix_init_quantum();
107 }
108
109 void matrix_power_up(void) {
110   mcp23018_status = init_mcp23018();
111
112   unselect_rows();
113   init_cols();
114
115   // initialize matrix state: all keys off
116   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
117     matrix[i] = 0;
118   }
119
120 #ifdef DEBUG_MATRIX_SCAN_RATE
121   matrix_timer      = timer_read32();
122   matrix_scan_count = 0;
123 #endif
124 }
125
126 // Reads and stores a row, returning
127 // whether a change occurred.
128 static inline bool store_raw_matrix_row(uint8_t index) {
129   matrix_row_t temp = read_cols(index);
130   if (raw_matrix[index] != temp) {
131     raw_matrix[index] = temp;
132     return true;
133   }
134   return false;
135 }
136
137 uint8_t matrix_scan(void) {
138   if (mcp23018_status) {  // if there was an error
139     if (++mcp23018_reset_loop == 0) {
140       // if (++mcp23018_reset_loop >= 1300) {
141       // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans
142       // this will be approx bit more frequent than once per second
143       print("trying to reset mcp23018\n");
144       mcp23018_status = init_mcp23018();
145       if (mcp23018_status) {
146         print("left side not responding\n");
147       } else {
148         print("left side attached\n");
149         ergodox_blink_all_leds();
150       }
151     }
152   }
153
154 #ifdef DEBUG_MATRIX_SCAN_RATE
155   matrix_scan_count++;
156
157   uint32_t timer_now = timer_read32();
158   if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) {
159     print("matrix scan frequency: ");
160     pdec(matrix_scan_count);
161     print("\n");
162
163     matrix_timer      = timer_now;
164     matrix_scan_count = 0;
165   }
166 #endif
167
168 #ifdef LEFT_LEDS
169   mcp23018_status = ergodox_left_leds_update();
170 #endif  // LEFT_LEDS
171   bool changed = false;  
172   for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) {
173     // select rows from left and right hands
174     uint8_t left_index = i;
175     uint8_t right_index = i + MATRIX_ROWS_PER_SIDE;
176     select_row(left_index);
177     select_row(right_index);
178
179     // we don't need a 30us delay anymore, because selecting a
180     // left-hand row requires more than 30us for i2c.
181     
182     changed |= store_raw_matrix_row(left_index);
183     changed |= store_raw_matrix_row(right_index);
184
185     unselect_rows();
186   }
187   
188   debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
189   matrix_scan_quantum();
190
191   return 1;
192 }
193
194 bool matrix_is_modified(void)  // deprecated and evidently not called.
195 {
196   return true;
197 }
198
199 inline bool matrix_is_on(uint8_t row, uint8_t col) { return (matrix[row] & ((matrix_row_t)1 << col)); }
200
201 inline matrix_row_t matrix_get_row(uint8_t row) { return matrix[row]; }
202
203 void matrix_print(void) {
204   print("\nr/c 0123456789ABCDEF\n");
205   for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
206     phex(row);
207     print(": ");
208     pbin_reverse16(matrix_get_row(row));
209     print("\n");
210   }
211 }
212
213 uint8_t matrix_key_count(void) {
214   uint8_t count = 0;
215   for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
216     count += bitpop16(matrix[i]);
217   }
218   return count;
219 }
220
221 /* Column pin configuration
222  *
223  * Teensy
224  * col: 0   1   2   3   4   5
225  * pin: F0  F1  F4  F5  F6  F7
226  *
227  * MCP23018
228  * col: 0   1   2   3   4   5
229  * pin: B5  B4  B3  B2  B1  B0
230  */
231 static void init_cols(void) {
232   // init on mcp23018
233   // not needed, already done as part of init_mcp23018()
234
235   // init on teensy
236   // Input with pull-up(DDR:0, PORT:1)
237   DDRF &= ~(1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
238   PORTF |= (1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 1 | 1 << 0);
239 }
240
241 static matrix_row_t read_cols(uint8_t row) {
242   if (row < 7) {
243     if (mcp23018_status) {  // if there was an error
244       return 0;
245     } else {
246       uint8_t data    = 0;
247       mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
248       if (mcp23018_status) goto out;
249       mcp23018_status = i2c_write(GPIOB, ERGODOX_EZ_I2C_TIMEOUT);
250       if (mcp23018_status) goto out;
251       mcp23018_status = i2c_start(I2C_ADDR_READ, ERGODOX_EZ_I2C_TIMEOUT);
252       if (mcp23018_status) goto out;
253       mcp23018_status = i2c_read_nack(ERGODOX_EZ_I2C_TIMEOUT);
254       if (mcp23018_status < 0) goto out;
255       data            = ~((uint8_t)mcp23018_status);
256       mcp23018_status = I2C_STATUS_SUCCESS;
257     out:
258       i2c_stop();
259       return data;
260     }
261   } else {
262     /* read from teensy
263      * bitmask is 0b11110011, but we want those all
264      * in the lower six bits.
265      * we'll return 1s for the top two, but that's harmless.
266      */
267
268     return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2));
269   }
270 }
271
272 /* Row pin configuration
273  *
274  * Teensy
275  * row: 7   8   9   10  11  12  13
276  * pin: B0  B1  B2  B3  D2  D3  C6
277  *
278  * MCP23018
279  * row: 0   1   2   3   4   5   6
280  * pin: A0  A1  A2  A3  A4  A5  A6
281  */
282 static void unselect_rows(void) {
283   // no need to unselect on mcp23018, because the select step sets all
284   // the other row bits high, and it's not changing to a different
285   // direction
286
287   // unselect on teensy
288   // Hi-Z(DDR:0, PORT:0) to unselect
289   DDRB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
290   PORTB &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
291   DDRD &= ~(1 << 2 | 1 << 3);
292   PORTD &= ~(1 << 2 | 1 << 3);
293   DDRC &= ~(1 << 6);
294   PORTC &= ~(1 << 6);
295 }
296
297 static void select_row(uint8_t row) {
298   if (row < 7) {
299     // select on mcp23018
300     if (mcp23018_status) {  // if there was an error
301                             // do nothing
302     } else {
303       // set active row low  : 0
304       // set other rows hi-Z : 1
305       mcp23018_status = i2c_start(I2C_ADDR_WRITE, ERGODOX_EZ_I2C_TIMEOUT);
306       if (mcp23018_status) goto out;
307       mcp23018_status = i2c_write(GPIOA, ERGODOX_EZ_I2C_TIMEOUT);
308       if (mcp23018_status) goto out;
309       mcp23018_status = i2c_write(0xFF & ~(1 << row), ERGODOX_EZ_I2C_TIMEOUT);
310       if (mcp23018_status) goto out;
311     out:
312       i2c_stop();
313     }
314   } else {
315     // select on teensy
316     // Output low(DDR:1, PORT:0) to select
317     switch (row) {
318       case 7:
319         DDRB |= (1 << 0);
320         PORTB &= ~(1 << 0);
321         break;
322       case 8:
323         DDRB |= (1 << 1);
324         PORTB &= ~(1 << 1);
325         break;
326       case 9:
327         DDRB |= (1 << 2);
328         PORTB &= ~(1 << 2);
329         break;
330       case 10:
331         DDRB |= (1 << 3);
332         PORTB &= ~(1 << 3);
333         break;
334       case 11:
335         DDRD |= (1 << 2);
336         PORTD &= ~(1 << 2);
337         break;
338       case 12:
339         DDRD |= (1 << 3);
340         PORTD &= ~(1 << 3);
341         break;
342       case 13:
343         DDRC |= (1 << 6);
344         PORTC &= ~(1 << 6);
345         break;
346     }
347   }
348 }