diff options
Diffstat (limited to 'tmk_core/common')
63 files changed, 7156 insertions, 0 deletions
diff --git a/tmk_core/common/action.c b/tmk_core/common/action.c new file mode 100644 index 000000000..ec8eeae7b --- /dev/null +++ b/tmk_core/common/action.c | |||
@@ -0,0 +1,565 @@ | |||
1 | /* | ||
2 | Copyright 2012,2013 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 | #include "host.h" | ||
18 | #include "keycode.h" | ||
19 | #include "keyboard.h" | ||
20 | #include "mousekey.h" | ||
21 | #include "command.h" | ||
22 | #include "led.h" | ||
23 | #include "backlight.h" | ||
24 | #include "action_layer.h" | ||
25 | #include "action_tapping.h" | ||
26 | #include "action_macro.h" | ||
27 | #include "action_util.h" | ||
28 | #include "action.h" | ||
29 | |||
30 | #ifdef DEBUG_ACTION | ||
31 | #include "debug.h" | ||
32 | #else | ||
33 | #include "nodebug.h" | ||
34 | #endif | ||
35 | |||
36 | |||
37 | void action_exec(keyevent_t event) | ||
38 | { | ||
39 | if (!IS_NOEVENT(event)) { | ||
40 | dprint("\n---- action_exec: start -----\n"); | ||
41 | dprint("EVENT: "); debug_event(event); dprintln(); | ||
42 | } | ||
43 | |||
44 | keyrecord_t record = { .event = event }; | ||
45 | |||
46 | #ifndef NO_ACTION_TAPPING | ||
47 | action_tapping_process(record); | ||
48 | #else | ||
49 | process_action(&record); | ||
50 | if (!IS_NOEVENT(record.event)) { | ||
51 | dprint("processed: "); debug_record(record); dprintln(); | ||
52 | } | ||
53 | #endif | ||
54 | } | ||
55 | |||
56 | void process_action(keyrecord_t *record) | ||
57 | { | ||
58 | keyevent_t event = record->event; | ||
59 | #ifndef NO_ACTION_TAPPING | ||
60 | uint8_t tap_count = record->tap.count; | ||
61 | #endif | ||
62 | |||
63 | if (IS_NOEVENT(event)) { return; } | ||
64 | |||
65 | action_t action = layer_switch_get_action(event.key); | ||
66 | dprint("ACTION: "); debug_action(action); | ||
67 | #ifndef NO_ACTION_LAYER | ||
68 | dprint(" layer_state: "); layer_debug(); | ||
69 | dprint(" default_layer_state: "); default_layer_debug(); | ||
70 | #endif | ||
71 | dprintln(); | ||
72 | |||
73 | switch (action.kind.id) { | ||
74 | /* Key and Mods */ | ||
75 | case ACT_LMODS: | ||
76 | case ACT_RMODS: | ||
77 | { | ||
78 | uint8_t mods = (action.kind.id == ACT_LMODS) ? action.key.mods : | ||
79 | action.key.mods<<4; | ||
80 | if (event.pressed) { | ||
81 | if (mods) { | ||
82 | add_weak_mods(mods); | ||
83 | send_keyboard_report(); | ||
84 | } | ||
85 | register_code(action.key.code); | ||
86 | } else { | ||
87 | unregister_code(action.key.code); | ||
88 | if (mods) { | ||
89 | del_weak_mods(mods); | ||
90 | send_keyboard_report(); | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | break; | ||
95 | #ifndef NO_ACTION_TAPPING | ||
96 | case ACT_LMODS_TAP: | ||
97 | case ACT_RMODS_TAP: | ||
98 | { | ||
99 | uint8_t mods = (action.kind.id == ACT_LMODS_TAP) ? action.key.mods : | ||
100 | action.key.mods<<4; | ||
101 | switch (action.layer_tap.code) { | ||
102 | #ifndef NO_ACTION_ONESHOT | ||
103 | case MODS_ONESHOT: | ||
104 | // Oneshot modifier | ||
105 | if (event.pressed) { | ||
106 | if (tap_count == 0) { | ||
107 | register_mods(mods); | ||
108 | } | ||
109 | else if (tap_count == 1) { | ||
110 | dprint("MODS_TAP: Oneshot: start\n"); | ||
111 | set_oneshot_mods(mods); | ||
112 | } | ||
113 | else { | ||
114 | register_mods(mods); | ||
115 | } | ||
116 | } else { | ||
117 | if (tap_count == 0) { | ||
118 | clear_oneshot_mods(); | ||
119 | unregister_mods(mods); | ||
120 | } | ||
121 | else if (tap_count == 1) { | ||
122 | // Retain Oneshot mods | ||
123 | } | ||
124 | else { | ||
125 | clear_oneshot_mods(); | ||
126 | unregister_mods(mods); | ||
127 | } | ||
128 | } | ||
129 | break; | ||
130 | #endif | ||
131 | case MODS_TAP_TOGGLE: | ||
132 | if (event.pressed) { | ||
133 | if (tap_count <= TAPPING_TOGGLE) { | ||
134 | register_mods(mods); | ||
135 | } | ||
136 | } else { | ||
137 | if (tap_count < TAPPING_TOGGLE) { | ||
138 | unregister_mods(mods); | ||
139 | } | ||
140 | } | ||
141 | break; | ||
142 | default: | ||
143 | if (event.pressed) { | ||
144 | if (tap_count > 0) { | ||
145 | if (record->tap.interrupted) { | ||
146 | dprint("MODS_TAP: Tap: Cancel: add_mods\n"); | ||
147 | // ad hoc: set 0 to cancel tap | ||
148 | record->tap.count = 0; | ||
149 | register_mods(mods); | ||
150 | } else { | ||
151 | dprint("MODS_TAP: Tap: register_code\n"); | ||
152 | register_code(action.key.code); | ||
153 | } | ||
154 | } else { | ||
155 | dprint("MODS_TAP: No tap: add_mods\n"); | ||
156 | register_mods(mods); | ||
157 | } | ||
158 | } else { | ||
159 | if (tap_count > 0) { | ||
160 | dprint("MODS_TAP: Tap: unregister_code\n"); | ||
161 | unregister_code(action.key.code); | ||
162 | } else { | ||
163 | dprint("MODS_TAP: No tap: add_mods\n"); | ||
164 | unregister_mods(mods); | ||
165 | } | ||
166 | } | ||
167 | break; | ||
168 | } | ||
169 | } | ||
170 | break; | ||
171 | #endif | ||
172 | #ifdef EXTRAKEY_ENABLE | ||
173 | /* other HID usage */ | ||
174 | case ACT_USAGE: | ||
175 | switch (action.usage.page) { | ||
176 | case PAGE_SYSTEM: | ||
177 | if (event.pressed) { | ||
178 | host_system_send(action.usage.code); | ||
179 | } else { | ||
180 | host_system_send(0); | ||
181 | } | ||
182 | break; | ||
183 | case PAGE_CONSUMER: | ||
184 | if (event.pressed) { | ||
185 | host_consumer_send(action.usage.code); | ||
186 | } else { | ||
187 | host_consumer_send(0); | ||
188 | } | ||
189 | break; | ||
190 | } | ||
191 | break; | ||
192 | #endif | ||
193 | #ifdef MOUSEKEY_ENABLE | ||
194 | /* Mouse key */ | ||
195 | case ACT_MOUSEKEY: | ||
196 | if (event.pressed) { | ||
197 | mousekey_on(action.key.code); | ||
198 | mousekey_send(); | ||
199 | } else { | ||
200 | mousekey_off(action.key.code); | ||
201 | mousekey_send(); | ||
202 | } | ||
203 | break; | ||
204 | #endif | ||
205 | #ifndef NO_ACTION_LAYER | ||
206 | case ACT_LAYER: | ||
207 | if (action.layer_bitop.on == 0) { | ||
208 | /* Default Layer Bitwise Operation */ | ||
209 | if (!event.pressed) { | ||
210 | uint8_t shift = action.layer_bitop.part*4; | ||
211 | uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift; | ||
212 | uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0; | ||
213 | switch (action.layer_bitop.op) { | ||
214 | case OP_BIT_AND: default_layer_and(bits | mask); break; | ||
215 | case OP_BIT_OR: default_layer_or(bits | mask); break; | ||
216 | case OP_BIT_XOR: default_layer_xor(bits | mask); break; | ||
217 | case OP_BIT_SET: default_layer_and(mask); default_layer_or(bits); break; | ||
218 | } | ||
219 | } | ||
220 | } else { | ||
221 | /* Layer Bitwise Operation */ | ||
222 | if (event.pressed ? (action.layer_bitop.on & ON_PRESS) : | ||
223 | (action.layer_bitop.on & ON_RELEASE)) { | ||
224 | uint8_t shift = action.layer_bitop.part*4; | ||
225 | uint32_t bits = ((uint32_t)action.layer_bitop.bits)<<shift; | ||
226 | uint32_t mask = (action.layer_bitop.xbit) ? ~(((uint32_t)0xf)<<shift) : 0; | ||
227 | switch (action.layer_bitop.op) { | ||
228 | case OP_BIT_AND: layer_and(bits | mask); break; | ||
229 | case OP_BIT_OR: layer_or(bits | mask); break; | ||
230 | case OP_BIT_XOR: layer_xor(bits | mask); break; | ||
231 | case OP_BIT_SET: layer_and(mask); layer_or(bits); break; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | break; | ||
236 | #ifndef NO_ACTION_TAPPING | ||
237 | case ACT_LAYER_TAP: | ||
238 | case ACT_LAYER_TAP_EXT: | ||
239 | switch (action.layer_tap.code) { | ||
240 | case 0xe0 ... 0xef: | ||
241 | /* layer On/Off with modifiers(left only) */ | ||
242 | if (event.pressed) { | ||
243 | layer_on(action.layer_tap.val); | ||
244 | register_mods(action.layer_tap.code & 0x0f); | ||
245 | } else { | ||
246 | layer_off(action.layer_tap.val); | ||
247 | unregister_mods(action.layer_tap.code & 0x0f); | ||
248 | } | ||
249 | break; | ||
250 | case OP_TAP_TOGGLE: | ||
251 | /* tap toggle */ | ||
252 | if (event.pressed) { | ||
253 | if (tap_count < TAPPING_TOGGLE) { | ||
254 | layer_invert(action.layer_tap.val); | ||
255 | } | ||
256 | } else { | ||
257 | if (tap_count <= TAPPING_TOGGLE) { | ||
258 | layer_invert(action.layer_tap.val); | ||
259 | } | ||
260 | } | ||
261 | break; | ||
262 | case OP_ON_OFF: | ||
263 | event.pressed ? layer_on(action.layer_tap.val) : | ||
264 | layer_off(action.layer_tap.val); | ||
265 | break; | ||
266 | case OP_OFF_ON: | ||
267 | event.pressed ? layer_off(action.layer_tap.val) : | ||
268 | layer_on(action.layer_tap.val); | ||
269 | break; | ||
270 | case OP_SET_CLEAR: | ||
271 | event.pressed ? layer_move(action.layer_tap.val) : | ||
272 | layer_clear(); | ||
273 | break; | ||
274 | default: | ||
275 | /* tap key */ | ||
276 | if (event.pressed) { | ||
277 | if (tap_count > 0) { | ||
278 | dprint("KEYMAP_TAP_KEY: Tap: register_code\n"); | ||
279 | register_code(action.layer_tap.code); | ||
280 | } else { | ||
281 | dprint("KEYMAP_TAP_KEY: No tap: On on press\n"); | ||
282 | layer_on(action.layer_tap.val); | ||
283 | } | ||
284 | } else { | ||
285 | if (tap_count > 0) { | ||
286 | dprint("KEYMAP_TAP_KEY: Tap: unregister_code\n"); | ||
287 | unregister_code(action.layer_tap.code); | ||
288 | } else { | ||
289 | dprint("KEYMAP_TAP_KEY: No tap: Off on release\n"); | ||
290 | layer_off(action.layer_tap.val); | ||
291 | } | ||
292 | } | ||
293 | break; | ||
294 | } | ||
295 | break; | ||
296 | #endif | ||
297 | #endif | ||
298 | /* Extentions */ | ||
299 | #ifndef NO_ACTION_MACRO | ||
300 | case ACT_MACRO: | ||
301 | action_macro_play(action_get_macro(record, action.func.id, action.func.opt)); | ||
302 | break; | ||
303 | #endif | ||
304 | #ifdef BACKLIGHT_ENABLE | ||
305 | case ACT_BACKLIGHT: | ||
306 | if (!event.pressed) { | ||
307 | switch (action.backlight.opt) { | ||
308 | case BACKLIGHT_INCREASE: | ||
309 | backlight_increase(); | ||
310 | break; | ||
311 | case BACKLIGHT_DECREASE: | ||
312 | backlight_decrease(); | ||
313 | break; | ||
314 | case BACKLIGHT_TOGGLE: | ||
315 | backlight_toggle(); | ||
316 | break; | ||
317 | case BACKLIGHT_STEP: | ||
318 | backlight_step(); | ||
319 | break; | ||
320 | case BACKLIGHT_LEVEL: | ||
321 | backlight_level(action.backlight.level); | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | break; | ||
326 | #endif | ||
327 | case ACT_COMMAND: | ||
328 | break; | ||
329 | #ifndef NO_ACTION_FUNCTION | ||
330 | case ACT_FUNCTION: | ||
331 | action_function(record, action.func.id, action.func.opt); | ||
332 | break; | ||
333 | #endif | ||
334 | default: | ||
335 | break; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | |||
340 | |||
341 | |||
342 | /* | ||
343 | * Utilities for actions. | ||
344 | */ | ||
345 | void register_code(uint8_t code) | ||
346 | { | ||
347 | if (code == KC_NO) { | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | #ifdef LOCKING_SUPPORT_ENABLE | ||
352 | else if (KC_LOCKING_CAPS == code) { | ||
353 | #ifdef LOCKING_RESYNC_ENABLE | ||
354 | // Resync: ignore if caps lock already is on | ||
355 | if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) return; | ||
356 | #endif | ||
357 | add_key(KC_CAPSLOCK); | ||
358 | send_keyboard_report(); | ||
359 | del_key(KC_CAPSLOCK); | ||
360 | send_keyboard_report(); | ||
361 | } | ||
362 | |||
363 | else if (KC_LOCKING_NUM == code) { | ||
364 | #ifdef LOCKING_RESYNC_ENABLE | ||
365 | if (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) return; | ||
366 | #endif | ||
367 | add_key(KC_NUMLOCK); | ||
368 | send_keyboard_report(); | ||
369 | del_key(KC_NUMLOCK); | ||
370 | send_keyboard_report(); | ||
371 | } | ||
372 | |||
373 | else if (KC_LOCKING_SCROLL == code) { | ||
374 | #ifdef LOCKING_RESYNC_ENABLE | ||
375 | if (host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK)) return; | ||
376 | #endif | ||
377 | add_key(KC_SCROLLLOCK); | ||
378 | send_keyboard_report(); | ||
379 | del_key(KC_SCROLLLOCK); | ||
380 | send_keyboard_report(); | ||
381 | } | ||
382 | #endif | ||
383 | |||
384 | else if IS_KEY(code) { | ||
385 | // TODO: should push command_proc out of this block? | ||
386 | if (command_proc(code)) return; | ||
387 | |||
388 | #ifndef NO_ACTION_ONESHOT | ||
389 | /* TODO: remove | ||
390 | if (oneshot_state.mods && !oneshot_state.disabled) { | ||
391 | uint8_t tmp_mods = get_mods(); | ||
392 | add_mods(oneshot_state.mods); | ||
393 | |||
394 | add_key(code); | ||
395 | send_keyboard_report(); | ||
396 | |||
397 | set_mods(tmp_mods); | ||
398 | send_keyboard_report(); | ||
399 | oneshot_cancel(); | ||
400 | } else | ||
401 | */ | ||
402 | #endif | ||
403 | { | ||
404 | add_key(code); | ||
405 | send_keyboard_report(); | ||
406 | } | ||
407 | } | ||
408 | else if IS_MOD(code) { | ||
409 | add_mods(MOD_BIT(code)); | ||
410 | send_keyboard_report(); | ||
411 | } | ||
412 | else if IS_SYSTEM(code) { | ||
413 | host_system_send(KEYCODE2SYSTEM(code)); | ||
414 | } | ||
415 | else if IS_CONSUMER(code) { | ||
416 | host_consumer_send(KEYCODE2CONSUMER(code)); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | void unregister_code(uint8_t code) | ||
421 | { | ||
422 | if (code == KC_NO) { | ||
423 | return; | ||
424 | } | ||
425 | |||
426 | #ifdef LOCKING_SUPPORT_ENABLE | ||
427 | else if (KC_LOCKING_CAPS == code) { | ||
428 | #ifdef LOCKING_RESYNC_ENABLE | ||
429 | // Resync: ignore if caps lock already is off | ||
430 | if (!(host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK))) return; | ||
431 | #endif | ||
432 | add_key(KC_CAPSLOCK); | ||
433 | send_keyboard_report(); | ||
434 | del_key(KC_CAPSLOCK); | ||
435 | send_keyboard_report(); | ||
436 | } | ||
437 | |||
438 | else if (KC_LOCKING_NUM == code) { | ||
439 | #ifdef LOCKING_RESYNC_ENABLE | ||
440 | if (!(host_keyboard_leds() & (1<<USB_LED_NUM_LOCK))) return; | ||
441 | #endif | ||
442 | add_key(KC_NUMLOCK); | ||
443 | send_keyboard_report(); | ||
444 | del_key(KC_NUMLOCK); | ||
445 | send_keyboard_report(); | ||
446 | } | ||
447 | |||
448 | else if (KC_LOCKING_SCROLL == code) { | ||
449 | #ifdef LOCKING_RESYNC_ENABLE | ||
450 | if (!(host_keyboard_leds() & (1<<USB_LED_SCROLL_LOCK))) return; | ||
451 | #endif | ||
452 | add_key(KC_SCROLLLOCK); | ||
453 | send_keyboard_report(); | ||
454 | del_key(KC_SCROLLLOCK); | ||
455 | send_keyboard_report(); | ||
456 | } | ||
457 | #endif | ||
458 | |||
459 | else if IS_KEY(code) { | ||
460 | del_key(code); | ||
461 | send_keyboard_report(); | ||
462 | } | ||
463 | else if IS_MOD(code) { | ||
464 | del_mods(MOD_BIT(code)); | ||
465 | send_keyboard_report(); | ||
466 | } | ||
467 | else if IS_SYSTEM(code) { | ||
468 | host_system_send(0); | ||
469 | } | ||
470 | else if IS_CONSUMER(code) { | ||
471 | host_consumer_send(0); | ||
472 | } | ||
473 | } | ||
474 | |||
475 | void register_mods(uint8_t mods) | ||
476 | { | ||
477 | if (mods) { | ||
478 | add_mods(mods); | ||
479 | send_keyboard_report(); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | void unregister_mods(uint8_t mods) | ||
484 | { | ||
485 | if (mods) { | ||
486 | del_mods(mods); | ||
487 | send_keyboard_report(); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | void clear_keyboard(void) | ||
492 | { | ||
493 | clear_mods(); | ||
494 | clear_keyboard_but_mods(); | ||
495 | } | ||
496 | |||
497 | void clear_keyboard_but_mods(void) | ||
498 | { | ||
499 | clear_weak_mods(); | ||
500 | clear_keys(); | ||
501 | send_keyboard_report(); | ||
502 | #ifdef MOUSEKEY_ENABLE | ||
503 | mousekey_clear(); | ||
504 | mousekey_send(); | ||
505 | #endif | ||
506 | #ifdef EXTRAKEY_ENABLE | ||
507 | host_system_send(0); | ||
508 | host_consumer_send(0); | ||
509 | #endif | ||
510 | } | ||
511 | |||
512 | bool is_tap_key(keypos_t key) | ||
513 | { | ||
514 | action_t action = layer_switch_get_action(key); | ||
515 | |||
516 | switch (action.kind.id) { | ||
517 | case ACT_LMODS_TAP: | ||
518 | case ACT_RMODS_TAP: | ||
519 | case ACT_LAYER_TAP: | ||
520 | case ACT_LAYER_TAP_EXT: | ||
521 | return true; | ||
522 | case ACT_MACRO: | ||
523 | case ACT_FUNCTION: | ||
524 | if (action.func.opt & FUNC_TAP) { return true; } | ||
525 | return false; | ||
526 | } | ||
527 | return false; | ||
528 | } | ||
529 | |||
530 | |||
531 | /* | ||
532 | * debug print | ||
533 | */ | ||
534 | void debug_event(keyevent_t event) | ||
535 | { | ||
536 | dprintf("%04X%c(%u)", (event.key.row<<8 | event.key.col), (event.pressed ? 'd' : 'u'), event.time); | ||
537 | } | ||
538 | |||
539 | void debug_record(keyrecord_t record) | ||
540 | { | ||
541 | debug_event(record.event); | ||
542 | #ifndef NO_ACTION_TAPPING | ||
543 | dprintf(":%u%c", record.tap.count, (record.tap.interrupted ? '-' : ' ')); | ||
544 | #endif | ||
545 | } | ||
546 | |||
547 | void debug_action(action_t action) | ||
548 | { | ||
549 | switch (action.kind.id) { | ||
550 | case ACT_LMODS: dprint("ACT_LMODS"); break; | ||
551 | case ACT_RMODS: dprint("ACT_RMODS"); break; | ||
552 | case ACT_LMODS_TAP: dprint("ACT_LMODS_TAP"); break; | ||
553 | case ACT_RMODS_TAP: dprint("ACT_RMODS_TAP"); break; | ||
554 | case ACT_USAGE: dprint("ACT_USAGE"); break; | ||
555 | case ACT_MOUSEKEY: dprint("ACT_MOUSEKEY"); break; | ||
556 | case ACT_LAYER: dprint("ACT_LAYER"); break; | ||
557 | case ACT_LAYER_TAP: dprint("ACT_LAYER_TAP"); break; | ||
558 | case ACT_LAYER_TAP_EXT: dprint("ACT_LAYER_TAP_EXT"); break; | ||
559 | case ACT_MACRO: dprint("ACT_MACRO"); break; | ||
560 | case ACT_COMMAND: dprint("ACT_COMMAND"); break; | ||
561 | case ACT_FUNCTION: dprint("ACT_FUNCTION"); break; | ||
562 | default: dprint("UNKNOWN"); break; | ||
563 | } | ||
564 | dprintf("[%X:%02X]", action.kind.param>>8, action.kind.param&0xff); | ||
565 | } | ||
diff --git a/tmk_core/common/action.h b/tmk_core/common/action.h new file mode 100644 index 000000000..8a4736d7b --- /dev/null +++ b/tmk_core/common/action.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | Copyright 2012,2013 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 | #ifndef ACTION_H | ||
18 | #define ACTION_H | ||
19 | |||
20 | #include <stdint.h> | ||
21 | #include <stdbool.h> | ||
22 | #include "keyboard.h" | ||
23 | #include "keycode.h" | ||
24 | #include "action_code.h" | ||
25 | #include "action_macro.h" | ||
26 | |||
27 | |||
28 | #ifdef __cplusplus | ||
29 | extern "C" { | ||
30 | #endif | ||
31 | |||
32 | /* tapping count and state */ | ||
33 | typedef struct { | ||
34 | bool interrupted :1; | ||
35 | bool reserved2 :1; | ||
36 | bool reserved1 :1; | ||
37 | bool reserved0 :1; | ||
38 | uint8_t count :4; | ||
39 | } tap_t; | ||
40 | |||
41 | /* Key event container for recording */ | ||
42 | typedef struct { | ||
43 | keyevent_t event; | ||
44 | #ifndef NO_ACTION_TAPPING | ||
45 | tap_t tap; | ||
46 | #endif | ||
47 | } keyrecord_t; | ||
48 | |||
49 | /* Execute action per keyevent */ | ||
50 | void action_exec(keyevent_t event); | ||
51 | |||
52 | /* action for key */ | ||
53 | action_t action_for_key(uint8_t layer, keypos_t key); | ||
54 | |||
55 | /* macro */ | ||
56 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt); | ||
57 | |||
58 | /* user defined special function */ | ||
59 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); | ||
60 | |||
61 | /* Utilities for actions. */ | ||
62 | void process_action(keyrecord_t *record); | ||
63 | void register_code(uint8_t code); | ||
64 | void unregister_code(uint8_t code); | ||
65 | void register_mods(uint8_t mods); | ||
66 | void unregister_mods(uint8_t mods); | ||
67 | //void set_mods(uint8_t mods); | ||
68 | void clear_keyboard(void); | ||
69 | void clear_keyboard_but_mods(void); | ||
70 | void layer_switch(uint8_t new_layer); | ||
71 | bool is_tap_key(keypos_t key); | ||
72 | |||
73 | /* debug */ | ||
74 | void debug_event(keyevent_t event); | ||
75 | void debug_record(keyrecord_t record); | ||
76 | void debug_action(action_t action); | ||
77 | |||
78 | #ifdef __cplusplus | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | #endif /* ACTION_H */ | ||
diff --git a/tmk_core/common/action_code.h b/tmk_core/common/action_code.h new file mode 100644 index 000000000..bc40e2c6f --- /dev/null +++ b/tmk_core/common/action_code.h | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef ACTION_CODE_H | ||
18 | #define ACTION_CODE_H | ||
19 | |||
20 | /* Action codes | ||
21 | * ============ | ||
22 | * 16bit code: action_kind(4bit) + action_parameter(12bit) | ||
23 | * | ||
24 | * | ||
25 | * Key Actions(00xx) | ||
26 | * ----------------- | ||
27 | * ACT_MODS(000r): | ||
28 | * 000r|0000|0000 0000 No action code | ||
29 | * 000r|0000|0000 0001 Transparent code | ||
30 | * 000r|0000| keycode Key | ||
31 | * 000r|mods|0000 0000 Modifiers | ||
32 | * 000r|mods| keycode Modifiers+Key(Modified key) | ||
33 | * r: Left/Right flag(Left:0, Right:1) | ||
34 | * | ||
35 | * ACT_MODS_TAP(001r): | ||
36 | * 001r|mods|0000 0000 Modifiers with OneShot | ||
37 | * 001r|mods|0000 0001 Modifiers with tap toggle | ||
38 | * 001r|mods|0000 00xx (reserved) | ||
39 | * 001r|mods| keycode Modifiers with Tap Key(Dual role) | ||
40 | * | ||
41 | * | ||
42 | * Other Keys(01xx) | ||
43 | * ---------------- | ||
44 | * ACT_USAGE(0100): TODO: Not needed? | ||
45 | * 0100|00| usage(10) System control(0x80) - General Desktop page(0x01) | ||
46 | * 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C) | ||
47 | * 0100|10| usage(10) (reserved) | ||
48 | * 0100|11| usage(10) (reserved) | ||
49 | * | ||
50 | * ACT_MOUSEKEY(0110): TODO: Not needed? | ||
51 | * 0101|xxxx| keycode Mouse key | ||
52 | * | ||
53 | * 011x|xxxx xxxx xxxx (reseved) | ||
54 | * | ||
55 | * | ||
56 | * Layer Actions(10xx) | ||
57 | * ------------------- | ||
58 | * ACT_LAYER(1000): | ||
59 | * 1000|oo00|pppE BBBB Default Layer Bitwise operation | ||
60 | * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET) | ||
61 | * ppp: 4-bit chunk part(0-7) | ||
62 | * EBBBB: bits and extra bit | ||
63 | * 1000|ooee|pppE BBBB Layer Bitwise Operation | ||
64 | * oo: operation(00:AND, 01:OR, 10:XOR, 11:SET) | ||
65 | * ppp: 4-bit chunk part(0-7) | ||
66 | * EBBBB: bits and extra bit | ||
67 | * ee: on event(01:press, 10:release, 11:both) | ||
68 | * | ||
69 | * 1001|xxxx|xxxx xxxx (reserved) | ||
70 | * 1001|oopp|BBBB BBBB 8-bit Bitwise Operation??? | ||
71 | * | ||
72 | * ACT_LAYER_TAP(101x): | ||
73 | * 101E|LLLL| keycode On/Off with tap key | ||
74 | * 101E|LLLL|1110 mods On/Off with modifiers(0xE0-EF) | ||
75 | * 101E|LLLL|1111 0000 Invert with tap toggle(0xF0) | ||
76 | * 101E|LLLL|1111 0001 On/Off | ||
77 | * 101E|LLLL|1111 0010 Off/On | ||
78 | * 101E|LLLL|1111 0011 Set/Clear | ||
79 | * 101E|LLLL|1111 xxxx Reserved(0xF4-FF) | ||
80 | * ELLLL: layer 0-31(E: extra bit for layer 16-31) | ||
81 | * | ||
82 | * | ||
83 | * Extensions(11xx) | ||
84 | * ---------------- | ||
85 | * ACT_MACRO(1100): | ||
86 | * 1100|opt | id(8) Macro play? | ||
87 | * 1100|1111| id(8) Macro record? | ||
88 | * | ||
89 | * ACT_BACKLIGHT(1101): | ||
90 | * 1101|opt |level(8) Backlight commands | ||
91 | * | ||
92 | * ACT_COMMAND(1110): | ||
93 | * 1110|opt | id(8) Built-in Command exec | ||
94 | * | ||
95 | * ACT_FUNCTION(1111): | ||
96 | * 1111| address(12) Function? | ||
97 | * 1111|opt | id(8) Function? | ||
98 | */ | ||
99 | enum action_kind_id { | ||
100 | /* Key Actions */ | ||
101 | ACT_MODS = 0b0000, | ||
102 | ACT_LMODS = 0b0000, | ||
103 | ACT_RMODS = 0b0001, | ||
104 | ACT_MODS_TAP = 0b0010, | ||
105 | ACT_LMODS_TAP = 0b0010, | ||
106 | ACT_RMODS_TAP = 0b0011, | ||
107 | /* Other Keys */ | ||
108 | ACT_USAGE = 0b0100, | ||
109 | ACT_MOUSEKEY = 0b0101, | ||
110 | /* Layer Actions */ | ||
111 | ACT_LAYER = 0b1000, | ||
112 | ACT_LAYER_TAP = 0b1010, /* Layer 0-15 */ | ||
113 | ACT_LAYER_TAP_EXT = 0b1011, /* Layer 16-31 */ | ||
114 | /* Extensions */ | ||
115 | ACT_MACRO = 0b1100, | ||
116 | ACT_BACKLIGHT = 0b1101, | ||
117 | ACT_COMMAND = 0b1110, | ||
118 | ACT_FUNCTION = 0b1111 | ||
119 | }; | ||
120 | |||
121 | |||
122 | /* Action Code Struct | ||
123 | * | ||
124 | * NOTE: | ||
125 | * In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15). | ||
126 | * AVR looks like a little endian in avr-gcc. | ||
127 | * Not portable across compiler/endianness? | ||
128 | * | ||
129 | * Byte order and bit order of 0x1234: | ||
130 | * Big endian: Little endian: | ||
131 | * -------------------- -------------------- | ||
132 | * FEDC BA98 7654 3210 0123 4567 89AB CDEF | ||
133 | * 0001 0010 0011 0100 0010 1100 0100 1000 | ||
134 | * 0x12 0x34 0x34 0x12 | ||
135 | */ | ||
136 | typedef union { | ||
137 | uint16_t code; | ||
138 | struct action_kind { | ||
139 | uint16_t param :12; | ||
140 | uint8_t id :4; | ||
141 | } kind; | ||
142 | struct action_key { | ||
143 | uint8_t code :8; | ||
144 | uint8_t mods :4; | ||
145 | uint8_t kind :4; | ||
146 | } key; | ||
147 | struct action_layer_bitop { | ||
148 | uint8_t bits :4; | ||
149 | uint8_t xbit :1; | ||
150 | uint8_t part :3; | ||
151 | uint8_t on :2; | ||
152 | uint8_t op :2; | ||
153 | uint8_t kind :4; | ||
154 | } layer_bitop; | ||
155 | struct action_layer_tap { | ||
156 | uint8_t code :8; | ||
157 | uint8_t val :5; | ||
158 | uint8_t kind :3; | ||
159 | } layer_tap; | ||
160 | struct action_usage { | ||
161 | uint16_t code :10; | ||
162 | uint8_t page :2; | ||
163 | uint8_t kind :4; | ||
164 | } usage; | ||
165 | struct action_backlight { | ||
166 | uint8_t level :8; | ||
167 | uint8_t opt :4; | ||
168 | uint8_t kind :4; | ||
169 | } backlight; | ||
170 | struct action_command { | ||
171 | uint8_t id :8; | ||
172 | uint8_t opt :4; | ||
173 | uint8_t kind :4; | ||
174 | } command; | ||
175 | struct action_function { | ||
176 | uint8_t id :8; | ||
177 | uint8_t opt :4; | ||
178 | uint8_t kind :4; | ||
179 | } func; | ||
180 | } action_t; | ||
181 | |||
182 | |||
183 | /* action utility */ | ||
184 | #define ACTION_NO 0 | ||
185 | #define ACTION_TRANSPARENT 1 | ||
186 | #define ACTION(kind, param) ((kind)<<12 | (param)) | ||
187 | |||
188 | |||
189 | /* | ||
190 | * Key Actions | ||
191 | */ | ||
192 | /* Mod bits: 43210 | ||
193 | * bit 0 ||||+- Control | ||
194 | * bit 1 |||+-- Shift | ||
195 | * bit 2 ||+--- Alt | ||
196 | * bit 3 |+---- Gui | ||
197 | * bit 4 +----- LR flag(Left:0, Right:1) | ||
198 | */ | ||
199 | enum mods_bit { | ||
200 | MOD_LCTL = 0x01, | ||
201 | MOD_LSFT = 0x02, | ||
202 | MOD_LALT = 0x04, | ||
203 | MOD_LGUI = 0x08, | ||
204 | MOD_RCTL = 0x11, | ||
205 | MOD_RSFT = 0x12, | ||
206 | MOD_RALT = 0x14, | ||
207 | MOD_RGUI = 0x18, | ||
208 | }; | ||
209 | enum mods_codes { | ||
210 | MODS_ONESHOT = 0x00, | ||
211 | MODS_TAP_TOGGLE = 0x01, | ||
212 | }; | ||
213 | #define ACTION_KEY(key) ACTION(ACT_MODS, (key)) | ||
214 | #define ACTION_MODS(mods) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | 0) | ||
215 | #define ACTION_MODS_KEY(mods, key) ACTION(ACT_MODS, ((mods)&0x1f)<<8 | (key)) | ||
216 | #define ACTION_MODS_TAP_KEY(mods, key) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | (key)) | ||
217 | #define ACTION_MODS_ONESHOT(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_ONESHOT) | ||
218 | #define ACTION_MODS_TAP_TOGGLE(mods) ACTION(ACT_MODS_TAP, ((mods)&0x1f)<<8 | MODS_TAP_TOGGLE) | ||
219 | |||
220 | |||
221 | /* | ||
222 | * Other Keys | ||
223 | */ | ||
224 | enum usage_pages { | ||
225 | PAGE_SYSTEM, | ||
226 | PAGE_CONSUMER | ||
227 | }; | ||
228 | #define ACTION_USAGE_SYSTEM(id) ACTION(ACT_USAGE, PAGE_SYSTEM<<10 | (id)) | ||
229 | #define ACTION_USAGE_CONSUMER(id) ACTION(ACT_USAGE, PAGE_CONSUMER<<10 | (id)) | ||
230 | #define ACTION_MOUSEKEY(key) ACTION(ACT_MOUSEKEY, key) | ||
231 | |||
232 | |||
233 | |||
234 | /* | ||
235 | * Layer Actions | ||
236 | */ | ||
237 | enum layer_param_on { | ||
238 | ON_PRESS = 1, | ||
239 | ON_RELEASE = 2, | ||
240 | ON_BOTH = 3, | ||
241 | }; | ||
242 | enum layer_param_bit_op { | ||
243 | OP_BIT_AND = 0, | ||
244 | OP_BIT_OR = 1, | ||
245 | OP_BIT_XOR = 2, | ||
246 | OP_BIT_SET = 3, | ||
247 | }; | ||
248 | enum layer_pram_tap_op { | ||
249 | OP_TAP_TOGGLE = 0xF0, | ||
250 | OP_ON_OFF, | ||
251 | OP_OFF_ON, | ||
252 | OP_SET_CLEAR, | ||
253 | }; | ||
254 | #define ACTION_LAYER_BITOP(op, part, bits, on) (ACT_LAYER<<12 | (op)<<10 | (on)<<8 | (part)<<5 | ((bits)&0x1f)) | ||
255 | #define ACTION_LAYER_TAP(layer, key) (ACT_LAYER_TAP<<12 | (layer)<<8 | (key)) | ||
256 | /* Default Layer */ | ||
257 | #define ACTION_DEFAULT_LAYER_SET(layer) ACTION_DEFAULT_LAYER_BIT_SET((layer)/4, 1<<((layer)%4)) | ||
258 | /* Layer Operation */ | ||
259 | #define ACTION_LAYER_CLEAR(on) ACTION_LAYER_BIT_AND(0, 0, (on)) | ||
260 | #define ACTION_LAYER_MOMENTARY(layer) ACTION_LAYER_ON_OFF(layer) | ||
261 | #define ACTION_LAYER_TOGGLE(layer) ACTION_LAYER_INVERT(layer, ON_RELEASE) | ||
262 | #define ACTION_LAYER_INVERT(layer, on) ACTION_LAYER_BIT_XOR((layer)/4, 1<<((layer)%4), (on)) | ||
263 | #define ACTION_LAYER_ON(layer, on) ACTION_LAYER_BIT_OR( (layer)/4, 1<<((layer)%4), (on)) | ||
264 | #define ACTION_LAYER_OFF(layer, on) ACTION_LAYER_BIT_AND((layer)/4, ~(1<<((layer)%4)), (on)) | ||
265 | #define ACTION_LAYER_SET(layer, on) ACTION_LAYER_BIT_SET((layer)/4, 1<<((layer)%4), (on)) | ||
266 | #define ACTION_LAYER_ON_OFF(layer) ACTION_LAYER_TAP((layer), OP_ON_OFF) | ||
267 | #define ACTION_LAYER_OFF_ON(layer) ACTION_LAYER_TAP((layer), OP_OFF_ON) | ||
268 | #define ACTION_LAYER_SET_CLEAR(layer) ACTION_LAYER_TAP((layer), OP_SET_CLEAR) | ||
269 | #define ACTION_LAYER_MODS(layer, mods) ACTION_LAYER_TAP((layer), 0xe0 | (mods)&0x0f) | ||
270 | /* With Tapping */ | ||
271 | #define ACTION_LAYER_TAP_KEY(layer, key) ACTION_LAYER_TAP((layer), (key)) | ||
272 | #define ACTION_LAYER_TAP_TOGGLE(layer) ACTION_LAYER_TAP((layer), OP_TAP_TOGGLE) | ||
273 | /* Bitwise Operation */ | ||
274 | #define ACTION_LAYER_BIT_AND(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), (on)) | ||
275 | #define ACTION_LAYER_BIT_OR( part, bits, on) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), (on)) | ||
276 | #define ACTION_LAYER_BIT_XOR(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), (on)) | ||
277 | #define ACTION_LAYER_BIT_SET(part, bits, on) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), (on)) | ||
278 | /* Default Layer Bitwise Operation */ | ||
279 | #define ACTION_DEFAULT_LAYER_BIT_AND(part, bits) ACTION_LAYER_BITOP(OP_BIT_AND, (part), (bits), 0) | ||
280 | #define ACTION_DEFAULT_LAYER_BIT_OR( part, bits) ACTION_LAYER_BITOP(OP_BIT_OR, (part), (bits), 0) | ||
281 | #define ACTION_DEFAULT_LAYER_BIT_XOR(part, bits) ACTION_LAYER_BITOP(OP_BIT_XOR, (part), (bits), 0) | ||
282 | #define ACTION_DEFAULT_LAYER_BIT_SET(part, bits) ACTION_LAYER_BITOP(OP_BIT_SET, (part), (bits), 0) | ||
283 | |||
284 | |||
285 | /* | ||
286 | * Extensions | ||
287 | */ | ||
288 | enum backlight_opt { | ||
289 | BACKLIGHT_INCREASE = 0, | ||
290 | BACKLIGHT_DECREASE = 1, | ||
291 | BACKLIGHT_TOGGLE = 2, | ||
292 | BACKLIGHT_STEP = 3, | ||
293 | BACKLIGHT_LEVEL = 4, | ||
294 | }; | ||
295 | /* Macro */ | ||
296 | #define ACTION_MACRO(id) ACTION(ACT_MACRO, (id)) | ||
297 | #define ACTION_MACRO_TAP(id) ACTION(ACT_MACRO, FUNC_TAP<<8 | (id)) | ||
298 | #define ACTION_MACRO_OPT(id, opt) ACTION(ACT_MACRO, (opt)<<8 | (id)) | ||
299 | /* Backlight */ | ||
300 | #define ACTION_BACKLIGHT_INCREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_INCREASE << 8) | ||
301 | #define ACTION_BACKLIGHT_DECREASE() ACTION(ACT_BACKLIGHT, BACKLIGHT_DECREASE << 8) | ||
302 | #define ACTION_BACKLIGHT_TOGGLE() ACTION(ACT_BACKLIGHT, BACKLIGHT_TOGGLE << 8) | ||
303 | #define ACTION_BACKLIGHT_STEP() ACTION(ACT_BACKLIGHT, BACKLIGHT_STEP << 8) | ||
304 | #define ACTION_BACKLIGHT_LEVEL(level) ACTION(ACT_BACKLIGHT, BACKLIGHT_LEVEL << 8 | level) | ||
305 | /* Command */ | ||
306 | #define ACTION_COMMAND(id, opt) ACTION(ACT_COMMAND, (opt)<<8 | (addr)) | ||
307 | /* Function */ | ||
308 | enum function_opts { | ||
309 | FUNC_TAP = 0x8, /* indciates function is tappable */ | ||
310 | }; | ||
311 | #define ACTION_FUNCTION(id) ACTION(ACT_FUNCTION, (id)) | ||
312 | #define ACTION_FUNCTION_TAP(id) ACTION(ACT_FUNCTION, FUNC_TAP<<8 | (id)) | ||
313 | #define ACTION_FUNCTION_OPT(id, opt) ACTION(ACT_FUNCTION, (opt)<<8 | (id)) | ||
314 | |||
315 | #endif /* ACTION_CODE_H */ | ||
diff --git a/tmk_core/common/action_layer.c b/tmk_core/common/action_layer.c new file mode 100644 index 000000000..c535615f4 --- /dev/null +++ b/tmk_core/common/action_layer.c | |||
@@ -0,0 +1,138 @@ | |||
1 | #include <stdint.h> | ||
2 | #include "keyboard.h" | ||
3 | #include "action.h" | ||
4 | #include "util.h" | ||
5 | #include "action_layer.h" | ||
6 | |||
7 | #ifdef DEBUG_ACTION | ||
8 | #include "debug.h" | ||
9 | #else | ||
10 | #include "nodebug.h" | ||
11 | #endif | ||
12 | |||
13 | |||
14 | /* | ||
15 | * Default Layer State | ||
16 | */ | ||
17 | uint32_t default_layer_state = 0; | ||
18 | |||
19 | static void default_layer_state_set(uint32_t state) | ||
20 | { | ||
21 | debug("default_layer_state: "); | ||
22 | default_layer_debug(); debug(" to "); | ||
23 | default_layer_state = state; | ||
24 | default_layer_debug(); debug("\n"); | ||
25 | clear_keyboard_but_mods(); // To avoid stuck keys | ||
26 | } | ||
27 | |||
28 | void default_layer_debug(void) | ||
29 | { | ||
30 | dprintf("%08lX(%u)", default_layer_state, biton32(default_layer_state)); | ||
31 | } | ||
32 | |||
33 | void default_layer_set(uint32_t state) | ||
34 | { | ||
35 | default_layer_state_set(state); | ||
36 | } | ||
37 | |||
38 | #ifndef NO_ACTION_LAYER | ||
39 | void default_layer_or(uint32_t state) | ||
40 | { | ||
41 | default_layer_state_set(default_layer_state | state); | ||
42 | } | ||
43 | void default_layer_and(uint32_t state) | ||
44 | { | ||
45 | default_layer_state_set(default_layer_state & state); | ||
46 | } | ||
47 | void default_layer_xor(uint32_t state) | ||
48 | { | ||
49 | default_layer_state_set(default_layer_state ^ state); | ||
50 | } | ||
51 | #endif | ||
52 | |||
53 | |||
54 | #ifndef NO_ACTION_LAYER | ||
55 | /* | ||
56 | * Keymap Layer State | ||
57 | */ | ||
58 | uint32_t layer_state = 0; | ||
59 | |||
60 | static void layer_state_set(uint32_t state) | ||
61 | { | ||
62 | dprint("layer_state: "); | ||
63 | layer_debug(); dprint(" to "); | ||
64 | layer_state = state; | ||
65 | layer_debug(); dprintln(); | ||
66 | clear_keyboard_but_mods(); // To avoid stuck keys | ||
67 | } | ||
68 | |||
69 | void layer_clear(void) | ||
70 | { | ||
71 | layer_state_set(0); | ||
72 | } | ||
73 | |||
74 | void layer_move(uint8_t layer) | ||
75 | { | ||
76 | layer_state_set(1UL<<layer); | ||
77 | } | ||
78 | |||
79 | void layer_on(uint8_t layer) | ||
80 | { | ||
81 | layer_state_set(layer_state | (1UL<<layer)); | ||
82 | } | ||
83 | |||
84 | void layer_off(uint8_t layer) | ||
85 | { | ||
86 | layer_state_set(layer_state & ~(1UL<<layer)); | ||
87 | } | ||
88 | |||
89 | void layer_invert(uint8_t layer) | ||
90 | { | ||
91 | layer_state_set(layer_state ^ (1UL<<layer)); | ||
92 | } | ||
93 | |||
94 | void layer_or(uint32_t state) | ||
95 | { | ||
96 | layer_state_set(layer_state | state); | ||
97 | } | ||
98 | void layer_and(uint32_t state) | ||
99 | { | ||
100 | layer_state_set(layer_state & state); | ||
101 | } | ||
102 | void layer_xor(uint32_t state) | ||
103 | { | ||
104 | layer_state_set(layer_state ^ state); | ||
105 | } | ||
106 | |||
107 | void layer_debug(void) | ||
108 | { | ||
109 | dprintf("%08lX(%u)", layer_state, biton32(layer_state)); | ||
110 | } | ||
111 | #endif | ||
112 | |||
113 | |||
114 | |||
115 | action_t layer_switch_get_action(keypos_t key) | ||
116 | { | ||
117 | action_t action; | ||
118 | action.code = ACTION_TRANSPARENT; | ||
119 | |||
120 | #ifndef NO_ACTION_LAYER | ||
121 | uint32_t layers = layer_state | default_layer_state; | ||
122 | /* check top layer first */ | ||
123 | for (int8_t i = 31; i >= 0; i--) { | ||
124 | if (layers & (1UL<<i)) { | ||
125 | action = action_for_key(i, key); | ||
126 | if (action.code != ACTION_TRANSPARENT) { | ||
127 | return action; | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | /* fall back to layer 0 */ | ||
132 | action = action_for_key(0, key); | ||
133 | return action; | ||
134 | #else | ||
135 | action = action_for_key(biton32(default_layer_state), key); | ||
136 | return action; | ||
137 | #endif | ||
138 | } | ||
diff --git a/tmk_core/common/action_layer.h b/tmk_core/common/action_layer.h new file mode 100644 index 000000000..b6da353cf --- /dev/null +++ b/tmk_core/common/action_layer.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef ACTION_LAYER_H | ||
18 | #define ACTION_LAYER_H | ||
19 | |||
20 | #include <stdint.h> | ||
21 | #include "keyboard.h" | ||
22 | #include "action.h" | ||
23 | |||
24 | |||
25 | /* | ||
26 | * Default Layer | ||
27 | */ | ||
28 | extern uint32_t default_layer_state; | ||
29 | void default_layer_debug(void); | ||
30 | void default_layer_set(uint32_t state); | ||
31 | |||
32 | #ifndef NO_ACTION_LAYER | ||
33 | /* bitwise operation */ | ||
34 | void default_layer_or(uint32_t state); | ||
35 | void default_layer_and(uint32_t state); | ||
36 | void default_layer_xor(uint32_t state); | ||
37 | #else | ||
38 | #define default_layer_or(state) | ||
39 | #define default_layer_and(state) | ||
40 | #define default_layer_xor(state) | ||
41 | #endif | ||
42 | |||
43 | |||
44 | /* | ||
45 | * Keymap Layer | ||
46 | */ | ||
47 | #ifndef NO_ACTION_LAYER | ||
48 | extern uint32_t layer_state; | ||
49 | void layer_debug(void); | ||
50 | void layer_clear(void); | ||
51 | void layer_move(uint8_t layer); | ||
52 | void layer_on(uint8_t layer); | ||
53 | void layer_off(uint8_t layer); | ||
54 | void layer_invert(uint8_t layer); | ||
55 | /* bitwise operation */ | ||
56 | void layer_or(uint32_t state); | ||
57 | void layer_and(uint32_t state); | ||
58 | void layer_xor(uint32_t state); | ||
59 | #else | ||
60 | #define layer_state 0 | ||
61 | #define layer_clear() | ||
62 | #define layer_move(layer) | ||
63 | #define layer_on(layer) | ||
64 | #define layer_off(layer) | ||
65 | #define layer_invert(layer) | ||
66 | |||
67 | #define layer_or(state) | ||
68 | #define layer_and(state) | ||
69 | #define layer_xor(state) | ||
70 | #define layer_debug() | ||
71 | #endif | ||
72 | |||
73 | |||
74 | /* return action depending on current layer status */ | ||
75 | action_t layer_switch_get_action(keypos_t key); | ||
76 | |||
77 | #endif | ||
diff --git a/tmk_core/common/action_macro.c b/tmk_core/common/action_macro.c new file mode 100644 index 000000000..ba93fc8b2 --- /dev/null +++ b/tmk_core/common/action_macro.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #include "action.h" | ||
18 | #include "action_util.h" | ||
19 | #include "action_macro.h" | ||
20 | #include "wait.h" | ||
21 | |||
22 | #ifdef DEBUG_ACTION | ||
23 | #include "debug.h" | ||
24 | #else | ||
25 | #include "nodebug.h" | ||
26 | #endif | ||
27 | |||
28 | |||
29 | #ifndef NO_ACTION_MACRO | ||
30 | |||
31 | #define MACRO_READ() (macro = MACRO_GET(macro_p++)) | ||
32 | void action_macro_play(const macro_t *macro_p) | ||
33 | { | ||
34 | macro_t macro = END; | ||
35 | uint8_t interval = 0; | ||
36 | |||
37 | if (!macro_p) return; | ||
38 | while (true) { | ||
39 | switch (MACRO_READ()) { | ||
40 | case KEY_DOWN: | ||
41 | MACRO_READ(); | ||
42 | dprintf("KEY_DOWN(%02X)\n", macro); | ||
43 | if (IS_MOD(macro)) { | ||
44 | add_weak_mods(MOD_BIT(macro)); | ||
45 | } else { | ||
46 | register_code(macro); | ||
47 | } | ||
48 | break; | ||
49 | case KEY_UP: | ||
50 | MACRO_READ(); | ||
51 | dprintf("KEY_UP(%02X)\n", macro); | ||
52 | if (IS_MOD(macro)) { | ||
53 | del_weak_mods(MOD_BIT(macro)); | ||
54 | } else { | ||
55 | unregister_code(macro); | ||
56 | } | ||
57 | break; | ||
58 | case WAIT: | ||
59 | MACRO_READ(); | ||
60 | dprintf("WAIT(%u)\n", macro); | ||
61 | { uint8_t ms = macro; while (ms--) wait_ms(1); } | ||
62 | break; | ||
63 | case INTERVAL: | ||
64 | interval = MACRO_READ(); | ||
65 | dprintf("INTERVAL(%u)\n", interval); | ||
66 | break; | ||
67 | case 0x04 ... 0x73: | ||
68 | dprintf("DOWN(%02X)\n", macro); | ||
69 | register_code(macro); | ||
70 | break; | ||
71 | case 0x84 ... 0xF3: | ||
72 | dprintf("UP(%02X)\n", macro); | ||
73 | unregister_code(macro&0x7F); | ||
74 | break; | ||
75 | case END: | ||
76 | default: | ||
77 | return; | ||
78 | } | ||
79 | // interval | ||
80 | { uint8_t ms = interval; while (ms--) wait_ms(1); } | ||
81 | } | ||
82 | } | ||
83 | #endif | ||
diff --git a/tmk_core/common/action_macro.h b/tmk_core/common/action_macro.h new file mode 100644 index 000000000..aedc32ec6 --- /dev/null +++ b/tmk_core/common/action_macro.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef ACTION_MACRO_H | ||
18 | #define ACTION_MACRO_H | ||
19 | #include <stdint.h> | ||
20 | #include "progmem.h" | ||
21 | |||
22 | |||
23 | #define MACRO_NONE 0 | ||
24 | #define MACRO(...) ({ static const macro_t __m[] PROGMEM = { __VA_ARGS__ }; &__m[0]; }) | ||
25 | #define MACRO_GET(p) pgm_read_byte(p) | ||
26 | |||
27 | typedef uint8_t macro_t; | ||
28 | |||
29 | |||
30 | #ifndef NO_ACTION_MACRO | ||
31 | void action_macro_play(const macro_t *macro_p); | ||
32 | #else | ||
33 | #define action_macro_play(macro) | ||
34 | #endif | ||
35 | |||
36 | |||
37 | |||
38 | /* Macro commands | ||
39 | * code(0x04-73) // key down(1byte) | ||
40 | * code(0x04-73) | 0x80 // key up(1byte) | ||
41 | * { KEY_DOWN, code(0x04-0xff) } // key down(2bytes) | ||
42 | * { KEY_UP, code(0x04-0xff) } // key up(2bytes) | ||
43 | * WAIT // wait milli-seconds | ||
44 | * INTERVAL // set interval between macro commands | ||
45 | * END // stop macro execution | ||
46 | * | ||
47 | * Ideas(Not implemented): | ||
48 | * modifiers | ||
49 | * system usage | ||
50 | * consumer usage | ||
51 | * unicode usage | ||
52 | * function call | ||
53 | * conditionals | ||
54 | * loop | ||
55 | */ | ||
56 | enum macro_command_id{ | ||
57 | /* 0x00 - 0x03 */ | ||
58 | END = 0x00, | ||
59 | KEY_DOWN, | ||
60 | KEY_UP, | ||
61 | |||
62 | /* 0x04 - 0x73 (reserved for keycode down) */ | ||
63 | |||
64 | /* 0x74 - 0x83 */ | ||
65 | WAIT = 0x74, | ||
66 | INTERVAL, | ||
67 | |||
68 | /* 0x84 - 0xf3 (reserved for keycode up) */ | ||
69 | |||
70 | /* 0xf4 - 0xff */ | ||
71 | }; | ||
72 | |||
73 | |||
74 | /* TODO: keycode:0x04-0x73 can be handled by 1byte command else 2bytes are needed | ||
75 | * if keycode between 0x04 and 0x73 | ||
76 | * keycode / (keycode|0x80) | ||
77 | * else | ||
78 | * {KEY_DOWN, keycode} / {KEY_UP, keycode} | ||
79 | */ | ||
80 | #define DOWN(key) KEY_DOWN, (key) | ||
81 | #define UP(key) KEY_UP, (key) | ||
82 | #define TYPE(key) DOWN(key), UP(key) | ||
83 | #define WAIT(ms) WAIT, (ms) | ||
84 | #define INTERVAL(ms) INTERVAL, (ms) | ||
85 | |||
86 | /* key down */ | ||
87 | #define D(key) DOWN(KC_##key) | ||
88 | /* key up */ | ||
89 | #define U(key) UP(KC_##key) | ||
90 | /* key type */ | ||
91 | #define T(key) TYPE(KC_##key) | ||
92 | /* wait */ | ||
93 | #define W(ms) WAIT(ms) | ||
94 | /* interval */ | ||
95 | #define I(ms) INTERVAL(ms) | ||
96 | |||
97 | /* for backward comaptibility */ | ||
98 | #define MD(key) DOWN(KC_##key) | ||
99 | #define MU(key) UP(KC_##key) | ||
100 | |||
101 | |||
102 | #endif /* ACTION_MACRO_H */ | ||
diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c new file mode 100644 index 000000000..826c23309 --- /dev/null +++ b/tmk_core/common/action_tapping.c | |||
@@ -0,0 +1,376 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stdbool.h> | ||
3 | #include "action.h" | ||
4 | #include "action_layer.h" | ||
5 | #include "action_tapping.h" | ||
6 | #include "keycode.h" | ||
7 | #include "timer.h" | ||
8 | |||
9 | #ifdef DEBUG_ACTION | ||
10 | #include "debug.h" | ||
11 | #else | ||
12 | #include "nodebug.h" | ||
13 | #endif | ||
14 | |||
15 | #ifndef NO_ACTION_TAPPING | ||
16 | |||
17 | #define IS_TAPPING() !IS_NOEVENT(tapping_key.event) | ||
18 | #define IS_TAPPING_PRESSED() (IS_TAPPING() && tapping_key.event.pressed) | ||
19 | #define IS_TAPPING_RELEASED() (IS_TAPPING() && !tapping_key.event.pressed) | ||
20 | #define IS_TAPPING_KEY(k) (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k))) | ||
21 | #define WITHIN_TAPPING_TERM(e) (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM) | ||
22 | |||
23 | |||
24 | static keyrecord_t tapping_key = {}; | ||
25 | static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {}; | ||
26 | static uint8_t waiting_buffer_head = 0; | ||
27 | static uint8_t waiting_buffer_tail = 0; | ||
28 | |||
29 | static bool process_tapping(keyrecord_t *record); | ||
30 | static bool waiting_buffer_enq(keyrecord_t record); | ||
31 | static void waiting_buffer_clear(void); | ||
32 | static bool waiting_buffer_typed(keyevent_t event); | ||
33 | static bool waiting_buffer_has_anykey_pressed(void); | ||
34 | static void waiting_buffer_scan_tap(void); | ||
35 | static void debug_tapping_key(void); | ||
36 | static void debug_waiting_buffer(void); | ||
37 | |||
38 | |||
39 | void action_tapping_process(keyrecord_t record) | ||
40 | { | ||
41 | if (process_tapping(&record)) { | ||
42 | if (!IS_NOEVENT(record.event)) { | ||
43 | debug("processed: "); debug_record(record); debug("\n"); | ||
44 | } | ||
45 | } else { | ||
46 | if (!waiting_buffer_enq(record)) { | ||
47 | // clear all in case of overflow. | ||
48 | debug("OVERFLOW: CLEAR ALL STATES\n"); | ||
49 | clear_keyboard(); | ||
50 | waiting_buffer_clear(); | ||
51 | tapping_key = (keyrecord_t){}; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | // process waiting_buffer | ||
56 | if (!IS_NOEVENT(record.event) && waiting_buffer_head != waiting_buffer_tail) { | ||
57 | debug("---- action_exec: process waiting_buffer -----\n"); | ||
58 | } | ||
59 | for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) { | ||
60 | if (process_tapping(&waiting_buffer[waiting_buffer_tail])) { | ||
61 | debug("processed: waiting_buffer["); debug_dec(waiting_buffer_tail); debug("] = "); | ||
62 | debug_record(waiting_buffer[waiting_buffer_tail]); debug("\n\n"); | ||
63 | } else { | ||
64 | break; | ||
65 | } | ||
66 | } | ||
67 | if (!IS_NOEVENT(record.event)) { | ||
68 | debug("\n"); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | |||
73 | /* Tapping | ||
74 | * | ||
75 | * Rule: Tap key is typed(pressed and released) within TAPPING_TERM. | ||
76 | * (without interfering by typing other key) | ||
77 | */ | ||
78 | /* return true when key event is processed or consumed. */ | ||
79 | bool process_tapping(keyrecord_t *keyp) | ||
80 | { | ||
81 | keyevent_t event = keyp->event; | ||
82 | |||
83 | // if tapping | ||
84 | if (IS_TAPPING_PRESSED()) { | ||
85 | if (WITHIN_TAPPING_TERM(event)) { | ||
86 | if (tapping_key.tap.count == 0) { | ||
87 | if (IS_TAPPING_KEY(event.key) && !event.pressed) { | ||
88 | // first tap! | ||
89 | debug("Tapping: First tap(0->1).\n"); | ||
90 | tapping_key.tap.count = 1; | ||
91 | debug_tapping_key(); | ||
92 | process_action(&tapping_key); | ||
93 | |||
94 | // copy tapping state | ||
95 | keyp->tap = tapping_key.tap; | ||
96 | // enqueue | ||
97 | return false; | ||
98 | } | ||
99 | #if TAPPING_TERM >= 500 | ||
100 | /* Process a key typed within TAPPING_TERM | ||
101 | * This can register the key before settlement of tapping, | ||
102 | * useful for long TAPPING_TERM but may prevent fast typing. | ||
103 | */ | ||
104 | else if (IS_RELEASED(event) && waiting_buffer_typed(event)) { | ||
105 | debug("Tapping: End. No tap. Interfered by typing key\n"); | ||
106 | process_action(&tapping_key); | ||
107 | tapping_key = (keyrecord_t){}; | ||
108 | debug_tapping_key(); | ||
109 | // enqueue | ||
110 | return false; | ||
111 | } | ||
112 | #endif | ||
113 | /* Process release event of a key pressed before tapping starts | ||
114 | * Without this unexpected repeating will occur with having fast repeating setting | ||
115 | * https://github.com/tmk/tmk_keyboard/issues/60 | ||
116 | */ | ||
117 | else if (IS_RELEASED(event) && !waiting_buffer_typed(event)) { | ||
118 | // Modifier should be retained till end of this tapping. | ||
119 | action_t action = layer_switch_get_action(event.key); | ||
120 | switch (action.kind.id) { | ||
121 | case ACT_LMODS: | ||
122 | case ACT_RMODS: | ||
123 | if (action.key.mods && !action.key.code) return false; | ||
124 | if (IS_MOD(action.key.code)) return false; | ||
125 | break; | ||
126 | case ACT_LMODS_TAP: | ||
127 | case ACT_RMODS_TAP: | ||
128 | if (action.key.mods && keyp->tap.count == 0) return false; | ||
129 | if (IS_MOD(action.key.code)) return false; | ||
130 | break; | ||
131 | } | ||
132 | // Release of key should be process immediately. | ||
133 | debug("Tapping: release event of a key pressed before tapping\n"); | ||
134 | process_action(keyp); | ||
135 | return true; | ||
136 | } | ||
137 | else { | ||
138 | // set interrupted flag when other key preesed during tapping | ||
139 | if (event.pressed) { | ||
140 | tapping_key.tap.interrupted = true; | ||
141 | } | ||
142 | // enqueue | ||
143 | return false; | ||
144 | } | ||
145 | } | ||
146 | // tap_count > 0 | ||
147 | else { | ||
148 | if (IS_TAPPING_KEY(event.key) && !event.pressed) { | ||
149 | debug("Tapping: Tap release("); debug_dec(tapping_key.tap.count); debug(")\n"); | ||
150 | keyp->tap = tapping_key.tap; | ||
151 | process_action(keyp); | ||
152 | tapping_key = *keyp; | ||
153 | debug_tapping_key(); | ||
154 | return true; | ||
155 | } | ||
156 | else if (is_tap_key(event.key) && event.pressed) { | ||
157 | if (tapping_key.tap.count > 1) { | ||
158 | debug("Tapping: Start new tap with releasing last tap(>1).\n"); | ||
159 | // unregister key | ||
160 | process_action(&(keyrecord_t){ | ||
161 | .tap = tapping_key.tap, | ||
162 | .event.key = tapping_key.event.key, | ||
163 | .event.time = event.time, | ||
164 | .event.pressed = false | ||
165 | }); | ||
166 | } else { | ||
167 | debug("Tapping: Start while last tap(1).\n"); | ||
168 | } | ||
169 | tapping_key = *keyp; | ||
170 | waiting_buffer_scan_tap(); | ||
171 | debug_tapping_key(); | ||
172 | return true; | ||
173 | } | ||
174 | else { | ||
175 | if (!IS_NOEVENT(event)) { | ||
176 | debug("Tapping: key event while last tap(>0).\n"); | ||
177 | } | ||
178 | process_action(keyp); | ||
179 | return true; | ||
180 | } | ||
181 | } | ||
182 | } | ||
183 | // after TAPPING_TERM | ||
184 | else { | ||
185 | if (tapping_key.tap.count == 0) { | ||
186 | debug("Tapping: End. Timeout. Not tap(0): "); | ||
187 | debug_event(event); debug("\n"); | ||
188 | process_action(&tapping_key); | ||
189 | tapping_key = (keyrecord_t){}; | ||
190 | debug_tapping_key(); | ||
191 | return false; | ||
192 | } else { | ||
193 | if (IS_TAPPING_KEY(event.key) && !event.pressed) { | ||
194 | debug("Tapping: End. last timeout tap release(>0)."); | ||
195 | keyp->tap = tapping_key.tap; | ||
196 | process_action(keyp); | ||
197 | tapping_key = (keyrecord_t){}; | ||
198 | return true; | ||
199 | } | ||
200 | else if (is_tap_key(event.key) && event.pressed) { | ||
201 | if (tapping_key.tap.count > 1) { | ||
202 | debug("Tapping: Start new tap with releasing last timeout tap(>1).\n"); | ||
203 | // unregister key | ||
204 | process_action(&(keyrecord_t){ | ||
205 | .tap = tapping_key.tap, | ||
206 | .event.key = tapping_key.event.key, | ||
207 | .event.time = event.time, | ||
208 | .event.pressed = false | ||
209 | }); | ||
210 | } else { | ||
211 | debug("Tapping: Start while last timeout tap(1).\n"); | ||
212 | } | ||
213 | tapping_key = *keyp; | ||
214 | waiting_buffer_scan_tap(); | ||
215 | debug_tapping_key(); | ||
216 | return true; | ||
217 | } | ||
218 | else { | ||
219 | if (!IS_NOEVENT(event)) { | ||
220 | debug("Tapping: key event while last timeout tap(>0).\n"); | ||
221 | } | ||
222 | process_action(keyp); | ||
223 | return true; | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | } else if (IS_TAPPING_RELEASED()) { | ||
228 | if (WITHIN_TAPPING_TERM(event)) { | ||
229 | if (event.pressed) { | ||
230 | if (IS_TAPPING_KEY(event.key)) { | ||
231 | if (!tapping_key.tap.interrupted && tapping_key.tap.count > 0) { | ||
232 | // sequential tap. | ||
233 | keyp->tap = tapping_key.tap; | ||
234 | if (keyp->tap.count < 15) keyp->tap.count += 1; | ||
235 | debug("Tapping: Tap press("); debug_dec(keyp->tap.count); debug(")\n"); | ||
236 | process_action(keyp); | ||
237 | tapping_key = *keyp; | ||
238 | debug_tapping_key(); | ||
239 | return true; | ||
240 | } else { | ||
241 | // FIX: start new tap again | ||
242 | tapping_key = *keyp; | ||
243 | return true; | ||
244 | } | ||
245 | } else if (is_tap_key(event.key)) { | ||
246 | // Sequential tap can be interfered with other tap key. | ||
247 | debug("Tapping: Start with interfering other tap.\n"); | ||
248 | tapping_key = *keyp; | ||
249 | waiting_buffer_scan_tap(); | ||
250 | debug_tapping_key(); | ||
251 | return true; | ||
252 | } else { | ||
253 | // should none in buffer | ||
254 | // FIX: interrupted when other key is pressed | ||
255 | tapping_key.tap.interrupted = true; | ||
256 | process_action(keyp); | ||
257 | return true; | ||
258 | } | ||
259 | } else { | ||
260 | if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n"); | ||
261 | process_action(keyp); | ||
262 | return true; | ||
263 | } | ||
264 | } else { | ||
265 | // FIX: process_aciton here? | ||
266 | // timeout. no sequential tap. | ||
267 | debug("Tapping: End(Timeout after releasing last tap): "); | ||
268 | debug_event(event); debug("\n"); | ||
269 | tapping_key = (keyrecord_t){}; | ||
270 | debug_tapping_key(); | ||
271 | return false; | ||
272 | } | ||
273 | } | ||
274 | // not tapping state | ||
275 | else { | ||
276 | if (event.pressed && is_tap_key(event.key)) { | ||
277 | debug("Tapping: Start(Press tap key).\n"); | ||
278 | tapping_key = *keyp; | ||
279 | waiting_buffer_scan_tap(); | ||
280 | debug_tapping_key(); | ||
281 | return true; | ||
282 | } else { | ||
283 | process_action(keyp); | ||
284 | return true; | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | |||
290 | /* | ||
291 | * Waiting buffer | ||
292 | */ | ||
293 | bool waiting_buffer_enq(keyrecord_t record) | ||
294 | { | ||
295 | if (IS_NOEVENT(record.event)) { | ||
296 | return true; | ||
297 | } | ||
298 | |||
299 | if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) { | ||
300 | debug("waiting_buffer_enq: Over flow.\n"); | ||
301 | return false; | ||
302 | } | ||
303 | |||
304 | waiting_buffer[waiting_buffer_head] = record; | ||
305 | waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE; | ||
306 | |||
307 | debug("waiting_buffer_enq: "); debug_waiting_buffer(); | ||
308 | return true; | ||
309 | } | ||
310 | |||
311 | void waiting_buffer_clear(void) | ||
312 | { | ||
313 | waiting_buffer_head = 0; | ||
314 | waiting_buffer_tail = 0; | ||
315 | } | ||
316 | |||
317 | bool waiting_buffer_typed(keyevent_t event) | ||
318 | { | ||
319 | for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { | ||
320 | if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed != waiting_buffer[i].event.pressed) { | ||
321 | return true; | ||
322 | } | ||
323 | } | ||
324 | return false; | ||
325 | } | ||
326 | |||
327 | bool waiting_buffer_has_anykey_pressed(void) | ||
328 | { | ||
329 | for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { | ||
330 | if (waiting_buffer[i].event.pressed) return true; | ||
331 | } | ||
332 | return false; | ||
333 | } | ||
334 | |||
335 | /* scan buffer for tapping */ | ||
336 | void waiting_buffer_scan_tap(void) | ||
337 | { | ||
338 | // tapping already is settled | ||
339 | if (tapping_key.tap.count > 0) return; | ||
340 | // invalid state: tapping_key released && tap.count == 0 | ||
341 | if (!tapping_key.event.pressed) return; | ||
342 | |||
343 | for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { | ||
344 | if (IS_TAPPING_KEY(waiting_buffer[i].event.key) && | ||
345 | !waiting_buffer[i].event.pressed && | ||
346 | WITHIN_TAPPING_TERM(waiting_buffer[i].event)) { | ||
347 | tapping_key.tap.count = 1; | ||
348 | waiting_buffer[i].tap.count = 1; | ||
349 | process_action(&tapping_key); | ||
350 | |||
351 | debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n"); | ||
352 | debug_waiting_buffer(); | ||
353 | return; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | |||
358 | |||
359 | /* | ||
360 | * debug print | ||
361 | */ | ||
362 | static void debug_tapping_key(void) | ||
363 | { | ||
364 | debug("TAPPING_KEY="); debug_record(tapping_key); debug("\n"); | ||
365 | } | ||
366 | |||
367 | static void debug_waiting_buffer(void) | ||
368 | { | ||
369 | debug("{ "); | ||
370 | for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) { | ||
371 | debug("["); debug_dec(i); debug("]="); debug_record(waiting_buffer[i]); debug(" "); | ||
372 | } | ||
373 | debug("}\n"); | ||
374 | } | ||
375 | |||
376 | #endif | ||
diff --git a/tmk_core/common/action_tapping.h b/tmk_core/common/action_tapping.h new file mode 100644 index 000000000..9b42d50dc --- /dev/null +++ b/tmk_core/common/action_tapping.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef ACTION_TAPPING_H | ||
18 | #define ACTION_TAPPING_H | ||
19 | |||
20 | |||
21 | |||
22 | /* period of tapping(ms) */ | ||
23 | #ifndef TAPPING_TERM | ||
24 | #define TAPPING_TERM 200 | ||
25 | #endif | ||
26 | |||
27 | /* tap count needed for toggling a feature */ | ||
28 | #ifndef TAPPING_TOGGLE | ||
29 | #define TAPPING_TOGGLE 5 | ||
30 | #endif | ||
31 | |||
32 | #define WAITING_BUFFER_SIZE 8 | ||
33 | |||
34 | |||
35 | #ifndef NO_ACTION_TAPPING | ||
36 | void action_tapping_process(keyrecord_t record); | ||
37 | #endif | ||
38 | |||
39 | #endif | ||
diff --git a/tmk_core/common/action_util.c b/tmk_core/common/action_util.c new file mode 100644 index 000000000..dbee630d1 --- /dev/null +++ b/tmk_core/common/action_util.c | |||
@@ -0,0 +1,307 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #include "host.h" | ||
18 | #include "report.h" | ||
19 | #include "debug.h" | ||
20 | #include "action_util.h" | ||
21 | #include "timer.h" | ||
22 | |||
23 | static inline void add_key_byte(uint8_t code); | ||
24 | static inline void del_key_byte(uint8_t code); | ||
25 | #ifdef NKRO_ENABLE | ||
26 | static inline void add_key_bit(uint8_t code); | ||
27 | static inline void del_key_bit(uint8_t code); | ||
28 | #endif | ||
29 | |||
30 | static uint8_t real_mods = 0; | ||
31 | static uint8_t weak_mods = 0; | ||
32 | |||
33 | #ifdef USB_6KRO_ENABLE | ||
34 | #define RO_ADD(a, b) ((a + b) % KEYBOARD_REPORT_KEYS) | ||
35 | #define RO_SUB(a, b) ((a - b + KEYBOARD_REPORT_KEYS) % KEYBOARD_REPORT_KEYS) | ||
36 | #define RO_INC(a) RO_ADD(a, 1) | ||
37 | #define RO_DEC(a) RO_SUB(a, 1) | ||
38 | static int8_t cb_head = 0; | ||
39 | static int8_t cb_tail = 0; | ||
40 | static int8_t cb_count = 0; | ||
41 | #endif | ||
42 | |||
43 | // TODO: pointer variable is not needed | ||
44 | //report_keyboard_t keyboard_report = {}; | ||
45 | report_keyboard_t *keyboard_report = &(report_keyboard_t){}; | ||
46 | |||
47 | #ifndef NO_ACTION_ONESHOT | ||
48 | static int8_t oneshot_mods = 0; | ||
49 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
50 | static int16_t oneshot_time = 0; | ||
51 | #endif | ||
52 | #endif | ||
53 | |||
54 | |||
55 | void send_keyboard_report(void) { | ||
56 | keyboard_report->mods = real_mods; | ||
57 | keyboard_report->mods |= weak_mods; | ||
58 | #ifndef NO_ACTION_ONESHOT | ||
59 | if (oneshot_mods) { | ||
60 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
61 | if (TIMER_DIFF_16(timer_read(), oneshot_time) >= ONESHOT_TIMEOUT) { | ||
62 | dprintf("Oneshot: timeout\n"); | ||
63 | clear_oneshot_mods(); | ||
64 | } | ||
65 | #endif | ||
66 | keyboard_report->mods |= oneshot_mods; | ||
67 | if (has_anykey()) { | ||
68 | clear_oneshot_mods(); | ||
69 | } | ||
70 | } | ||
71 | #endif | ||
72 | host_keyboard_send(keyboard_report); | ||
73 | } | ||
74 | |||
75 | /* key */ | ||
76 | void add_key(uint8_t key) | ||
77 | { | ||
78 | #ifdef NKRO_ENABLE | ||
79 | if (keyboard_nkro) { | ||
80 | add_key_bit(key); | ||
81 | return; | ||
82 | } | ||
83 | #endif | ||
84 | add_key_byte(key); | ||
85 | } | ||
86 | |||
87 | void del_key(uint8_t key) | ||
88 | { | ||
89 | #ifdef NKRO_ENABLE | ||
90 | if (keyboard_nkro) { | ||
91 | del_key_bit(key); | ||
92 | return; | ||
93 | } | ||
94 | #endif | ||
95 | del_key_byte(key); | ||
96 | } | ||
97 | |||
98 | void clear_keys(void) | ||
99 | { | ||
100 | // not clear mods | ||
101 | for (int8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) { | ||
102 | keyboard_report->raw[i] = 0; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | |||
107 | /* modifier */ | ||
108 | uint8_t get_mods(void) { return real_mods; } | ||
109 | void add_mods(uint8_t mods) { real_mods |= mods; } | ||
110 | void del_mods(uint8_t mods) { real_mods &= ~mods; } | ||
111 | void set_mods(uint8_t mods) { real_mods = mods; } | ||
112 | void clear_mods(void) { real_mods = 0; } | ||
113 | |||
114 | /* weak modifier */ | ||
115 | uint8_t get_weak_mods(void) { return weak_mods; } | ||
116 | void add_weak_mods(uint8_t mods) { weak_mods |= mods; } | ||
117 | void del_weak_mods(uint8_t mods) { weak_mods &= ~mods; } | ||
118 | void set_weak_mods(uint8_t mods) { weak_mods = mods; } | ||
119 | void clear_weak_mods(void) { weak_mods = 0; } | ||
120 | |||
121 | /* Oneshot modifier */ | ||
122 | #ifndef NO_ACTION_ONESHOT | ||
123 | void set_oneshot_mods(uint8_t mods) | ||
124 | { | ||
125 | oneshot_mods = mods; | ||
126 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
127 | oneshot_time = timer_read(); | ||
128 | #endif | ||
129 | } | ||
130 | void clear_oneshot_mods(void) | ||
131 | { | ||
132 | oneshot_mods = 0; | ||
133 | #if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) | ||
134 | oneshot_time = 0; | ||
135 | #endif | ||
136 | } | ||
137 | #endif | ||
138 | |||
139 | |||
140 | |||
141 | |||
142 | /* | ||
143 | * inspect keyboard state | ||
144 | */ | ||
145 | uint8_t has_anykey(void) | ||
146 | { | ||
147 | uint8_t cnt = 0; | ||
148 | for (uint8_t i = 1; i < KEYBOARD_REPORT_SIZE; i++) { | ||
149 | if (keyboard_report->raw[i]) | ||
150 | cnt++; | ||
151 | } | ||
152 | return cnt; | ||
153 | } | ||
154 | |||
155 | uint8_t has_anymod(void) | ||
156 | { | ||
157 | return bitpop(real_mods); | ||
158 | } | ||
159 | |||
160 | uint8_t get_first_key(void) | ||
161 | { | ||
162 | #ifdef NKRO_ENABLE | ||
163 | if (keyboard_nkro) { | ||
164 | uint8_t i = 0; | ||
165 | for (; i < KEYBOARD_REPORT_BITS && !keyboard_report->nkro.bits[i]; i++) | ||
166 | ; | ||
167 | return i<<3 | biton(keyboard_report->nkro.bits[i]); | ||
168 | } | ||
169 | #endif | ||
170 | #ifdef USB_6KRO_ENABLE | ||
171 | uint8_t i = cb_head; | ||
172 | do { | ||
173 | if (keyboard_report->keys[i] != 0) { | ||
174 | break; | ||
175 | } | ||
176 | i = RO_INC(i); | ||
177 | } while (i != cb_tail); | ||
178 | return keyboard_report->keys[i]; | ||
179 | #else | ||
180 | return keyboard_report->keys[0]; | ||
181 | #endif | ||
182 | } | ||
183 | |||
184 | |||
185 | |||
186 | /* local functions */ | ||
187 | static inline void add_key_byte(uint8_t code) | ||
188 | { | ||
189 | #ifdef USB_6KRO_ENABLE | ||
190 | int8_t i = cb_head; | ||
191 | int8_t empty = -1; | ||
192 | if (cb_count) { | ||
193 | do { | ||
194 | if (keyboard_report->keys[i] == code) { | ||
195 | return; | ||
196 | } | ||
197 | if (empty == -1 && keyboard_report->keys[i] == 0) { | ||
198 | empty = i; | ||
199 | } | ||
200 | i = RO_INC(i); | ||
201 | } while (i != cb_tail); | ||
202 | if (i == cb_tail) { | ||
203 | if (cb_tail == cb_head) { | ||
204 | // buffer is full | ||
205 | if (empty == -1) { | ||
206 | // pop head when has no empty space | ||
207 | cb_head = RO_INC(cb_head); | ||
208 | cb_count--; | ||
209 | } | ||
210 | else { | ||
211 | // left shift when has empty space | ||
212 | uint8_t offset = 1; | ||
213 | i = RO_INC(empty); | ||
214 | do { | ||
215 | if (keyboard_report->keys[i] != 0) { | ||
216 | keyboard_report->keys[empty] = keyboard_report->keys[i]; | ||
217 | keyboard_report->keys[i] = 0; | ||
218 | empty = RO_INC(empty); | ||
219 | } | ||
220 | else { | ||
221 | offset++; | ||
222 | } | ||
223 | i = RO_INC(i); | ||
224 | } while (i != cb_tail); | ||
225 | cb_tail = RO_SUB(cb_tail, offset); | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | // add to tail | ||
231 | keyboard_report->keys[cb_tail] = code; | ||
232 | cb_tail = RO_INC(cb_tail); | ||
233 | cb_count++; | ||
234 | #else | ||
235 | int8_t i = 0; | ||
236 | int8_t empty = -1; | ||
237 | for (; i < KEYBOARD_REPORT_KEYS; i++) { | ||
238 | if (keyboard_report->keys[i] == code) { | ||
239 | break; | ||
240 | } | ||
241 | if (empty == -1 && keyboard_report->keys[i] == 0) { | ||
242 | empty = i; | ||
243 | } | ||
244 | } | ||
245 | if (i == KEYBOARD_REPORT_KEYS) { | ||
246 | if (empty != -1) { | ||
247 | keyboard_report->keys[empty] = code; | ||
248 | } | ||
249 | } | ||
250 | #endif | ||
251 | } | ||
252 | |||
253 | static inline void del_key_byte(uint8_t code) | ||
254 | { | ||
255 | #ifdef USB_6KRO_ENABLE | ||
256 | uint8_t i = cb_head; | ||
257 | if (cb_count) { | ||
258 | do { | ||
259 | if (keyboard_report->keys[i] == code) { | ||
260 | keyboard_report->keys[i] = 0; | ||
261 | cb_count--; | ||
262 | if (cb_count == 0) { | ||
263 | // reset head and tail | ||
264 | cb_tail = cb_head = 0; | ||
265 | } | ||
266 | if (i == RO_DEC(cb_tail)) { | ||
267 | // left shift when next to tail | ||
268 | do { | ||
269 | cb_tail = RO_DEC(cb_tail); | ||
270 | if (keyboard_report->keys[RO_DEC(cb_tail)] != 0) { | ||
271 | break; | ||
272 | } | ||
273 | } while (cb_tail != cb_head); | ||
274 | } | ||
275 | break; | ||
276 | } | ||
277 | i = RO_INC(i); | ||
278 | } while (i != cb_tail); | ||
279 | } | ||
280 | #else | ||
281 | for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | ||
282 | if (keyboard_report->keys[i] == code) { | ||
283 | keyboard_report->keys[i] = 0; | ||
284 | } | ||
285 | } | ||
286 | #endif | ||
287 | } | ||
288 | |||
289 | #ifdef NKRO_ENABLE | ||
290 | static inline void add_key_bit(uint8_t code) | ||
291 | { | ||
292 | if ((code>>3) < KEYBOARD_REPORT_BITS) { | ||
293 | keyboard_report->nkro.bits[code>>3] |= 1<<(code&7); | ||
294 | } else { | ||
295 | dprintf("add_key_bit: can't add: %02X\n", code); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static inline void del_key_bit(uint8_t code) | ||
300 | { | ||
301 | if ((code>>3) < KEYBOARD_REPORT_BITS) { | ||
302 | keyboard_report->nkro.bits[code>>3] &= ~(1<<(code&7)); | ||
303 | } else { | ||
304 | dprintf("del_key_bit: can't del: %02X\n", code); | ||
305 | } | ||
306 | } | ||
307 | #endif | ||
diff --git a/tmk_core/common/action_util.h b/tmk_core/common/action_util.h new file mode 100644 index 000000000..a955638b4 --- /dev/null +++ b/tmk_core/common/action_util.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef ACTION_UTIL_H | ||
18 | #define ACTION_UTIL_H | ||
19 | |||
20 | #include <stdint.h> | ||
21 | #include "report.h" | ||
22 | |||
23 | #ifdef __cplusplus | ||
24 | extern "C" { | ||
25 | #endif | ||
26 | |||
27 | extern report_keyboard_t *keyboard_report; | ||
28 | |||
29 | void send_keyboard_report(void); | ||
30 | |||
31 | /* key */ | ||
32 | void add_key(uint8_t key); | ||
33 | void del_key(uint8_t key); | ||
34 | void clear_keys(void); | ||
35 | |||
36 | /* modifier */ | ||
37 | uint8_t get_mods(void); | ||
38 | void add_mods(uint8_t mods); | ||
39 | void del_mods(uint8_t mods); | ||
40 | void set_mods(uint8_t mods); | ||
41 | void clear_mods(void); | ||
42 | |||
43 | /* weak modifier */ | ||
44 | uint8_t get_weak_mods(void); | ||
45 | void add_weak_mods(uint8_t mods); | ||
46 | void del_weak_mods(uint8_t mods); | ||
47 | void set_weak_mods(uint8_t mods); | ||
48 | void clear_weak_mods(void); | ||
49 | |||
50 | /* oneshot modifier */ | ||
51 | void set_oneshot_mods(uint8_t mods); | ||
52 | void clear_oneshot_mods(void); | ||
53 | void oneshot_toggle(void); | ||
54 | void oneshot_enable(void); | ||
55 | void oneshot_disable(void); | ||
56 | |||
57 | /* inspect */ | ||
58 | uint8_t has_anykey(void); | ||
59 | uint8_t has_anymod(void); | ||
60 | uint8_t get_first_key(void); | ||
61 | |||
62 | #ifdef __cplusplus | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | #endif | ||
diff --git a/tmk_core/common/avr/bootloader.c b/tmk_core/common/avr/bootloader.c new file mode 100644 index 000000000..cda295b18 --- /dev/null +++ b/tmk_core/common/avr/bootloader.c | |||
@@ -0,0 +1,148 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <avr/io.h> | ||
4 | #include <avr/interrupt.h> | ||
5 | #include <avr/wdt.h> | ||
6 | #include <util/delay.h> | ||
7 | #include "bootloader.h" | ||
8 | |||
9 | #ifdef PROTOCOL_LUFA | ||
10 | #include <LUFA/Drivers/USB/USB.h> | ||
11 | #endif | ||
12 | |||
13 | |||
14 | /* Boot Section Size in *BYTEs* | ||
15 | * Teensy halfKay 512 | ||
16 | * Teensy++ halfKay 1024 | ||
17 | * Atmel DFU loader 4096 | ||
18 | * LUFA bootloader 4096 | ||
19 | * USBaspLoader 2048 | ||
20 | */ | ||
21 | #ifndef BOOTLOADER_SIZE | ||
22 | #warning To use bootloader_jump() you need to define BOOTLOADER_SIZE in config.h. | ||
23 | #define BOOTLOADER_SIZE 4096 | ||
24 | #endif | ||
25 | |||
26 | #define FLASH_SIZE (FLASHEND + 1L) | ||
27 | #define BOOTLOADER_START (FLASH_SIZE - BOOTLOADER_SIZE) | ||
28 | |||
29 | |||
30 | /* | ||
31 | * Entering the Bootloader via Software | ||
32 | * http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html | ||
33 | */ | ||
34 | #define BOOTLOADER_RESET_KEY 0xB007B007 | ||
35 | uint32_t reset_key __attribute__ ((section (".noinit"))); | ||
36 | |||
37 | /* initialize MCU status by watchdog reset */ | ||
38 | void bootloader_jump(void) { | ||
39 | #ifdef PROTOCOL_LUFA | ||
40 | USB_Disable(); | ||
41 | cli(); | ||
42 | _delay_ms(2000); | ||
43 | #endif | ||
44 | |||
45 | #ifdef PROTOCOL_PJRC | ||
46 | cli(); | ||
47 | UDCON = 1; | ||
48 | USBCON = (1<<FRZCLK); | ||
49 | UCSR1B = 0; | ||
50 | _delay_ms(5); | ||
51 | #endif | ||
52 | |||
53 | // watchdog reset | ||
54 | reset_key = BOOTLOADER_RESET_KEY; | ||
55 | wdt_enable(WDTO_250MS); | ||
56 | for (;;); | ||
57 | } | ||
58 | |||
59 | |||
60 | /* this runs before main() */ | ||
61 | void bootloader_jump_after_watchdog_reset(void) __attribute__ ((used, naked, section (".init3"))); | ||
62 | void bootloader_jump_after_watchdog_reset(void) | ||
63 | { | ||
64 | if ((MCUSR & (1<<WDRF)) && reset_key == BOOTLOADER_RESET_KEY) { | ||
65 | reset_key = 0; | ||
66 | |||
67 | // My custom USBasploader requires this to come up. | ||
68 | MCUSR = 0; | ||
69 | |||
70 | // Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog. | ||
71 | MCUSR &= ~(1<<WDRF); | ||
72 | wdt_disable(); | ||
73 | |||
74 | // This is compled into 'icall', address should be in word unit, not byte. | ||
75 | ((void (*)(void))(BOOTLOADER_START/2))(); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | |||
80 | #if 0 | ||
81 | /* Jumping To The Bootloader | ||
82 | * http://www.pjrc.com/teensy/jump_to_bootloader.html | ||
83 | * | ||
84 | * This method doen't work when using LUFA. idk why. | ||
85 | * - needs to initialize more regisers or interrupt setting? | ||
86 | */ | ||
87 | void bootloader_jump(void) { | ||
88 | #ifdef PROTOCOL_LUFA | ||
89 | USB_Disable(); | ||
90 | cli(); | ||
91 | _delay_ms(2000); | ||
92 | #endif | ||
93 | |||
94 | #ifdef PROTOCOL_PJRC | ||
95 | cli(); | ||
96 | UDCON = 1; | ||
97 | USBCON = (1<<FRZCLK); | ||
98 | UCSR1B = 0; | ||
99 | _delay_ms(5); | ||
100 | #endif | ||
101 | |||
102 | /* | ||
103 | * Initialize | ||
104 | */ | ||
105 | #if defined(__AVR_AT90USB162__) | ||
106 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; | ||
107 | TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0; | ||
108 | DDRB = 0; DDRC = 0; DDRD = 0; | ||
109 | PORTB = 0; PORTC = 0; PORTD = 0; | ||
110 | #elif defined(__AVR_ATmega32U4__) | ||
111 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
112 | TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0; | ||
113 | DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0; | ||
114 | PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
115 | #elif defined(__AVR_AT90USB646__) | ||
116 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
117 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; | ||
118 | DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; | ||
119 | PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
120 | #elif defined(__AVR_AT90USB1286__) | ||
121 | EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0; | ||
122 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0; | ||
123 | DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; | ||
124 | PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0; | ||
125 | #endif | ||
126 | |||
127 | /* | ||
128 | * USBaspLoader | ||
129 | */ | ||
130 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) | ||
131 | // This makes custom USBasploader come up. | ||
132 | MCUSR = 0; | ||
133 | |||
134 | // initialize ports | ||
135 | PORTB = 0; PORTC= 0; PORTD = 0; | ||
136 | DDRB = 0; DDRC= 0; DDRD = 0; | ||
137 | |||
138 | // disable interrupts | ||
139 | EIMSK = 0; EECR = 0; SPCR = 0; | ||
140 | ACSR = 0; SPMCSR = 0; WDTCSR = 0; PCICR = 0; | ||
141 | TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; | ||
142 | ADCSRA = 0; TWCR = 0; UCSR0B = 0; | ||
143 | #endif | ||
144 | |||
145 | // This is compled into 'icall', address should be in word unit, not byte. | ||
146 | ((void (*)(void))(BOOTLOADER_START/2))(); | ||
147 | } | ||
148 | #endif | ||
diff --git a/tmk_core/common/avr/eeconfig.c b/tmk_core/common/avr/eeconfig.c new file mode 100644 index 000000000..5bd47dc6a --- /dev/null +++ b/tmk_core/common/avr/eeconfig.c | |||
@@ -0,0 +1,45 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <avr/eeprom.h> | ||
4 | #include "eeconfig.h" | ||
5 | |||
6 | void eeconfig_init(void) | ||
7 | { | ||
8 | eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); | ||
9 | eeprom_write_byte(EECONFIG_DEBUG, 0); | ||
10 | eeprom_write_byte(EECONFIG_DEFAULT_LAYER, 0); | ||
11 | eeprom_write_byte(EECONFIG_KEYMAP, 0); | ||
12 | eeprom_write_byte(EECONFIG_MOUSEKEY_ACCEL, 0); | ||
13 | #ifdef BACKLIGHT_ENABLE | ||
14 | eeprom_write_byte(EECONFIG_BACKLIGHT, 0); | ||
15 | #endif | ||
16 | } | ||
17 | |||
18 | void eeconfig_enable(void) | ||
19 | { | ||
20 | eeprom_write_word(EECONFIG_MAGIC, EECONFIG_MAGIC_NUMBER); | ||
21 | } | ||
22 | |||
23 | void eeconfig_disable(void) | ||
24 | { | ||
25 | eeprom_write_word(EECONFIG_MAGIC, 0xFFFF); | ||
26 | } | ||
27 | |||
28 | bool eeconfig_is_enabled(void) | ||
29 | { | ||
30 | return (eeprom_read_word(EECONFIG_MAGIC) == EECONFIG_MAGIC_NUMBER); | ||
31 | } | ||
32 | |||
33 | uint8_t eeconfig_read_debug(void) { return eeprom_read_byte(EECONFIG_DEBUG); } | ||
34 | void eeconfig_write_debug(uint8_t val) { eeprom_write_byte(EECONFIG_DEBUG, val); } | ||
35 | |||
36 | uint8_t eeconfig_read_default_layer(void) { return eeprom_read_byte(EECONFIG_DEFAULT_LAYER); } | ||
37 | void eeconfig_write_default_layer(uint8_t val) { eeprom_write_byte(EECONFIG_DEFAULT_LAYER, val); } | ||
38 | |||
39 | uint8_t eeconfig_read_keymap(void) { return eeprom_read_byte(EECONFIG_KEYMAP); } | ||
40 | void eeconfig_write_keymap(uint8_t val) { eeprom_write_byte(EECONFIG_KEYMAP, val); } | ||
41 | |||
42 | #ifdef BACKLIGHT_ENABLE | ||
43 | uint8_t eeconfig_read_backlight(void) { return eeprom_read_byte(EECONFIG_BACKLIGHT); } | ||
44 | void eeconfig_write_backlight(uint8_t val) { eeprom_write_byte(EECONFIG_BACKLIGHT, val); } | ||
45 | #endif | ||
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c new file mode 100644 index 000000000..80243f02b --- /dev/null +++ b/tmk_core/common/avr/suspend.c | |||
@@ -0,0 +1,122 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include <avr/sleep.h> | ||
3 | #include <avr/wdt.h> | ||
4 | #include <avr/interrupt.h> | ||
5 | #include "matrix.h" | ||
6 | #include "action.h" | ||
7 | #include "backlight.h" | ||
8 | #include "suspend_avr.h" | ||
9 | #include "suspend.h" | ||
10 | #include "timer.h" | ||
11 | #ifdef PROTOCOL_LUFA | ||
12 | #include "lufa.h" | ||
13 | #endif | ||
14 | |||
15 | |||
16 | #define wdt_intr_enable(value) \ | ||
17 | __asm__ __volatile__ ( \ | ||
18 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
19 | "cli" "\n\t" \ | ||
20 | "wdr" "\n\t" \ | ||
21 | "sts %0,%1" "\n\t" \ | ||
22 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
23 | "sts %0,%2" "\n\t" \ | ||
24 | : /* no outputs */ \ | ||
25 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
26 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
27 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ | ||
28 | _BV(WDIE) | (value & 0x07)) ) \ | ||
29 | : "r0" \ | ||
30 | ) | ||
31 | |||
32 | |||
33 | void suspend_idle(uint8_t time) | ||
34 | { | ||
35 | cli(); | ||
36 | set_sleep_mode(SLEEP_MODE_IDLE); | ||
37 | sleep_enable(); | ||
38 | sei(); | ||
39 | sleep_cpu(); | ||
40 | sleep_disable(); | ||
41 | } | ||
42 | |||
43 | /* Power down MCU with watchdog timer | ||
44 | * wdto: watchdog timer timeout defined in <avr/wdt.h> | ||
45 | * WDTO_15MS | ||
46 | * WDTO_30MS | ||
47 | * WDTO_60MS | ||
48 | * WDTO_120MS | ||
49 | * WDTO_250MS | ||
50 | * WDTO_500MS | ||
51 | * WDTO_1S | ||
52 | * WDTO_2S | ||
53 | * WDTO_4S | ||
54 | * WDTO_8S | ||
55 | */ | ||
56 | static uint8_t wdt_timeout = 0; | ||
57 | static void power_down(uint8_t wdto) | ||
58 | { | ||
59 | #ifdef PROTOCOL_LUFA | ||
60 | if (USB_DeviceState == DEVICE_STATE_Configured) return; | ||
61 | #endif | ||
62 | wdt_timeout = wdto; | ||
63 | |||
64 | // Watchdog Interrupt Mode | ||
65 | wdt_intr_enable(wdto); | ||
66 | |||
67 | // TODO: more power saving | ||
68 | // See PicoPower application note | ||
69 | // - I/O port input with pullup | ||
70 | // - prescale clock | ||
71 | // - BOD disable | ||
72 | // - Power Reduction Register PRR | ||
73 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); | ||
74 | sleep_enable(); | ||
75 | sei(); | ||
76 | sleep_cpu(); | ||
77 | sleep_disable(); | ||
78 | |||
79 | // Disable watchdog after sleep | ||
80 | wdt_disable(); | ||
81 | } | ||
82 | |||
83 | void suspend_power_down(void) | ||
84 | { | ||
85 | power_down(WDTO_15MS); | ||
86 | } | ||
87 | |||
88 | bool suspend_wakeup_condition(void) | ||
89 | { | ||
90 | matrix_power_up(); | ||
91 | matrix_scan(); | ||
92 | matrix_power_down(); | ||
93 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | ||
94 | if (matrix_get_row(r)) return true; | ||
95 | } | ||
96 | return false; | ||
97 | } | ||
98 | |||
99 | // run immediately after wakeup | ||
100 | void suspend_wakeup_init(void) | ||
101 | { | ||
102 | // clear keyboard state | ||
103 | clear_keyboard(); | ||
104 | #ifdef BACKLIGHT_ENABLE | ||
105 | backlight_init(); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | #ifndef NO_SUSPEND_POWER_DOWN | ||
110 | /* watchdog timeout */ | ||
111 | ISR(WDT_vect) | ||
112 | { | ||
113 | // compensate timer for sleep | ||
114 | switch (wdt_timeout) { | ||
115 | case WDTO_15MS: | ||
116 | timer_count += 15 + 2; // WDTO_15MS + 2(from observation) | ||
117 | break; | ||
118 | default: | ||
119 | ; | ||
120 | } | ||
121 | } | ||
122 | #endif | ||
diff --git a/tmk_core/common/avr/suspend_avr.h b/tmk_core/common/avr/suspend_avr.h new file mode 100644 index 000000000..357102da4 --- /dev/null +++ b/tmk_core/common/avr/suspend_avr.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #ifndef SUSPEND_AVR_H | ||
2 | #define SUSPEND_AVR_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <stdbool.h> | ||
6 | #include <avr/sleep.h> | ||
7 | #include <avr/wdt.h> | ||
8 | #include <avr/interrupt.h> | ||
9 | |||
10 | |||
11 | #define wdt_intr_enable(value) \ | ||
12 | __asm__ __volatile__ ( \ | ||
13 | "in __tmp_reg__,__SREG__" "\n\t" \ | ||
14 | "cli" "\n\t" \ | ||
15 | "wdr" "\n\t" \ | ||
16 | "sts %0,%1" "\n\t" \ | ||
17 | "out __SREG__,__tmp_reg__" "\n\t" \ | ||
18 | "sts %0,%2" "\n\t" \ | ||
19 | : /* no outputs */ \ | ||
20 | : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \ | ||
21 | "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \ | ||
22 | "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \ | ||
23 | _BV(WDIE) | (value & 0x07)) ) \ | ||
24 | : "r0" \ | ||
25 | ) | ||
26 | |||
27 | #endif | ||
diff --git a/tmk_core/common/avr/timer.c b/tmk_core/common/avr/timer.c new file mode 100644 index 000000000..292b41c3a --- /dev/null +++ b/tmk_core/common/avr/timer.c | |||
@@ -0,0 +1,117 @@ | |||
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 <avr/io.h> | ||
19 | #include <avr/interrupt.h> | ||
20 | #include <stdint.h> | ||
21 | #include "timer_avr.h" | ||
22 | #include "timer.h" | ||
23 | |||
24 | |||
25 | // counter resolution 1ms | ||
26 | // NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }} | ||
27 | volatile uint32_t timer_count = 0; | ||
28 | |||
29 | void timer_init(void) | ||
30 | { | ||
31 | // Timer0 CTC mode | ||
32 | TCCR0A = 0x02; | ||
33 | |||
34 | #if TIMER_PRESCALER == 1 | ||
35 | TCCR0B = 0x01; | ||
36 | #elif TIMER_PRESCALER == 8 | ||
37 | TCCR0B = 0x02; | ||
38 | #elif TIMER_PRESCALER == 64 | ||
39 | TCCR0B = 0x03; | ||
40 | #elif TIMER_PRESCALER == 256 | ||
41 | TCCR0B = 0x04; | ||
42 | #elif TIMER_PRESCALER == 1024 | ||
43 | TCCR0B = 0x05; | ||
44 | #else | ||
45 | # error "Timer prescaler value is NOT vaild." | ||
46 | #endif | ||
47 | |||
48 | OCR0A = TIMER_RAW_TOP; | ||
49 | TIMSK0 = (1<<OCIE0A); | ||
50 | } | ||
51 | |||
52 | inline | ||
53 | void timer_clear(void) | ||
54 | { | ||
55 | uint8_t sreg = SREG; | ||
56 | cli(); | ||
57 | timer_count = 0; | ||
58 | SREG = sreg; | ||
59 | } | ||
60 | |||
61 | inline | ||
62 | uint16_t timer_read(void) | ||
63 | { | ||
64 | uint32_t t; | ||
65 | |||
66 | uint8_t sreg = SREG; | ||
67 | cli(); | ||
68 | t = timer_count; | ||
69 | SREG = sreg; | ||
70 | |||
71 | return (t & 0xFFFF); | ||
72 | } | ||
73 | |||
74 | inline | ||
75 | uint32_t timer_read32(void) | ||
76 | { | ||
77 | uint32_t t; | ||
78 | |||
79 | uint8_t sreg = SREG; | ||
80 | cli(); | ||
81 | t = timer_count; | ||
82 | SREG = sreg; | ||
83 | |||
84 | return t; | ||
85 | } | ||
86 | |||
87 | inline | ||
88 | uint16_t timer_elapsed(uint16_t last) | ||
89 | { | ||
90 | uint32_t t; | ||
91 | |||
92 | uint8_t sreg = SREG; | ||
93 | cli(); | ||
94 | t = timer_count; | ||
95 | SREG = sreg; | ||
96 | |||
97 | return TIMER_DIFF_16((t & 0xFFFF), last); | ||
98 | } | ||
99 | |||
100 | inline | ||
101 | uint32_t timer_elapsed32(uint32_t last) | ||
102 | { | ||
103 | uint32_t t; | ||
104 | |||
105 | uint8_t sreg = SREG; | ||
106 | cli(); | ||
107 | t = timer_count; | ||
108 | SREG = sreg; | ||
109 | |||
110 | return TIMER_DIFF_32(t, last); | ||
111 | } | ||
112 | |||
113 | // excecuted once per 1ms.(excess for just timer count?) | ||
114 | ISR(TIMER0_COMPA_vect) | ||
115 | { | ||
116 | timer_count++; | ||
117 | } | ||
diff --git a/tmk_core/common/avr/timer_avr.h b/tmk_core/common/avr/timer_avr.h new file mode 100644 index 000000000..0e85eb101 --- /dev/null +++ b/tmk_core/common/avr/timer_avr.h | |||
@@ -0,0 +1,42 @@ | |||
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 | #ifndef TIMER_AVR_H | ||
19 | #define TIMER_AVR_H 1 | ||
20 | |||
21 | #include <stdint.h> | ||
22 | |||
23 | #ifndef TIMER_PRESCALER | ||
24 | # if F_CPU > 16000000 | ||
25 | # define TIMER_PRESCALER 256 | ||
26 | # elif F_CPU > 2000000 | ||
27 | # define TIMER_PRESCALER 64 | ||
28 | # elif F_CPU > 250000 | ||
29 | # define TIMER_PRESCALER 8 | ||
30 | # else | ||
31 | # define TIMER_PRESCALER 1 | ||
32 | # endif | ||
33 | #endif | ||
34 | #define TIMER_RAW_FREQ (F_CPU/TIMER_PRESCALER) | ||
35 | #define TIMER_RAW TCNT0 | ||
36 | #define TIMER_RAW_TOP (TIMER_RAW_FREQ/1000) | ||
37 | |||
38 | #if (TIMER_RAW_TOP > 255) | ||
39 | # error "Timer0 can't count 1ms at this clock freq. Use larger prescaler." | ||
40 | #endif | ||
41 | |||
42 | #endif | ||
diff --git a/tmk_core/common/avr/xprintf.S b/tmk_core/common/avr/xprintf.S new file mode 100644 index 000000000..0cec70ce2 --- /dev/null +++ b/tmk_core/common/avr/xprintf.S | |||
@@ -0,0 +1,500 @@ | |||
1 | ;---------------------------------------------------------------------------; | ||
2 | ; Extended itoa, puts, printf and atoi (C)ChaN, 2011 | ||
3 | ;---------------------------------------------------------------------------; | ||
4 | |||
5 | // Base size is 152 bytes | ||
6 | #define CR_CRLF 0 // Convert \n to \r\n (+10 bytes) | ||
7 | #define USE_XPRINTF 1 // Enable xprintf function (+194 bytes) | ||
8 | #define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes) | ||
9 | #define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes) | ||
10 | #define USE_XATOI 0 // Enable xatoi function (+182 bytes) | ||
11 | |||
12 | |||
13 | #if FLASHEND > 0x1FFFF | ||
14 | #error xitoa module does not support 256K devices | ||
15 | #endif | ||
16 | |||
17 | .nolist | ||
18 | #include <avr/io.h> // Include device specific definitions. | ||
19 | .list | ||
20 | |||
21 | #ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw". | ||
22 | .macro _LPMI reg | ||
23 | lpm \reg, Z+ | ||
24 | .endm | ||
25 | .macro _MOVW dh,dl, sh,sl | ||
26 | movw \dl, \sl | ||
27 | .endm | ||
28 | #else // Earlier devices do not have "lpm Rd,Z+" nor "movw". | ||
29 | .macro _LPMI reg | ||
30 | lpm | ||
31 | mov \reg, r0 | ||
32 | adiw ZL, 1 | ||
33 | .endm | ||
34 | .macro _MOVW dh,dl, sh,sl | ||
35 | mov \dl, \sl | ||
36 | mov \dh, \sh | ||
37 | .endm | ||
38 | #endif | ||
39 | |||
40 | |||
41 | |||
42 | ;--------------------------------------------------------------------------- | ||
43 | ; Stub function to forward to user output function | ||
44 | ; | ||
45 | ;Prototype: void xputc (char chr // a character to be output | ||
46 | ; ); | ||
47 | ;Size: 12/12 words | ||
48 | |||
49 | .section .bss | ||
50 | .global xfunc_out ; xfunc_out must be initialized before using this module. | ||
51 | xfunc_out: .ds.w 1 | ||
52 | .section .text | ||
53 | |||
54 | |||
55 | .func xputc | ||
56 | .global xputc | ||
57 | xputc: | ||
58 | #if CR_CRLF | ||
59 | cpi r24, 10 ;LF --> CRLF | ||
60 | brne 1f ; | ||
61 | ldi r24, 13 ; | ||
62 | rcall 1f ; | ||
63 | ldi r24, 10 ;/ | ||
64 | 1: | ||
65 | #endif | ||
66 | push ZH | ||
67 | push ZL | ||
68 | lds ZL, xfunc_out+0 ;Pointer to the registered output function. | ||
69 | lds ZH, xfunc_out+1 ;/ | ||
70 | sbiw ZL, 0 ;Skip if null | ||
71 | breq 2f ;/ | ||
72 | icall | ||
73 | 2: pop ZL | ||
74 | pop ZH | ||
75 | ret | ||
76 | .endfunc | ||
77 | |||
78 | |||
79 | |||
80 | ;--------------------------------------------------------------------------- | ||
81 | ; Direct ROM string output | ||
82 | ; | ||
83 | ;Prototype: void xputs (const char *str_p // rom string to be output | ||
84 | ; ); | ||
85 | |||
86 | .func xputs | ||
87 | .global xputs | ||
88 | xputs: | ||
89 | _MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string | ||
90 | 1: _LPMI r24 | ||
91 | cpi r24, 0 | ||
92 | breq 2f | ||
93 | rcall xputc | ||
94 | rjmp 1b | ||
95 | 2: ret | ||
96 | .endfunc | ||
97 | |||
98 | |||
99 | ;--------------------------------------------------------------------------- | ||
100 | ; Extended direct numeral string output (32bit version) | ||
101 | ; | ||
102 | ;Prototype: void xitoa (long value, // value to be output | ||
103 | ; char radix, // radix | ||
104 | ; char width); // minimum width | ||
105 | ; | ||
106 | |||
107 | .func xitoa | ||
108 | .global xitoa | ||
109 | xitoa: | ||
110 | ;r25:r22 = value, r20 = base, r18 = digits | ||
111 | clr r31 ;r31 = stack level | ||
112 | ldi r30, ' ' ;r30 = sign | ||
113 | ldi r19, ' ' ;r19 = filler | ||
114 | sbrs r20, 7 ;When base indicates signd format and the value | ||
115 | rjmp 0f ;is minus, add a '-'. | ||
116 | neg r20 ; | ||
117 | sbrs r25, 7 ; | ||
118 | rjmp 0f ; | ||
119 | ldi r30, '-' ; | ||
120 | com r22 ; | ||
121 | com r23 ; | ||
122 | com r24 ; | ||
123 | com r25 ; | ||
124 | adc r22, r1 ; | ||
125 | adc r23, r1 ; | ||
126 | adc r24, r1 ; | ||
127 | adc r25, r1 ;/ | ||
128 | 0: sbrs r18, 7 ;When digits indicates zero filled, | ||
129 | rjmp 1f ;filler is '0'. | ||
130 | neg r18 ; | ||
131 | ldi r19, '0' ;/ | ||
132 | ;----- string conversion loop | ||
133 | 1: ldi r21, 32 ;r26 = r25:r22 % r20 | ||
134 | clr r26 ;r25:r22 /= r20 | ||
135 | 2: lsl r22 ; | ||
136 | rol r23 ; | ||
137 | rol r24 ; | ||
138 | rol r25 ; | ||
139 | rol r26 ; | ||
140 | cp r26, r20 ; | ||
141 | brcs 3f ; | ||
142 | sub r26, r20 ; | ||
143 | inc r22 ; | ||
144 | 3: dec r21 ; | ||
145 | brne 2b ;/ | ||
146 | cpi r26, 10 ;r26 is a numeral digit '0'-'F' | ||
147 | brcs 4f ; | ||
148 | subi r26, -7 ; | ||
149 | 4: subi r26, -'0' ;/ | ||
150 | push r26 ;Stack it | ||
151 | inc r31 ;/ | ||
152 | cp r22, r1 ;Repeat until r25:r22 gets zero | ||
153 | cpc r23, r1 ; | ||
154 | cpc r24, r1 ; | ||
155 | cpc r25, r1 ; | ||
156 | brne 1b ;/ | ||
157 | |||
158 | cpi r30, '-' ;Minus sign if needed | ||
159 | brne 5f ; | ||
160 | push r30 ; | ||
161 | inc r31 ;/ | ||
162 | 5: cp r31, r18 ;Filler | ||
163 | brcc 6f ; | ||
164 | push r19 ; | ||
165 | inc r31 ; | ||
166 | rjmp 5b ;/ | ||
167 | |||
168 | 6: pop r24 ;Flush stacked digits and exit | ||
169 | rcall xputc ; | ||
170 | dec r31 ; | ||
171 | brne 6b ;/ | ||
172 | |||
173 | ret | ||
174 | .endfunc | ||
175 | |||
176 | |||
177 | |||
178 | ;---------------------------------------------------------------------------; | ||
179 | ; Formatted string output (16/32bit version) | ||
180 | ; | ||
181 | ;Prototype: | ||
182 | ; void __xprintf (const char *format_p, ...); | ||
183 | ; void __xsprintf(char*, const char *format_p, ...); | ||
184 | ; void __xfprintf(void(*func)(char), const char *format_p, ...); | ||
185 | ; | ||
186 | |||
187 | #if USE_XPRINTF | ||
188 | |||
189 | .func xvprintf | ||
190 | xvprintf: | ||
191 | ld ZL, Y+ ;Z = pointer to format string | ||
192 | ld ZH, Y+ ;/ | ||
193 | |||
194 | 0: _LPMI r24 ;Get a format char | ||
195 | cpi r24, 0 ;End of format string? | ||
196 | breq 90f ;/ | ||
197 | cpi r24, '%' ;Is format? | ||
198 | breq 20f ;/ | ||
199 | 1: rcall xputc ;Put a normal character | ||
200 | rjmp 0b ;/ | ||
201 | 90: ret | ||
202 | |||
203 | 20: ldi r18, 0 ;r18: digits | ||
204 | clt ;T: filler | ||
205 | _LPMI r21 ;Get flags | ||
206 | cpi r21, '%' ;Is a %? | ||
207 | breq 1b ;/ | ||
208 | cpi r21, '0' ;Zero filled? | ||
209 | brne 23f ; | ||
210 | set ;/ | ||
211 | 22: _LPMI r21 ;Get width | ||
212 | 23: cpi r21, '9'+1 ; | ||
213 | brcc 24f ; | ||
214 | subi r21, '0' ; | ||
215 | brcs 90b ; | ||
216 | lsl r18 ; | ||
217 | mov r0, r18 ; | ||
218 | lsl r18 ; | ||
219 | lsl r18 ; | ||
220 | add r18, r0 ; | ||
221 | add r18, r21 ; | ||
222 | rjmp 22b ;/ | ||
223 | |||
224 | 24: brtc 25f ;get value (low word) | ||
225 | neg r18 ; | ||
226 | 25: ld r24, Y+ ; | ||
227 | ld r25, Y+ ;/ | ||
228 | cpi r21, 'c' ;Is type character? | ||
229 | breq 1b ;/ | ||
230 | cpi r21, 's' ;Is type RAM string? | ||
231 | breq 50f ;/ | ||
232 | cpi r21, 'S' ;Is type ROM string? | ||
233 | breq 60f ;/ | ||
234 | _MOVW r23,r22,r25,r24 ;r25:r22 = value | ||
235 | clr r24 ; | ||
236 | clr r25 ; | ||
237 | clt ;/ | ||
238 | cpi r21, 'l' ;Is long int? | ||
239 | brne 26f ; | ||
240 | ld r24, Y+ ;get value (high word) | ||
241 | ld r25, Y+ ; | ||
242 | set ; | ||
243 | _LPMI r21 ;/ | ||
244 | 26: cpi r21, 'd' ;Is type signed decimal? | ||
245 | brne 27f ;/ | ||
246 | ldi r20, -10 ; | ||
247 | brts 40f ; | ||
248 | sbrs r23, 7 ; | ||
249 | rjmp 40f ; | ||
250 | ldi r24, -1 ; | ||
251 | ldi r25, -1 ; | ||
252 | rjmp 40f ;/ | ||
253 | 27: cpi r21, 'u' ;Is type unsigned decimal? | ||
254 | ldi r20, 10 ; | ||
255 | breq 40f ;/ | ||
256 | cpi r21, 'X' ;Is type hexdecimal? | ||
257 | ldi r20, 16 ; | ||
258 | breq 40f ;/ | ||
259 | cpi r21, 'b' ;Is type binary? | ||
260 | ldi r20, 2 ; | ||
261 | breq 40f ;/ | ||
262 | ret ;abort | ||
263 | 40: push ZH ;Output the value | ||
264 | push ZL ; | ||
265 | rcall xitoa ; | ||
266 | 42: pop ZL ; | ||
267 | pop ZH ; | ||
268 | rjmp 0b ;/ | ||
269 | |||
270 | 50: push ZH ;Put a string on the RAM | ||
271 | push ZL | ||
272 | _MOVW ZH,ZL, r25,r24 | ||
273 | 51: ld r24, Z+ | ||
274 | cpi r24, 0 | ||
275 | breq 42b | ||
276 | rcall xputc | ||
277 | rjmp 51b | ||
278 | |||
279 | 60: push ZH ;Put a string on the ROM | ||
280 | push ZL | ||
281 | rcall xputs | ||
282 | rjmp 42b | ||
283 | .endfunc | ||
284 | |||
285 | |||
286 | .func __xprintf | ||
287 | .global __xprintf | ||
288 | __xprintf: | ||
289 | push YH | ||
290 | push YL | ||
291 | in YL, _SFR_IO_ADDR(SPL) | ||
292 | #ifdef SPH | ||
293 | in YH, _SFR_IO_ADDR(SPH) | ||
294 | #else | ||
295 | clr YH | ||
296 | #endif | ||
297 | adiw YL, 5 ;Y = pointer to arguments | ||
298 | rcall xvprintf | ||
299 | pop YL | ||
300 | pop YH | ||
301 | ret | ||
302 | .endfunc | ||
303 | |||
304 | |||
305 | #if USE_XSPRINTF | ||
306 | |||
307 | .func __xsprintf | ||
308 | putram: | ||
309 | _MOVW ZH,ZL, r15,r14 | ||
310 | st Z+, r24 | ||
311 | _MOVW r15,r14, ZH,ZL | ||
312 | ret | ||
313 | .global __xsprintf | ||
314 | __xsprintf: | ||
315 | push YH | ||
316 | push YL | ||
317 | in YL, _SFR_IO_ADDR(SPL) | ||
318 | #ifdef SPH | ||
319 | in YH, _SFR_IO_ADDR(SPH) | ||
320 | #else | ||
321 | clr YH | ||
322 | #endif | ||
323 | adiw YL, 5 ;Y = pointer to arguments | ||
324 | lds ZL, xfunc_out+0 ;Save registered output function | ||
325 | lds ZH, xfunc_out+1 ; | ||
326 | push ZL ; | ||
327 | push ZH ;/ | ||
328 | ldi ZL, lo8(pm(putram));Set local output function | ||
329 | ldi ZH, hi8(pm(putram)); | ||
330 | sts xfunc_out+0, ZL ; | ||
331 | sts xfunc_out+1, ZH ;/ | ||
332 | push r15 ;Initialize pointer to string buffer | ||
333 | push r14 ; | ||
334 | ld r14, Y+ ; | ||
335 | ld r15, Y+ ;/ | ||
336 | rcall xvprintf | ||
337 | _MOVW ZH,ZL, r15,r14 ;Terminate string | ||
338 | st Z, r1 ; | ||
339 | pop r14 ; | ||
340 | pop r15 ;/ | ||
341 | pop ZH ;Restore registered output function | ||
342 | pop ZL ; | ||
343 | sts xfunc_out+0, ZL ; | ||
344 | sts xfunc_out+1, ZH ;/ | ||
345 | pop YL | ||
346 | pop YH | ||
347 | ret | ||
348 | .endfunc | ||
349 | #endif | ||
350 | |||
351 | |||
352 | #if USE_XFPRINTF | ||
353 | .func __xfprintf | ||
354 | .global __xfprintf | ||
355 | __xfprintf: | ||
356 | push YH | ||
357 | push YL | ||
358 | in YL, _SFR_IO_ADDR(SPL) | ||
359 | #ifdef SPH | ||
360 | in YH, _SFR_IO_ADDR(SPH) | ||
361 | #else | ||
362 | clr YH | ||
363 | #endif | ||
364 | adiw YL, 5 ;Y = pointer to arguments | ||
365 | lds ZL, xfunc_out+0 ;Save registered output function | ||
366 | lds ZH, xfunc_out+1 ; | ||
367 | push ZL ; | ||
368 | push ZH ;/ | ||
369 | ld ZL, Y+ ;Set output function | ||
370 | ld ZH, Y+ ; | ||
371 | sts xfunc_out+0, ZL ; | ||
372 | sts xfunc_out+1, ZH ;/ | ||
373 | rcall xvprintf | ||
374 | pop ZH ;Restore registered output function | ||
375 | pop ZL ; | ||
376 | sts xfunc_out+0, ZL ; | ||
377 | sts xfunc_out+1, ZH ;/ | ||
378 | pop YL | ||
379 | pop YH | ||
380 | ret | ||
381 | .endfunc | ||
382 | #endif | ||
383 | |||
384 | #endif | ||
385 | |||
386 | |||
387 | |||
388 | ;--------------------------------------------------------------------------- | ||
389 | ; Extended numeral string input | ||
390 | ; | ||
391 | ;Prototype: | ||
392 | ; char xatoi ( /* 1: Successful, 0: Failed */ | ||
393 | ; const char **str, /* pointer to pointer to source string */ | ||
394 | ; long *res /* result */ | ||
395 | ; ); | ||
396 | ; | ||
397 | |||
398 | |||
399 | #if USE_XATOI | ||
400 | .func xatoi | ||
401 | .global xatoi | ||
402 | xatoi: | ||
403 | _MOVW r1, r0, r23, r22 | ||
404 | _MOVW XH, XL, r25, r24 | ||
405 | ld ZL, X+ | ||
406 | ld ZH, X+ | ||
407 | clr r18 ;r21:r18 = 0; | ||
408 | clr r19 ; | ||
409 | clr r20 ; | ||
410 | clr r21 ;/ | ||
411 | clt ;T = 0; | ||
412 | |||
413 | ldi r25, 10 ;r25 = 10; | ||
414 | rjmp 41f ;/ | ||
415 | 40: adiw ZL, 1 ;Z++; | ||
416 | 41: ld r22, Z ;r22 = *Z; | ||
417 | cpi r22, ' ' ;if(r22 == ' ') continue | ||
418 | breq 40b ;/ | ||
419 | brcs 70f ;if(r22 < ' ') error; | ||
420 | cpi r22, '-' ;if(r22 == '-') { | ||
421 | brne 42f ; T = 1; | ||
422 | set ; continue; | ||
423 | rjmp 40b ;} | ||
424 | 42: cpi r22, '9'+1 ;if(r22 > '9') error; | ||
425 | brcc 70f ;/ | ||
426 | cpi r22, '0' ;if(r22 < '0') error; | ||
427 | brcs 70f ;/ | ||
428 | brne 51f ;if(r22 > '0') cv_start; | ||
429 | ldi r25, 8 ;r25 = 8; | ||
430 | adiw ZL, 1 ;r22 = *(++Z); | ||
431 | ld r22, Z ;/ | ||
432 | cpi r22, ' '+1 ;if(r22 <= ' ') exit; | ||
433 | brcs 80f ;/ | ||
434 | cpi r22, 'b' ;if(r22 == 'b') { | ||
435 | brne 43f ; r25 = 2; | ||
436 | ldi r25, 2 ; cv_start; | ||
437 | rjmp 50f ;} | ||
438 | 43: cpi r22, 'x' ;if(r22 != 'x') error; | ||
439 | brne 51f ;/ | ||
440 | ldi r25, 16 ;r25 = 16; | ||
441 | |||
442 | 50: adiw ZL, 1 ;Z++; | ||
443 | ld r22, Z ;r22 = *Z; | ||
444 | 51: cpi r22, ' '+1 ;if(r22 <= ' ') break; | ||
445 | brcs 80f ;/ | ||
446 | cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20; | ||
447 | brcs 52f ; | ||
448 | subi r22, 0x20 ;/ | ||
449 | 52: subi r22, '0' ;if((r22 -= '0') < 0) error; | ||
450 | brcs 70f ;/ | ||
451 | cpi r22, 10 ;if(r22 >= 10) { | ||
452 | brcs 53f ; r22 -= 7; | ||
453 | subi r22, 7 ; if(r22 < 10) | ||
454 | cpi r22, 10 ; | ||
455 | brcs 70f ;} | ||
456 | 53: cp r22, r25 ;if(r22 >= r25) error; | ||
457 | brcc 70f ;/ | ||
458 | 60: ldi r24, 33 ;r21:r18 *= r25; | ||
459 | sub r23, r23 ; | ||
460 | 61: brcc 62f ; | ||
461 | add r23, r25 ; | ||
462 | 62: lsr r23 ; | ||
463 | ror r21 ; | ||
464 | ror r20 ; | ||
465 | ror r19 ; | ||
466 | ror r18 ; | ||
467 | dec r24 ; | ||
468 | brne 61b ;/ | ||
469 | add r18, r22 ;r21:r18 += r22; | ||
470 | adc r19, r24 ; | ||
471 | adc r20, r24 ; | ||
472 | adc r21, r24 ;/ | ||
473 | rjmp 50b ;repeat | ||
474 | |||
475 | 70: ldi r24, 0 | ||
476 | rjmp 81f | ||
477 | 80: ldi r24, 1 | ||
478 | 81: brtc 82f | ||
479 | clr r22 | ||
480 | com r18 | ||
481 | com r19 | ||
482 | com r20 | ||
483 | com r21 | ||
484 | adc r18, r22 | ||
485 | adc r19, r22 | ||
486 | adc r20, r22 | ||
487 | adc r21, r22 | ||
488 | 82: st -X, ZH | ||
489 | st -X, ZL | ||
490 | _MOVW XH, XL, r1, r0 | ||
491 | st X+, r18 | ||
492 | st X+, r19 | ||
493 | st X+, r20 | ||
494 | st X+, r21 | ||
495 | clr r1 | ||
496 | ret | ||
497 | .endfunc | ||
498 | #endif | ||
499 | |||
500 | |||
diff --git a/tmk_core/common/avr/xprintf.h b/tmk_core/common/avr/xprintf.h new file mode 100644 index 000000000..59c6f2531 --- /dev/null +++ b/tmk_core/common/avr/xprintf.h | |||
@@ -0,0 +1,111 @@ | |||
1 | /*--------------------------------------------------------------------------- | ||
2 | Extended itoa, puts and printf (C)ChaN, 2011 | ||
3 | -----------------------------------------------------------------------------*/ | ||
4 | |||
5 | #ifndef XPRINTF_H | ||
6 | #define XPRINTF_H | ||
7 | |||
8 | #include <inttypes.h> | ||
9 | #include <avr/pgmspace.h> | ||
10 | |||
11 | #ifdef __cplusplus | ||
12 | extern "C" { | ||
13 | #endif | ||
14 | |||
15 | extern void (*xfunc_out)(uint8_t); | ||
16 | #define xdev_out(func) xfunc_out = (void(*)(uint8_t))(func) | ||
17 | |||
18 | /* This is a pointer to user defined output function. It must be initialized | ||
19 | before using this modle. | ||
20 | */ | ||
21 | |||
22 | void xputc(char chr); | ||
23 | |||
24 | /* This is a stub function to forward outputs to user defined output function. | ||
25 | All outputs from this module are output via this function. | ||
26 | */ | ||
27 | |||
28 | |||
29 | /*-----------------------------------------------------------------------------*/ | ||
30 | void xputs(const char *string_p); | ||
31 | |||
32 | /* The string placed in the ROM is forwarded to xputc() directly. | ||
33 | */ | ||
34 | |||
35 | |||
36 | /*-----------------------------------------------------------------------------*/ | ||
37 | void xitoa(long value, char radix, char width); | ||
38 | |||
39 | /* Extended itoa(). | ||
40 | |||
41 | value radix width output | ||
42 | 100 10 6 " 100" | ||
43 | 100 10 -6 "000100" | ||
44 | 100 10 0 "100" | ||
45 | 4294967295 10 0 "4294967295" | ||
46 | 4294967295 -10 0 "-1" | ||
47 | 655360 16 -8 "000A0000" | ||
48 | 1024 16 0 "400" | ||
49 | 0x55 2 -8 "01010101" | ||
50 | */ | ||
51 | |||
52 | |||
53 | /*-----------------------------------------------------------------------------*/ | ||
54 | #define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__) | ||
55 | #define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__) | ||
56 | #define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__) | ||
57 | |||
58 | void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */ | ||
59 | void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */ | ||
60 | void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */ | ||
61 | |||
62 | /* Format string is placed in the ROM. The format flags is similar to printf(). | ||
63 | |||
64 | %[flag][width][size]type | ||
65 | |||
66 | flag | ||
67 | A '0' means filled with '0' when output is shorter than width. | ||
68 | ' ' is used in default. This is effective only numeral type. | ||
69 | width | ||
70 | Minimum width in decimal number. This is effective only numeral type. | ||
71 | Default width is zero. | ||
72 | size | ||
73 | A 'l' means the argument is long(32bit). Default is short(16bit). | ||
74 | This is effective only numeral type. | ||
75 | type | ||
76 | 'c' : Character, argument is the value | ||
77 | 's' : String placed on the RAM, argument is the pointer | ||
78 | 'S' : String placed on the ROM, argument is the pointer | ||
79 | 'd' : Signed decimal, argument is the value | ||
80 | 'u' : Unsigned decimal, argument is the value | ||
81 | 'X' : Hexdecimal, argument is the value | ||
82 | 'b' : Binary, argument is the value | ||
83 | '%' : '%' | ||
84 | |||
85 | */ | ||
86 | |||
87 | |||
88 | /*-----------------------------------------------------------------------------*/ | ||
89 | char xatoi(char **str, long *ret); | ||
90 | |||
91 | /* Get value of the numeral string. | ||
92 | |||
93 | str | ||
94 | Pointer to pointer to source string | ||
95 | |||
96 | "0b11001010" binary | ||
97 | "0377" octal | ||
98 | "0xff800" hexdecimal | ||
99 | "1250000" decimal | ||
100 | "-25000" decimal | ||
101 | |||
102 | ret | ||
103 | Pointer to return value | ||
104 | */ | ||
105 | |||
106 | #ifdef __cplusplus | ||
107 | } | ||
108 | #endif | ||
109 | |||
110 | #endif | ||
111 | |||
diff --git a/tmk_core/common/backlight.c b/tmk_core/common/backlight.c new file mode 100644 index 000000000..558ad9b01 --- /dev/null +++ b/tmk_core/common/backlight.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | Copyright 2013 Mathias Andersson <wraul@dbox.se> | ||
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 "backlight.h" | ||
19 | #include "eeconfig.h" | ||
20 | #include "debug.h" | ||
21 | |||
22 | backlight_config_t backlight_config; | ||
23 | |||
24 | void backlight_init(void) | ||
25 | { | ||
26 | /* check signature */ | ||
27 | if (!eeconfig_is_enabled()) { | ||
28 | eeconfig_init(); | ||
29 | } | ||
30 | backlight_config.raw = eeconfig_read_backlight(); | ||
31 | backlight_set(backlight_config.enable ? backlight_config.level : 0); | ||
32 | } | ||
33 | |||
34 | void backlight_increase(void) | ||
35 | { | ||
36 | if(backlight_config.level < BACKLIGHT_LEVELS) | ||
37 | { | ||
38 | backlight_config.level++; | ||
39 | backlight_config.enable = 1; | ||
40 | eeconfig_write_backlight(backlight_config.raw); | ||
41 | } | ||
42 | dprintf("backlight increase: %u\n", backlight_config.level); | ||
43 | backlight_set(backlight_config.level); | ||
44 | } | ||
45 | |||
46 | void backlight_decrease(void) | ||
47 | { | ||
48 | if(backlight_config.level > 0) | ||
49 | { | ||
50 | backlight_config.level--; | ||
51 | backlight_config.enable = !!backlight_config.level; | ||
52 | eeconfig_write_backlight(backlight_config.raw); | ||
53 | } | ||
54 | dprintf("backlight decrease: %u\n", backlight_config.level); | ||
55 | backlight_set(backlight_config.level); | ||
56 | } | ||
57 | |||
58 | void backlight_toggle(void) | ||
59 | { | ||
60 | backlight_config.enable ^= 1; | ||
61 | eeconfig_write_backlight(backlight_config.raw); | ||
62 | dprintf("backlight toggle: %u\n", backlight_config.enable); | ||
63 | backlight_set(backlight_config.enable ? backlight_config.level : 0); | ||
64 | } | ||
65 | |||
66 | void backlight_step(void) | ||
67 | { | ||
68 | backlight_config.level++; | ||
69 | if(backlight_config.level > BACKLIGHT_LEVELS) | ||
70 | { | ||
71 | backlight_config.level = 0; | ||
72 | } | ||
73 | backlight_config.enable = !!backlight_config.level; | ||
74 | eeconfig_write_backlight(backlight_config.raw); | ||
75 | dprintf("backlight step: %u\n", backlight_config.level); | ||
76 | backlight_set(backlight_config.level); | ||
77 | } | ||
78 | |||
79 | void backlight_level(uint8_t level) | ||
80 | { | ||
81 | backlight_config.level ^= level; | ||
82 | backlight_config.enable = !!backlight_config.level; | ||
83 | eeconfig_write_backlight(backlight_config.raw); | ||
84 | backlight_set(backlight_config.level); | ||
85 | } | ||
diff --git a/tmk_core/common/backlight.h b/tmk_core/common/backlight.h new file mode 100644 index 000000000..525ec8bbe --- /dev/null +++ b/tmk_core/common/backlight.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | Copyright 2013 Mathias Andersson <wraul@dbox.se> | ||
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 | #ifndef BACKLIGHT_H | ||
19 | #define BACKLIGHT_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include <stdbool.h> | ||
23 | |||
24 | typedef union { | ||
25 | uint8_t raw; | ||
26 | struct { | ||
27 | bool enable :1; | ||
28 | uint8_t level :7; | ||
29 | }; | ||
30 | } backlight_config_t; | ||
31 | |||
32 | void backlight_init(void); | ||
33 | void backlight_increase(void); | ||
34 | void backlight_decrease(void); | ||
35 | void backlight_toggle(void); | ||
36 | void backlight_step(void); | ||
37 | void backlight_set(uint8_t level); | ||
38 | void backlight_level(uint8_t level); | ||
39 | |||
40 | #endif | ||
diff --git a/tmk_core/common/bootloader.h b/tmk_core/common/bootloader.h new file mode 100644 index 000000000..44775039d --- /dev/null +++ b/tmk_core/common/bootloader.h | |||
@@ -0,0 +1,25 @@ | |||
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 | #ifndef BOOTLOADER_H | ||
19 | #define BOOTLOADER_H | ||
20 | |||
21 | |||
22 | /* give code for your bootloader to come up if needed */ | ||
23 | void bootloader_jump(void); | ||
24 | |||
25 | #endif | ||
diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c new file mode 100644 index 000000000..b002a5856 --- /dev/null +++ b/tmk_core/common/bootmagic.c | |||
@@ -0,0 +1,128 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <util/delay.h> | ||
4 | #include "matrix.h" | ||
5 | #include "bootloader.h" | ||
6 | #include "debug.h" | ||
7 | #include "keymap.h" | ||
8 | #include "host.h" | ||
9 | #include "action_layer.h" | ||
10 | #include "eeconfig.h" | ||
11 | #include "bootmagic.h" | ||
12 | |||
13 | |||
14 | void bootmagic(void) | ||
15 | { | ||
16 | /* check signature */ | ||
17 | if (!eeconfig_is_enabled()) { | ||
18 | eeconfig_init(); | ||
19 | } | ||
20 | |||
21 | /* do scans in case of bounce */ | ||
22 | print("boogmagic scan: ... "); | ||
23 | uint8_t scan = 100; | ||
24 | while (scan--) { matrix_scan(); _delay_ms(10); } | ||
25 | print("done.\n"); | ||
26 | |||
27 | /* bootmagic skip */ | ||
28 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SKIP)) { | ||
29 | return; | ||
30 | } | ||
31 | |||
32 | /* eeconfig clear */ | ||
33 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_EEPROM_CLEAR)) { | ||
34 | eeconfig_init(); | ||
35 | } | ||
36 | |||
37 | /* bootloader */ | ||
38 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_BOOTLOADER)) { | ||
39 | bootloader_jump(); | ||
40 | } | ||
41 | |||
42 | /* debug enable */ | ||
43 | debug_config.raw = eeconfig_read_debug(); | ||
44 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_ENABLE)) { | ||
45 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_MATRIX)) { | ||
46 | debug_config.matrix = !debug_config.matrix; | ||
47 | } else if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_KEYBOARD)) { | ||
48 | debug_config.keyboard = !debug_config.keyboard; | ||
49 | } else if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEBUG_MOUSE)) { | ||
50 | debug_config.mouse = !debug_config.mouse; | ||
51 | } else { | ||
52 | debug_config.enable = !debug_config.enable; | ||
53 | } | ||
54 | } | ||
55 | eeconfig_write_debug(debug_config.raw); | ||
56 | |||
57 | /* keymap config */ | ||
58 | keymap_config.raw = eeconfig_read_keymap(); | ||
59 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK)) { | ||
60 | keymap_config.swap_control_capslock = !keymap_config.swap_control_capslock; | ||
61 | } | ||
62 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL)) { | ||
63 | keymap_config.capslock_to_control = !keymap_config.capslock_to_control; | ||
64 | } | ||
65 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_LALT_LGUI)) { | ||
66 | keymap_config.swap_lalt_lgui = !keymap_config.swap_lalt_lgui; | ||
67 | } | ||
68 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_RALT_RGUI)) { | ||
69 | keymap_config.swap_ralt_rgui = !keymap_config.swap_ralt_rgui; | ||
70 | } | ||
71 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_NO_GUI)) { | ||
72 | keymap_config.no_gui = !keymap_config.no_gui; | ||
73 | } | ||
74 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_GRAVE_ESC)) { | ||
75 | keymap_config.swap_grave_esc = !keymap_config.swap_grave_esc; | ||
76 | } | ||
77 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE)) { | ||
78 | keymap_config.swap_backslash_backspace = !keymap_config.swap_backslash_backspace; | ||
79 | } | ||
80 | if (bootmagic_scan_keycode(BOOTMAGIC_HOST_NKRO)) { | ||
81 | keymap_config.nkro = !keymap_config.nkro; | ||
82 | } | ||
83 | eeconfig_write_keymap(keymap_config.raw); | ||
84 | |||
85 | #ifdef NKRO_ENABLE | ||
86 | keyboard_nkro = keymap_config.nkro; | ||
87 | #endif | ||
88 | |||
89 | /* default layer */ | ||
90 | uint8_t default_layer = 0; | ||
91 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_0)) { default_layer |= (1<<0); } | ||
92 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_1)) { default_layer |= (1<<1); } | ||
93 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_2)) { default_layer |= (1<<2); } | ||
94 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_3)) { default_layer |= (1<<3); } | ||
95 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_4)) { default_layer |= (1<<4); } | ||
96 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_5)) { default_layer |= (1<<5); } | ||
97 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_6)) { default_layer |= (1<<6); } | ||
98 | if (bootmagic_scan_keycode(BOOTMAGIC_KEY_DEFAULT_LAYER_7)) { default_layer |= (1<<7); } | ||
99 | if (default_layer) { | ||
100 | eeconfig_write_default_layer(default_layer); | ||
101 | default_layer_set((uint32_t)default_layer); | ||
102 | } else { | ||
103 | default_layer = eeconfig_read_default_layer(); | ||
104 | default_layer_set((uint32_t)default_layer); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static bool scan_keycode(uint8_t keycode) | ||
109 | { | ||
110 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | ||
111 | matrix_row_t matrix_row = matrix_get_row(r); | ||
112 | for (uint8_t c = 0; c < MATRIX_COLS; c++) { | ||
113 | if (matrix_row & ((matrix_row_t)1<<c)) { | ||
114 | if (keycode == keymap_key_to_keycode(0, (keypos_t){ .row = r, .col = c })) { | ||
115 | return true; | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | return false; | ||
121 | } | ||
122 | |||
123 | bool bootmagic_scan_keycode(uint8_t keycode) | ||
124 | { | ||
125 | if (!scan_keycode(BOOTMAGIC_KEY_SALT)) return false; | ||
126 | |||
127 | return scan_keycode(keycode); | ||
128 | } | ||
diff --git a/tmk_core/common/bootmagic.h b/tmk_core/common/bootmagic.h new file mode 100644 index 000000000..8f6618f4b --- /dev/null +++ b/tmk_core/common/bootmagic.h | |||
@@ -0,0 +1,100 @@ | |||
1 | #ifndef BOOTMAGIC_H | ||
2 | #define BOOTMAGIC_H | ||
3 | |||
4 | |||
5 | /* bootmagic salt key */ | ||
6 | #ifndef BOOTMAGIC_KEY_SALT | ||
7 | #define BOOTMAGIC_KEY_SALT KC_SPACE | ||
8 | #endif | ||
9 | |||
10 | /* skip bootmagic and eeconfig */ | ||
11 | #ifndef BOOTMAGIC_KEY_SKIP | ||
12 | #define BOOTMAGIC_KEY_SKIP KC_ESC | ||
13 | #endif | ||
14 | |||
15 | /* eeprom clear */ | ||
16 | #ifndef BOOTMAGIC_KEY_EEPROM_CLEAR | ||
17 | #define BOOTMAGIC_KEY_EEPROM_CLEAR KC_BSPACE | ||
18 | #endif | ||
19 | |||
20 | /* kick up bootloader */ | ||
21 | #ifndef BOOTMAGIC_KEY_BOOTLOADER | ||
22 | #define BOOTMAGIC_KEY_BOOTLOADER KC_B | ||
23 | #endif | ||
24 | |||
25 | /* debug enable */ | ||
26 | #ifndef BOOTMAGIC_KEY_DEBUG_ENABLE | ||
27 | #define BOOTMAGIC_KEY_DEBUG_ENABLE KC_D | ||
28 | #endif | ||
29 | #ifndef BOOTMAGIC_KEY_DEBUG_MATRIX | ||
30 | #define BOOTMAGIC_KEY_DEBUG_MATRIX KC_X | ||
31 | #endif | ||
32 | #ifndef BOOTMAGIC_KEY_DEBUG_KEYBOARD | ||
33 | #define BOOTMAGIC_KEY_DEBUG_KEYBOARD KC_K | ||
34 | #endif | ||
35 | #ifndef BOOTMAGIC_KEY_DEBUG_MOUSE | ||
36 | #define BOOTMAGIC_KEY_DEBUG_MOUSE KC_M | ||
37 | #endif | ||
38 | |||
39 | /* | ||
40 | * keymap config | ||
41 | */ | ||
42 | #ifndef BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK | ||
43 | #define BOOTMAGIC_KEY_SWAP_CONTROL_CAPSLOCK KC_LCTRL | ||
44 | #endif | ||
45 | #ifndef BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL | ||
46 | #define BOOTMAGIC_KEY_CAPSLOCK_TO_CONTROL KC_CAPSLOCK | ||
47 | #endif | ||
48 | #ifndef BOOTMAGIC_KEY_SWAP_LALT_LGUI | ||
49 | #define BOOTMAGIC_KEY_SWAP_LALT_LGUI KC_LALT | ||
50 | #endif | ||
51 | #ifndef BOOTMAGIC_KEY_SWAP_RALT_RGUI | ||
52 | #define BOOTMAGIC_KEY_SWAP_RALT_RGUI KC_RALT | ||
53 | #endif | ||
54 | #ifndef BOOTMAGIC_KEY_NO_GUI | ||
55 | #define BOOTMAGIC_KEY_NO_GUI KC_LGUI | ||
56 | #endif | ||
57 | #ifndef BOOTMAGIC_KEY_SWAP_GRAVE_ESC | ||
58 | #define BOOTMAGIC_KEY_SWAP_GRAVE_ESC KC_GRAVE | ||
59 | #endif | ||
60 | #ifndef BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE | ||
61 | #define BOOTMAGIC_KEY_SWAP_BACKSLASH_BACKSPACE KC_BSLASH | ||
62 | #endif | ||
63 | #ifndef BOOTMAGIC_HOST_NKRO | ||
64 | #define BOOTMAGIC_HOST_NKRO KC_N | ||
65 | #endif | ||
66 | |||
67 | |||
68 | /* | ||
69 | * change default layer | ||
70 | */ | ||
71 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_0 | ||
72 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_0 KC_0 | ||
73 | #endif | ||
74 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_1 | ||
75 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_1 KC_1 | ||
76 | #endif | ||
77 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_2 | ||
78 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_2 KC_2 | ||
79 | #endif | ||
80 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_3 | ||
81 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_3 KC_3 | ||
82 | #endif | ||
83 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_4 | ||
84 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_4 KC_4 | ||
85 | #endif | ||
86 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_5 | ||
87 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_5 KC_5 | ||
88 | #endif | ||
89 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_6 | ||
90 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_6 KC_6 | ||
91 | #endif | ||
92 | #ifndef BOOTMAGIC_KEY_DEFAULT_LAYER_7 | ||
93 | #define BOOTMAGIC_KEY_DEFAULT_LAYER_7 KC_7 | ||
94 | #endif | ||
95 | |||
96 | |||
97 | void bootmagic(void); | ||
98 | bool bootmagic_scan_keycode(uint8_t keycode); | ||
99 | |||
100 | #endif | ||
diff --git a/tmk_core/common/command.c b/tmk_core/common/command.c new file mode 100644 index 000000000..fbaa9f2d7 --- /dev/null +++ b/tmk_core/common/command.c | |||
@@ -0,0 +1,644 @@ | |||
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 | #include <stdint.h> | ||
18 | #include <stdbool.h> | ||
19 | #include <util/delay.h> | ||
20 | #include "keycode.h" | ||
21 | #include "host.h" | ||
22 | #include "keymap.h" | ||
23 | #include "print.h" | ||
24 | #include "debug.h" | ||
25 | #include "util.h" | ||
26 | #include "timer.h" | ||
27 | #include "keyboard.h" | ||
28 | #include "bootloader.h" | ||
29 | #include "action_layer.h" | ||
30 | #include "action_util.h" | ||
31 | #include "eeconfig.h" | ||
32 | #include "sleep_led.h" | ||
33 | #include "led.h" | ||
34 | #include "command.h" | ||
35 | #include "backlight.h" | ||
36 | |||
37 | #ifdef MOUSEKEY_ENABLE | ||
38 | #include "mousekey.h" | ||
39 | #endif | ||
40 | |||
41 | #ifdef PROTOCOL_PJRC | ||
42 | # include "usb_keyboard.h" | ||
43 | # ifdef EXTRAKEY_ENABLE | ||
44 | # include "usb_extra.h" | ||
45 | # endif | ||
46 | #endif | ||
47 | |||
48 | #ifdef PROTOCOL_VUSB | ||
49 | # include "usbdrv.h" | ||
50 | #endif | ||
51 | |||
52 | |||
53 | static bool command_common(uint8_t code); | ||
54 | static void command_common_help(void); | ||
55 | static bool command_console(uint8_t code); | ||
56 | static void command_console_help(void); | ||
57 | #ifdef MOUSEKEY_ENABLE | ||
58 | static bool mousekey_console(uint8_t code); | ||
59 | static void mousekey_console_help(void); | ||
60 | #endif | ||
61 | |||
62 | static uint8_t numkey2num(uint8_t code); | ||
63 | static void switch_default_layer(uint8_t layer); | ||
64 | |||
65 | |||
66 | command_state_t command_state = ONESHOT; | ||
67 | |||
68 | |||
69 | bool command_proc(uint8_t code) | ||
70 | { | ||
71 | switch (command_state) { | ||
72 | case ONESHOT: | ||
73 | if (!IS_COMMAND()) | ||
74 | return false; | ||
75 | return (command_extra(code) || command_common(code)); | ||
76 | break; | ||
77 | case CONSOLE: | ||
78 | if (IS_COMMAND()) | ||
79 | return (command_extra(code) || command_common(code)); | ||
80 | else | ||
81 | return (command_console_extra(code) || command_console(code)); | ||
82 | break; | ||
83 | #ifdef MOUSEKEY_ENABLE | ||
84 | case MOUSEKEY: | ||
85 | mousekey_console(code); | ||
86 | break; | ||
87 | #endif | ||
88 | default: | ||
89 | command_state = ONESHOT; | ||
90 | return false; | ||
91 | } | ||
92 | return true; | ||
93 | } | ||
94 | |||
95 | /* TODO: Refactoring is needed. */ | ||
96 | /* This allows to define extra commands. return false when not processed. */ | ||
97 | bool command_extra(uint8_t code) __attribute__ ((weak)); | ||
98 | bool command_extra(uint8_t code) | ||
99 | { | ||
100 | return false; | ||
101 | } | ||
102 | |||
103 | bool command_console_extra(uint8_t code) __attribute__ ((weak)); | ||
104 | bool command_console_extra(uint8_t code) | ||
105 | { | ||
106 | return false; | ||
107 | } | ||
108 | |||
109 | |||
110 | /*********************************************************** | ||
111 | * Command common | ||
112 | ***********************************************************/ | ||
113 | static void command_common_help(void) | ||
114 | { | ||
115 | print("\n\n----- Command Help -----\n"); | ||
116 | print("c: enter console mode\n"); | ||
117 | print("d: toggle debug enable\n"); | ||
118 | print("x: toggle matrix debug\n"); | ||
119 | print("k: toggle keyboard debug\n"); | ||
120 | print("m: toggle mouse debug\n"); | ||
121 | #ifdef SLEEP_LED_ENABLE | ||
122 | print("z: toggle sleep LED test\n"); | ||
123 | #endif | ||
124 | print("v: print device version & info\n"); | ||
125 | print("t: print timer count\n"); | ||
126 | print("s: print status\n"); | ||
127 | print("e: print eeprom config\n"); | ||
128 | #ifdef NKRO_ENABLE | ||
129 | print("n: toggle NKRO\n"); | ||
130 | #endif | ||
131 | print("0/F10: switch to Layer0 \n"); | ||
132 | print("1/F1: switch to Layer1 \n"); | ||
133 | print("2/F2: switch to Layer2 \n"); | ||
134 | print("3/F3: switch to Layer3 \n"); | ||
135 | print("4/F4: switch to Layer4 \n"); | ||
136 | print("PScr: power down/remote wake-up\n"); | ||
137 | print("Caps: Lock Keyboard(Child Proof)\n"); | ||
138 | print("Paus: jump to bootloader\n"); | ||
139 | } | ||
140 | |||
141 | #ifdef BOOTMAGIC_ENABLE | ||
142 | static void print_eeconfig(void) | ||
143 | { | ||
144 | print("default_layer: "); print_dec(eeconfig_read_default_layer()); print("\n"); | ||
145 | |||
146 | debug_config_t dc; | ||
147 | dc.raw = eeconfig_read_debug(); | ||
148 | print("debug_config.raw: "); print_hex8(dc.raw); print("\n"); | ||
149 | print(".enable: "); print_dec(dc.enable); print("\n"); | ||
150 | print(".matrix: "); print_dec(dc.matrix); print("\n"); | ||
151 | print(".keyboard: "); print_dec(dc.keyboard); print("\n"); | ||
152 | print(".mouse: "); print_dec(dc.mouse); print("\n"); | ||
153 | |||
154 | keymap_config_t kc; | ||
155 | kc.raw = eeconfig_read_keymap(); | ||
156 | print("keymap_config.raw: "); print_hex8(kc.raw); print("\n"); | ||
157 | print(".swap_control_capslock: "); print_dec(kc.swap_control_capslock); print("\n"); | ||
158 | print(".capslock_to_control: "); print_dec(kc.capslock_to_control); print("\n"); | ||
159 | print(".swap_lalt_lgui: "); print_dec(kc.swap_lalt_lgui); print("\n"); | ||
160 | print(".swap_ralt_rgui: "); print_dec(kc.swap_ralt_rgui); print("\n"); | ||
161 | print(".no_gui: "); print_dec(kc.no_gui); print("\n"); | ||
162 | print(".swap_grave_esc: "); print_dec(kc.swap_grave_esc); print("\n"); | ||
163 | print(".swap_backslash_backspace: "); print_dec(kc.swap_backslash_backspace); print("\n"); | ||
164 | print(".nkro: "); print_dec(kc.nkro); print("\n"); | ||
165 | |||
166 | #ifdef BACKLIGHT_ENABLE | ||
167 | backlight_config_t bc; | ||
168 | bc.raw = eeconfig_read_backlight(); | ||
169 | print("backlight_config.raw: "); print_hex8(bc.raw); print("\n"); | ||
170 | print(".enable: "); print_dec(bc.enable); print("\n"); | ||
171 | print(".level: "); print_dec(bc.level); print("\n"); | ||
172 | #endif | ||
173 | } | ||
174 | #endif | ||
175 | |||
176 | static bool command_common(uint8_t code) | ||
177 | { | ||
178 | static host_driver_t *host_driver = 0; | ||
179 | switch (code) { | ||
180 | #ifdef SLEEP_LED_ENABLE | ||
181 | case KC_Z: | ||
182 | // test breathing sleep LED | ||
183 | print("Sleep LED test\n"); | ||
184 | sleep_led_toggle(); | ||
185 | led_set(host_keyboard_leds()); | ||
186 | break; | ||
187 | #endif | ||
188 | #ifdef BOOTMAGIC_ENABLE | ||
189 | case KC_E: | ||
190 | print("eeconfig:\n"); | ||
191 | print_eeconfig(); | ||
192 | break; | ||
193 | #endif | ||
194 | case KC_CAPSLOCK: | ||
195 | if (host_get_driver()) { | ||
196 | host_driver = host_get_driver(); | ||
197 | clear_keyboard(); | ||
198 | host_set_driver(0); | ||
199 | print("Locked.\n"); | ||
200 | } else { | ||
201 | host_set_driver(host_driver); | ||
202 | print("Unlocked.\n"); | ||
203 | } | ||
204 | break; | ||
205 | case KC_H: | ||
206 | case KC_SLASH: /* ? */ | ||
207 | command_common_help(); | ||
208 | break; | ||
209 | case KC_C: | ||
210 | debug_matrix = false; | ||
211 | debug_keyboard = false; | ||
212 | debug_mouse = false; | ||
213 | debug_enable = false; | ||
214 | command_console_help(); | ||
215 | print("\nEnter Console Mode\n"); | ||
216 | print("C> "); | ||
217 | command_state = CONSOLE; | ||
218 | break; | ||
219 | case KC_PAUSE: | ||
220 | clear_keyboard(); | ||
221 | print("\n\nJump to bootloader... "); | ||
222 | _delay_ms(1000); | ||
223 | bootloader_jump(); // not return | ||
224 | print("not supported.\n"); | ||
225 | break; | ||
226 | case KC_D: | ||
227 | if (debug_enable) { | ||
228 | print("\nDEBUG: disabled.\n"); | ||
229 | debug_matrix = false; | ||
230 | debug_keyboard = false; | ||
231 | debug_mouse = false; | ||
232 | debug_enable = false; | ||
233 | } else { | ||
234 | print("\nDEBUG: enabled.\n"); | ||
235 | debug_enable = true; | ||
236 | } | ||
237 | break; | ||
238 | case KC_X: // debug matrix toggle | ||
239 | debug_matrix = !debug_matrix; | ||
240 | if (debug_matrix) { | ||
241 | print("\nDEBUG: matrix enabled.\n"); | ||
242 | debug_enable = true; | ||
243 | } else { | ||
244 | print("\nDEBUG: matrix disabled.\n"); | ||
245 | } | ||
246 | break; | ||
247 | case KC_K: // debug keyboard toggle | ||
248 | debug_keyboard = !debug_keyboard; | ||
249 | if (debug_keyboard) { | ||
250 | print("\nDEBUG: keyboard enabled.\n"); | ||
251 | debug_enable = true; | ||
252 | } else { | ||
253 | print("\nDEBUG: keyboard disabled.\n"); | ||
254 | } | ||
255 | break; | ||
256 | case KC_M: // debug mouse toggle | ||
257 | debug_mouse = !debug_mouse; | ||
258 | if (debug_mouse) { | ||
259 | print("\nDEBUG: mouse enabled.\n"); | ||
260 | debug_enable = true; | ||
261 | } else { | ||
262 | print("\nDEBUG: mouse disabled.\n"); | ||
263 | } | ||
264 | break; | ||
265 | case KC_V: // print version & information | ||
266 | print("\n\n----- Version -----\n"); | ||
267 | print("DESC: " STR(DESCRIPTION) "\n"); | ||
268 | print("VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") " | ||
269 | "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") " | ||
270 | "VER: " STR(DEVICE_VER) "\n"); | ||
271 | print("BUILD: " STR(VERSION) " (" __TIME__ " " __DATE__ ")\n"); | ||
272 | /* build options */ | ||
273 | print("OPTIONS:" | ||
274 | #ifdef PROTOCOL_PJRC | ||
275 | " PJRC" | ||
276 | #endif | ||
277 | #ifdef PROTOCOL_LUFA | ||
278 | " LUFA" | ||
279 | #endif | ||
280 | #ifdef PROTOCOL_VUSB | ||
281 | " VUSB" | ||
282 | #endif | ||
283 | #ifdef BOOTMAGIC_ENABLE | ||
284 | " BOOTMAGIC" | ||
285 | #endif | ||
286 | #ifdef MOUSEKEY_ENABLE | ||
287 | " MOUSEKEY" | ||
288 | #endif | ||
289 | #ifdef EXTRAKEY_ENABLE | ||
290 | " EXTRAKEY" | ||
291 | #endif | ||
292 | #ifdef CONSOLE_ENABLE | ||
293 | " CONSOLE" | ||
294 | #endif | ||
295 | #ifdef COMMAND_ENABLE | ||
296 | " COMMAND" | ||
297 | #endif | ||
298 | #ifdef NKRO_ENABLE | ||
299 | " NKRO" | ||
300 | #endif | ||
301 | #ifdef KEYMAP_SECTION_ENABLE | ||
302 | " KEYMAP_SECTION" | ||
303 | #endif | ||
304 | " " STR(BOOTLOADER_SIZE) "\n"); | ||
305 | |||
306 | print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__) | ||
307 | " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__ | ||
308 | " AVR_ARCH: avr" STR(__AVR_ARCH__) "\n"); | ||
309 | break; | ||
310 | case KC_T: // print timer | ||
311 | print_val_hex32(timer_count); | ||
312 | break; | ||
313 | case KC_S: | ||
314 | print("\n\n----- Status -----\n"); | ||
315 | print_val_hex8(host_keyboard_leds()); | ||
316 | print_val_hex8(keyboard_protocol); | ||
317 | print_val_hex8(keyboard_idle); | ||
318 | #ifdef PROTOCOL_PJRC | ||
319 | print_val_hex8(UDCON); | ||
320 | print_val_hex8(UDIEN); | ||
321 | print_val_hex8(UDINT); | ||
322 | print_val_hex8(usb_keyboard_leds); | ||
323 | print_val_hex8(usb_keyboard_idle_count); | ||
324 | #endif | ||
325 | |||
326 | #ifdef PROTOCOL_PJRC | ||
327 | # if USB_COUNT_SOF | ||
328 | print_val_hex8(usbSofCount); | ||
329 | # endif | ||
330 | #endif | ||
331 | break; | ||
332 | #ifdef NKRO_ENABLE | ||
333 | case KC_N: | ||
334 | clear_keyboard(); //Prevents stuck keys. | ||
335 | keyboard_nkro = !keyboard_nkro; | ||
336 | if (keyboard_nkro) | ||
337 | print("NKRO: enabled\n"); | ||
338 | else | ||
339 | print("NKRO: disabled\n"); | ||
340 | break; | ||
341 | #endif | ||
342 | #ifdef EXTRAKEY_ENABLE | ||
343 | case KC_PSCREEN: | ||
344 | // TODO: Power key should take this feature? otherwise any key during suspend. | ||
345 | #ifdef PROTOCOL_PJRC | ||
346 | if (suspend && remote_wakeup) { | ||
347 | usb_remote_wakeup(); | ||
348 | } else { | ||
349 | host_system_send(SYSTEM_POWER_DOWN); | ||
350 | host_system_send(0); | ||
351 | _delay_ms(500); | ||
352 | } | ||
353 | #else | ||
354 | host_system_send(SYSTEM_POWER_DOWN); | ||
355 | _delay_ms(100); | ||
356 | host_system_send(0); | ||
357 | _delay_ms(500); | ||
358 | #endif | ||
359 | break; | ||
360 | #endif | ||
361 | case KC_ESC: | ||
362 | case KC_GRV: | ||
363 | case KC_0: | ||
364 | switch_default_layer(0); | ||
365 | break; | ||
366 | case KC_1 ... KC_9: | ||
367 | switch_default_layer((code - KC_1) + 1); | ||
368 | break; | ||
369 | case KC_F1 ... KC_F12: | ||
370 | switch_default_layer((code - KC_F1) + 1); | ||
371 | break; | ||
372 | default: | ||
373 | print("?"); | ||
374 | return false; | ||
375 | } | ||
376 | return true; | ||
377 | } | ||
378 | |||
379 | |||
380 | /*********************************************************** | ||
381 | * Command console | ||
382 | ***********************************************************/ | ||
383 | static void command_console_help(void) | ||
384 | { | ||
385 | print("\n\n----- Console Help -----\n"); | ||
386 | print("ESC/q: quit\n"); | ||
387 | #ifdef MOUSEKEY_ENABLE | ||
388 | print("m: mousekey\n"); | ||
389 | #endif | ||
390 | } | ||
391 | |||
392 | static bool command_console(uint8_t code) | ||
393 | { | ||
394 | switch (code) { | ||
395 | case KC_H: | ||
396 | case KC_SLASH: /* ? */ | ||
397 | command_console_help(); | ||
398 | break; | ||
399 | case KC_Q: | ||
400 | case KC_ESC: | ||
401 | print("\nQuit Console Mode\n"); | ||
402 | command_state = ONESHOT; | ||
403 | return false; | ||
404 | #ifdef MOUSEKEY_ENABLE | ||
405 | case KC_M: | ||
406 | mousekey_console_help(); | ||
407 | print("\nEnter Mousekey Console\n"); | ||
408 | print("M0>"); | ||
409 | command_state = MOUSEKEY; | ||
410 | return true; | ||
411 | #endif | ||
412 | default: | ||
413 | print("?"); | ||
414 | return false; | ||
415 | } | ||
416 | print("C> "); | ||
417 | return true; | ||
418 | } | ||
419 | |||
420 | |||
421 | #ifdef MOUSEKEY_ENABLE | ||
422 | /*********************************************************** | ||
423 | * Mousekey console | ||
424 | ***********************************************************/ | ||
425 | static uint8_t mousekey_param = 0; | ||
426 | |||
427 | static void mousekey_param_print(void) | ||
428 | { | ||
429 | print("\n\n----- Mousekey Parameters -----\n"); | ||
430 | print("1: mk_delay(*10ms): "); pdec(mk_delay); print("\n"); | ||
431 | print("2: mk_interval(ms): "); pdec(mk_interval); print("\n"); | ||
432 | print("3: mk_max_speed: "); pdec(mk_max_speed); print("\n"); | ||
433 | print("4: mk_time_to_max: "); pdec(mk_time_to_max); print("\n"); | ||
434 | print("5: mk_wheel_max_speed: "); pdec(mk_wheel_max_speed); print("\n"); | ||
435 | print("6: mk_wheel_time_to_max: "); pdec(mk_wheel_time_to_max); print("\n"); | ||
436 | } | ||
437 | |||
438 | #define PRINT_SET_VAL(v) print(#v " = "); print_dec(v); print("\n"); | ||
439 | static void mousekey_param_inc(uint8_t param, uint8_t inc) | ||
440 | { | ||
441 | switch (param) { | ||
442 | case 1: | ||
443 | if (mk_delay + inc < UINT8_MAX) | ||
444 | mk_delay += inc; | ||
445 | else | ||
446 | mk_delay = UINT8_MAX; | ||
447 | PRINT_SET_VAL(mk_delay); | ||
448 | break; | ||
449 | case 2: | ||
450 | if (mk_interval + inc < UINT8_MAX) | ||
451 | mk_interval += inc; | ||
452 | else | ||
453 | mk_interval = UINT8_MAX; | ||
454 | PRINT_SET_VAL(mk_interval); | ||
455 | break; | ||
456 | case 3: | ||
457 | if (mk_max_speed + inc < UINT8_MAX) | ||
458 | mk_max_speed += inc; | ||
459 | else | ||
460 | mk_max_speed = UINT8_MAX; | ||
461 | PRINT_SET_VAL(mk_max_speed); | ||
462 | break; | ||
463 | case 4: | ||
464 | if (mk_time_to_max + inc < UINT8_MAX) | ||
465 | mk_time_to_max += inc; | ||
466 | else | ||
467 | mk_time_to_max = UINT8_MAX; | ||
468 | PRINT_SET_VAL(mk_time_to_max); | ||
469 | break; | ||
470 | case 5: | ||
471 | if (mk_wheel_max_speed + inc < UINT8_MAX) | ||
472 | mk_wheel_max_speed += inc; | ||
473 | else | ||
474 | mk_wheel_max_speed = UINT8_MAX; | ||
475 | PRINT_SET_VAL(mk_wheel_max_speed); | ||
476 | break; | ||
477 | case 6: | ||
478 | if (mk_wheel_time_to_max + inc < UINT8_MAX) | ||
479 | mk_wheel_time_to_max += inc; | ||
480 | else | ||
481 | mk_wheel_time_to_max = UINT8_MAX; | ||
482 | PRINT_SET_VAL(mk_wheel_time_to_max); | ||
483 | break; | ||
484 | } | ||
485 | } | ||
486 | |||
487 | static void mousekey_param_dec(uint8_t param, uint8_t dec) | ||
488 | { | ||
489 | switch (param) { | ||
490 | case 1: | ||
491 | if (mk_delay > dec) | ||
492 | mk_delay -= dec; | ||
493 | else | ||
494 | mk_delay = 0; | ||
495 | PRINT_SET_VAL(mk_delay); | ||
496 | break; | ||
497 | case 2: | ||
498 | if (mk_interval > dec) | ||
499 | mk_interval -= dec; | ||
500 | else | ||
501 | mk_interval = 0; | ||
502 | PRINT_SET_VAL(mk_interval); | ||
503 | break; | ||
504 | case 3: | ||
505 | if (mk_max_speed > dec) | ||
506 | mk_max_speed -= dec; | ||
507 | else | ||
508 | mk_max_speed = 0; | ||
509 | PRINT_SET_VAL(mk_max_speed); | ||
510 | break; | ||
511 | case 4: | ||
512 | if (mk_time_to_max > dec) | ||
513 | mk_time_to_max -= dec; | ||
514 | else | ||
515 | mk_time_to_max = 0; | ||
516 | PRINT_SET_VAL(mk_time_to_max); | ||
517 | break; | ||
518 | case 5: | ||
519 | if (mk_wheel_max_speed > dec) | ||
520 | mk_wheel_max_speed -= dec; | ||
521 | else | ||
522 | mk_wheel_max_speed = 0; | ||
523 | PRINT_SET_VAL(mk_wheel_max_speed); | ||
524 | break; | ||
525 | case 6: | ||
526 | if (mk_wheel_time_to_max > dec) | ||
527 | mk_wheel_time_to_max -= dec; | ||
528 | else | ||
529 | mk_wheel_time_to_max = 0; | ||
530 | PRINT_SET_VAL(mk_wheel_time_to_max); | ||
531 | break; | ||
532 | } | ||
533 | } | ||
534 | |||
535 | static void mousekey_console_help(void) | ||
536 | { | ||
537 | print("\n\n----- Mousekey Parameters Help -----\n"); | ||
538 | print("ESC/q: quit\n"); | ||
539 | print("1: select mk_delay(*10ms)\n"); | ||
540 | print("2: select mk_interval(ms)\n"); | ||
541 | print("3: select mk_max_speed\n"); | ||
542 | print("4: select mk_time_to_max\n"); | ||
543 | print("5: select mk_wheel_max_speed\n"); | ||
544 | print("6: select mk_wheel_time_to_max\n"); | ||
545 | print("p: print parameters\n"); | ||
546 | print("d: set default values\n"); | ||
547 | print("up: increase parameters(+1)\n"); | ||
548 | print("down: decrease parameters(-1)\n"); | ||
549 | print("pgup: increase parameters(+10)\n"); | ||
550 | print("pgdown: decrease parameters(-10)\n"); | ||
551 | print("\nspeed = delta * max_speed * (repeat / time_to_max)\n"); | ||
552 | print("where delta: cursor="); pdec(MOUSEKEY_MOVE_DELTA); | ||
553 | print(", wheel="); pdec(MOUSEKEY_WHEEL_DELTA); print("\n"); | ||
554 | print("See http://en.wikipedia.org/wiki/Mouse_keys\n"); | ||
555 | } | ||
556 | |||
557 | static bool mousekey_console(uint8_t code) | ||
558 | { | ||
559 | switch (code) { | ||
560 | case KC_H: | ||
561 | case KC_SLASH: /* ? */ | ||
562 | mousekey_console_help(); | ||
563 | break; | ||
564 | case KC_Q: | ||
565 | case KC_ESC: | ||
566 | mousekey_param = 0; | ||
567 | print("\nQuit Mousekey Console\n"); | ||
568 | print("C> "); | ||
569 | command_state = CONSOLE; | ||
570 | return false; | ||
571 | case KC_P: | ||
572 | mousekey_param_print(); | ||
573 | break; | ||
574 | case KC_1: | ||
575 | case KC_2: | ||
576 | case KC_3: | ||
577 | case KC_4: | ||
578 | case KC_5: | ||
579 | case KC_6: | ||
580 | case KC_7: | ||
581 | case KC_8: | ||
582 | case KC_9: | ||
583 | case KC_0: | ||
584 | mousekey_param = numkey2num(code); | ||
585 | print("selected parameter: "); pdec(mousekey_param); print("\n"); | ||
586 | break; | ||
587 | case KC_UP: | ||
588 | mousekey_param_inc(mousekey_param, 1); | ||
589 | break; | ||
590 | case KC_DOWN: | ||
591 | mousekey_param_dec(mousekey_param, 1); | ||
592 | break; | ||
593 | case KC_PGUP: | ||
594 | mousekey_param_inc(mousekey_param, 10); | ||
595 | break; | ||
596 | case KC_PGDN: | ||
597 | mousekey_param_dec(mousekey_param, 10); | ||
598 | break; | ||
599 | case KC_D: | ||
600 | mk_delay = MOUSEKEY_DELAY/10; | ||
601 | mk_interval = MOUSEKEY_INTERVAL; | ||
602 | mk_max_speed = MOUSEKEY_MAX_SPEED; | ||
603 | mk_time_to_max = MOUSEKEY_TIME_TO_MAX; | ||
604 | mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; | ||
605 | mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; | ||
606 | print("set default values.\n"); | ||
607 | break; | ||
608 | default: | ||
609 | print("?"); | ||
610 | return false; | ||
611 | } | ||
612 | print("M"); pdec(mousekey_param); print("> "); | ||
613 | return true; | ||
614 | } | ||
615 | #endif | ||
616 | |||
617 | |||
618 | /*********************************************************** | ||
619 | * Utilities | ||
620 | ***********************************************************/ | ||
621 | static uint8_t numkey2num(uint8_t code) | ||
622 | { | ||
623 | switch (code) { | ||
624 | case KC_1: return 1; | ||
625 | case KC_2: return 2; | ||
626 | case KC_3: return 3; | ||
627 | case KC_4: return 4; | ||
628 | case KC_5: return 5; | ||
629 | case KC_6: return 6; | ||
630 | case KC_7: return 7; | ||
631 | case KC_8: return 8; | ||
632 | case KC_9: return 9; | ||
633 | case KC_0: return 0; | ||
634 | } | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | static void switch_default_layer(uint8_t layer) | ||
639 | { | ||
640 | print("switch_default_layer: "); print_dec(biton32(default_layer_state)); | ||
641 | print(" to "); print_dec(layer); print("\n"); | ||
642 | default_layer_set(1UL<<layer); | ||
643 | clear_keyboard(); | ||
644 | } | ||
diff --git a/tmk_core/common/command.h b/tmk_core/common/command.h new file mode 100644 index 000000000..b57a6c1ce --- /dev/null +++ b/tmk_core/common/command.h | |||
@@ -0,0 +1,35 @@ | |||
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 | #ifndef COMMAND_H | ||
19 | #define COMMAND | ||
20 | |||
21 | /* TODO: Refactoring */ | ||
22 | typedef enum { ONESHOT, CONSOLE, MOUSEKEY } command_state_t; | ||
23 | extern command_state_t command_state; | ||
24 | |||
25 | /* This allows to extend commands. Return false when command is not processed. */ | ||
26 | bool command_extra(uint8_t code); | ||
27 | bool command_console_extra(uint8_t code); | ||
28 | |||
29 | #ifdef COMMAND_ENABLE | ||
30 | bool command_proc(uint8_t code); | ||
31 | #else | ||
32 | #define command_proc(code) false | ||
33 | #endif | ||
34 | |||
35 | #endif | ||
diff --git a/tmk_core/common/debug.c b/tmk_core/common/debug.c new file mode 100644 index 000000000..18613fc28 --- /dev/null +++ b/tmk_core/common/debug.c | |||
@@ -0,0 +1,24 @@ | |||
1 | #include <stdbool.h> | ||
2 | #include "debug.h" | ||
3 | |||
4 | #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) | ||
5 | |||
6 | debug_config_t debug_config = { | ||
7 | /* GCC Bug 10676 - Using unnamed fields in initializers | ||
8 | * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=10676 */ | ||
9 | #if GCC_VERSION >= 40600 | ||
10 | .enable = false, | ||
11 | .matrix = false, | ||
12 | .keyboard = false, | ||
13 | .mouse = false, | ||
14 | .reserved = 0 | ||
15 | #else | ||
16 | { | ||
17 | false, // .enable | ||
18 | false, // .matrix | ||
19 | false, // .keyboard | ||
20 | false, // .mouse | ||
21 | 0 // .reserved | ||
22 | } | ||
23 | #endif | ||
24 | }; | ||
diff --git a/tmk_core/common/debug.h b/tmk_core/common/debug.h new file mode 100644 index 000000000..3cbe2092d --- /dev/null +++ b/tmk_core/common/debug.h | |||
@@ -0,0 +1,117 @@ | |||
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 | #ifndef DEBUG_H | ||
19 | #define DEBUG_H 1 | ||
20 | |||
21 | #include <stdbool.h> | ||
22 | #include "print.h" | ||
23 | |||
24 | |||
25 | #ifdef __cplusplus | ||
26 | extern "C" { | ||
27 | #endif | ||
28 | |||
29 | /* | ||
30 | * Debug output control | ||
31 | */ | ||
32 | typedef union { | ||
33 | struct { | ||
34 | bool enable:1; | ||
35 | bool matrix:1; | ||
36 | bool keyboard:1; | ||
37 | bool mouse:1; | ||
38 | uint8_t reserved:4; | ||
39 | }; | ||
40 | uint8_t raw; | ||
41 | } debug_config_t; | ||
42 | |||
43 | extern debug_config_t debug_config; | ||
44 | |||
45 | #ifdef __cplusplus | ||
46 | } | ||
47 | #endif | ||
48 | |||
49 | /* for backward compatibility */ | ||
50 | #define debug_enable (debug_config.enable) | ||
51 | #define debug_matrix (debug_config.matrix) | ||
52 | #define debug_keyboard (debug_config.keyboard) | ||
53 | #define debug_mouse (debug_config.mouse) | ||
54 | |||
55 | |||
56 | /* | ||
57 | * Debug print utils | ||
58 | */ | ||
59 | #ifndef NO_DEBUG | ||
60 | |||
61 | #define dprint(s) do { if (debug_enable) print(s); } while (0) | ||
62 | #define dprintln(s) do { if (debug_enable) println(s); } while (0) | ||
63 | #define dprintf(fmt, ...) do { if (debug_enable) xprintf(fmt, ##__VA_ARGS__); } while (0) | ||
64 | #define dmsg(s) dprintf("%s at %s: %S\n", __FILE__, __LINE__, PSTR(s)) | ||
65 | |||
66 | /* Deprecated. DO NOT USE these anymore, use dprintf instead. */ | ||
67 | #define debug(s) do { if (debug_enable) print(s); } while (0) | ||
68 | #define debugln(s) do { if (debug_enable) println(s); } while (0) | ||
69 | #define debug_msg(s) do { \ | ||
70 | if (debug_enable) { \ | ||
71 | print(__FILE__); print(" at "); print_dec(__LINE__); print(" in "); print(": "); print(s); \ | ||
72 | } \ | ||
73 | } while (0) | ||
74 | #define debug_dec(data) do { if (debug_enable) print_dec(data); } while (0) | ||
75 | #define debug_decs(data) do { if (debug_enable) print_decs(data); } while (0) | ||
76 | #define debug_hex4(data) do { if (debug_enable) print_hex4(data); } while (0) | ||
77 | #define debug_hex8(data) do { if (debug_enable) print_hex8(data); } while (0) | ||
78 | #define debug_hex16(data) do { if (debug_enable) print_hex16(data); } while (0) | ||
79 | #define debug_hex32(data) do { if (debug_enable) print_hex32(data); } while (0) | ||
80 | #define debug_bin8(data) do { if (debug_enable) print_bin8(data); } while (0) | ||
81 | #define debug_bin16(data) do { if (debug_enable) print_bin16(data); } while (0) | ||
82 | #define debug_bin32(data) do { if (debug_enable) print_bin32(data); } while (0) | ||
83 | #define debug_bin_reverse8(data) do { if (debug_enable) print_bin_reverse8(data); } while (0) | ||
84 | #define debug_bin_reverse16(data) do { if (debug_enable) print_bin_reverse16(data); } while (0) | ||
85 | #define debug_bin_reverse32(data) do { if (debug_enable) print_bin_reverse32(data); } while (0) | ||
86 | #define debug_hex(data) debug_hex8(data) | ||
87 | #define debug_bin(data) debug_bin8(data) | ||
88 | #define debug_bin_reverse(data) debug_bin8(data) | ||
89 | |||
90 | #else /* NO_DEBUG */ | ||
91 | |||
92 | #define dprint(s) | ||
93 | #define dprintln(s) | ||
94 | #define dprintf(fmt, ...) | ||
95 | #define dmsg(s) | ||
96 | #define debug(s) | ||
97 | #define debugln(s) | ||
98 | #define debug_msg(s) | ||
99 | #define debug_dec(data) | ||
100 | #define debug_decs(data) | ||
101 | #define debug_hex4(data) | ||
102 | #define debug_hex8(data) | ||
103 | #define debug_hex16(data) | ||
104 | #define debug_hex32(data) | ||
105 | #define debug_bin8(data) | ||
106 | #define debug_bin16(data) | ||
107 | #define debug_bin32(data) | ||
108 | #define debug_bin_reverse8(data) | ||
109 | #define debug_bin_reverse16(data) | ||
110 | #define debug_bin_reverse32(data) | ||
111 | #define debug_hex(data) | ||
112 | #define debug_bin(data) | ||
113 | #define debug_bin_reverse(data) | ||
114 | |||
115 | #endif /* NO_DEBUG */ | ||
116 | |||
117 | #endif | ||
diff --git a/tmk_core/common/eeconfig.h b/tmk_core/common/eeconfig.h new file mode 100644 index 000000000..3cd1a174f --- /dev/null +++ b/tmk_core/common/eeconfig.h | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef EECONFIG_H | ||
19 | #define EECONFIG_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include <stdbool.h> | ||
23 | |||
24 | |||
25 | #define EECONFIG_MAGIC_NUMBER (uint16_t)0xFEED | ||
26 | |||
27 | /* eeprom parameteter address */ | ||
28 | #define EECONFIG_MAGIC (uint16_t *)0 | ||
29 | #define EECONFIG_DEBUG (uint8_t *)2 | ||
30 | #define EECONFIG_DEFAULT_LAYER (uint8_t *)3 | ||
31 | #define EECONFIG_KEYMAP (uint8_t *)4 | ||
32 | #define EECONFIG_MOUSEKEY_ACCEL (uint8_t *)5 | ||
33 | #define EECONFIG_BACKLIGHT (uint8_t *)6 | ||
34 | |||
35 | |||
36 | /* debug bit */ | ||
37 | #define EECONFIG_DEBUG_ENABLE (1<<0) | ||
38 | #define EECONFIG_DEBUG_MATRIX (1<<1) | ||
39 | #define EECONFIG_DEBUG_KEYBOARD (1<<2) | ||
40 | #define EECONFIG_DEBUG_MOUSE (1<<3) | ||
41 | |||
42 | /* keyconf bit */ | ||
43 | #define EECONFIG_KEYMAP_SWAP_CONTROL_CAPSLOCK (1<<0) | ||
44 | #define EECONFIG_KEYMAP_CAPSLOCK_TO_CONTROL (1<<1) | ||
45 | #define EECONFIG_KEYMAP_SWAP_LALT_LGUI (1<<2) | ||
46 | #define EECONFIG_KEYMAP_SWAP_RALT_RGUI (1<<3) | ||
47 | #define EECONFIG_KEYMAP_NO_GUI (1<<4) | ||
48 | #define EECONFIG_KEYMAP_SWAP_GRAVE_ESC (1<<5) | ||
49 | #define EECONFIG_KEYMAP_SWAP_BACKSLASH_BACKSPACE (1<<6) | ||
50 | #define EECONFIG_KEYMAP_NKRO (1<<7) | ||
51 | |||
52 | |||
53 | bool eeconfig_is_enabled(void); | ||
54 | |||
55 | void eeconfig_init(void); | ||
56 | |||
57 | void eeconfig_enable(void); | ||
58 | |||
59 | void eeconfig_disable(void); | ||
60 | |||
61 | uint8_t eeconfig_read_debug(void); | ||
62 | void eeconfig_write_debug(uint8_t val); | ||
63 | |||
64 | uint8_t eeconfig_read_default_layer(void); | ||
65 | void eeconfig_write_default_layer(uint8_t val); | ||
66 | |||
67 | uint8_t eeconfig_read_keymap(void); | ||
68 | void eeconfig_write_keymap(uint8_t val); | ||
69 | |||
70 | #ifdef BACKLIGHT_ENABLE | ||
71 | uint8_t eeconfig_read_backlight(void); | ||
72 | void eeconfig_write_backlight(uint8_t val); | ||
73 | #endif | ||
74 | |||
75 | #endif | ||
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c new file mode 100644 index 000000000..e9b791670 --- /dev/null +++ b/tmk_core/common/host.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | Copyright 2011,2012 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 <avr/interrupt.h> | ||
20 | #include "keycode.h" | ||
21 | #include "host.h" | ||
22 | #include "util.h" | ||
23 | #include "debug.h" | ||
24 | |||
25 | |||
26 | #ifdef NKRO_ENABLE | ||
27 | bool keyboard_nkro = true; | ||
28 | #endif | ||
29 | |||
30 | static host_driver_t *driver; | ||
31 | static uint16_t last_system_report = 0; | ||
32 | static uint16_t last_consumer_report = 0; | ||
33 | |||
34 | |||
35 | void host_set_driver(host_driver_t *d) | ||
36 | { | ||
37 | driver = d; | ||
38 | } | ||
39 | |||
40 | host_driver_t *host_get_driver(void) | ||
41 | { | ||
42 | return driver; | ||
43 | } | ||
44 | |||
45 | uint8_t host_keyboard_leds(void) | ||
46 | { | ||
47 | if (!driver) return 0; | ||
48 | return (*driver->keyboard_leds)(); | ||
49 | } | ||
50 | /* send report */ | ||
51 | void host_keyboard_send(report_keyboard_t *report) | ||
52 | { | ||
53 | if (!driver) return; | ||
54 | (*driver->send_keyboard)(report); | ||
55 | |||
56 | if (debug_keyboard) { | ||
57 | dprint("keyboard_report: "); | ||
58 | for (uint8_t i = 0; i < KEYBOARD_REPORT_SIZE; i++) { | ||
59 | dprintf("%02X ", report->raw[i]); | ||
60 | } | ||
61 | dprint("\n"); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | void host_mouse_send(report_mouse_t *report) | ||
66 | { | ||
67 | if (!driver) return; | ||
68 | (*driver->send_mouse)(report); | ||
69 | } | ||
70 | |||
71 | void host_system_send(uint16_t report) | ||
72 | { | ||
73 | if (report == last_system_report) return; | ||
74 | last_system_report = report; | ||
75 | |||
76 | if (!driver) return; | ||
77 | (*driver->send_system)(report); | ||
78 | } | ||
79 | |||
80 | void host_consumer_send(uint16_t report) | ||
81 | { | ||
82 | if (report == last_consumer_report) return; | ||
83 | last_consumer_report = report; | ||
84 | |||
85 | if (!driver) return; | ||
86 | (*driver->send_consumer)(report); | ||
87 | } | ||
88 | |||
89 | uint16_t host_last_sysytem_report(void) | ||
90 | { | ||
91 | return last_system_report; | ||
92 | } | ||
93 | |||
94 | uint16_t host_last_consumer_report(void) | ||
95 | { | ||
96 | return last_consumer_report; | ||
97 | } | ||
diff --git a/tmk_core/common/host.h b/tmk_core/common/host.h new file mode 100644 index 000000000..918af69e8 --- /dev/null +++ b/tmk_core/common/host.h | |||
@@ -0,0 +1,57 @@ | |||
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 | #ifndef HOST_H | ||
19 | #define HOST_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include <stdbool.h> | ||
23 | #include "report.h" | ||
24 | #include "host_driver.h" | ||
25 | |||
26 | |||
27 | #ifdef __cplusplus | ||
28 | extern "C" { | ||
29 | #endif | ||
30 | |||
31 | #ifdef NKRO_ENABLE | ||
32 | extern bool keyboard_nkro; | ||
33 | #endif | ||
34 | |||
35 | extern uint8_t keyboard_idle; | ||
36 | extern uint8_t keyboard_protocol; | ||
37 | |||
38 | |||
39 | /* host driver */ | ||
40 | void host_set_driver(host_driver_t *driver); | ||
41 | host_driver_t *host_get_driver(void); | ||
42 | |||
43 | /* host driver interface */ | ||
44 | uint8_t host_keyboard_leds(void); | ||
45 | void host_keyboard_send(report_keyboard_t *report); | ||
46 | void host_mouse_send(report_mouse_t *report); | ||
47 | void host_system_send(uint16_t data); | ||
48 | void host_consumer_send(uint16_t data); | ||
49 | |||
50 | uint16_t host_last_sysytem_report(void); | ||
51 | uint16_t host_last_consumer_report(void); | ||
52 | |||
53 | #ifdef __cplusplus | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | #endif | ||
diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h new file mode 100644 index 000000000..edb9e5dd9 --- /dev/null +++ b/tmk_core/common/host_driver.h | |||
@@ -0,0 +1,33 @@ | |||
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 | #ifndef HOST_DRIVER_H | ||
19 | #define HOST_DRIVER_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include "report.h" | ||
23 | |||
24 | |||
25 | typedef struct { | ||
26 | uint8_t (*keyboard_leds)(void); | ||
27 | void (*send_keyboard)(report_keyboard_t *); | ||
28 | void (*send_mouse)(report_mouse_t *); | ||
29 | void (*send_system)(uint16_t); | ||
30 | void (*send_consumer)(uint16_t); | ||
31 | } host_driver_t; | ||
32 | |||
33 | #endif | ||
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c new file mode 100644 index 000000000..1e3fb510a --- /dev/null +++ b/tmk_core/common/keyboard.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | Copyright 2011,2012,2013 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 | #include <stdint.h> | ||
18 | #include "keyboard.h" | ||
19 | #include "matrix.h" | ||
20 | #include "keymap.h" | ||
21 | #include "host.h" | ||
22 | #include "led.h" | ||
23 | #include "keycode.h" | ||
24 | #include "timer.h" | ||
25 | #include "print.h" | ||
26 | #include "debug.h" | ||
27 | #include "command.h" | ||
28 | #include "util.h" | ||
29 | #include "sendchar.h" | ||
30 | #include "bootmagic.h" | ||
31 | #include "eeconfig.h" | ||
32 | #include "backlight.h" | ||
33 | #ifdef MOUSEKEY_ENABLE | ||
34 | # include "mousekey.h" | ||
35 | #endif | ||
36 | #ifdef PS2_MOUSE_ENABLE | ||
37 | # include "ps2_mouse.h" | ||
38 | #endif | ||
39 | #ifdef SERIAL_MOUSE_ENABLE | ||
40 | #include "serial_mouse.h" | ||
41 | #endif | ||
42 | |||
43 | |||
44 | #ifdef MATRIX_HAS_GHOST | ||
45 | static bool has_ghost_in_row(uint8_t row) | ||
46 | { | ||
47 | matrix_row_t matrix_row = matrix_get_row(row); | ||
48 | // No ghost exists when less than 2 keys are down on the row | ||
49 | if (((matrix_row - 1) & matrix_row) == 0) | ||
50 | return false; | ||
51 | |||
52 | // Ghost occurs when the row shares column line with other row | ||
53 | for (uint8_t i=0; i < MATRIX_ROWS; i++) { | ||
54 | if (i != row && (matrix_get_row(i) & matrix_row)) | ||
55 | return true; | ||
56 | } | ||
57 | return false; | ||
58 | } | ||
59 | #endif | ||
60 | |||
61 | |||
62 | void keyboard_init(void) | ||
63 | { | ||
64 | timer_init(); | ||
65 | matrix_init(); | ||
66 | #ifdef PS2_MOUSE_ENABLE | ||
67 | ps2_mouse_init(); | ||
68 | #endif | ||
69 | #ifdef SERIAL_MOUSE_ENABLE | ||
70 | serial_mouse_init(); | ||
71 | #endif | ||
72 | |||
73 | |||
74 | #ifdef BOOTMAGIC_ENABLE | ||
75 | bootmagic(); | ||
76 | #endif | ||
77 | |||
78 | #ifdef BACKLIGHT_ENABLE | ||
79 | backlight_init(); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * Do keyboard routine jobs: scan mantrix, light LEDs, ... | ||
85 | * This is repeatedly called as fast as possible. | ||
86 | */ | ||
87 | void keyboard_task(void) | ||
88 | { | ||
89 | static matrix_row_t matrix_prev[MATRIX_ROWS]; | ||
90 | static uint8_t led_status = 0; | ||
91 | matrix_row_t matrix_row = 0; | ||
92 | matrix_row_t matrix_change = 0; | ||
93 | |||
94 | matrix_scan(); | ||
95 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | ||
96 | matrix_row = matrix_get_row(r); | ||
97 | matrix_change = matrix_row ^ matrix_prev[r]; | ||
98 | if (matrix_change) { | ||
99 | if (debug_matrix) matrix_print(); | ||
100 | #ifdef MATRIX_HAS_GHOST | ||
101 | if (has_ghost_in_row(r)) { | ||
102 | matrix_prev[r] = matrix_row; | ||
103 | continue; | ||
104 | } | ||
105 | #endif | ||
106 | for (uint8_t c = 0; c < MATRIX_COLS; c++) { | ||
107 | if (matrix_change & ((matrix_row_t)1<<c)) { | ||
108 | action_exec((keyevent_t){ | ||
109 | .key = (keypos_t){ .row = r, .col = c }, | ||
110 | .pressed = (matrix_row & ((matrix_row_t)1<<c)), | ||
111 | .time = (timer_read() | 1) /* time should not be 0 */ | ||
112 | }); | ||
113 | // record a processed key | ||
114 | matrix_prev[r] ^= ((matrix_row_t)1<<c); | ||
115 | // process a key per task call | ||
116 | goto MATRIX_LOOP_END; | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | // call with pseudo tick event when no real key event. | ||
122 | action_exec(TICK); | ||
123 | |||
124 | MATRIX_LOOP_END: | ||
125 | |||
126 | #ifdef MOUSEKEY_ENABLE | ||
127 | // mousekey repeat & acceleration | ||
128 | mousekey_task(); | ||
129 | #endif | ||
130 | |||
131 | #ifdef PS2_MOUSE_ENABLE | ||
132 | ps2_mouse_task(); | ||
133 | #endif | ||
134 | |||
135 | #ifdef SERIAL_MOUSE_ENABLE | ||
136 | serial_mouse_task(); | ||
137 | #endif | ||
138 | |||
139 | // update LED | ||
140 | if (led_status != host_keyboard_leds()) { | ||
141 | led_status = host_keyboard_leds(); | ||
142 | keyboard_set_leds(led_status); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | void keyboard_set_leds(uint8_t leds) | ||
147 | { | ||
148 | if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); } | ||
149 | led_set(leds); | ||
150 | } | ||
diff --git a/tmk_core/common/keyboard.h b/tmk_core/common/keyboard.h new file mode 100644 index 000000000..6442716fc --- /dev/null +++ b/tmk_core/common/keyboard.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | Copyright 2011,2012,2013 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 | #ifndef KEYBOARD_H | ||
19 | #define KEYBOARD_H | ||
20 | |||
21 | #include <stdbool.h> | ||
22 | #include <stdint.h> | ||
23 | |||
24 | |||
25 | #ifdef __cplusplus | ||
26 | extern "C" { | ||
27 | #endif | ||
28 | |||
29 | /* key matrix position */ | ||
30 | typedef struct { | ||
31 | uint8_t col; | ||
32 | uint8_t row; | ||
33 | } keypos_t; | ||
34 | |||
35 | /* key event */ | ||
36 | typedef struct { | ||
37 | keypos_t key; | ||
38 | bool pressed; | ||
39 | uint16_t time; | ||
40 | } keyevent_t; | ||
41 | |||
42 | /* equivalent test of keypos_t */ | ||
43 | #define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col) | ||
44 | |||
45 | /* Rules for No Event: | ||
46 | * 1) (time == 0) to handle (keyevent_t){} as empty event | ||
47 | * 2) Matrix(255, 255) to make TICK event available | ||
48 | */ | ||
49 | static inline bool IS_NOEVENT(keyevent_t event) { return event.time == 0 || (event.key.row == 255 && event.key.col == 255); } | ||
50 | static inline bool IS_PRESSED(keyevent_t event) { return (!IS_NOEVENT(event) && event.pressed); } | ||
51 | static inline bool IS_RELEASED(keyevent_t event) { return (!IS_NOEVENT(event) && !event.pressed); } | ||
52 | |||
53 | /* Tick event */ | ||
54 | #define TICK (keyevent_t){ \ | ||
55 | .key = (keypos_t){ .row = 255, .col = 255 }, \ | ||
56 | .pressed = false, \ | ||
57 | .time = (timer_read() | 1) \ | ||
58 | } | ||
59 | |||
60 | |||
61 | void keyboard_init(void); | ||
62 | void keyboard_task(void); | ||
63 | void keyboard_set_leds(uint8_t leds); | ||
64 | |||
65 | __attribute__ ((weak)) void matrix_power_up(void) {} | ||
66 | __attribute__ ((weak)) void matrix_power_down(void) {} | ||
67 | |||
68 | #ifdef __cplusplus | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | #endif | ||
diff --git a/tmk_core/common/keycode.h b/tmk_core/common/keycode.h new file mode 100644 index 000000000..ac4ef00db --- /dev/null +++ b/tmk_core/common/keycode.h | |||
@@ -0,0 +1,489 @@ | |||
1 | /* | ||
2 | Copyright 2011,2012 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 | /* | ||
19 | * Keycodes based on HID Usage Keyboard/Keypad Page(0x07) plus special codes | ||
20 | * http://www.usb.org/developers/devclass_docs/Hut1_12.pdf | ||
21 | */ | ||
22 | #ifndef KEYCODE_H | ||
23 | #define KEYCODE_H | ||
24 | |||
25 | |||
26 | #define IS_ERROR(code) (KC_ROLL_OVER <= (code) && (code) <= KC_UNDEFINED) | ||
27 | #define IS_ANY(code) (KC_A <= (code) && (code) <= 0xFF) | ||
28 | #define IS_KEY(code) (KC_A <= (code) && (code) <= KC_EXSEL) | ||
29 | #define IS_MOD(code) (KC_LCTRL <= (code) && (code) <= KC_RGUI) | ||
30 | |||
31 | |||
32 | #define IS_SPECIAL(code) ((0xA5 <= (code) && (code) <= 0xDF) || (0xE8 <= (code) && (code) <= 0xFF)) | ||
33 | #define IS_SYSTEM(code) (KC_PWR <= (code) && (code) <= KC_WAKE) | ||
34 | #define IS_CONSUMER(code) (KC_MUTE <= (code) && (code) <= KC_WFAV) | ||
35 | #define IS_FN(code) (KC_FN0 <= (code) && (code) <= KC_FN31) | ||
36 | #define IS_MOUSEKEY(code) (KC_MS_UP <= (code) && (code) <= KC_MS_ACCEL2) | ||
37 | #define IS_MOUSEKEY_MOVE(code) (KC_MS_UP <= (code) && (code) <= KC_MS_RIGHT) | ||
38 | #define IS_MOUSEKEY_BUTTON(code) (KC_MS_BTN1 <= (code) && (code) <= KC_MS_BTN5) | ||
39 | #define IS_MOUSEKEY_WHEEL(code) (KC_MS_WH_UP <= (code) && (code) <= KC_MS_WH_RIGHT) | ||
40 | #define IS_MOUSEKEY_ACCEL(code) (KC_MS_ACCEL0 <= (code) && (code) <= KC_MS_ACCEL2) | ||
41 | |||
42 | #define MOD_BIT(code) (1<<MOD_INDEX(code)) | ||
43 | #define MOD_INDEX(code) ((code) & 0x07) | ||
44 | #define FN_BIT(code) (1<<FN_INDEX(code)) | ||
45 | #define FN_INDEX(code) ((code) - KC_FN0) | ||
46 | #define FN_MIN KC_FN0 | ||
47 | #define FN_MAX KC_FN31 | ||
48 | |||
49 | |||
50 | /* | ||
51 | * Short names for ease of definition of keymap | ||
52 | */ | ||
53 | #define KC_LCTL KC_LCTRL | ||
54 | #define KC_RCTL KC_RCTRL | ||
55 | #define KC_LSFT KC_LSHIFT | ||
56 | #define KC_RSFT KC_RSHIFT | ||
57 | #define KC_ESC KC_ESCAPE | ||
58 | #define KC_BSPC KC_BSPACE | ||
59 | #define KC_ENT KC_ENTER | ||
60 | #define KC_DEL KC_DELETE | ||
61 | #define KC_INS KC_INSERT | ||
62 | #define KC_CAPS KC_CAPSLOCK | ||
63 | #define KC_CLCK KC_CAPSLOCK | ||
64 | #define KC_RGHT KC_RIGHT | ||
65 | #define KC_PGDN KC_PGDOWN | ||
66 | #define KC_PSCR KC_PSCREEN | ||
67 | #define KC_SLCK KC_SCROLLLOCK | ||
68 | #define KC_PAUS KC_PAUSE | ||
69 | #define KC_BRK KC_PAUSE | ||
70 | #define KC_NLCK KC_NUMLOCK | ||
71 | #define KC_SPC KC_SPACE | ||
72 | #define KC_MINS KC_MINUS | ||
73 | #define KC_EQL KC_EQUAL | ||
74 | #define KC_GRV KC_GRAVE | ||
75 | #define KC_RBRC KC_RBRACKET | ||
76 | #define KC_LBRC KC_LBRACKET | ||
77 | #define KC_COMM KC_COMMA | ||
78 | #define KC_BSLS KC_BSLASH | ||
79 | #define KC_SLSH KC_SLASH | ||
80 | #define KC_SCLN KC_SCOLON | ||
81 | #define KC_QUOT KC_QUOTE | ||
82 | #define KC_APP KC_APPLICATION | ||
83 | #define KC_NUHS KC_NONUS_HASH | ||
84 | #define KC_NUBS KC_NONUS_BSLASH | ||
85 | #define KC_LCAP KC_LOCKING_CAPS | ||
86 | #define KC_LNUM KC_LOCKING_NUM | ||
87 | #define KC_LSCR KC_LOCKING_SCROLL | ||
88 | #define KC_ERAS KC_ALT_ERASE, | ||
89 | #define KC_CLR KC_CLEAR | ||
90 | /* Japanese specific */ | ||
91 | #define KC_ZKHK KC_GRAVE | ||
92 | #define KC_RO KC_INT1 | ||
93 | #define KC_KANA KC_INT2 | ||
94 | #define KC_JYEN KC_INT3 | ||
95 | #define KC_HENK KC_INT4 | ||
96 | #define KC_MHEN KC_INT5 | ||
97 | /* Keypad */ | ||
98 | #define KC_P1 KC_KP_1 | ||
99 | #define KC_P2 KC_KP_2 | ||
100 | #define KC_P3 KC_KP_3 | ||
101 | #define KC_P4 KC_KP_4 | ||
102 | #define KC_P5 KC_KP_5 | ||
103 | #define KC_P6 KC_KP_6 | ||
104 | #define KC_P7 KC_KP_7 | ||
105 | #define KC_P8 KC_KP_8 | ||
106 | #define KC_P9 KC_KP_9 | ||
107 | #define KC_P0 KC_KP_0 | ||
108 | #define KC_PDOT KC_KP_DOT | ||
109 | #define KC_PCMM KC_KP_COMMA | ||
110 | #define KC_PSLS KC_KP_SLASH | ||
111 | #define KC_PAST KC_KP_ASTERISK | ||
112 | #define KC_PMNS KC_KP_MINUS | ||
113 | #define KC_PPLS KC_KP_PLUS | ||
114 | #define KC_PEQL KC_KP_EQUAL | ||
115 | #define KC_PENT KC_KP_ENTER | ||
116 | /* Mousekey */ | ||
117 | #define KC_MS_U KC_MS_UP | ||
118 | #define KC_MS_D KC_MS_DOWN | ||
119 | #define KC_MS_L KC_MS_LEFT | ||
120 | #define KC_MS_R KC_MS_RIGHT | ||
121 | #define KC_BTN1 KC_MS_BTN1 | ||
122 | #define KC_BTN2 KC_MS_BTN2 | ||
123 | #define KC_BTN3 KC_MS_BTN3 | ||
124 | #define KC_BTN4 KC_MS_BTN4 | ||
125 | #define KC_BTN5 KC_MS_BTN5 | ||
126 | #define KC_WH_U KC_MS_WH_UP | ||
127 | #define KC_WH_D KC_MS_WH_DOWN | ||
128 | #define KC_WH_L KC_MS_WH_LEFT | ||
129 | #define KC_WH_R KC_MS_WH_RIGHT | ||
130 | #define KC_ACL0 KC_MS_ACCEL0 | ||
131 | #define KC_ACL1 KC_MS_ACCEL1 | ||
132 | #define KC_ACL2 KC_MS_ACCEL2 | ||
133 | /* Sytem Control */ | ||
134 | #define KC_PWR KC_SYSTEM_POWER | ||
135 | #define KC_SLEP KC_SYSTEM_SLEEP | ||
136 | #define KC_WAKE KC_SYSTEM_WAKE | ||
137 | /* Consumer Page */ | ||
138 | #define KC_MUTE KC_AUDIO_MUTE | ||
139 | #define KC_VOLU KC_AUDIO_VOL_UP | ||
140 | #define KC_VOLD KC_AUDIO_VOL_DOWN | ||
141 | #define KC_MNXT KC_MEDIA_NEXT_TRACK | ||
142 | #define KC_MPRV KC_MEDIA_PREV_TRACK | ||
143 | #define KC_MFFD KC_MEDIA_FAST_FORWARD | ||
144 | #define KC_MRWD KC_MEDIA_REWIND | ||
145 | #define KC_MSTP KC_MEDIA_STOP | ||
146 | #define KC_MPLY KC_MEDIA_PLAY_PAUSE | ||
147 | #define KC_MSEL KC_MEDIA_SELECT | ||
148 | #define KC_EJCT KC_MEDIA_EJECT | ||
149 | #define KC_MAIL KC_MAIL | ||
150 | #define KC_CALC KC_CALCULATOR | ||
151 | #define KC_MYCM KC_MY_COMPUTER | ||
152 | #define KC_WSCH KC_WWW_SEARCH | ||
153 | #define KC_WHOM KC_WWW_HOME | ||
154 | #define KC_WBAK KC_WWW_BACK | ||
155 | #define KC_WFWD KC_WWW_FORWARD | ||
156 | #define KC_WSTP KC_WWW_STOP | ||
157 | #define KC_WREF KC_WWW_REFRESH | ||
158 | #define KC_WFAV KC_WWW_FAVORITES | ||
159 | /* Transparent */ | ||
160 | #define KC_TRANSPARENT 1 | ||
161 | #define KC_TRNS KC_TRANSPARENT | ||
162 | |||
163 | |||
164 | |||
165 | /* USB HID Keyboard/Keypad Usage(0x07) */ | ||
166 | enum hid_keyboard_keypad_usage { | ||
167 | KC_NO = 0x00, | ||
168 | KC_ROLL_OVER, | ||
169 | KC_POST_FAIL, | ||
170 | KC_UNDEFINED, | ||
171 | KC_A, | ||
172 | KC_B, | ||
173 | KC_C, | ||
174 | KC_D, | ||
175 | KC_E, | ||
176 | KC_F, | ||
177 | KC_G, | ||
178 | KC_H, | ||
179 | KC_I, | ||
180 | KC_J, | ||
181 | KC_K, | ||
182 | KC_L, | ||
183 | KC_M, /* 0x10 */ | ||
184 | KC_N, | ||
185 | KC_O, | ||
186 | KC_P, | ||
187 | KC_Q, | ||
188 | KC_R, | ||
189 | KC_S, | ||
190 | KC_T, | ||
191 | KC_U, | ||
192 | KC_V, | ||
193 | KC_W, | ||
194 | KC_X, | ||
195 | KC_Y, | ||
196 | KC_Z, | ||
197 | KC_1, | ||
198 | KC_2, | ||
199 | KC_3, /* 0x20 */ | ||
200 | KC_4, | ||
201 | KC_5, | ||
202 | KC_6, | ||
203 | KC_7, | ||
204 | KC_8, | ||
205 | KC_9, | ||
206 | KC_0, | ||
207 | KC_ENTER, | ||
208 | KC_ESCAPE, | ||
209 | KC_BSPACE, | ||
210 | KC_TAB, | ||
211 | KC_SPACE, | ||
212 | KC_MINUS, | ||
213 | KC_EQUAL, | ||
214 | KC_LBRACKET, | ||
215 | KC_RBRACKET, /* 0x30 */ | ||
216 | KC_BSLASH, /* \ (and |) */ | ||
217 | KC_NONUS_HASH, /* Non-US # and ~ */ | ||
218 | KC_SCOLON, /* ; (and :) */ | ||
219 | KC_QUOTE, /* ' and " */ | ||
220 | KC_GRAVE, /* Grave accent and tilde */ | ||
221 | KC_COMMA, /* , and < */ | ||
222 | KC_DOT, /* . and > */ | ||
223 | KC_SLASH, /* / and ? */ | ||
224 | KC_CAPSLOCK, | ||
225 | KC_F1, | ||
226 | KC_F2, | ||
227 | KC_F3, | ||
228 | KC_F4, | ||
229 | KC_F5, | ||
230 | KC_F6, | ||
231 | KC_F7, /* 0x40 */ | ||
232 | KC_F8, | ||
233 | KC_F9, | ||
234 | KC_F10, | ||
235 | KC_F11, | ||
236 | KC_F12, | ||
237 | KC_PSCREEN, | ||
238 | KC_SCROLLLOCK, | ||
239 | KC_PAUSE, | ||
240 | KC_INSERT, | ||
241 | KC_HOME, | ||
242 | KC_PGUP, | ||
243 | KC_DELETE, | ||
244 | KC_END, | ||
245 | KC_PGDOWN, | ||
246 | KC_RIGHT, | ||
247 | KC_LEFT, /* 0x50 */ | ||
248 | KC_DOWN, | ||
249 | KC_UP, | ||
250 | KC_NUMLOCK, | ||
251 | KC_KP_SLASH, | ||
252 | KC_KP_ASTERISK, | ||
253 | KC_KP_MINUS, | ||
254 | KC_KP_PLUS, | ||
255 | KC_KP_ENTER, | ||
256 | KC_KP_1, | ||
257 | KC_KP_2, | ||
258 | KC_KP_3, | ||
259 | KC_KP_4, | ||
260 | KC_KP_5, | ||
261 | KC_KP_6, | ||
262 | KC_KP_7, | ||
263 | KC_KP_8, /* 0x60 */ | ||
264 | KC_KP_9, | ||
265 | KC_KP_0, | ||
266 | KC_KP_DOT, | ||
267 | KC_NONUS_BSLASH, /* Non-US \ and | */ | ||
268 | KC_APPLICATION, | ||
269 | KC_POWER, | ||
270 | KC_KP_EQUAL, | ||
271 | KC_F13, | ||
272 | KC_F14, | ||
273 | KC_F15, | ||
274 | KC_F16, | ||
275 | KC_F17, | ||
276 | KC_F18, | ||
277 | KC_F19, | ||
278 | KC_F20, | ||
279 | KC_F21, /* 0x70 */ | ||
280 | KC_F22, | ||
281 | KC_F23, | ||
282 | KC_F24, | ||
283 | KC_EXECUTE, | ||
284 | KC_HELP, | ||
285 | KC_MENU, | ||
286 | KC_SELECT, | ||
287 | KC_STOP, | ||
288 | KC_AGAIN, | ||
289 | KC_UNDO, | ||
290 | KC_CUT, | ||
291 | KC_COPY, | ||
292 | KC_PASTE, | ||
293 | KC_FIND, | ||
294 | KC__MUTE, | ||
295 | KC__VOLUP, /* 0x80 */ | ||
296 | KC__VOLDOWN, | ||
297 | KC_LOCKING_CAPS, /* locking Caps Lock */ | ||
298 | KC_LOCKING_NUM, /* locking Num Lock */ | ||
299 | KC_LOCKING_SCROLL, /* locking Scroll Lock */ | ||
300 | KC_KP_COMMA, | ||
301 | KC_KP_EQUAL_AS400, /* equal sign on AS/400 */ | ||
302 | KC_INT1, | ||
303 | KC_INT2, | ||
304 | KC_INT3, | ||
305 | KC_INT4, | ||
306 | KC_INT5, | ||
307 | KC_INT6, | ||
308 | KC_INT7, | ||
309 | KC_INT8, | ||
310 | KC_INT9, | ||
311 | KC_LANG1, /* 0x90 */ | ||
312 | KC_LANG2, | ||
313 | KC_LANG3, | ||
314 | KC_LANG4, | ||
315 | KC_LANG5, | ||
316 | KC_LANG6, | ||
317 | KC_LANG7, | ||
318 | KC_LANG8, | ||
319 | KC_LANG9, | ||
320 | KC_ALT_ERASE, | ||
321 | KC_SYSREQ, | ||
322 | KC_CANCEL, | ||
323 | KC_CLEAR, | ||
324 | KC_PRIOR, | ||
325 | KC_RETURN, | ||
326 | KC_SEPARATOR, | ||
327 | KC_OUT, /* 0xA0 */ | ||
328 | KC_OPER, | ||
329 | KC_CLEAR_AGAIN, | ||
330 | KC_CRSEL, | ||
331 | KC_EXSEL, /* 0xA4 */ | ||
332 | |||
333 | /* NOTE: 0xA5-DF are used for internal special purpose */ | ||
334 | |||
335 | #if 0 | ||
336 | /* NOTE: Following codes(0xB0-DD) are not used. Leave them for reference. */ | ||
337 | KC_KP_00 = 0xB0, | ||
338 | KC_KP_000, | ||
339 | KC_THOUSANDS_SEPARATOR, | ||
340 | KC_DECIMAL_SEPARATOR, | ||
341 | KC_CURRENCY_UNIT, | ||
342 | KC_CURRENCY_SUB_UNIT, | ||
343 | KC_KP_LPAREN, | ||
344 | KC_KP_RPAREN, | ||
345 | KC_KP_LCBRACKET, /* { */ | ||
346 | KC_KP_RCBRACKET, /* } */ | ||
347 | KC_KP_TAB, | ||
348 | KC_KP_BSPACE, | ||
349 | KC_KP_A, | ||
350 | KC_KP_B, | ||
351 | KC_KP_C, | ||
352 | KC_KP_D, | ||
353 | KC_KP_E, /* 0xC0 */ | ||
354 | KC_KP_F, | ||
355 | KC_KP_XOR, | ||
356 | KC_KP_HAT, | ||
357 | KC_KP_PERC, | ||
358 | KC_KP_LT, | ||
359 | KC_KP_GT, | ||
360 | KC_KP_AND, | ||
361 | KC_KP_LAZYAND, | ||
362 | KC_KP_OR, | ||
363 | KC_KP_LAZYOR, | ||
364 | KC_KP_COLON, | ||
365 | KC_KP_HASH, | ||
366 | KC_KP_SPACE, | ||
367 | KC_KP_ATMARK, | ||
368 | KC_KP_EXCLAMATION, | ||
369 | KC_KP_MEM_STORE, /* 0xD0 */ | ||
370 | KC_KP_MEM_RECALL, | ||
371 | KC_KP_MEM_CLEAR, | ||
372 | KC_KP_MEM_ADD, | ||
373 | KC_KP_MEM_SUB, | ||
374 | KC_KP_MEM_MUL, | ||
375 | KC_KP_MEM_DIV, | ||
376 | KC_KP_PLUS_MINUS, | ||
377 | KC_KP_CLEAR, | ||
378 | KC_KP_CLEAR_ENTRY, | ||
379 | KC_KP_BINARY, | ||
380 | KC_KP_OCTAL, | ||
381 | KC_KP_DECIMAL, | ||
382 | KC_KP_HEXADECIMAL, /* 0xDD */ | ||
383 | #endif | ||
384 | |||
385 | /* Modifiers */ | ||
386 | KC_LCTRL = 0xE0, | ||
387 | KC_LSHIFT, | ||
388 | KC_LALT, | ||
389 | KC_LGUI, | ||
390 | KC_RCTRL, | ||
391 | KC_RSHIFT, | ||
392 | KC_RALT, | ||
393 | KC_RGUI, | ||
394 | |||
395 | /* NOTE: 0xE8-FF are used for internal special purpose */ | ||
396 | }; | ||
397 | |||
398 | /* Special keycodes */ | ||
399 | /* NOTE: 0xA5-DF and 0xE8-FF are used for internal special purpose */ | ||
400 | enum internal_special_keycodes { | ||
401 | /* System Control */ | ||
402 | KC_SYSTEM_POWER = 0xA5, | ||
403 | KC_SYSTEM_SLEEP, | ||
404 | KC_SYSTEM_WAKE, | ||
405 | |||
406 | /* Media Control */ | ||
407 | KC_AUDIO_MUTE, | ||
408 | KC_AUDIO_VOL_UP, | ||
409 | KC_AUDIO_VOL_DOWN, | ||
410 | KC_MEDIA_NEXT_TRACK, | ||
411 | KC_MEDIA_PREV_TRACK, | ||
412 | KC_MEDIA_STOP, | ||
413 | KC_MEDIA_PLAY_PAUSE, | ||
414 | KC_MEDIA_SELECT, | ||
415 | KC_MEDIA_EJECT, | ||
416 | KC_MAIL, | ||
417 | KC_CALCULATOR, | ||
418 | KC_MY_COMPUTER, | ||
419 | KC_WWW_SEARCH, | ||
420 | KC_WWW_HOME, | ||
421 | KC_WWW_BACK, | ||
422 | KC_WWW_FORWARD, | ||
423 | KC_WWW_STOP, | ||
424 | KC_WWW_REFRESH, | ||
425 | KC_WWW_FAVORITES, | ||
426 | KC_MEDIA_FAST_FORWARD, | ||
427 | KC_MEDIA_REWIND, /* 0xBC */ | ||
428 | |||
429 | /* Fn key */ | ||
430 | KC_FN0 = 0xC0, | ||
431 | KC_FN1, | ||
432 | KC_FN2, | ||
433 | KC_FN3, | ||
434 | KC_FN4, | ||
435 | KC_FN5, | ||
436 | KC_FN6, | ||
437 | KC_FN7, | ||
438 | KC_FN8, | ||
439 | KC_FN9, | ||
440 | KC_FN10, | ||
441 | KC_FN11, | ||
442 | KC_FN12, | ||
443 | KC_FN13, | ||
444 | KC_FN14, | ||
445 | KC_FN15, | ||
446 | |||
447 | KC_FN16 = 0xD0, | ||
448 | KC_FN17, | ||
449 | KC_FN18, | ||
450 | KC_FN19, | ||
451 | KC_FN20, | ||
452 | KC_FN21, | ||
453 | KC_FN22, | ||
454 | KC_FN23, | ||
455 | KC_FN24, | ||
456 | KC_FN25, | ||
457 | KC_FN26, | ||
458 | KC_FN27, | ||
459 | KC_FN28, | ||
460 | KC_FN29, | ||
461 | KC_FN30, | ||
462 | KC_FN31, /* 0xDF */ | ||
463 | |||
464 | /**************************************/ | ||
465 | /* 0xE0-E7 for Modifiers. DO NOT USE. */ | ||
466 | /**************************************/ | ||
467 | |||
468 | /* Mousekey */ | ||
469 | KC_MS_UP = 0xF0, | ||
470 | KC_MS_DOWN, | ||
471 | KC_MS_LEFT, | ||
472 | KC_MS_RIGHT, | ||
473 | KC_MS_BTN1, | ||
474 | KC_MS_BTN2, | ||
475 | KC_MS_BTN3, | ||
476 | KC_MS_BTN4, | ||
477 | KC_MS_BTN5, /* 0xF8 */ | ||
478 | /* Mousekey wheel */ | ||
479 | KC_MS_WH_UP, | ||
480 | KC_MS_WH_DOWN, | ||
481 | KC_MS_WH_LEFT, | ||
482 | KC_MS_WH_RIGHT, /* 0xFC */ | ||
483 | /* Mousekey accel */ | ||
484 | KC_MS_ACCEL0, | ||
485 | KC_MS_ACCEL1, | ||
486 | KC_MS_ACCEL2 /* 0xFF */ | ||
487 | }; | ||
488 | |||
489 | #endif /* KEYCODE_H */ | ||
diff --git a/tmk_core/common/keymap.c b/tmk_core/common/keymap.c new file mode 100644 index 000000000..4c0b61b8c --- /dev/null +++ b/tmk_core/common/keymap.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #include "keymap.h" | ||
18 | #include "report.h" | ||
19 | #include "keycode.h" | ||
20 | #include "action_layer.h" | ||
21 | #include "action.h" | ||
22 | #include "action_macro.h" | ||
23 | #include "debug.h" | ||
24 | |||
25 | |||
26 | static action_t keycode_to_action(uint8_t keycode); | ||
27 | |||
28 | |||
29 | /* converts key to action */ | ||
30 | action_t action_for_key(uint8_t layer, keypos_t key) | ||
31 | { | ||
32 | uint8_t keycode = keymap_key_to_keycode(layer, key); | ||
33 | switch (keycode) { | ||
34 | case KC_FN0 ... KC_FN31: | ||
35 | return keymap_fn_to_action(keycode); | ||
36 | #ifdef BOOTMAGIC_ENABLE | ||
37 | case KC_CAPSLOCK: | ||
38 | case KC_LOCKING_CAPS: | ||
39 | if (keymap_config.swap_control_capslock || keymap_config.capslock_to_control) { | ||
40 | return keycode_to_action(KC_LCTL); | ||
41 | } | ||
42 | return keycode_to_action(keycode); | ||
43 | case KC_LCTL: | ||
44 | if (keymap_config.swap_control_capslock) { | ||
45 | return keycode_to_action(KC_CAPSLOCK); | ||
46 | } | ||
47 | return keycode_to_action(KC_LCTL); | ||
48 | case KC_LALT: | ||
49 | if (keymap_config.swap_lalt_lgui) { | ||
50 | if (keymap_config.no_gui) { | ||
51 | return keycode_to_action(ACTION_NO); | ||
52 | } | ||
53 | return keycode_to_action(KC_LGUI); | ||
54 | } | ||
55 | return keycode_to_action(KC_LALT); | ||
56 | case KC_LGUI: | ||
57 | if (keymap_config.swap_lalt_lgui) { | ||
58 | return keycode_to_action(KC_LALT); | ||
59 | } | ||
60 | if (keymap_config.no_gui) { | ||
61 | return keycode_to_action(ACTION_NO); | ||
62 | } | ||
63 | return keycode_to_action(KC_LGUI); | ||
64 | case KC_RALT: | ||
65 | if (keymap_config.swap_ralt_rgui) { | ||
66 | if (keymap_config.no_gui) { | ||
67 | return keycode_to_action(ACTION_NO); | ||
68 | } | ||
69 | return keycode_to_action(KC_RGUI); | ||
70 | } | ||
71 | return keycode_to_action(KC_RALT); | ||
72 | case KC_RGUI: | ||
73 | if (keymap_config.swap_ralt_rgui) { | ||
74 | return keycode_to_action(KC_RALT); | ||
75 | } | ||
76 | if (keymap_config.no_gui) { | ||
77 | return keycode_to_action(ACTION_NO); | ||
78 | } | ||
79 | return keycode_to_action(KC_RGUI); | ||
80 | case KC_GRAVE: | ||
81 | if (keymap_config.swap_grave_esc) { | ||
82 | return keycode_to_action(KC_ESC); | ||
83 | } | ||
84 | return keycode_to_action(KC_GRAVE); | ||
85 | case KC_ESC: | ||
86 | if (keymap_config.swap_grave_esc) { | ||
87 | return keycode_to_action(KC_GRAVE); | ||
88 | } | ||
89 | return keycode_to_action(KC_ESC); | ||
90 | case KC_BSLASH: | ||
91 | if (keymap_config.swap_backslash_backspace) { | ||
92 | return keycode_to_action(KC_BSPACE); | ||
93 | } | ||
94 | return keycode_to_action(KC_BSLASH); | ||
95 | case KC_BSPACE: | ||
96 | if (keymap_config.swap_backslash_backspace) { | ||
97 | return keycode_to_action(KC_BSLASH); | ||
98 | } | ||
99 | return keycode_to_action(KC_BSPACE); | ||
100 | #endif | ||
101 | default: | ||
102 | return keycode_to_action(keycode); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | |||
107 | /* Macro */ | ||
108 | __attribute__ ((weak)) | ||
109 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
110 | { | ||
111 | return MACRO_NONE; | ||
112 | } | ||
113 | |||
114 | /* Function */ | ||
115 | __attribute__ ((weak)) | ||
116 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
117 | { | ||
118 | } | ||
119 | |||
120 | |||
121 | |||
122 | /* translates keycode to action */ | ||
123 | static action_t keycode_to_action(uint8_t keycode) | ||
124 | { | ||
125 | action_t action; | ||
126 | switch (keycode) { | ||
127 | case KC_A ... KC_EXSEL: | ||
128 | case KC_LCTRL ... KC_RGUI: | ||
129 | action.code = ACTION_KEY(keycode); | ||
130 | break; | ||
131 | case KC_SYSTEM_POWER ... KC_SYSTEM_WAKE: | ||
132 | action.code = ACTION_USAGE_SYSTEM(KEYCODE2SYSTEM(keycode)); | ||
133 | break; | ||
134 | case KC_AUDIO_MUTE ... KC_WWW_FAVORITES: | ||
135 | action.code = ACTION_USAGE_CONSUMER(KEYCODE2CONSUMER(keycode)); | ||
136 | break; | ||
137 | case KC_MS_UP ... KC_MS_ACCEL2: | ||
138 | action.code = ACTION_MOUSEKEY(keycode); | ||
139 | break; | ||
140 | case KC_TRNS: | ||
141 | action.code = ACTION_TRANSPARENT; | ||
142 | break; | ||
143 | default: | ||
144 | action.code = ACTION_NO; | ||
145 | break; | ||
146 | } | ||
147 | return action; | ||
148 | } | ||
149 | |||
150 | |||
151 | |||
152 | #ifdef USE_LEGACY_KEYMAP | ||
153 | /* | ||
154 | * Legacy keymap support | ||
155 | * Consider using new keymap API instead. | ||
156 | */ | ||
157 | __attribute__ ((weak)) | ||
158 | uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key) | ||
159 | { | ||
160 | return keymap_get_keycode(layer, key.row, key.col); | ||
161 | } | ||
162 | |||
163 | |||
164 | /* Legacy keymap support */ | ||
165 | __attribute__ ((weak)) | ||
166 | action_t keymap_fn_to_action(uint8_t keycode) | ||
167 | { | ||
168 | action_t action = { .code = ACTION_NO }; | ||
169 | switch (keycode) { | ||
170 | case KC_FN0 ... KC_FN31: | ||
171 | { | ||
172 | uint8_t layer = keymap_fn_layer(FN_INDEX(keycode)); | ||
173 | uint8_t key = keymap_fn_keycode(FN_INDEX(keycode)); | ||
174 | if (key) { | ||
175 | action.code = ACTION_LAYER_TAP_KEY(layer, key); | ||
176 | } else { | ||
177 | action.code = ACTION_LAYER_MOMENTARY(layer); | ||
178 | } | ||
179 | } | ||
180 | return action; | ||
181 | default: | ||
182 | return action; | ||
183 | } | ||
184 | } | ||
185 | #endif | ||
diff --git a/tmk_core/common/keymap.h b/tmk_core/common/keymap.h new file mode 100644 index 000000000..e1a6f992e --- /dev/null +++ b/tmk_core/common/keymap.h | |||
@@ -0,0 +1,71 @@ | |||
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 | #ifndef KEYMAP_H | ||
19 | #define KEYMAP_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include <stdbool.h> | ||
23 | #include "action.h" | ||
24 | |||
25 | |||
26 | #ifdef BOOTMAGIC_ENABLE | ||
27 | /* NOTE: Not portable. Bit field order depends on implementation */ | ||
28 | typedef union { | ||
29 | uint8_t raw; | ||
30 | struct { | ||
31 | bool swap_control_capslock:1; | ||
32 | bool capslock_to_control:1; | ||
33 | bool swap_lalt_lgui:1; | ||
34 | bool swap_ralt_rgui:1; | ||
35 | bool no_gui:1; | ||
36 | bool swap_grave_esc:1; | ||
37 | bool swap_backslash_backspace:1; | ||
38 | bool nkro:1; | ||
39 | }; | ||
40 | } keymap_config_t; | ||
41 | keymap_config_t keymap_config; | ||
42 | #endif | ||
43 | |||
44 | |||
45 | /* translates key to keycode */ | ||
46 | uint8_t keymap_key_to_keycode(uint8_t layer, keypos_t key); | ||
47 | |||
48 | /* translates Fn keycode to action */ | ||
49 | action_t keymap_fn_to_action(uint8_t keycode); | ||
50 | |||
51 | |||
52 | |||
53 | #ifdef USE_LEGACY_KEYMAP | ||
54 | /* | ||
55 | * Legacy keymap | ||
56 | * Consider using new keymap API above instead. | ||
57 | */ | ||
58 | /* keycode of key */ | ||
59 | __attribute__ ((deprecated)) | ||
60 | uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col); | ||
61 | |||
62 | /* layer to move during press Fn key */ | ||
63 | __attribute__ ((deprecated)) | ||
64 | uint8_t keymap_fn_layer(uint8_t fn_bits); | ||
65 | |||
66 | /* keycode to send when release Fn key without using */ | ||
67 | __attribute__ ((deprecated)) | ||
68 | uint8_t keymap_fn_keycode(uint8_t fn_bits); | ||
69 | #endif | ||
70 | |||
71 | #endif | ||
diff --git a/tmk_core/common/led.h b/tmk_core/common/led.h new file mode 100644 index 000000000..402a247b9 --- /dev/null +++ b/tmk_core/common/led.h | |||
@@ -0,0 +1,33 @@ | |||
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 | #ifndef LED_H | ||
19 | #define LED_H | ||
20 | #include "stdint.h" | ||
21 | |||
22 | |||
23 | /* keyboard LEDs */ | ||
24 | #define USB_LED_NUM_LOCK 0 | ||
25 | #define USB_LED_CAPS_LOCK 1 | ||
26 | #define USB_LED_SCROLL_LOCK 2 | ||
27 | #define USB_LED_COMPOSE 3 | ||
28 | #define USB_LED_KANA 4 | ||
29 | |||
30 | |||
31 | void led_set(uint8_t usb_led); | ||
32 | |||
33 | #endif | ||
diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h new file mode 100644 index 000000000..107ee7265 --- /dev/null +++ b/tmk_core/common/matrix.h | |||
@@ -0,0 +1,68 @@ | |||
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 | #ifndef MATRIX_H | ||
19 | #define MATRIX_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include <stdbool.h> | ||
23 | |||
24 | |||
25 | #if (MATRIX_COLS <= 8) | ||
26 | typedef uint8_t matrix_row_t; | ||
27 | #elif (MATRIX_COLS <= 16) | ||
28 | typedef uint16_t matrix_row_t; | ||
29 | #elif (MATRIX_COLS <= 32) | ||
30 | typedef uint32_t matrix_row_t; | ||
31 | #else | ||
32 | #error "MATRIX_COLS: invalid value" | ||
33 | #endif | ||
34 | |||
35 | #define MATRIX_IS_ON(row, col) (matrix_get_row(row) && (1<<col)) | ||
36 | |||
37 | |||
38 | #ifdef __cplusplus | ||
39 | extern "C" { | ||
40 | #endif | ||
41 | |||
42 | /* number of matrix rows */ | ||
43 | uint8_t matrix_rows(void); | ||
44 | /* number of matrix columns */ | ||
45 | uint8_t matrix_cols(void); | ||
46 | /* intialize matrix for scaning. should be called once. */ | ||
47 | void matrix_init(void); | ||
48 | /* scan all key states on matrix */ | ||
49 | uint8_t matrix_scan(void); | ||
50 | /* whether modified from previous scan. used after matrix_scan. */ | ||
51 | bool matrix_is_modified(void) __attribute__ ((deprecated)); | ||
52 | /* whether a swtich is on */ | ||
53 | bool matrix_is_on(uint8_t row, uint8_t col); | ||
54 | /* matrix state on row */ | ||
55 | matrix_row_t matrix_get_row(uint8_t row); | ||
56 | /* print matrix for debug */ | ||
57 | void matrix_print(void); | ||
58 | |||
59 | |||
60 | /* power control */ | ||
61 | void matrix_power_up(void); | ||
62 | void matrix_power_down(void); | ||
63 | |||
64 | #ifdef __cplusplus | ||
65 | } | ||
66 | #endif | ||
67 | |||
68 | #endif | ||
diff --git a/tmk_core/common/mbed/bootloader.c b/tmk_core/common/mbed/bootloader.c new file mode 100644 index 000000000..b51e83943 --- /dev/null +++ b/tmk_core/common/mbed/bootloader.c | |||
@@ -0,0 +1,4 @@ | |||
1 | #include "bootloader.h" | ||
2 | |||
3 | |||
4 | void bootloader_jump(void) {} | ||
diff --git a/tmk_core/common/mbed/suspend.c b/tmk_core/common/mbed/suspend.c new file mode 100644 index 000000000..32651574f --- /dev/null +++ b/tmk_core/common/mbed/suspend.c | |||
@@ -0,0 +1,6 @@ | |||
1 | #include <stdbool.h> | ||
2 | |||
3 | |||
4 | void suspend_power_down(void) {} | ||
5 | bool suspend_wakeup_condition(void) { return true; } | ||
6 | void suspend_wakeup_init(void) {} | ||
diff --git a/tmk_core/common/mbed/timer.c b/tmk_core/common/mbed/timer.c new file mode 100644 index 000000000..c357ceb78 --- /dev/null +++ b/tmk_core/common/mbed/timer.c | |||
@@ -0,0 +1,41 @@ | |||
1 | #include "cmsis.h" | ||
2 | #include "timer.h" | ||
3 | |||
4 | /* Mill second tick count */ | ||
5 | volatile uint32_t timer_count = 0; | ||
6 | |||
7 | /* Timer interrupt handler */ | ||
8 | void SysTick_Handler(void) { | ||
9 | timer_count++; | ||
10 | } | ||
11 | |||
12 | void timer_init(void) | ||
13 | { | ||
14 | timer_count = 0; | ||
15 | SysTick_Config(SystemCoreClock / 1000); /* 1ms tick */ | ||
16 | } | ||
17 | |||
18 | void timer_clear(void) | ||
19 | { | ||
20 | timer_count = 0; | ||
21 | } | ||
22 | |||
23 | uint16_t timer_read(void) | ||
24 | { | ||
25 | return (uint16_t)(timer_count & 0xFFFF); | ||
26 | } | ||
27 | |||
28 | uint32_t timer_read32(void) | ||
29 | { | ||
30 | return timer_count; | ||
31 | } | ||
32 | |||
33 | uint16_t timer_elapsed(uint16_t last) | ||
34 | { | ||
35 | return TIMER_DIFF_16(timer_read(), last); | ||
36 | } | ||
37 | |||
38 | uint32_t timer_elapsed32(uint32_t last) | ||
39 | { | ||
40 | return TIMER_DIFF_32(timer_read32(), last); | ||
41 | } | ||
diff --git a/tmk_core/common/mbed/xprintf.cpp b/tmk_core/common/mbed/xprintf.cpp new file mode 100644 index 000000000..3647ece75 --- /dev/null +++ b/tmk_core/common/mbed/xprintf.cpp | |||
@@ -0,0 +1,51 @@ | |||
1 | #include <cstdarg> | ||
2 | //#include <stdarg.h> | ||
3 | #include "mbed.h" | ||
4 | #include "mbed/xprintf.h" | ||
5 | |||
6 | |||
7 | #define STRING_STACK_LIMIT 120 | ||
8 | |||
9 | //TODO | ||
10 | int xprintf(const char* format, ...) { return 0; } | ||
11 | |||
12 | #if 0 | ||
13 | /* mbed Serial */ | ||
14 | Serial ser(UART_TX, UART_RX); | ||
15 | |||
16 | /* TODO: Need small implementation for embedded */ | ||
17 | int xprintf(const char* format, ...) | ||
18 | { | ||
19 | /* copy from mbed/common/RawSerial.cpp */ | ||
20 | std::va_list arg; | ||
21 | va_start(arg, format); | ||
22 | int len = vsnprintf(NULL, 0, format, arg); | ||
23 | if (len < STRING_STACK_LIMIT) { | ||
24 | char temp[STRING_STACK_LIMIT]; | ||
25 | vsprintf(temp, format, arg); | ||
26 | ser.puts(temp); | ||
27 | } else { | ||
28 | char *temp = new char[len + 1]; | ||
29 | vsprintf(temp, format, arg); | ||
30 | ser.puts(temp); | ||
31 | delete[] temp; | ||
32 | } | ||
33 | va_end(arg); | ||
34 | return len; | ||
35 | |||
36 | /* Fail: __builtin_va_arg_pack? | ||
37 | * https://gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/Constructing-Calls.html#Constructing-Calls | ||
38 | void *arg = __builtin_apply_args(); | ||
39 | void *ret = __builtin_apply((void*)(&(ser.printf)), arg, 100); | ||
40 | __builtin_return(ret) | ||
41 | */ | ||
42 | /* Fail: varargs can not be passed to printf | ||
43 | //int r = ser.printf("test %i\r\n", 123); | ||
44 | va_list arg; | ||
45 | va_start(arg, format); | ||
46 | int r = ser.printf(format, arg); | ||
47 | va_end(arg); | ||
48 | return r; | ||
49 | */ | ||
50 | } | ||
51 | #endif | ||
diff --git a/tmk_core/common/mbed/xprintf.h b/tmk_core/common/mbed/xprintf.h new file mode 100644 index 000000000..26bc529e5 --- /dev/null +++ b/tmk_core/common/mbed/xprintf.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef XPRINTF_H | ||
2 | #define XPRINTF_H | ||
3 | |||
4 | //#define xprintf(format, ...) __xprintf(format, ##__VA_ARGS__) | ||
5 | |||
6 | #ifdef __cplusplus | ||
7 | extern "C" { | ||
8 | #endif | ||
9 | |||
10 | int xprintf(const char *format, ...); | ||
11 | |||
12 | #ifdef __cplusplus | ||
13 | } | ||
14 | #endif | ||
15 | |||
16 | |||
17 | #endif | ||
diff --git a/tmk_core/common/mousekey.c b/tmk_core/common/mousekey.c new file mode 100644 index 000000000..23469476e --- /dev/null +++ b/tmk_core/common/mousekey.c | |||
@@ -0,0 +1,196 @@ | |||
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 "keycode.h" | ||
20 | #include "host.h" | ||
21 | #include "timer.h" | ||
22 | #include "print.h" | ||
23 | #include "debug.h" | ||
24 | #include "mousekey.h" | ||
25 | |||
26 | |||
27 | |||
28 | static report_mouse_t mouse_report = {}; | ||
29 | static uint8_t mousekey_repeat = 0; | ||
30 | static uint8_t mousekey_accel = 0; | ||
31 | |||
32 | static void mousekey_debug(void); | ||
33 | |||
34 | |||
35 | /* | ||
36 | * Mouse keys acceleration algorithm | ||
37 | * http://en.wikipedia.org/wiki/Mouse_keys | ||
38 | * | ||
39 | * speed = delta * max_speed * (repeat / time_to_max)**((1000+curve)/1000) | ||
40 | */ | ||
41 | /* milliseconds between the initial key press and first repeated motion event (0-2550) */ | ||
42 | uint8_t mk_delay = MOUSEKEY_DELAY/10; | ||
43 | /* milliseconds between repeated motion events (0-255) */ | ||
44 | uint8_t mk_interval = MOUSEKEY_INTERVAL; | ||
45 | /* steady speed (in action_delta units) applied each event (0-255) */ | ||
46 | uint8_t mk_max_speed = MOUSEKEY_MAX_SPEED; | ||
47 | /* number of events (count) accelerating to steady speed (0-255) */ | ||
48 | uint8_t mk_time_to_max = MOUSEKEY_TIME_TO_MAX; | ||
49 | /* ramp used to reach maximum pointer speed (NOT SUPPORTED) */ | ||
50 | //int8_t mk_curve = 0; | ||
51 | /* wheel params */ | ||
52 | uint8_t mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED; | ||
53 | uint8_t mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX; | ||
54 | |||
55 | |||
56 | static uint16_t last_timer = 0; | ||
57 | |||
58 | |||
59 | static uint8_t move_unit(void) | ||
60 | { | ||
61 | uint16_t unit; | ||
62 | if (mousekey_accel & (1<<0)) { | ||
63 | unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed)/4; | ||
64 | } else if (mousekey_accel & (1<<1)) { | ||
65 | unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed)/2; | ||
66 | } else if (mousekey_accel & (1<<2)) { | ||
67 | unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed); | ||
68 | } else if (mousekey_repeat == 0) { | ||
69 | unit = MOUSEKEY_MOVE_DELTA; | ||
70 | } else if (mousekey_repeat >= mk_time_to_max) { | ||
71 | unit = MOUSEKEY_MOVE_DELTA * mk_max_speed; | ||
72 | } else { | ||
73 | unit = (MOUSEKEY_MOVE_DELTA * mk_max_speed * mousekey_repeat) / mk_time_to_max; | ||
74 | } | ||
75 | return (unit > MOUSEKEY_MOVE_MAX ? MOUSEKEY_MOVE_MAX : (unit == 0 ? 1 : unit)); | ||
76 | } | ||
77 | |||
78 | static uint8_t wheel_unit(void) | ||
79 | { | ||
80 | uint16_t unit; | ||
81 | if (mousekey_accel & (1<<0)) { | ||
82 | unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed)/4; | ||
83 | } else if (mousekey_accel & (1<<1)) { | ||
84 | unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed)/2; | ||
85 | } else if (mousekey_accel & (1<<2)) { | ||
86 | unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed); | ||
87 | } else if (mousekey_repeat == 0) { | ||
88 | unit = MOUSEKEY_WHEEL_DELTA; | ||
89 | } else if (mousekey_repeat >= mk_wheel_time_to_max) { | ||
90 | unit = MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed; | ||
91 | } else { | ||
92 | unit = (MOUSEKEY_WHEEL_DELTA * mk_wheel_max_speed * mousekey_repeat) / mk_wheel_time_to_max; | ||
93 | } | ||
94 | return (unit > MOUSEKEY_WHEEL_MAX ? MOUSEKEY_WHEEL_MAX : (unit == 0 ? 1 : unit)); | ||
95 | } | ||
96 | |||
97 | void mousekey_task(void) | ||
98 | { | ||
99 | if (timer_elapsed(last_timer) < (mousekey_repeat ? mk_interval : mk_delay*10)) | ||
100 | return; | ||
101 | |||
102 | if (mouse_report.x == 0 && mouse_report.y == 0 && mouse_report.v == 0 && mouse_report.h == 0) | ||
103 | return; | ||
104 | |||
105 | if (mousekey_repeat != UINT8_MAX) | ||
106 | mousekey_repeat++; | ||
107 | |||
108 | |||
109 | if (mouse_report.x > 0) mouse_report.x = move_unit(); | ||
110 | if (mouse_report.x < 0) mouse_report.x = move_unit() * -1; | ||
111 | if (mouse_report.y > 0) mouse_report.y = move_unit(); | ||
112 | if (mouse_report.y < 0) mouse_report.y = move_unit() * -1; | ||
113 | |||
114 | /* diagonal move [1/sqrt(2) = 0.7] */ | ||
115 | if (mouse_report.x && mouse_report.y) { | ||
116 | mouse_report.x *= 0.7; | ||
117 | mouse_report.y *= 0.7; | ||
118 | } | ||
119 | |||
120 | if (mouse_report.v > 0) mouse_report.v = wheel_unit(); | ||
121 | if (mouse_report.v < 0) mouse_report.v = wheel_unit() * -1; | ||
122 | if (mouse_report.h > 0) mouse_report.h = wheel_unit(); | ||
123 | if (mouse_report.h < 0) mouse_report.h = wheel_unit() * -1; | ||
124 | |||
125 | mousekey_send(); | ||
126 | } | ||
127 | |||
128 | void mousekey_on(uint8_t code) | ||
129 | { | ||
130 | if (code == KC_MS_UP) mouse_report.y = move_unit() * -1; | ||
131 | else if (code == KC_MS_DOWN) mouse_report.y = move_unit(); | ||
132 | else if (code == KC_MS_LEFT) mouse_report.x = move_unit() * -1; | ||
133 | else if (code == KC_MS_RIGHT) mouse_report.x = move_unit(); | ||
134 | else if (code == KC_MS_WH_UP) mouse_report.v = wheel_unit(); | ||
135 | else if (code == KC_MS_WH_DOWN) mouse_report.v = wheel_unit() * -1; | ||
136 | else if (code == KC_MS_WH_LEFT) mouse_report.h = wheel_unit() * -1; | ||
137 | else if (code == KC_MS_WH_RIGHT) mouse_report.h = wheel_unit(); | ||
138 | else if (code == KC_MS_BTN1) mouse_report.buttons |= MOUSE_BTN1; | ||
139 | else if (code == KC_MS_BTN2) mouse_report.buttons |= MOUSE_BTN2; | ||
140 | else if (code == KC_MS_BTN3) mouse_report.buttons |= MOUSE_BTN3; | ||
141 | else if (code == KC_MS_BTN4) mouse_report.buttons |= MOUSE_BTN4; | ||
142 | else if (code == KC_MS_BTN5) mouse_report.buttons |= MOUSE_BTN5; | ||
143 | else if (code == KC_MS_ACCEL0) mousekey_accel |= (1<<0); | ||
144 | else if (code == KC_MS_ACCEL1) mousekey_accel |= (1<<1); | ||
145 | else if (code == KC_MS_ACCEL2) mousekey_accel |= (1<<2); | ||
146 | } | ||
147 | |||
148 | void mousekey_off(uint8_t code) | ||
149 | { | ||
150 | if (code == KC_MS_UP && mouse_report.y < 0) mouse_report.y = 0; | ||
151 | else if (code == KC_MS_DOWN && mouse_report.y > 0) mouse_report.y = 0; | ||
152 | else if (code == KC_MS_LEFT && mouse_report.x < 0) mouse_report.x = 0; | ||
153 | else if (code == KC_MS_RIGHT && mouse_report.x > 0) mouse_report.x = 0; | ||
154 | else if (code == KC_MS_WH_UP && mouse_report.v > 0) mouse_report.v = 0; | ||
155 | else if (code == KC_MS_WH_DOWN && mouse_report.v < 0) mouse_report.v = 0; | ||
156 | else if (code == KC_MS_WH_LEFT && mouse_report.h < 0) mouse_report.h = 0; | ||
157 | else if (code == KC_MS_WH_RIGHT && mouse_report.h > 0) mouse_report.h = 0; | ||
158 | else if (code == KC_MS_BTN1) mouse_report.buttons &= ~MOUSE_BTN1; | ||
159 | else if (code == KC_MS_BTN2) mouse_report.buttons &= ~MOUSE_BTN2; | ||
160 | else if (code == KC_MS_BTN3) mouse_report.buttons &= ~MOUSE_BTN3; | ||
161 | else if (code == KC_MS_BTN4) mouse_report.buttons &= ~MOUSE_BTN4; | ||
162 | else if (code == KC_MS_BTN5) mouse_report.buttons &= ~MOUSE_BTN5; | ||
163 | else if (code == KC_MS_ACCEL0) mousekey_accel &= ~(1<<0); | ||
164 | else if (code == KC_MS_ACCEL1) mousekey_accel &= ~(1<<1); | ||
165 | else if (code == KC_MS_ACCEL2) mousekey_accel &= ~(1<<2); | ||
166 | |||
167 | if (mouse_report.x == 0 && mouse_report.y == 0 && mouse_report.v == 0 && mouse_report.h == 0) | ||
168 | mousekey_repeat = 0; | ||
169 | } | ||
170 | |||
171 | void mousekey_send(void) | ||
172 | { | ||
173 | mousekey_debug(); | ||
174 | host_mouse_send(&mouse_report); | ||
175 | last_timer = timer_read(); | ||
176 | } | ||
177 | |||
178 | void mousekey_clear(void) | ||
179 | { | ||
180 | mouse_report = (report_mouse_t){}; | ||
181 | mousekey_repeat = 0; | ||
182 | mousekey_accel = 0; | ||
183 | } | ||
184 | |||
185 | static void mousekey_debug(void) | ||
186 | { | ||
187 | if (!debug_mouse) return; | ||
188 | print("mousekey [btn|x y v h](rep/acl): ["); | ||
189 | phex(mouse_report.buttons); print("|"); | ||
190 | print_decs(mouse_report.x); print(" "); | ||
191 | print_decs(mouse_report.y); print(" "); | ||
192 | print_decs(mouse_report.v); print(" "); | ||
193 | print_decs(mouse_report.h); print("]("); | ||
194 | print_dec(mousekey_repeat); print("/"); | ||
195 | print_dec(mousekey_accel); print(")\n"); | ||
196 | } | ||
diff --git a/tmk_core/common/mousekey.h b/tmk_core/common/mousekey.h new file mode 100644 index 000000000..6eede06b4 --- /dev/null +++ b/tmk_core/common/mousekey.h | |||
@@ -0,0 +1,77 @@ | |||
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 | #ifndef MOUSEKEY_H | ||
19 | #define MOUSEKEY_H | ||
20 | |||
21 | #include <stdbool.h> | ||
22 | #include "host.h" | ||
23 | |||
24 | |||
25 | /* max value on report descriptor */ | ||
26 | #define MOUSEKEY_MOVE_MAX 127 | ||
27 | #define MOUSEKEY_WHEEL_MAX 127 | ||
28 | |||
29 | #ifndef MOUSEKEY_MOVE_DELTA | ||
30 | #define MOUSEKEY_MOVE_DELTA 5 | ||
31 | #endif | ||
32 | #ifndef MOUSEKEY_WHEEL_DELTA | ||
33 | #define MOUSEKEY_WHEEL_DELTA 1 | ||
34 | #endif | ||
35 | #ifndef MOUSEKEY_DELAY | ||
36 | #define MOUSEKEY_DELAY 300 | ||
37 | #endif | ||
38 | #ifndef MOUSEKEY_INTERVAL | ||
39 | #define MOUSEKEY_INTERVAL 50 | ||
40 | #endif | ||
41 | #ifndef MOUSEKEY_MAX_SPEED | ||
42 | #define MOUSEKEY_MAX_SPEED 10 | ||
43 | #endif | ||
44 | #ifndef MOUSEKEY_TIME_TO_MAX | ||
45 | #define MOUSEKEY_TIME_TO_MAX 20 | ||
46 | #endif | ||
47 | #ifndef MOUSEKEY_WHEEL_MAX_SPEED | ||
48 | #define MOUSEKEY_WHEEL_MAX_SPEED 8 | ||
49 | #endif | ||
50 | #ifndef MOUSEKEY_WHEEL_TIME_TO_MAX | ||
51 | #define MOUSEKEY_WHEEL_TIME_TO_MAX 40 | ||
52 | #endif | ||
53 | |||
54 | |||
55 | #ifdef __cplusplus | ||
56 | extern "C" { | ||
57 | #endif | ||
58 | |||
59 | extern uint8_t mk_delay; | ||
60 | extern uint8_t mk_interval; | ||
61 | extern uint8_t mk_max_speed; | ||
62 | extern uint8_t mk_time_to_max; | ||
63 | extern uint8_t mk_wheel_max_speed; | ||
64 | extern uint8_t mk_wheel_time_to_max; | ||
65 | |||
66 | |||
67 | void mousekey_task(void); | ||
68 | void mousekey_on(uint8_t code); | ||
69 | void mousekey_off(uint8_t code); | ||
70 | void mousekey_clear(void); | ||
71 | void mousekey_send(void); | ||
72 | |||
73 | #ifdef __cplusplus | ||
74 | } | ||
75 | #endif | ||
76 | |||
77 | #endif | ||
diff --git a/tmk_core/common/nodebug.h b/tmk_core/common/nodebug.h new file mode 100644 index 000000000..93309ada4 --- /dev/null +++ b/tmk_core/common/nodebug.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | Copyright 2013 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 | #ifndef NODEBUG_H | ||
19 | #define NODEBUG_H 1 | ||
20 | |||
21 | #define NO_DEBUG | ||
22 | #include "debug.h" | ||
23 | #undef NO_DEBUG | ||
24 | |||
25 | #endif | ||
diff --git a/tmk_core/common/print.c b/tmk_core/common/print.c new file mode 100644 index 000000000..ca94e1e5d --- /dev/null +++ b/tmk_core/common/print.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* Copyright 2012,2013 Jun Wako <wakojun@gmail.com> */ | ||
2 | /* Very basic print functions, intended to be used with usb_debug_only.c | ||
3 | * http://www.pjrc.com/teensy/ | ||
4 | * Copyright (c) 2008 PJRC.COM, LLC | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #include <stdint.h> | ||
26 | #include "print.h" | ||
27 | |||
28 | |||
29 | #ifndef NO_PRINT | ||
30 | |||
31 | #if defined(__AVR__) | ||
32 | |||
33 | #define sendchar(c) xputc(c) | ||
34 | |||
35 | |||
36 | void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) | ||
37 | { | ||
38 | xdev_out(sendchar_func); | ||
39 | } | ||
40 | |||
41 | #elif defined(__arm__) | ||
42 | |||
43 | // TODO | ||
44 | //void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { } | ||
45 | |||
46 | #endif | ||
47 | |||
48 | #endif | ||
diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h new file mode 100644 index 000000000..c0e9e1430 --- /dev/null +++ b/tmk_core/common/print.h | |||
@@ -0,0 +1,137 @@ | |||
1 | /* Copyright 2012 Jun Wako <wakojun@gmail.com> */ | ||
2 | /* Very basic print functions, intended to be used with usb_debug_only.c | ||
3 | * http://www.pjrc.com/teensy/ | ||
4 | * Copyright (c) 2008 PJRC.COM, LLC | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | * of this software and associated documentation files (the "Software"), to deal | ||
8 | * in the Software without restriction, including without limitation the rights | ||
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | * copies of the Software, and to permit persons to whom the Software is | ||
11 | * furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | * THE SOFTWARE. | ||
23 | */ | ||
24 | |||
25 | #ifndef PRINT_H__ | ||
26 | #define PRINT_H__ 1 | ||
27 | |||
28 | #include <stdint.h> | ||
29 | #include <stdbool.h> | ||
30 | #include "util.h" | ||
31 | |||
32 | |||
33 | |||
34 | |||
35 | #ifndef NO_PRINT | ||
36 | |||
37 | |||
38 | #if defined(__AVR__) | ||
39 | |||
40 | #include "avr/xprintf.h" | ||
41 | #define print(s) xputs(PSTR(s)) | ||
42 | #define println(s) xputs(PSTR(s "\r\n")) | ||
43 | |||
44 | #ifdef __cplusplus | ||
45 | extern "C" | ||
46 | #endif | ||
47 | /* function pointer of sendchar to be used by print utility */ | ||
48 | void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t)); | ||
49 | |||
50 | #elif defined(__arm__) | ||
51 | |||
52 | #include "mbed/xprintf.h" | ||
53 | |||
54 | #define print(s) xprintf(s) | ||
55 | #define println(s) xprintf(s "\r\n") | ||
56 | |||
57 | /* TODO: to select output destinations: UART/USBSerial */ | ||
58 | #define print_set_sendchar(func) | ||
59 | |||
60 | #endif /* __AVR__ */ | ||
61 | |||
62 | |||
63 | /* decimal */ | ||
64 | #define print_dec(i) xprintf("%u", i) | ||
65 | #define print_decs(i) xprintf("%d", i) | ||
66 | /* hex */ | ||
67 | #define print_hex4(i) xprintf("%X", i) | ||
68 | #define print_hex8(i) xprintf("%02X", i) | ||
69 | #define print_hex16(i) xprintf("%04X", i) | ||
70 | #define print_hex32(i) xprintf("%08lX", i) | ||
71 | /* binary */ | ||
72 | #define print_bin4(i) xprintf("%04b", i) | ||
73 | #define print_bin8(i) xprintf("%08b", i) | ||
74 | #define print_bin16(i) xprintf("%016b", i) | ||
75 | #define print_bin32(i) xprintf("%032lb", i) | ||
76 | #define print_bin_reverse8(i) xprintf("%08b", bitrev(i)) | ||
77 | #define print_bin_reverse16(i) xprintf("%016b", bitrev16(i)) | ||
78 | #define print_bin_reverse32(i) xprintf("%032lb", bitrev32(i)) | ||
79 | /* print value utility */ | ||
80 | #define print_val_dec(v) xprintf(#v ": %u\n", v) | ||
81 | #define print_val_decs(v) xprintf(#v ": %d\n", v) | ||
82 | #define print_val_hex8(v) xprintf(#v ": %X\n", v) | ||
83 | #define print_val_hex16(v) xprintf(#v ": %02X\n", v) | ||
84 | #define print_val_hex32(v) xprintf(#v ": %04lX\n", v) | ||
85 | #define print_val_bin8(v) xprintf(#v ": %08b\n", v) | ||
86 | #define print_val_bin16(v) xprintf(#v ": %016b\n", v) | ||
87 | #define print_val_bin32(v) xprintf(#v ": %032lb\n", v) | ||
88 | #define print_val_bin_reverse8(v) xprintf(#v ": %08b\n", bitrev(v)) | ||
89 | #define print_val_bin_reverse16(v) xprintf(#v ": %016b\n", bitrev16(v)) | ||
90 | #define print_val_bin_reverse32(v) xprintf(#v ": %032lb\n", bitrev32(v)) | ||
91 | |||
92 | #else /* NO_PRINT */ | ||
93 | |||
94 | #define xprintf | ||
95 | #define print | ||
96 | #define println | ||
97 | #define print_set_sendchar(func) | ||
98 | #define print_dec(data) | ||
99 | #define print_decs(data) | ||
100 | #define print_hex4(data) | ||
101 | #define print_hex8(data) | ||
102 | #define print_hex16(data) | ||
103 | #define print_hex32(data) | ||
104 | #define print_bin4(data) | ||
105 | #define print_bin8(data) | ||
106 | #define print_bin16(data) | ||
107 | #define print_bin32(data) | ||
108 | #define print_bin_reverse8(data) | ||
109 | #define print_bin_reverse16(data) | ||
110 | #define print_bin_reverse32(data) | ||
111 | #define print_val_dec(v) | ||
112 | #define print_val_decs(v) | ||
113 | #define print_val_hex8(v) | ||
114 | #define print_val_hex16(v) | ||
115 | #define print_val_hex32(v) | ||
116 | #define print_val_bin8(v) | ||
117 | #define print_val_bin16(v) | ||
118 | #define print_val_bin32(v) | ||
119 | #define print_val_bin_reverse8(v) | ||
120 | #define print_val_bin_reverse16(v) | ||
121 | #define print_val_bin_reverse32(v) | ||
122 | |||
123 | #endif /* NO_PRINT */ | ||
124 | |||
125 | |||
126 | /* Backward compatiblitly for old name */ | ||
127 | #define pdec(data) print_dec(data) | ||
128 | #define pdec16(data) print_dec(data) | ||
129 | #define phex(data) print_hex8(data) | ||
130 | #define phex16(data) print_hex16(data) | ||
131 | #define pbin(data) print_bin8(data) | ||
132 | #define pbin16(data) print_bin16(data) | ||
133 | #define pbin_reverse(data) print_bin_reverse8(data) | ||
134 | #define pbin_reverse16(data) print_bin_reverse16(data) | ||
135 | |||
136 | |||
137 | #endif | ||
diff --git a/tmk_core/common/progmem.h b/tmk_core/common/progmem.h new file mode 100644 index 000000000..199b1bedf --- /dev/null +++ b/tmk_core/common/progmem.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef PROGMEM_H | ||
2 | #define PROGMEM_H 1 | ||
3 | |||
4 | #if defined(__AVR__) | ||
5 | # include <avr/pgmspace.h> | ||
6 | #elif defined(__arm__) | ||
7 | # define PROGMEM | ||
8 | # define pgm_read_byte(p) *(p) | ||
9 | # define pgm_read_word(p) *(p) | ||
10 | #endif | ||
11 | |||
12 | #endif | ||
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h new file mode 100644 index 000000000..f6c0a315d --- /dev/null +++ b/tmk_core/common/report.h | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | Copyright 2011,2012 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 | #ifndef REPORT_H | ||
19 | #define REPORT_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | #include "keycode.h" | ||
23 | |||
24 | |||
25 | /* report id */ | ||
26 | #define REPORT_ID_MOUSE 1 | ||
27 | #define REPORT_ID_SYSTEM 2 | ||
28 | #define REPORT_ID_CONSUMER 3 | ||
29 | |||
30 | /* mouse buttons */ | ||
31 | #define MOUSE_BTN1 (1<<0) | ||
32 | #define MOUSE_BTN2 (1<<1) | ||
33 | #define MOUSE_BTN3 (1<<2) | ||
34 | #define MOUSE_BTN4 (1<<3) | ||
35 | #define MOUSE_BTN5 (1<<4) | ||
36 | |||
37 | /* Consumer Page(0x0C) | ||
38 | * following are supported by Windows: http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx | ||
39 | */ | ||
40 | #define AUDIO_MUTE 0x00E2 | ||
41 | #define AUDIO_VOL_UP 0x00E9 | ||
42 | #define AUDIO_VOL_DOWN 0x00EA | ||
43 | #define TRANSPORT_NEXT_TRACK 0x00B5 | ||
44 | #define TRANSPORT_PREV_TRACK 0x00B6 | ||
45 | #define TRANSPORT_STOP 0x00B7 | ||
46 | #define TRANSPORT_STOP_EJECT 0x00CC | ||
47 | #define TRANSPORT_PLAY_PAUSE 0x00CD | ||
48 | /* application launch */ | ||
49 | #define AL_CC_CONFIG 0x0183 | ||
50 | #define AL_EMAIL 0x018A | ||
51 | #define AL_CALCULATOR 0x0192 | ||
52 | #define AL_LOCAL_BROWSER 0x0194 | ||
53 | /* application control */ | ||
54 | #define AC_SEARCH 0x0221 | ||
55 | #define AC_HOME 0x0223 | ||
56 | #define AC_BACK 0x0224 | ||
57 | #define AC_FORWARD 0x0225 | ||
58 | #define AC_STOP 0x0226 | ||
59 | #define AC_REFRESH 0x0227 | ||
60 | #define AC_BOOKMARKS 0x022A | ||
61 | /* supplement for Bluegiga iWRAP HID(not supported by Windows?) */ | ||
62 | #define AL_LOCK 0x019E | ||
63 | #define TRANSPORT_RECORD 0x00B2 | ||
64 | #define TRANSPORT_FAST_FORWARD 0x00B3 | ||
65 | #define TRANSPORT_REWIND 0x00B4 | ||
66 | #define TRANSPORT_EJECT 0x00B8 | ||
67 | #define AC_MINIMIZE 0x0206 | ||
68 | |||
69 | /* Generic Desktop Page(0x01) - system power control */ | ||
70 | #define SYSTEM_POWER_DOWN 0x0081 | ||
71 | #define SYSTEM_SLEEP 0x0082 | ||
72 | #define SYSTEM_WAKE_UP 0x0083 | ||
73 | |||
74 | |||
75 | /* key report size(NKRO or boot mode) */ | ||
76 | #if defined(PROTOCOL_PJRC) && defined(NKRO_ENABLE) | ||
77 | # include "usb.h" | ||
78 | # define KEYBOARD_REPORT_SIZE KBD2_SIZE | ||
79 | # define KEYBOARD_REPORT_KEYS (KBD2_SIZE - 2) | ||
80 | # define KEYBOARD_REPORT_BITS (KBD2_SIZE - 1) | ||
81 | |||
82 | #elif defined(PROTOCOL_LUFA) && defined(NKRO_ENABLE) | ||
83 | # include "protocol/lufa/descriptor.h" | ||
84 | # define KEYBOARD_REPORT_SIZE NKRO_EPSIZE | ||
85 | # define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2) | ||
86 | # define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1) | ||
87 | |||
88 | #else | ||
89 | # define KEYBOARD_REPORT_SIZE 8 | ||
90 | # define KEYBOARD_REPORT_KEYS 6 | ||
91 | #endif | ||
92 | |||
93 | |||
94 | #ifdef __cplusplus | ||
95 | extern "C" { | ||
96 | #endif | ||
97 | |||
98 | /* | ||
99 | * keyboard report is 8-byte array retains state of 8 modifiers and 6 keys. | ||
100 | * | ||
101 | * byte |0 |1 |2 |3 |4 |5 |6 |7 | ||
102 | * -----+--------+--------+--------+--------+--------+--------+--------+-------- | ||
103 | * desc |mods |reserved|keys[0] |keys[1] |keys[2] |keys[3] |keys[4] |keys[5] | ||
104 | * | ||
105 | * It is exended to 16 bytes to retain 120keys+8mods when NKRO mode. | ||
106 | * | ||
107 | * byte |0 |1 |2 |3 |4 |5 |6 |7 ... |15 | ||
108 | * -----+--------+--------+--------+--------+--------+--------+--------+-------- +-------- | ||
109 | * desc |mods |bits[0] |bits[1] |bits[2] |bits[3] |bits[4] |bits[5] |bits[6] ... |bit[14] | ||
110 | * | ||
111 | * mods retains state of 8 modifiers. | ||
112 | * | ||
113 | * bit |0 |1 |2 |3 |4 |5 |6 |7 | ||
114 | * -----+--------+--------+--------+--------+--------+--------+--------+-------- | ||
115 | * desc |Lcontrol|Lshift |Lalt |Lgui |Rcontrol|Rshift |Ralt |Rgui | ||
116 | * | ||
117 | */ | ||
118 | typedef union { | ||
119 | uint8_t raw[KEYBOARD_REPORT_SIZE]; | ||
120 | struct { | ||
121 | uint8_t mods; | ||
122 | uint8_t reserved; | ||
123 | uint8_t keys[KEYBOARD_REPORT_KEYS]; | ||
124 | }; | ||
125 | #ifdef NKRO_ENABLE | ||
126 | struct { | ||
127 | uint8_t mods; | ||
128 | uint8_t bits[KEYBOARD_REPORT_BITS]; | ||
129 | } nkro; | ||
130 | #endif | ||
131 | } __attribute__ ((packed)) report_keyboard_t; | ||
132 | /* | ||
133 | typedef struct { | ||
134 | uint8_t mods; | ||
135 | uint8_t reserved; | ||
136 | uint8_t keys[REPORT_KEYS]; | ||
137 | } __attribute__ ((packed)) report_keyboard_t; | ||
138 | */ | ||
139 | |||
140 | typedef struct { | ||
141 | uint8_t buttons; | ||
142 | int8_t x; | ||
143 | int8_t y; | ||
144 | int8_t v; | ||
145 | int8_t h; | ||
146 | } __attribute__ ((packed)) report_mouse_t; | ||
147 | |||
148 | |||
149 | /* keycode to system usage */ | ||
150 | #define KEYCODE2SYSTEM(key) \ | ||
151 | (key == KC_SYSTEM_POWER ? SYSTEM_POWER_DOWN : \ | ||
152 | (key == KC_SYSTEM_SLEEP ? SYSTEM_SLEEP : \ | ||
153 | (key == KC_SYSTEM_WAKE ? SYSTEM_WAKE_UP : 0))) | ||
154 | |||
155 | /* keycode to consumer usage */ | ||
156 | #define KEYCODE2CONSUMER(key) \ | ||
157 | (key == KC_AUDIO_MUTE ? AUDIO_MUTE : \ | ||
158 | (key == KC_AUDIO_VOL_UP ? AUDIO_VOL_UP : \ | ||
159 | (key == KC_AUDIO_VOL_DOWN ? AUDIO_VOL_DOWN : \ | ||
160 | (key == KC_MEDIA_NEXT_TRACK ? TRANSPORT_NEXT_TRACK : \ | ||
161 | (key == KC_MEDIA_PREV_TRACK ? TRANSPORT_PREV_TRACK : \ | ||
162 | (key == KC_MEDIA_FAST_FORWARD ? TRANSPORT_FAST_FORWARD : \ | ||
163 | (key == KC_MEDIA_REWIND ? TRANSPORT_REWIND : \ | ||
164 | (key == KC_MEDIA_STOP ? TRANSPORT_STOP : \ | ||
165 | (key == KC_MEDIA_EJECT ? TRANSPORT_STOP_EJECT : \ | ||
166 | (key == KC_MEDIA_PLAY_PAUSE ? TRANSPORT_PLAY_PAUSE : \ | ||
167 | (key == KC_MEDIA_SELECT ? AL_CC_CONFIG : \ | ||
168 | (key == KC_MAIL ? AL_EMAIL : \ | ||
169 | (key == KC_CALCULATOR ? AL_CALCULATOR : \ | ||
170 | (key == KC_MY_COMPUTER ? AL_LOCAL_BROWSER : \ | ||
171 | (key == KC_WWW_SEARCH ? AC_SEARCH : \ | ||
172 | (key == KC_WWW_HOME ? AC_HOME : \ | ||
173 | (key == KC_WWW_BACK ? AC_BACK : \ | ||
174 | (key == KC_WWW_FORWARD ? AC_FORWARD : \ | ||
175 | (key == KC_WWW_STOP ? AC_STOP : \ | ||
176 | (key == KC_WWW_REFRESH ? AC_REFRESH : \ | ||
177 | (key == KC_WWW_FAVORITES ? AC_BOOKMARKS : 0))))))))))))))))))))) | ||
178 | |||
179 | #ifdef __cplusplus | ||
180 | } | ||
181 | #endif | ||
182 | |||
183 | #endif | ||
diff --git a/tmk_core/common/sendchar.h b/tmk_core/common/sendchar.h new file mode 100644 index 000000000..7a64d00c7 --- /dev/null +++ b/tmk_core/common/sendchar.h | |||
@@ -0,0 +1,35 @@ | |||
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 | #ifndef SENDCHAR_H | ||
19 | #define SENDCHAR_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | |||
23 | |||
24 | #ifdef __cplusplus | ||
25 | extern "C" { | ||
26 | #endif | ||
27 | |||
28 | /* transmit a character. return 0 on success, -1 on error. */ | ||
29 | int8_t sendchar(uint8_t c); | ||
30 | |||
31 | #ifdef __cplusplus | ||
32 | } | ||
33 | #endif | ||
34 | |||
35 | #endif | ||
diff --git a/tmk_core/common/sendchar_null.c b/tmk_core/common/sendchar_null.c new file mode 100644 index 000000000..293330622 --- /dev/null +++ b/tmk_core/common/sendchar_null.c | |||
@@ -0,0 +1,23 @@ | |||
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 | #include "sendchar.h" | ||
18 | |||
19 | |||
20 | int8_t sendchar(uint8_t c) | ||
21 | { | ||
22 | return 0; | ||
23 | } | ||
diff --git a/tmk_core/common/sendchar_uart.c b/tmk_core/common/sendchar_uart.c new file mode 100644 index 000000000..0241859eb --- /dev/null +++ b/tmk_core/common/sendchar_uart.c | |||
@@ -0,0 +1,25 @@ | |||
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 | #include "uart.h" | ||
18 | #include "sendchar.h" | ||
19 | |||
20 | |||
21 | int8_t sendchar(uint8_t c) | ||
22 | { | ||
23 | uart_putchar(c); | ||
24 | return 0; | ||
25 | } | ||
diff --git a/tmk_core/common/sleep_led.c b/tmk_core/common/sleep_led.c new file mode 100644 index 000000000..dab3eb0f3 --- /dev/null +++ b/tmk_core/common/sleep_led.c | |||
@@ -0,0 +1,95 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <avr/io.h> | ||
3 | #include <avr/interrupt.h> | ||
4 | #include <avr/pgmspace.h> | ||
5 | #include "led.h" | ||
6 | #include "sleep_led.h" | ||
7 | |||
8 | /* Software PWM | ||
9 | * ______ ______ __ | ||
10 | * | ON |___OFF___| ON |___OFF___| .... | ||
11 | * |<-------------->|<-------------->|<- .... | ||
12 | * PWM period PWM period | ||
13 | * | ||
14 | * 256 interrupts/period[resolution] | ||
15 | * 64 periods/second[frequency] | ||
16 | * 256*64 interrupts/second | ||
17 | * F_CPU/(256*64) clocks/interrupt | ||
18 | */ | ||
19 | #define SLEEP_LED_TIMER_TOP F_CPU/(256*64) | ||
20 | |||
21 | void sleep_led_init(void) | ||
22 | { | ||
23 | /* Timer1 setup */ | ||
24 | /* CTC mode */ | ||
25 | TCCR1B |= _BV(WGM12); | ||
26 | /* Clock selelct: clk/1 */ | ||
27 | TCCR1B |= _BV(CS10); | ||
28 | /* Set TOP value */ | ||
29 | uint8_t sreg = SREG; | ||
30 | cli(); | ||
31 | OCR1AH = (SLEEP_LED_TIMER_TOP>>8)&0xff; | ||
32 | OCR1AL = SLEEP_LED_TIMER_TOP&0xff; | ||
33 | SREG = sreg; | ||
34 | } | ||
35 | |||
36 | void sleep_led_enable(void) | ||
37 | { | ||
38 | /* Enable Compare Match Interrupt */ | ||
39 | TIMSK1 |= _BV(OCIE1A); | ||
40 | } | ||
41 | |||
42 | void sleep_led_disable(void) | ||
43 | { | ||
44 | /* Disable Compare Match Interrupt */ | ||
45 | TIMSK1 &= ~_BV(OCIE1A); | ||
46 | } | ||
47 | |||
48 | void sleep_led_toggle(void) | ||
49 | { | ||
50 | /* Disable Compare Match Interrupt */ | ||
51 | TIMSK1 ^= _BV(OCIE1A); | ||
52 | } | ||
53 | |||
54 | |||
55 | /* Breathing Sleep LED brighness(PWM On period) table | ||
56 | * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle | ||
57 | * | ||
58 | * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63 | ||
59 | * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i } | ||
60 | */ | ||
61 | static const uint8_t breathing_table[64] PROGMEM = { | ||
62 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, | ||
63 | 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, | ||
64 | 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, | ||
65 | 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
66 | }; | ||
67 | |||
68 | ISR(TIMER1_COMPA_vect) | ||
69 | { | ||
70 | /* Software PWM | ||
71 | * timer:1111 1111 1111 1111 | ||
72 | * \_____/\/ \_______/____ count(0-255) | ||
73 | * \ \______________ duration of step(4) | ||
74 | * \__________________ index of step table(0-63) | ||
75 | */ | ||
76 | static union { | ||
77 | uint16_t row; | ||
78 | struct { | ||
79 | uint8_t count:8; | ||
80 | uint8_t duration:2; | ||
81 | uint8_t index:6; | ||
82 | } pwm; | ||
83 | } timer = { .row = 0 }; | ||
84 | |||
85 | timer.row++; | ||
86 | |||
87 | // LED on | ||
88 | if (timer.pwm.count == 0) { | ||
89 | led_set(1<<USB_LED_CAPS_LOCK); | ||
90 | } | ||
91 | // LED off | ||
92 | if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) { | ||
93 | led_set(0); | ||
94 | } | ||
95 | } | ||
diff --git a/tmk_core/common/sleep_led.h b/tmk_core/common/sleep_led.h new file mode 100644 index 000000000..6bdcf558a --- /dev/null +++ b/tmk_core/common/sleep_led.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef SLEEP_LED_H | ||
2 | #define SLEEP_LED_H | ||
3 | |||
4 | |||
5 | #ifdef SLEEP_LED_ENABLE | ||
6 | |||
7 | void sleep_led_init(void); | ||
8 | void sleep_led_enable(void); | ||
9 | void sleep_led_disable(void); | ||
10 | void sleep_led_toggle(void); | ||
11 | |||
12 | #else | ||
13 | |||
14 | #define sleep_led_init() | ||
15 | #define sleep_led_enable() | ||
16 | #define sleep_led_disable() | ||
17 | #define sleep_led_toggle() | ||
18 | |||
19 | #endif | ||
20 | |||
21 | #endif | ||
diff --git a/tmk_core/common/suspend.h b/tmk_core/common/suspend.h new file mode 100644 index 000000000..80617a824 --- /dev/null +++ b/tmk_core/common/suspend.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef SUSPEND_H | ||
2 | #define SUSPEND_H | ||
3 | |||
4 | #include <stdint.h> | ||
5 | #include <stdbool.h> | ||
6 | |||
7 | |||
8 | void suspend_idle(uint8_t timeout); | ||
9 | void suspend_power_down(void); | ||
10 | bool suspend_wakeup_condition(void); | ||
11 | void suspend_wakeup_init(void); | ||
12 | |||
13 | #endif | ||
diff --git a/tmk_core/common/timer.h b/tmk_core/common/timer.h new file mode 100644 index 000000000..fe23f87ae --- /dev/null +++ b/tmk_core/common/timer.h | |||
@@ -0,0 +1,53 @@ | |||
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 | #ifndef TIMER_H | ||
19 | #define TIMER_H 1 | ||
20 | |||
21 | #include <stdint.h> | ||
22 | |||
23 | #if defined(__AVR__) | ||
24 | #include "avr/timer_avr.h" | ||
25 | #endif | ||
26 | |||
27 | |||
28 | #define TIMER_DIFF(a, b, max) ((a) >= (b) ? (a) - (b) : (max) - (b) + (a)) | ||
29 | #define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX) | ||
30 | #define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX) | ||
31 | #define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX) | ||
32 | #define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b) | ||
33 | |||
34 | |||
35 | #ifdef __cplusplus | ||
36 | extern "C" { | ||
37 | #endif | ||
38 | |||
39 | extern volatile uint32_t timer_count; | ||
40 | |||
41 | |||
42 | void timer_init(void); | ||
43 | void timer_clear(void); | ||
44 | uint16_t timer_read(void); | ||
45 | uint32_t timer_read32(void); | ||
46 | uint16_t timer_elapsed(uint16_t last); | ||
47 | uint32_t timer_elapsed32(uint32_t last); | ||
48 | |||
49 | #ifdef __cplusplus | ||
50 | } | ||
51 | #endif | ||
52 | |||
53 | #endif | ||
diff --git a/tmk_core/common/uart.c b/tmk_core/common/uart.c new file mode 100644 index 000000000..c17649b08 --- /dev/null +++ b/tmk_core/common/uart.c | |||
@@ -0,0 +1,129 @@ | |||
1 | // TODO: Teensy support(ATMega32u4/AT90USB128) | ||
2 | // Fixed for Arduino Duemilanove ATmega168p by Jun Wako | ||
3 | /* UART Example for Teensy USB Development Board | ||
4 | * http://www.pjrc.com/teensy/ | ||
5 | * Copyright (c) 2009 PJRC.COM, LLC | ||
6 | * | ||
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
8 | * of this software and associated documentation files (the "Software"), to deal | ||
9 | * in the Software without restriction, including without limitation the rights | ||
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
11 | * copies of the Software, and to permit persons to whom the Software is | ||
12 | * furnished to do so, subject to the following conditions: | ||
13 | * | ||
14 | * The above copyright notice and this permission notice shall be included in | ||
15 | * all copies or substantial portions of the Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
23 | * THE SOFTWARE. | ||
24 | */ | ||
25 | |||
26 | // Version 1.0: Initial Release | ||
27 | // Version 1.1: Add support for Teensy 2.0, minor optimizations | ||
28 | |||
29 | |||
30 | #include <avr/io.h> | ||
31 | #include <avr/interrupt.h> | ||
32 | |||
33 | #include "uart.h" | ||
34 | |||
35 | // These buffers may be any size from 2 to 256 bytes. | ||
36 | #define RX_BUFFER_SIZE 64 | ||
37 | #define TX_BUFFER_SIZE 40 | ||
38 | |||
39 | static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; | ||
40 | static volatile uint8_t tx_buffer_head; | ||
41 | static volatile uint8_t tx_buffer_tail; | ||
42 | static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; | ||
43 | static volatile uint8_t rx_buffer_head; | ||
44 | static volatile uint8_t rx_buffer_tail; | ||
45 | |||
46 | // Initialize the UART | ||
47 | void uart_init(uint32_t baud) | ||
48 | { | ||
49 | cli(); | ||
50 | UBRR0 = (F_CPU / 4 / baud - 1) / 2; | ||
51 | UCSR0A = (1<<U2X0); | ||
52 | UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); | ||
53 | UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); | ||
54 | tx_buffer_head = tx_buffer_tail = 0; | ||
55 | rx_buffer_head = rx_buffer_tail = 0; | ||
56 | sei(); | ||
57 | } | ||
58 | |||
59 | // Transmit a byte | ||
60 | void uart_putchar(uint8_t c) | ||
61 | { | ||
62 | uint8_t i; | ||
63 | |||
64 | i = tx_buffer_head + 1; | ||
65 | if (i >= TX_BUFFER_SIZE) i = 0; | ||
66 | while (tx_buffer_tail == i) ; // wait until space in buffer | ||
67 | //cli(); | ||
68 | tx_buffer[i] = c; | ||
69 | tx_buffer_head = i; | ||
70 | UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0) | (1<<UDRIE0); | ||
71 | //sei(); | ||
72 | } | ||
73 | |||
74 | // Receive a byte | ||
75 | uint8_t uart_getchar(void) | ||
76 | { | ||
77 | uint8_t c, i; | ||
78 | |||
79 | while (rx_buffer_head == rx_buffer_tail) ; // wait for character | ||
80 | i = rx_buffer_tail + 1; | ||
81 | if (i >= RX_BUFFER_SIZE) i = 0; | ||
82 | c = rx_buffer[i]; | ||
83 | rx_buffer_tail = i; | ||
84 | return c; | ||
85 | } | ||
86 | |||
87 | // Return the number of bytes waiting in the receive buffer. | ||
88 | // Call this before uart_getchar() to check if it will need | ||
89 | // to wait for a byte to arrive. | ||
90 | uint8_t uart_available(void) | ||
91 | { | ||
92 | uint8_t head, tail; | ||
93 | |||
94 | head = rx_buffer_head; | ||
95 | tail = rx_buffer_tail; | ||
96 | if (head >= tail) return head - tail; | ||
97 | return RX_BUFFER_SIZE + head - tail; | ||
98 | } | ||
99 | |||
100 | // Transmit Interrupt | ||
101 | ISR(USART_UDRE_vect) | ||
102 | { | ||
103 | uint8_t i; | ||
104 | |||
105 | if (tx_buffer_head == tx_buffer_tail) { | ||
106 | // buffer is empty, disable transmit interrupt | ||
107 | UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); | ||
108 | } else { | ||
109 | i = tx_buffer_tail + 1; | ||
110 | if (i >= TX_BUFFER_SIZE) i = 0; | ||
111 | UDR0 = tx_buffer[i]; | ||
112 | tx_buffer_tail = i; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | // Receive Interrupt | ||
117 | ISR(USART_RX_vect) | ||
118 | { | ||
119 | uint8_t c, i; | ||
120 | |||
121 | c = UDR0; | ||
122 | i = rx_buffer_head + 1; | ||
123 | if (i >= RX_BUFFER_SIZE) i = 0; | ||
124 | if (i != rx_buffer_tail) { | ||
125 | rx_buffer[i] = c; | ||
126 | rx_buffer_head = i; | ||
127 | } | ||
128 | } | ||
129 | |||
diff --git a/tmk_core/common/uart.h b/tmk_core/common/uart.h new file mode 100644 index 000000000..41136a396 --- /dev/null +++ b/tmk_core/common/uart.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef _uart_included_h_ | ||
2 | #define _uart_included_h_ | ||
3 | |||
4 | #include <stdint.h> | ||
5 | |||
6 | void uart_init(uint32_t baud); | ||
7 | void uart_putchar(uint8_t c); | ||
8 | uint8_t uart_getchar(void); | ||
9 | uint8_t uart_available(void); | ||
10 | |||
11 | #endif | ||
diff --git a/tmk_core/common/util.c b/tmk_core/common/util.c new file mode 100644 index 000000000..7e0d54299 --- /dev/null +++ b/tmk_core/common/util.c | |||
@@ -0,0 +1,101 @@ | |||
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 "util.h" | ||
19 | |||
20 | // bit population - return number of on-bit | ||
21 | uint8_t bitpop(uint8_t bits) | ||
22 | { | ||
23 | uint8_t c; | ||
24 | for (c = 0; bits; c++) | ||
25 | bits &= bits - 1; | ||
26 | return c; | ||
27 | /* | ||
28 | const uint8_t bit_count[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; | ||
29 | return bit_count[bits>>4] + bit_count[bits&0x0F] | ||
30 | */ | ||
31 | } | ||
32 | |||
33 | uint8_t bitpop16(uint16_t bits) | ||
34 | { | ||
35 | uint8_t c; | ||
36 | for (c = 0; bits; c++) | ||
37 | bits &= bits - 1; | ||
38 | return c; | ||
39 | } | ||
40 | |||
41 | uint8_t bitpop32(uint32_t bits) | ||
42 | { | ||
43 | uint8_t c; | ||
44 | for (c = 0; bits; c++) | ||
45 | bits &= bits - 1; | ||
46 | return c; | ||
47 | } | ||
48 | |||
49 | // most significant on-bit - return highest location of on-bit | ||
50 | // NOTE: return 0 when bit0 is on or all bits are off | ||
51 | uint8_t biton(uint8_t bits) | ||
52 | { | ||
53 | uint8_t n = 0; | ||
54 | if (bits >> 4) { bits >>= 4; n += 4;} | ||
55 | if (bits >> 2) { bits >>= 2; n += 2;} | ||
56 | if (bits >> 1) { bits >>= 1; n += 1;} | ||
57 | return n; | ||
58 | } | ||
59 | |||
60 | uint8_t biton16(uint16_t bits) | ||
61 | { | ||
62 | uint8_t n = 0; | ||
63 | if (bits >> 8) { bits >>= 8; n += 8;} | ||
64 | if (bits >> 4) { bits >>= 4; n += 4;} | ||
65 | if (bits >> 2) { bits >>= 2; n += 2;} | ||
66 | if (bits >> 1) { bits >>= 1; n += 1;} | ||
67 | return n; | ||
68 | } | ||
69 | |||
70 | uint8_t biton32(uint32_t bits) | ||
71 | { | ||
72 | uint8_t n = 0; | ||
73 | if (bits >>16) { bits >>=16; n +=16;} | ||
74 | if (bits >> 8) { bits >>= 8; n += 8;} | ||
75 | if (bits >> 4) { bits >>= 4; n += 4;} | ||
76 | if (bits >> 2) { bits >>= 2; n += 2;} | ||
77 | if (bits >> 1) { bits >>= 1; n += 1;} | ||
78 | return n; | ||
79 | } | ||
80 | |||
81 | |||
82 | |||
83 | uint8_t bitrev(uint8_t bits) | ||
84 | { | ||
85 | bits = (bits & 0x0f)<<4 | (bits & 0xf0)>>4; | ||
86 | bits = (bits & 0b00110011)<<2 | (bits & 0b11001100)>>2; | ||
87 | bits = (bits & 0b01010101)<<1 | (bits & 0b10101010)>>1; | ||
88 | return bits; | ||
89 | } | ||
90 | |||
91 | uint16_t bitrev16(uint16_t bits) | ||
92 | { | ||
93 | bits = bitrev(bits & 0x00ff)<<8 | bitrev((bits & 0xff00)>>8); | ||
94 | return bits; | ||
95 | } | ||
96 | |||
97 | uint32_t bitrev32(uint32_t bits) | ||
98 | { | ||
99 | bits = (uint32_t)bitrev16(bits & 0x0000ffff)<<16 | bitrev16((bits & 0xffff0000)>>16); | ||
100 | return bits; | ||
101 | } | ||
diff --git a/tmk_core/common/util.h b/tmk_core/common/util.h new file mode 100644 index 000000000..7451cc084 --- /dev/null +++ b/tmk_core/common/util.h | |||
@@ -0,0 +1,43 @@ | |||
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 | #ifndef UTIL_H | ||
19 | #define UTIL_H | ||
20 | |||
21 | #include <stdint.h> | ||
22 | |||
23 | // convert to L string | ||
24 | #define LSTR(s) XLSTR(s) | ||
25 | #define XLSTR(s) L ## #s | ||
26 | // convert to string | ||
27 | #define STR(s) XSTR(s) | ||
28 | #define XSTR(s) #s | ||
29 | |||
30 | |||
31 | uint8_t bitpop(uint8_t bits); | ||
32 | uint8_t bitpop16(uint16_t bits); | ||
33 | uint8_t bitpop32(uint32_t bits); | ||
34 | |||
35 | uint8_t biton(uint8_t bits); | ||
36 | uint8_t biton16(uint16_t bits); | ||
37 | uint8_t biton32(uint32_t bits); | ||
38 | |||
39 | uint8_t bitrev(uint8_t bits); | ||
40 | uint16_t bitrev16(uint16_t bits); | ||
41 | uint32_t bitrev32(uint32_t bits); | ||
42 | |||
43 | #endif | ||
diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h new file mode 100644 index 000000000..40d00b0c7 --- /dev/null +++ b/tmk_core/common/wait.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef WAIT_H | ||
2 | #define WAIT_H | ||
3 | |||
4 | #ifdef __cplusplus | ||
5 | extern "C" { | ||
6 | #endif | ||
7 | |||
8 | #if defined(__AVR__) | ||
9 | # include <util/delay.h> | ||
10 | # define wait_ms(ms) _delay_ms(ms) | ||
11 | # define wait_us(us) _delay_us(us) | ||
12 | #elif defined(__arm__) | ||
13 | # include "wait_api.h" | ||
14 | #endif | ||
15 | |||
16 | #ifdef __cplusplus | ||
17 | } | ||
18 | #endif | ||
19 | |||
20 | #endif | ||