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