Merge pull request #81 from bgould/master
[tmk_keyboard.git] / converter / terminal_bluefruit / matrix.c
1 /*
2 Copyright 2011 Jun Wako <wakojun@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 #include <stdint.h>
19 #include <stdbool.h>
20 #include <avr/io.h>
21 #include <util/delay.h>
22 #include "print.h"
23 #include "util.h"
24 #include "debug.h"
25 #include "ps2.h"
26 #include "matrix.h"
27
28
29 static void matrix_make(uint8_t code);
30 static void matrix_break(uint8_t code);
31 #ifdef MATRIX_HAS_GHOST
32 static bool matrix_has_ghost_in_row(uint8_t row);
33 #endif
34
35
36 /*
37 * Matrix Array usage:
38 * 'Scan Code Set 3' is assigned into 17x8 cell matrix.
39 *
40 * 8bit wide
41 * +---------+
42 * 0| |
43 * :| | 0x00-0x87
44 * ;| |
45 * 17| |
46 * +---------+
47 */
48 static uint8_t matrix[MATRIX_ROWS];
49 #define ROW(code) (code>>3)
50 #define COL(code) (code&0x07)
51
52 static bool is_modified = false;
53
54
55 inline
56 uint8_t matrix_rows(void)
57 {
58 return MATRIX_ROWS;
59 }
60
61 inline
62 uint8_t matrix_cols(void)
63 {
64 return MATRIX_COLS;
65 }
66
67 void matrix_init(void)
68 {
69 debug_enable = true;
70 //debug_matrix = true;
71 //debug_keyboard = true;
72 //debug_mouse = false;
73
74 ps2_host_init();
75
76 // initialize matrix state: all keys off
77 for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
78
79 return;
80 }
81
82 uint8_t matrix_scan(void)
83 {
84
85 // scan code reading states
86 static enum {
87 RESET,
88 RESET_RESPONSE,
89 KBD_ID0,
90 KBD_ID1,
91 CONFIG,
92 READY,
93 F0,
94 } state = RESET;
95
96 is_modified = false;
97
98 uint8_t code;
99 if ((code = ps2_host_recv())) {
100 debug("r"); debug_hex(code); debug(" ");
101 }
102
103 switch (state) {
104 case RESET:
105 debug("wFF ");
106 if (ps2_host_send(0xFF) == 0xFA) {
107 debug("[ack]\nRESET_RESPONSE: ");
108 state = RESET_RESPONSE;
109 }
110 break;
111 case RESET_RESPONSE:
112 if (code == 0xAA) {
113 debug("[ok]\nKBD_ID: ");
114 state = KBD_ID0;
115 } else if (code) {
116 debug("err\nRESET: ");
117 state = RESET;
118 }
119 break;
120 // after reset receive keyboad ID(2 bytes)
121 case KBD_ID0:
122 if (code) {
123 state = KBD_ID1;
124 }
125 break;
126 case KBD_ID1:
127 if (code) {
128 debug("\nCONFIG: ");
129 state = CONFIG;
130 }
131 break;
132 case CONFIG:
133 debug("wF8 ");
134 if (ps2_host_send(0xF8) == 0xFA) {
135 debug("[ack]\nREADY\n");
136 state = READY;
137 }
138 break;
139 case READY:
140 switch (code) {
141 case 0x00:
142 break;
143 case 0xF0:
144 state = F0;
145 debug(" ");
146 break;
147 default: // normal key make
148 if (code < 0x88) {
149 matrix_make(code);
150 } else {
151 debug("unexpected scan code at READY: "); debug_hex(code); debug("\n");
152 }
153 state = READY;
154 debug("\n");
155 }
156 break;
157 case F0: // Break code
158 switch (code) {
159 case 0x00:
160 break;
161 default:
162 if (code < 0x88) {
163 matrix_break(code);
164 } else {
165 debug("unexpected scan code at F0: "); debug_hex(code); debug("\n");
166 }
167 state = READY;
168 debug("\n");
169 }
170 break;
171 }
172 return 1;
173 }
174
175 bool matrix_is_modified(void)
176 {
177 return is_modified;
178 }
179
180 inline
181 bool matrix_has_ghost(void)
182 {
183 #ifdef MATRIX_HAS_GHOST
184 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
185 if (matrix_has_ghost_in_row(i))
186 return true;
187 }
188 #endif
189 return false;
190 }
191
192 inline
193 bool matrix_is_on(uint8_t row, uint8_t col)
194 {
195 return (matrix[row] & (1<<col));
196 }
197
198 inline
199 uint8_t matrix_get_row(uint8_t row)
200 {
201 return matrix[row];
202 }
203
204 void matrix_print(void)
205 {
206 print("\nr/c 01234567\n");
207 for (uint8_t row = 0; row < matrix_rows(); row++) {
208 phex(row); print(": ");
209 pbin_reverse(matrix_get_row(row));
210 #ifdef MATRIX_HAS_GHOST
211 if (matrix_has_ghost_in_row(row)) {
212 print(" <ghost");
213 }
214 #endif
215 print("\n");
216 }
217 }
218
219 uint8_t matrix_key_count(void)
220 {
221 uint8_t count = 0;
222 for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
223 count += bitpop(matrix[i]);
224 }
225 return count;
226 }
227
228 #ifdef MATRIX_HAS_GHOST
229 inline
230 static bool matrix_has_ghost_in_row(uint8_t row)
231 {
232 // no ghost exists in case less than 2 keys on
233 if (((matrix[row] - 1) & matrix[row]) == 0)
234 return false;
235
236 // ghost exists in case same state as other row
237 for (uint8_t i=0; i < MATRIX_ROWS; i++) {
238 if (i != row && (matrix[i] & matrix[row]) == matrix[row])
239 return true;
240 }
241 return false;
242 }
243 #endif
244
245
246 inline
247 static void matrix_make(uint8_t code)
248 {
249 if (!matrix_is_on(ROW(code), COL(code))) {
250 matrix[ROW(code)] |= 1<<COL(code);
251 is_modified = true;
252 }
253 }
254
255 inline
256 static void matrix_break(uint8_t code)
257 {
258 if (matrix_is_on(ROW(code), COL(code))) {
259 matrix[ROW(code)] &= ~(1<<COL(code));
260 is_modified = true;
261 }
262 }
Imprint / Impressum