]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/ergodox/matrix.c
Layers reordered, according to Hasu's reccomendation + minor tweaks
[tmk_firmware.git] / keyboard / ergodox / matrix.c
1 /*
2 Copyright 2013 Oleg Kostyuk <cub.uanic@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 <util/delay.h>
25 #include "action_layer.h"
26 #include "print.h"
27 #include "debug.h"
28 #include "util.h"
29 #include "matrix.h"
30 #include "ergodox.h"
31 #include "i2cmaster.h"
32 #ifdef DEBUG_MATRIX_FREQ
33 #include  "timer.h"
34 #endif
35
36 #ifndef DEBOUNCE
37 #   define DEBOUNCE     5
38 #endif
39 static uint8_t debouncing = DEBOUNCE;
40
41 /* matrix state(1:on, 0:off) */
42 static matrix_row_t matrix[MATRIX_ROWS];
43 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
44
45 static matrix_row_t read_cols(uint8_t row);
46 static void init_cols(void);
47 static void unselect_rows();
48 static void select_row(uint8_t row);
49
50 static uint8_t mcp23018_status;
51
52 #ifdef DEBUG_MATRIX_FREQ
53 uint32_t matrix_timer;
54 uint32_t matrix_scan_count;
55 #endif
56
57 inline
58 uint8_t matrix_rows(void)
59 {
60     return MATRIX_ROWS;
61 }
62
63 inline
64 uint8_t matrix_cols(void)
65 {
66     return MATRIX_COLS;
67 }
68
69 void matrix_init(void)
70 {
71     // initialize row and col
72     init_ergodox();
73     mcp23018_status = init_mcp23018();
74     unselect_rows();
75     init_cols();
76
77     // initialize matrix state: all keys off
78     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
79         matrix[i] = 0;
80         matrix_debouncing[i] = 0;
81     }
82
83 #ifdef DEBUG_MATRIX_FREQ
84     matrix_timer = timer_read32();
85     matrix_scan_count = 0;
86 #endif
87 }
88
89 uint8_t matrix_scan(void)
90 {
91 #ifdef DEBUG_MATRIX_FREQ
92     matrix_scan_count++;
93
94     uint32_t timer_now = timer_read32();
95     if (TIMER_DIFF_32(timer_now, matrix_timer)>1000) {
96         print("matrix scan frequency: ");
97         pdec(matrix_scan_count);
98         print("\n");
99
100         matrix_timer = timer_now;
101         matrix_scan_count = 0;
102     }
103 #endif
104
105 #ifdef KEYMAP_CUB
106     uint8_t layer = biton32(layer_state);
107
108     ergodox_board_led_off();
109     switch (layer) {
110         case 1:
111             // all
112             ergodox_left_led_1_on();
113             ergodox_left_led_2_on();
114             ergodox_left_led_3_on();
115             break;
116         case 2:
117             // blue
118             ergodox_left_led_1_off();
119             ergodox_left_led_2_on();
120             ergodox_left_led_3_off();
121             break;
122         case 3:
123             // green
124             ergodox_left_led_1_off();
125             ergodox_left_led_2_off();
126             ergodox_left_led_3_on();
127             break;
128         case 6:
129             ergodox_board_led_on();
130             // break missed intentionally
131         case 4:
132         case 5:
133             // red
134             ergodox_left_led_1_on();
135             ergodox_left_led_2_off();
136             ergodox_left_led_3_off();
137             break;
138         default:
139             // none
140             ergodox_left_led_1_off();
141             ergodox_left_led_2_off();
142             ergodox_left_led_3_off();
143             break;
144     }
145
146     mcp23018_status = ergodox_left_leds_update();
147 #endif
148
149     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
150         select_row(i);
151         matrix_row_t cols = read_cols(i);
152         if (matrix_debouncing[i] != cols) {
153             matrix_debouncing[i] = cols;
154             if (debouncing) {
155                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
156             }
157             debouncing = DEBOUNCE;
158         }
159         unselect_rows();
160     }
161
162     if (debouncing) {
163         if (--debouncing) {
164             _delay_ms(1);
165         } else {
166             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
167                 matrix[i] = matrix_debouncing[i];
168             }
169         }
170     }
171
172     return 1;
173 }
174
175 bool matrix_is_modified(void)
176 {
177     if (debouncing) return false;
178     return true;
179 }
180
181 inline
182 bool matrix_is_on(uint8_t row, uint8_t col)
183 {
184     return (matrix[row] & ((matrix_row_t)1<<col));
185 }
186
187 inline
188 matrix_row_t matrix_get_row(uint8_t row)
189 {
190     return matrix[row];
191 }
192
193 void matrix_print(void)
194 {
195     print("\nr/c 0123456789ABCDEF\n");
196     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
197         phex(row); print(": ");
198         pbin_reverse16(matrix_get_row(row));
199         print("\n");
200     }
201 }
202
203 uint8_t matrix_key_count(void)
204 {
205     uint8_t count = 0;
206     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
207         count += bitpop16(matrix[i]);
208     }
209     return count;
210 }
211
212 /* Column pin configuration
213  *
214  * Teensy
215  * col: 0   1   2   3   4   5
216  * pin: F0  F1  F4  F5  F6  F7 
217  *
218  * MCP23018
219  * col: 0   1   2   3   4   5
220  * pin: B5  B4  B3  B2  B1  B0 
221  */
222 static void  init_cols(void)
223 {
224     // init on mcp23018
225     // not needed, already done as part of init_mcp23018()
226
227     // init on teensy
228     // Input with pull-up(DDR:0, PORT:1)
229     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
230     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
231 }
232
233 static matrix_row_t read_cols(uint8_t row)
234 {
235     if (row < 7) {
236         if (mcp23018_status) { // if there was an error
237             return 0;
238         } else {
239             uint8_t data = 0;
240             mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
241             mcp23018_status = i2c_write(GPIOB);             if (mcp23018_status) goto out;
242             mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out;
243             data = i2c_readNak();
244             data = ~data;
245         out:
246             i2c_stop();
247             return data;
248         }
249     } else {
250         _delay_us(30);  // without this wait read unstable value.
251         // read from teensy
252         return
253             (PINF&(1<<0) ? 0 : (1<<0)) |
254             (PINF&(1<<1) ? 0 : (1<<1)) |
255             (PINF&(1<<4) ? 0 : (1<<2)) |
256             (PINF&(1<<5) ? 0 : (1<<3)) |
257             (PINF&(1<<6) ? 0 : (1<<4)) |
258             (PINF&(1<<7) ? 0 : (1<<5)) ;
259     }
260 }
261
262 /* Row pin configuration
263  *
264  * Teensy
265  * row: 7   8   9   10  11  12  13
266  * pin: B0  B1  B2  B3  D2  D3  C6
267  *
268  * MCP23018
269  * row: 0   1   2   3   4   5   6
270  * pin: A0  A1  A2  A3  A4  A5  A6
271  */
272 static void unselect_rows(void)
273 {
274     // unselect on mcp23018
275     if (mcp23018_status) { // if there was an error
276         // do nothing
277     } else {
278         // set all rows hi-Z : 1
279         mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
280         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out;
281         mcp23018_status = i2c_write( 0xFF
282                               & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
283                           );                            if (mcp23018_status) goto out;
284     out:
285         i2c_stop();
286     }
287
288     // unselect on teensy
289     // Hi-Z(DDR:0, PORT:0) to unselect
290     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
291     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
292     DDRD  &= ~(1<<2 | 1<<3);
293     PORTD &= ~(1<<2 | 1<<3);
294     DDRC  &= ~(1<<6);
295     PORTC &= ~(1<<6);
296 }
297
298 static void select_row(uint8_t row)
299 {
300     if (row < 7) {
301         // select on mcp23018
302         if (mcp23018_status) { // if there was an error
303             // do nothing
304         } else {
305             // set active row low  : 0
306             // set other rows hi-Z : 1
307             mcp23018_status = i2c_start(I2C_ADDR_WRITE);        if (mcp23018_status) goto out;
308             mcp23018_status = i2c_write(GPIOA);                 if (mcp23018_status) goto out;
309             mcp23018_status = i2c_write( 0xFF & ~(1<<row) 
310                                   & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
311                               );                                if (mcp23018_status) goto out;
312         out:
313             i2c_stop();
314         }
315     } else {
316         // select on teensy
317         // Output low(DDR:1, PORT:0) to select
318         switch (row) {
319             case 7:
320                 DDRB  |= (1<<0);
321                 PORTB &= ~(1<<0);
322                 break;
323             case 8:
324                 DDRB  |= (1<<1);
325                 PORTB &= ~(1<<1);
326                 break;
327             case 9:
328                 DDRB  |= (1<<2);
329                 PORTB &= ~(1<<2);
330                 break;
331             case 10:
332                 DDRB  |= (1<<3);
333                 PORTB &= ~(1<<3);
334                 break;
335             case 11:
336                 DDRD  |= (1<<2);
337                 PORTD &= ~(1<<3);
338                 break;
339             case 12:
340                 DDRD  |= (1<<3);
341                 PORTD &= ~(1<<3);
342                 break;
343             case 13:
344                 DDRC  |= (1<<6);
345                 PORTC &= ~(1<<6);
346                 break;
347         }
348     }
349 }
350