]> git.donarmstrong.com Git - qmk_firmware.git/blob - quantum/matrix.c
Merge branch 'master' of https://github.com/Skrymir/qmk_firmware
[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 #if defined(__AVR__)
21 #include <avr/io.h>
22 #endif
23 #include "wait.h"
24 #include "print.h"
25 #include "debug.h"
26 #include "util.h"
27 #include "matrix.h"
28
29 /* Set 0 if debouncing isn't needed */
30
31 #ifndef DEBOUNCING_DELAY
32 #   define DEBOUNCING_DELAY 5
33 #endif
34 static uint8_t debouncing = DEBOUNCING_DELAY;
35
36 static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
37 static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
38
39 /* matrix state(1:on, 0:off) */
40 static matrix_row_t matrix[MATRIX_ROWS];
41 static matrix_row_t matrix_debouncing[MATRIX_ROWS];
42
43 #if DIODE_DIRECTION == ROW2COL
44     static matrix_row_t matrix_reversed[MATRIX_COLS];
45     static matrix_row_t matrix_reversed_debouncing[MATRIX_COLS];
46 #endif
47
48 #if MATRIX_COLS > 16
49     #define SHIFTER 1UL
50 #else
51     #define SHIFTER 1
52 #endif
53
54 static matrix_row_t read_cols(void);
55 static void init_cols(void);
56 static void unselect_rows(void);
57 static void select_row(uint8_t row);
58
59 __attribute__ ((weak))
60 void matrix_init_quantum(void) {
61     matrix_init_kb();
62 }
63
64 __attribute__ ((weak))
65 void matrix_scan_quantum(void) {
66     matrix_scan_kb();
67 }
68
69 __attribute__ ((weak))
70 void matrix_init_kb(void) {
71     matrix_init_user();
72 }
73
74 __attribute__ ((weak))
75 void matrix_scan_kb(void) {
76     matrix_scan_user();
77 }
78
79 __attribute__ ((weak))
80 void matrix_init_user(void) {
81 }
82
83 __attribute__ ((weak))
84 void matrix_scan_user(void) {
85 }
86
87 inline
88 uint8_t matrix_rows(void) {
89     return MATRIX_ROWS;
90 }
91
92 inline
93 uint8_t matrix_cols(void) {
94     return MATRIX_COLS;
95 }
96
97 // void matrix_power_up(void) {
98 // #if DIODE_DIRECTION == COL2ROW
99 //     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
100 //         /* DDRxn */
101 //         _SFR_IO8((row_pins[r] >> 4) + 1) |= _BV(row_pins[r] & 0xF);
102 //         toggle_row(r);
103 //     }
104 //     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
105 //         /* PORTxn */
106 //         _SFR_IO8((col_pins[c] >> 4) + 2) |= _BV(col_pins[c] & 0xF);
107 //     }
108 // #else
109 //     for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
110 //         /* DDRxn */
111 //         _SFR_IO8((col_pins[c] >> 4) + 1) |= _BV(col_pins[c] & 0xF);
112 //         toggle_col(c);
113 //     }
114 //     for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
115 //         /* PORTxn */
116 //         _SFR_IO8((row_pins[r] >> 4) + 2) |= _BV(row_pins[r] & 0xF);
117 //     }
118 // #endif
119 // }
120
121 void matrix_init(void) {
122     // To use PORTF disable JTAG with writing JTD bit twice within four cycles.
123     #ifdef __AVR_ATmega32U4__
124         MCUCR |= _BV(JTD);
125         MCUCR |= _BV(JTD);
126     #endif
127
128     // initialize row and col
129     unselect_rows();
130     init_cols();
131
132     // initialize matrix state: all keys off
133     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
134         matrix[i] = 0;
135         matrix_debouncing[i] = 0;
136     }
137
138     matrix_init_quantum();
139 }
140
141 uint8_t matrix_scan(void)
142 {
143
144 #if DIODE_DIRECTION == COL2ROW
145     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
146         select_row(i);
147         wait_us(30);  // without this wait read unstable value.
148         matrix_row_t cols = read_cols();
149         if (matrix_debouncing[i] != cols) {
150             matrix_debouncing[i] = cols;
151             if (debouncing) {
152                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
153             }
154             debouncing = DEBOUNCING_DELAY;
155         }
156         unselect_rows();
157     }
158
159     if (debouncing) {
160         if (--debouncing) {
161             wait_ms(1);
162         } else {
163             for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
164                 matrix[i] = matrix_debouncing[i];
165             }
166         }
167     }
168 #else
169     for (uint8_t i = 0; i < MATRIX_COLS; i++) {
170         select_row(i);
171         wait_us(30);  // without this wait read unstable value.
172         matrix_row_t rows = read_cols();
173         if (matrix_reversed_debouncing[i] != rows) {
174             matrix_reversed_debouncing[i] = rows;
175             if (debouncing) {
176                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
177             }
178             debouncing = DEBOUNCING_DELAY;
179         }
180         unselect_rows();
181     }
182
183     if (debouncing) {
184         if (--debouncing) {
185             wait_ms(1);
186         } else {
187             for (uint8_t i = 0; i < MATRIX_COLS; i++) {
188                 matrix_reversed[i] = matrix_reversed_debouncing[i];
189             }
190         }
191     }
192     for (uint8_t y = 0; y < MATRIX_ROWS; y++) {
193         matrix_row_t row = 0;
194         for (uint8_t x = 0; x < MATRIX_COLS; x++) {
195             row |= ((matrix_reversed[x] & (1<<y)) >> y) << x;
196         }
197         matrix[y] = row;
198     }
199 #endif
200
201     matrix_scan_quantum();
202
203     return 1;
204 }
205
206 bool matrix_is_modified(void)
207 {
208     if (debouncing) return false;
209     return true;
210 }
211
212 inline
213 bool matrix_is_on(uint8_t row, uint8_t col)
214 {
215     return (matrix[row] & ((matrix_row_t)1<col));
216 }
217
218 inline
219 matrix_row_t matrix_get_row(uint8_t row)
220 {
221     return matrix[row];
222 }
223
224 void matrix_print(void)
225 {
226     print("\nr/c 0123456789ABCDEF\n");
227     for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
228         phex(row); print(": ");
229         pbin_reverse16(matrix_get_row(row));
230         print("\n");
231     }
232 }
233
234 uint8_t matrix_key_count(void)
235 {
236     uint8_t count = 0;
237     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
238         count += bitpop16(matrix[i]);
239     }
240     return count;
241 }
242
243 static void init_cols(void)
244 {
245 #if DIODE_DIRECTION == COL2ROW
246     for(int x = 0; x < MATRIX_COLS; x++) {
247         int pin = col_pins[x];
248 #else
249     for(int x = 0; x < MATRIX_ROWS; x++) {
250         int pin = row_pins[x];
251 #endif
252         _SFR_IO8((pin >> 4) + 1) &=  ~_BV(pin & 0xF);
253         _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
254     }
255 }
256
257 static matrix_row_t read_cols(void)
258 {
259     matrix_row_t result = 0;
260
261 #if DIODE_DIRECTION == COL2ROW
262     for(int x = 0; x < MATRIX_COLS; x++) {     
263         int pin = col_pins[x];
264 #else
265     for(int x = 0; x < MATRIX_ROWS; x++) {
266         int pin = row_pins[x];
267 #endif
268         result |= (_SFR_IO8(pin >> 4) & _BV(pin & 0xF)) ? 0 : (SHIFTER << x);
269     }
270     return result;
271 }
272
273 static void unselect_rows(void)
274 {
275 #if DIODE_DIRECTION == COL2ROW
276     for(int x = 0; x < MATRIX_ROWS; x++) { 
277         int pin = row_pins[x];
278 #else
279     for(int x = 0; x < MATRIX_COLS; x++) { 
280         int pin = col_pins[x];
281 #endif
282         _SFR_IO8((pin >> 4) + 1) &=  ~_BV(pin & 0xF);
283         _SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF);
284     }
285 }
286
287 static void select_row(uint8_t row)
288 {
289
290 #if DIODE_DIRECTION == COL2ROW
291     int pin = row_pins[row];
292 #else
293     int pin = col_pins[row];
294 #endif
295     _SFR_IO8((pin >> 4) + 1) |=  _BV(pin & 0xF);
296     _SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF);
297 }