148c6a51 |
1 | /* |
2 | Copyright 2016 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 | |
21 | // USB HID host |
22 | #include "Usb.h" |
23 | #include "usbhub.h" |
24 | #include "hid.h" |
25 | #include "hidboot.h" |
26 | #include "parser.h" |
27 | |
28 | #include "keycode.h" |
29 | #include "util.h" |
30 | #include "print.h" |
31 | #include "debug.h" |
32 | #include "timer.h" |
33 | #include "matrix.h" |
34 | #include "led.h" |
51326077 |
35 | #include "host.h" |
36 | #include "keyboard.h" |
148c6a51 |
37 | |
38 | |
39 | /* KEY CODE to Matrix |
40 | * |
41 | * HID keycode(1 byte): |
42 | * Higher 5 bits indicates ROW and lower 3 bits COL. |
43 | * |
44 | * 7 6 5 4 3 2 1 0 |
45 | * +---------------+ |
46 | * | ROW | COL | |
47 | * +---------------+ |
48 | * |
49 | * Matrix space(16 * 16): |
50 | * r\c0123456789ABCDEF |
51 | * 0 +----------------+ |
52 | * : | | |
53 | * : | | |
54 | * 16 +----------------+ |
55 | */ |
56 | #define ROW_MASK 0xF0 |
57 | #define COL_MASK 0x0F |
58 | #define CODE(row, col) (((row) << 4) | (col)) |
59 | #define ROW(code) (((code) & ROW_MASK) >> 4) |
60 | #define COL(code) ((code) & COL_MASK) |
61 | #define ROW_BITS(code) (1 << COL(code)) |
62 | |
63 | |
64 | // Integrated key state of all keyboards |
65 | static report_keyboard_t keyboard_report; |
66 | |
67 | static bool matrix_is_mod =false; |
68 | |
69 | /* |
70 | * USB Host Shield HID keyboards |
71 | * This supports two cascaded hubs and four keyboards |
72 | */ |
73 | USB usb_host; |
74 | USBHub hub1(&usb_host); |
75 | USBHub hub2(&usb_host); |
76 | HIDBoot<HID_PROTOCOL_KEYBOARD> kbd1(&usb_host); |
77 | HIDBoot<HID_PROTOCOL_KEYBOARD> kbd2(&usb_host); |
78 | HIDBoot<HID_PROTOCOL_KEYBOARD> kbd3(&usb_host); |
79 | HIDBoot<HID_PROTOCOL_KEYBOARD> kbd4(&usb_host); |
80 | KBDReportParser kbd_parser1; |
81 | KBDReportParser kbd_parser2; |
82 | KBDReportParser kbd_parser3; |
83 | KBDReportParser kbd_parser4; |
84 | |
85 | |
86 | uint8_t matrix_rows(void) { return MATRIX_ROWS; } |
87 | uint8_t matrix_cols(void) { return MATRIX_COLS; } |
88 | bool matrix_has_ghost(void) { return false; } |
89 | void matrix_init(void) { |
90 | // USB Host Shield setup |
91 | usb_host.Init(); |
92 | kbd1.SetReportParser(0, (HIDReportParser*)&kbd_parser1); |
93 | kbd2.SetReportParser(0, (HIDReportParser*)&kbd_parser2); |
94 | kbd3.SetReportParser(0, (HIDReportParser*)&kbd_parser3); |
95 | kbd4.SetReportParser(0, (HIDReportParser*)&kbd_parser4); |
96 | } |
97 | |
98 | static void or_report(report_keyboard_t report) { |
99 | // integrate reports into keyboard_report |
100 | keyboard_report.mods |= report.mods; |
101 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { |
102 | if (IS_ANY(report.keys[i])) { |
103 | for (uint8_t j = 0; j < KEYBOARD_REPORT_KEYS; j++) { |
104 | if (! keyboard_report.keys[j]) { |
105 | keyboard_report.keys[j] = report.keys[i]; |
106 | break; |
107 | } |
108 | } |
109 | } |
110 | } |
111 | } |
112 | |
113 | uint8_t matrix_scan(void) { |
114 | static uint16_t last_time_stamp1 = 0; |
115 | static uint16_t last_time_stamp2 = 0; |
116 | static uint16_t last_time_stamp3 = 0; |
117 | static uint16_t last_time_stamp4 = 0; |
118 | |
119 | // check report came from keyboards |
120 | if (kbd_parser1.time_stamp != last_time_stamp1 || |
121 | kbd_parser2.time_stamp != last_time_stamp2 || |
122 | kbd_parser3.time_stamp != last_time_stamp3 || |
123 | kbd_parser4.time_stamp != last_time_stamp4) { |
124 | |
125 | last_time_stamp1 = kbd_parser1.time_stamp; |
126 | last_time_stamp2 = kbd_parser2.time_stamp; |
127 | last_time_stamp3 = kbd_parser3.time_stamp; |
128 | last_time_stamp4 = kbd_parser4.time_stamp; |
129 | |
130 | // clear and integrate all reports |
131 | keyboard_report = {}; |
132 | or_report(kbd_parser1.report); |
133 | or_report(kbd_parser2.report); |
134 | or_report(kbd_parser3.report); |
135 | or_report(kbd_parser4.report); |
136 | |
137 | matrix_is_mod = true; |
138 | |
139 | dprintf("state: %02X %02X", keyboard_report.mods, keyboard_report.reserved); |
140 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { |
141 | dprintf(" %02X", keyboard_report.keys[i]); |
142 | } |
143 | dprint("\r\n"); |
144 | } else { |
145 | matrix_is_mod = false; |
146 | } |
147 | |
148 | uint16_t timer; |
149 | timer = timer_read(); |
150 | usb_host.Task(); |
151 | timer = timer_elapsed(timer); |
152 | if (timer > 100) { |
153 | dprintf("host.Task: %d\n", timer); |
154 | } |
155 | |
51326077 |
156 | static uint8_t usb_state = 0; |
157 | if (usb_state != usb_host.getUsbTaskState()) { |
158 | usb_state = usb_host.getUsbTaskState(); |
159 | dprintf("usb_state: %02X\n", usb_state); |
160 | |
161 | // restore LED state when keyboard comes up |
162 | if (usb_state == USB_STATE_RUNNING) { |
163 | keyboard_set_leds(host_keyboard_leds()); |
164 | } |
165 | } |
148c6a51 |
166 | return 1; |
167 | } |
168 | |
169 | bool matrix_is_modified(void) { |
170 | return matrix_is_mod; |
171 | } |
172 | |
173 | bool matrix_is_on(uint8_t row, uint8_t col) { |
174 | uint8_t code = CODE(row, col); |
175 | |
176 | if (IS_MOD(code)) { |
177 | if (keyboard_report.mods & ROW_BITS(code)) { |
178 | return true; |
179 | } |
180 | } |
181 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { |
182 | if (keyboard_report.keys[i] == code) { |
183 | return true; |
184 | } |
185 | } |
186 | return false; |
187 | } |
188 | |
189 | matrix_row_t matrix_get_row(uint8_t row) { |
190 | uint16_t row_bits = 0; |
191 | |
192 | if (IS_MOD(CODE(row, 0)) && keyboard_report.mods) { |
193 | row_bits |= keyboard_report.mods; |
194 | } |
195 | |
196 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { |
197 | if (IS_ANY(keyboard_report.keys[i])) { |
198 | if (row == ROW(keyboard_report.keys[i])) { |
199 | row_bits |= ROW_BITS(keyboard_report.keys[i]); |
200 | } |
201 | } |
202 | } |
203 | return row_bits; |
204 | } |
205 | |
206 | uint8_t matrix_key_count(void) { |
207 | uint8_t count = 0; |
208 | |
209 | count += bitpop(keyboard_report.mods); |
210 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { |
211 | if (IS_ANY(keyboard_report.keys[i])) { |
212 | count++; |
213 | } |
214 | } |
215 | return count; |
216 | } |
217 | |
218 | void matrix_print(void) { |
219 | print("\nr/c 0123456789ABCDEF\n"); |
220 | for (uint8_t row = 0; row < matrix_rows(); row++) { |
221 | xprintf("%02d: ", row); |
222 | print_bin_reverse16(matrix_get_row(row)); |
223 | print("\n"); |
224 | } |
225 | } |
226 | |
227 | void led_set(uint8_t usb_led) |
228 | { |
229 | kbd1.SetReport(0, 0, 2, 0, 1, &usb_led); |
230 | kbd2.SetReport(0, 0, 2, 0, 1, &usb_led); |
231 | kbd3.SetReport(0, 0, 2, 0, 1, &usb_led); |
232 | kbd4.SetReport(0, 0, 2, 0, 1, &usb_led); |
233 | } |