]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/ergodox/matrix.c
Split Layer2 into two independent layers
[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         case 8:
118             // blue
119             ergodox_left_led_1_off();
120             ergodox_left_led_2_on();
121             ergodox_left_led_3_off();
122             break;
123         case 3:
124             // green
125             ergodox_left_led_1_off();
126             ergodox_left_led_2_off();
127             ergodox_left_led_3_on();
128             break;
129         case 6:
130             ergodox_board_led_on();
131             // break missed intentionally
132         case 4:
133         case 5:
134         case 7:
135             // red
136             ergodox_left_led_1_on();
137             ergodox_left_led_2_off();
138             ergodox_left_led_3_off();
139             break;
140         default:
141             // none
142             ergodox_left_led_1_off();
143             ergodox_left_led_2_off();
144             ergodox_left_led_3_off();
145             break;
146     }
147
148     mcp23018_status = ergodox_left_leds_update();
149 #endif
150
151     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
152         select_row(i);
153         matrix_row_t cols = read_cols(i);
154         if (matrix_debouncing[i] != cols) {
155             matrix_debouncing[i] = cols;
156             if (debouncing) {
157                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
158             }
159             debouncing = DEBOUNCE;
160         }
161         unselect_rows();
162     }
163
164     if (debouncing) {
165         if (--debouncing) {
166             _delay_ms(1);
167         } else {
168             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
169                 matrix[i] = matrix_debouncing[i];
170             }
171         }
172     }
173
174     return 1;
175 }
176
177 bool matrix_is_modified(void)
178 {
179     if (debouncing) return false;
180     return true;
181 }
182
183 inline
184 bool matrix_is_on(uint8_t row, uint8_t col)
185 {
186     return (matrix[row] & ((matrix_row_t)1<<col));
187 }
188
189 inline
190 matrix_row_t matrix_get_row(uint8_t row)
191 {
192     return matrix[row];
193 }
194
195 void matrix_print(void)
196 {
197     print("\nr/c 0123456789ABCDEF\n");
198     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
199         phex(row); print(": ");
200         pbin_reverse16(matrix_get_row(row));
201         print("\n");
202     }
203 }
204
205 uint8_t matrix_key_count(void)
206 {
207     uint8_t count = 0;
208     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
209         count += bitpop16(matrix[i]);
210     }
211     return count;
212 }
213
214 /* Column pin configuration
215  *
216  * Teensy
217  * col: 0   1   2   3   4   5
218  * pin: F0  F1  F4  F5  F6  F7 
219  *
220  * MCP23018
221  * col: 0   1   2   3   4   5
222  * pin: B5  B4  B3  B2  B1  B0 
223  */
224 static void  init_cols(void)
225 {
226     // init on mcp23018
227     // not needed, already done as part of init_mcp23018()
228
229     // init on teensy
230     // Input with pull-up(DDR:0, PORT:1)
231     DDRF  &= ~(1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
232     PORTF |=  (1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<1 | 1<<0);
233 }
234
235 static matrix_row_t read_cols(uint8_t row)
236 {
237     if (row < 7) {
238         if (mcp23018_status) { // if there was an error
239             return 0;
240         } else {
241             uint8_t data = 0;
242             mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
243             mcp23018_status = i2c_write(GPIOB);             if (mcp23018_status) goto out;
244             mcp23018_status = i2c_start(I2C_ADDR_READ);     if (mcp23018_status) goto out;
245             data = i2c_readNak();
246             data = ~data;
247         out:
248             i2c_stop();
249             return data;
250         }
251     } else {
252         _delay_us(30);  // without this wait read unstable value.
253         // read from teensy
254         return
255             (PINF&(1<<0) ? 0 : (1<<0)) |
256             (PINF&(1<<1) ? 0 : (1<<1)) |
257             (PINF&(1<<4) ? 0 : (1<<2)) |
258             (PINF&(1<<5) ? 0 : (1<<3)) |
259             (PINF&(1<<6) ? 0 : (1<<4)) |
260             (PINF&(1<<7) ? 0 : (1<<5)) ;
261     }
262 }
263
264 /* Row pin configuration
265  *
266  * Teensy
267  * row: 7   8   9   10  11  12  13
268  * pin: B0  B1  B2  B3  D2  D3  C6
269  *
270  * MCP23018
271  * row: 0   1   2   3   4   5   6
272  * pin: A0  A1  A2  A3  A4  A5  A6
273  */
274 static void unselect_rows(void)
275 {
276     // unselect on mcp23018
277     if (mcp23018_status) { // if there was an error
278         // do nothing
279     } else {
280         // set all rows hi-Z : 1
281         mcp23018_status = i2c_start(I2C_ADDR_WRITE);    if (mcp23018_status) goto out;
282         mcp23018_status = i2c_write(GPIOA);             if (mcp23018_status) goto out;
283         mcp23018_status = i2c_write( 0xFF
284                               & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
285                           );                            if (mcp23018_status) goto out;
286     out:
287         i2c_stop();
288     }
289
290     // unselect on teensy
291     // Hi-Z(DDR:0, PORT:0) to unselect
292     DDRB  &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
293     PORTB &= ~(1<<0 | 1<<1 | 1<<2 | 1<<3);
294     DDRD  &= ~(1<<2 | 1<<3);
295     PORTD &= ~(1<<2 | 1<<3);
296     DDRC  &= ~(1<<6);
297     PORTC &= ~(1<<6);
298 }
299
300 static void select_row(uint8_t row)
301 {
302     if (row < 7) {
303         // select on mcp23018
304         if (mcp23018_status) { // if there was an error
305             // do nothing
306         } else {
307             // set active row low  : 0
308             // set other rows hi-Z : 1
309             mcp23018_status = i2c_start(I2C_ADDR_WRITE);        if (mcp23018_status) goto out;
310             mcp23018_status = i2c_write(GPIOA);                 if (mcp23018_status) goto out;
311             mcp23018_status = i2c_write( 0xFF & ~(1<<row) 
312                                   & ~(ergodox_left_led_3<<LEFT_LED_3_SHIFT)
313                               );                                if (mcp23018_status) goto out;
314         out:
315             i2c_stop();
316         }
317     } else {
318         // select on teensy
319         // Output low(DDR:1, PORT:0) to select
320         switch (row) {
321             case 7:
322                 DDRB  |= (1<<0);
323                 PORTB &= ~(1<<0);
324                 break;
325             case 8:
326                 DDRB  |= (1<<1);
327                 PORTB &= ~(1<<1);
328                 break;
329             case 9:
330                 DDRB  |= (1<<2);
331                 PORTB &= ~(1<<2);
332                 break;
333             case 10:
334                 DDRB  |= (1<<3);
335                 PORTB &= ~(1<<3);
336                 break;
337             case 11:
338                 DDRD  |= (1<<2);
339                 PORTD &= ~(1<<3);
340                 break;
341             case 12:
342                 DDRD  |= (1<<3);
343                 PORTD &= ~(1<<3);
344                 break;
345             case 13:
346                 DDRC  |= (1<<6);
347                 PORTC &= ~(1<<6);
348                 break;
349         }
350     }
351 }
352