]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/matrix.c
Backlight abstraction and other changes (#439)
[qmk_firmware.git] / quantum / matrix.c
1 /*
2 Copyright 2012 Jun Wako
3 Copyright 2014 Jack Humbert
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <avr/io.h>
21 #include "wait.h"
22 #include "print.h"
23 #include "debug.h"
24 #include "util.h"
25 #include "matrix.h"
26
27 #ifdef MATRIX_HAS_GHOST
28 #   error "The universal matrix.c file cannot be used for this keyboard."
29 #endif
30
31 #ifndef DEBOUNCING_DELAY
32 #   define DEBOUNCING_DELAY 5
33 #endif
34
35 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
36 static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
37 /* matrix state */
38 #if DIODE_DIRECTION == COL2ROW
39 static matrix_row_t matrix[MATRIX_ROWS];
40 #else
41 static matrix_col_t matrix[MATRIX_COLS];
42 #endif
43 static int8_t debouncing_delay = -1;
44
45 #if DIODE_DIRECTION == COL2ROW
46 static void toggle_row(uint8_t row);
47 static matrix_row_t read_cols(void);
48 #else
49 static void toggle_col(uint8_t col);
50 static matrix_col_t read_rows(void);
51 #endif
52
53 __attribute__ ((weak))
54 void matrix_init_quantum(void) {
55     matrix_init_kb();
56 }
57
58 __attribute__ ((weak))
59 void matrix_scan_quantum(void) {
60     matrix_scan_kb();
61 }
62
63 __attribute__ ((weak))
64 void matrix_init_kb(void) {
65     matrix_init_user();
66 }
67
68 __attribute__ ((weak))
69 void matrix_scan_kb(void) {
70     matrix_scan_user();
71 }
72
73 __attribute__ ((weak))
74 void matrix_init_user(void) {
75 }
76
77 __attribute__ ((weak))
78 void matrix_scan_user(void) {
79 }
80
81 uint8_t matrix_rows(void) {
82     return MATRIX_ROWS;
83 }
84
85 uint8_t matrix_cols(void) {
86     return MATRIX_COLS;
87 }
88
89 void matrix_power_up(void) {
90 #if DIODE_DIRECTION == COL2ROW
91     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
92         /* DDRxn */
93         _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
94         toggle_row(r);
95     }
96     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
97         /* PORTxn */
98         _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
99     }
100 #else
101     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
102         /* DDRxn */
103         _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
104         toggle_col(c);
105     }
106     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
107         /* PORTxn */
108         _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
109     }
110 #endif
111 }
112
113 void matrix_init(void) {
114     /* frees PORTF by setting the JTD bit twice within four cycles */
115     #ifdef __AVR_ATmega32U4__
116         MCUCR |= _BV(JTD);
117         MCUCR |= _BV(JTD);
118     #endif
119     /* initializes the I/O pins */
120 #if DIODE_DIRECTION == COL2ROW
121     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
122         /* DDRxn */
123         _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
124         toggle_row(r);
125     }
126     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
127         /* PORTxn */
128         _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
129     }
130 #else
131     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
132         /* DDRxn */
133         _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
134         toggle_col(c);
135     }
136     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
137         /* PORTxn */
138         _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
139     }
140 #endif
141     matrix_init_quantum();
142 }
143
144 #if DIODE_DIRECTION == COL2ROW
145 uint8_t matrix_scan(void) {
146     static matrix_row_t debouncing_matrix[MATRIX_ROWS];
147     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
148         toggle_row(r);
149         matrix_row_t state = read_cols();
150         if (debouncing_matrix[r] != state) {
151             debouncing_matrix[r] = state;
152             debouncing_delay = DEBOUNCING_DELAY;
153         }
154         toggle_row(r);
155     }
156     if (debouncing_delay >= 0) {
157         dprintf("Debouncing delay remaining: %X\n", debouncing_delay);
158         --debouncing_delay;
159         if (debouncing_delay >= 0) {
160             wait_ms(1);
161         }
162         else {
163             for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
164                 matrix[r] = debouncing_matrix[r];
165             }
166         }
167     }
168     matrix_scan_quantum();
169     return 1;
170 }
171
172 static void toggle_row(uint8_t row) {
173     /* PINxn */
174     _SFR_IO8((row_pins[row] >> 4)) = _BV(row_pins[row] & 0xF);
175 }
176
177 static matrix_row_t read_cols(void) {
178     matrix_row_t state = 0;
179     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
180         /* PINxn */
181         if (!(_SFR_IO8((col_pins[c] >> 4)) & _BV(col_pins[c] & 0xF))) {
182             state |= (matrix_row_t)1 << c;
183         }
184     }
185     return state;
186 }
187
188 matrix_row_t matrix_get_row(uint8_t row) {
189     return matrix[row];
190 }
191
192 #else
193 uint8_t matrix_scan(void) {
194     static matrix_col_t debouncing_matrix[MATRIX_COLS];
195     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
196         toggle_col(c);
197         matrix_col_t state = read_rows();
198         if (debouncing_matrix[c] != state) {
199             debouncing_matrix[c] = state;
200             debouncing_delay = DEBOUNCING_DELAY;
201         }
202         toggle_col(c);
203     }
204     if (debouncing_delay >= 0) {
205         dprintf("Debouncing delay remaining: %X\n", debouncing_delay);
206         --debouncing_delay;
207         if (debouncing_delay >= 0) {
208             wait_ms(1);
209         }
210         else {
211             for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
212                 matrix[c] = debouncing_matrix[c];
213             }
214         }
215     }
216     matrix_scan_quantum();
217     return 1;
218 }
219
220 static void toggle_col(uint8_t col) {
221     /* PINxn */
222     _SFR_IO8((col_pins[col] >> 4)) = _BV(col_pins[col] & 0xF);
223 }
224
225 static matrix_col_t read_rows(void) {
226     matrix_col_t state = 0;
227     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
228         /* PINxn */
229         if (!(_SFR_IO8((row_pins[r] >> 4)) & _BV(row_pins[r] & 0xF))) {
230             state |= (matrix_col_t)1 << r;
231         }
232     }
233     return state;
234 }
235
236 matrix_row_t matrix_get_row(uint8_t row) {
237     matrix_row_t state = 0;
238     matrix_col_t mask = (matrix_col_t)1 << row;
239     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
240         if (matrix[c] & mask) {
241             state |= (matrix_row_t)1 << c;
242         }
243     }
244     return state;
245 }
246
247 #endif
248
249 bool matrix_is_modified(void) {
250     if (debouncing_delay >= 0) return false;
251     return true;
252 }
253
254 bool matrix_is_on(uint8_t row, uint8_t col) {
255     return matrix_get_row(row) & (matrix_row_t)1 << col;
256 }
257
258 void matrix_print(void) {
259     dprintln("Human-readable matrix state:");
260     for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
261         dprintf("State of row %X: %016b\n", r, bitrev16(matrix_get_row(r)));
262     }
263 }
264
265 uint8_t matrix_key_count(void) {
266     uint8_t count = 0;
267     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
268         count += bitpop16(matrix_get_row(r));
269     }
270     return count;
271 }