92fa693595a4012b631a08da74f18601c42dc10b
[tmk_keyboard.git] / converter / xt_usb / matrix.c
1 /*
2 Copyright 2011 Jun Wako <wakojun@gmail.com>
3 Copyright 2016 Ethan Apodaca <papodaca@gmail.com>
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
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include "action.h"
22 #include "print.h"
23 #include "util.h"
24 #include "debug.h"
25 #include "xt.h"
26 #include "matrix.h"
27
28
29 static void matrix_make(uint8_t code);
30 static void matrix_break(uint8_t code);
31 static void matrix_clear(void);
32 #ifdef MATRIX_HAS_GHOST
33 static bool matrix_has_ghost_in_row(uint8_t row);
34 #endif
35
36 static uint8_t matrix[MATRIX_ROWS];
37 #define ROW(code) (code>>3)
38 #define COL(code) (code&0x07)
39
40 // matrix positions for exceptional keys
41 #define PRINT_SCREEN (0x7C)
42 #define PAUSE (0x7D)
43
44 static bool is_modified = false;
45
46
47 inline
48 uint8_t matrix_rows(void)
49 {
50 return MATRIX_ROWS;
51 }
52
53 inline
54 uint8_t matrix_cols(void)
55 {
56 return MATRIX_COLS;
57 }
58
59 void matrix_init(void)
60 {
61 debug_enable = true;
62 xt_host_init();
63
64 // initialize matrix state: all keys off
65 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
66
67 return;
68 }
69
70 static uint8_t move_codes(uint8_t code) {
71 switch(code) {
72 case 0x10:
73 code += 0x5E;
74 break;
75 case 0x19:
76 code += 0x41;
77 break;
78 case 0x1C:
79 case 0x1D:
80 code += 0x38;
81 break;
82 case 0x20:
83 case 0x21:
84 case 0x22:
85 case 0x24:
86 code += 0x40;
87 break;
88 case 0x2E:
89 case 0x30:
90 case 0x32:
91 code += 0x44;
92 break;
93 case 0x35:
94 case 0x38:
95 code += 0x21;
96 break;
97 case 0x47:
98 case 0x48:
99 case 0x49:
100 case 0x4B:
101 case 0x4D:
102 case 0x4F:
103 case 0x50:
104 case 0x51:
105 case 0x52:
106 case 0x53:
107 code += 0x28;
108 break;
109 }
110 return code;
111 }
112
113 uint8_t matrix_scan(void)
114 {
115
116 // scan code reading states
117 static enum {
118 INIT,
119 E0,
120 E0_2A,
121 E0_2A_E0,
122 E0_B7,
123 E0_B7_E0,
124
125 // print screen
126 E1,
127 E1_1D,
128 E1_1D_45,
129 E1_1D_45_E1,
130 E1_1D_45_E1_9D,
131 // pause
132 } state = INIT;
133
134
135 is_modified = false;
136
137 // 'pseudo break code' hack
138 if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
139 matrix_break(PAUSE);
140 }
141
142 uint8_t code = xt_host_recv();
143 switch (state) {
144 case INIT:
145 switch (code) {
146 case 0xE0:
147 state = E0;
148 break;
149 case 0xE1:
150 state = E1;
151 break;
152 default: // normal key make
153 if (code < 0x80 && code != 0x00) {
154 xprintf("make: %X\r\n", code);
155 matrix_make(code);
156 } else if (code > 0x80 && code < 0xFF && code != 0x00) {
157 xprintf("break %X\r\n", code);
158 matrix_break(code - 0x80);
159 }
160 state = INIT;
161 }
162 break;
163 case E0: // E0-Prefixed
164 switch (code) { //move these codes to unused places on the matrix
165 case 0x2A:
166 state = E0_2A;
167 break;
168 case 0xB7:
169 state = E0_B7;
170 break;
171 default:
172 if (code < 0x80 && code != 0x00) {
173 matrix_make(move_codes(code));
174 } else if (code > 0x80 && code < 0xFF && code != 0x00) {
175 matrix_break(move_codes(code - 0x80));
176 }
177 state = INIT;
178 }
179 break;
180 case E0_2A:
181 if(code == 0xE0)
182 state = E0_2A_E0;
183 else
184 state = INIT;
185 break;
186 case E0_2A_E0:
187 if(code == 0x37)
188 matrix_make(PRINT_SCREEN);
189 else
190 state = INIT;
191 break;
192 case E0_B7:
193 if(code == 0xE0)
194 state = E0_B7;
195 else
196 state = INIT;
197 break;
198 case E0_B7_E0:
199 if(code == 0xAA)
200 matrix_break(PRINT_SCREEN);
201 else
202 state = INIT;
203 break;
204 case E1:
205 if (code == 0x1D)
206 state = E1_1D;
207 else
208 state = INIT;
209 break;
210 case E1_1D:
211 if(code == 0x45)
212 state = E1_1D_45;
213 else
214 state = INIT;
215 break;
216 case E1_1D_45:
217 if(code == 0xE1)
218 state = E1_1D_45_E1;
219 else
220 state = INIT;
221 break;
222 case E1_1D_45_E1:
223 if(code == 0x9D)
224 state = E1_1D_45_E1_9D;
225 else
226 state = INIT;
227 break;
228 case E1_1D_45_E1_9D:
229 if(code == 0xC5)
230 matrix_make(PAUSE);
231 else
232 state = INIT;
233 break;
234 default:
235 state = INIT;
236 }
237 return 1;
238 }
239
240 bool matrix_is_modified(void)
241 {
242 return is_modified;
243 }
244
245 inline
246 bool matrix_has_ghost(void)
247 {
248 #ifdef MATRIX_HAS_GHOST
249 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
250 if (matrix_has_ghost_in_row(i))
251 return true;
252 }
253 #endif
254 return false;
255 }
256
257 inline
258 bool matrix_is_on(uint8_t row, uint8_t col)
259 {
260 return (matrix[row] & (1<<col));
261 }
262
263 inline
264 uint8_t matrix_get_row(uint8_t row)
265 {
266 return matrix[row];
267 }
268
269 void matrix_print(void)
270 {
271 print("\nr/c 01234567\n");
272 for (uint8_t row = 0; row < matrix_rows(); row++) {
273 phex(row); print(": ");
274 pbin_reverse(matrix_get_row(row));
275 #ifdef MATRIX_HAS_GHOST
276 if (matrix_has_ghost_in_row(row)) {
277 print(" <ghost");
278 }
279 #endif
280 print("\n");
281 }
282 }
283
284 uint8_t matrix_key_count(void)
285 {
286 uint8_t count = 0;
287 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
288 count += bitpop(matrix[i]);
289 }
290 return count;
291 }
292
293 #ifdef MATRIX_HAS_GHOST
294 inline
295 static bool matrix_has_ghost_in_row(uint8_t row)
296 {
297 // no ghost exists in case less than 2 keys on
298 if (((matrix[row] - 1) & matrix[row]) == 0)
299 return false;
300
301 // ghost exists in case same state as other row
302 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
303 if (i != row && (matrix[i] & matrix[row]) == matrix[row])
304 return true;
305 }
306 return false;
307 }
308 #endif
309
310
311 inline
312 static void matrix_make(uint8_t code)
313 {
314 if (!matrix_is_on(ROW(code), COL(code))) {
315 matrix[ROW(code)] |= 1<<COL(code);
316 is_modified = true;
317 }
318 }
319
320 inline
321 static void matrix_break(uint8_t code)
322 {
323 if (matrix_is_on(ROW(code), COL(code))) {
324 matrix[ROW(code)] &= ~(1<<COL(code));
325 is_modified = true;
326 }
327 }
328
329 inline
330 static void matrix_clear(void)
331 {
332 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
333 }
Imprint / Impressum