command.c
19646 bytes
1/*
2Copyright 2011 Jun Wako <wakojun@gmail.com>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17#include <stdint.h>
18#include <stdbool.h>
19#include "wait.h"
20#include "keycode.h"
21#include "host.h"
22#include "print.h"
23#include "debug.h"
24#include "util.h"
25#include "timer.h"
26#include "keyboard.h"
27#include "bootloader.h"
28#include "action_layer.h"
29#include "action_util.h"
30#include "eeconfig.h"
31#include "sleep_led.h"
32#include "led.h"
33#include "command.h"
34#include "quantum.h"
35#include "usb_device_state.h"
36#include "version.h"
37
38#ifdef BACKLIGHT_ENABLE
39# include "backlight.h"
40#endif
41
42#if defined(MOUSEKEY_ENABLE)
43# include "mousekey.h"
44#endif
45
46#ifdef AUDIO_ENABLE
47# include "audio.h"
48#endif /* AUDIO_ENABLE */
49
50static bool command_common(uint8_t code);
51static void command_common_help(void);
52static void print_version(void);
53static void print_status(void);
54static bool command_console(uint8_t code);
55static void command_console_help(void);
56#if defined(MOUSEKEY_ENABLE)
57static bool mousekey_console(uint8_t code);
58#endif
59
60static void switch_default_layer(uint8_t layer);
61
62command_state_t command_state = ONESHOT;
63
64bool command_proc(uint8_t code) {
65 switch (command_state) {
66 case ONESHOT:
67 if (!IS_COMMAND()) return false;
68 return (command_extra(code) || command_common(code));
69 break;
70 case CONSOLE:
71 if (IS_COMMAND())
72 return (command_extra(code) || command_common(code));
73 else
74 return (command_console_extra(code) || command_console(code));
75 break;
76#if defined(MOUSEKEY_ENABLE)
77 case MOUSEKEY:
78 mousekey_console(code);
79 break;
80#endif
81 default:
82 command_state = ONESHOT;
83 return false;
84 }
85 return true;
86}
87
88/* TODO: Refactoring is needed. */
89/* This allows to define extra commands. return false when not processed. */
90bool command_extra(uint8_t code) __attribute__((weak));
91bool command_extra(uint8_t code) {
92 (void)code;
93 return false;
94}
95
96bool command_console_extra(uint8_t code) __attribute__((weak));
97bool command_console_extra(uint8_t code) {
98 (void)code;
99 return false;
100}
101
102/***********************************************************
103 * Command common
104 ***********************************************************/
105
106static void command_common_help(void) {
107 print(/* clang-format off */
108 "\n\t- Magic -\n"
109
110 STR(MAGIC_KEY_DEBUG) ": Debug Message Toggle\n"
111 STR(MAGIC_KEY_DEBUG_MATRIX) ": Matrix Debug Mode Toggle"
112 " - Show keypresses in matrix grid\n"
113 STR(MAGIC_KEY_DEBUG_KBD) ": Keyboard Debug Toggle"
114 " - Show keypress report\n"
115 STR(MAGIC_KEY_DEBUG_MOUSE) ": Debug Mouse Toggle\n"
116 STR(MAGIC_KEY_VERSION) ": Version\n"
117 STR(MAGIC_KEY_STATUS) ": Status\n"
118 STR(MAGIC_KEY_CONSOLE) ": Activate Console Mode\n"
119
120#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
121 STR(MAGIC_KEY_LAYER0) ": Switch to Layer 0\n"
122 STR(MAGIC_KEY_LAYER1) ": Switch to Layer 1\n"
123 STR(MAGIC_KEY_LAYER2) ": Switch to Layer 2\n"
124 STR(MAGIC_KEY_LAYER3) ": Switch to Layer 3\n"
125 STR(MAGIC_KEY_LAYER4) ": Switch to Layer 4\n"
126 STR(MAGIC_KEY_LAYER5) ": Switch to Layer 5\n"
127 STR(MAGIC_KEY_LAYER6) ": Switch to Layer 6\n"
128 STR(MAGIC_KEY_LAYER7) ": Switch to Layer 7\n"
129 STR(MAGIC_KEY_LAYER8) ": Switch to Layer 8\n"
130 STR(MAGIC_KEY_LAYER9) ": Switch to Layer 9\n"
131#endif
132
133#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
134 "F1-F10: Switch to Layer 0-9 (F10 = L0)\n"
135#endif
136
137#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
138 "0-9: Switch to Layer 0-9\n"
139#endif
140
141 STR(MAGIC_KEY_LAYER0_ALT) ": Switch to Layer 0 (alternate)\n"
142
143 STR(MAGIC_KEY_BOOTLOADER) ": Jump to Bootloader\n"
144 STR(MAGIC_KEY_BOOTLOADER_ALT) ": Jump to Bootloader (alternate)\n"
145
146#ifdef KEYBOARD_LOCK_ENABLE
147 STR(MAGIC_KEY_LOCK) ": Lock Keyboard\n"
148#endif
149
150 STR(MAGIC_KEY_EEPROM) ": Print EEPROM Settings\n"
151 STR(MAGIC_KEY_EEPROM_CLEAR) ": Clear EEPROM\n"
152
153#ifdef NKRO_ENABLE
154 STR(MAGIC_KEY_NKRO) ": NKRO Toggle\n"
155#endif
156
157#ifdef SLEEP_LED_ENABLE
158 STR(MAGIC_KEY_SLEEP_LED) ": Sleep LED Test\n"
159#endif
160 ); /* clang-format on */
161}
162
163static void print_version(void) {
164 xprintf("%s", /* clang-format off */
165 "\n\t- Version -\n"
166 "VID: " STR(VENDOR_ID) "(" STR(MANUFACTURER) ") "
167 "PID: " STR(PRODUCT_ID) "(" STR(PRODUCT) ") "
168 "VER: " STR(DEVICE_VER) "\n"
169 "BUILD: (" __DATE__ ")\n"
170#ifndef SKIP_VERSION
171# ifdef PROTOCOL_CHIBIOS
172 "CHIBIOS: " STR(CHIBIOS_VERSION)
173 ", CONTRIB: " STR(CHIBIOS_CONTRIB_VERSION) "\n"
174# endif
175#endif
176
177 /* build options */
178 "OPTIONS:"
179
180#ifdef PROTOCOL_LUFA
181 " LUFA"
182#endif
183#ifdef PROTOCOL_VUSB
184 " VUSB"
185#endif
186#ifdef BOOTMAGIC_ENABLE
187 " BOOTMAGIC"
188#endif
189#ifdef MOUSEKEY_ENABLE
190 " MOUSEKEY"
191#endif
192#ifdef EXTRAKEY_ENABLE
193 " EXTRAKEY"
194#endif
195#ifdef CONSOLE_ENABLE
196 " CONSOLE"
197#endif
198#ifdef COMMAND_ENABLE
199 " COMMAND"
200#endif
201#ifdef NKRO_ENABLE
202 " NKRO"
203#endif
204#ifdef LTO_ENABLE
205 " LTO"
206#endif
207
208 " " STR(BOOTLOADER_SIZE) "\n"
209
210 "GCC: " STR(__GNUC__)
211 "." STR(__GNUC_MINOR__)
212 "." STR(__GNUC_PATCHLEVEL__)
213#if defined(__AVR__)
214 " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
215 " AVR_ARCH: avr" STR(__AVR_ARCH__)
216#endif
217 "\n"
218 ); /* clang-format on */
219}
220
221static void print_status(void) {
222 xprintf(/* clang-format off */
223 "\n\t- Status -\n"
224
225 "host_keyboard_leds(): %02X\n"
226 "keyboard_protocol: %02X\n"
227 "keyboard_idle: %02X\n"
228#ifdef NKRO_ENABLE
229 "keymap_config.nkro: %02X\n"
230#endif
231 "timer_read32(): %08lX\n"
232
233 , host_keyboard_leds()
234 , usb_device_state_get_protocol()
235 , usb_device_state_get_idle_rate()
236#ifdef NKRO_ENABLE
237 , keymap_config.nkro
238#endif
239 , timer_read32()
240
241 ); /* clang-format on */
242}
243
244#if !defined(NO_PRINT) && !defined(USER_PRINT)
245static void print_eeconfig(void) {
246 xprintf("eeconfig:\ndefault_layer: %u\n", eeconfig_read_default_layer());
247
248 debug_config_t dc;
249 dc.raw = eeconfig_read_debug();
250 xprintf(/* clang-format off */
251
252 "debug_config.raw: %02X\n"
253 ".enable: %u\n"
254 ".matrix: %u\n"
255 ".keyboard: %u\n"
256 ".mouse: %u\n"
257
258 , dc.raw
259 , dc.enable
260 , dc.matrix
261 , dc.keyboard
262 , dc.mouse
263 ); /* clang-format on */
264
265 keymap_config_t kc;
266 kc.raw = eeconfig_read_keymap();
267 xprintf(/* clang-format off */
268
269 "keymap_config.raw: %02X\n"
270 ".swap_control_capslock: %u\n"
271 ".capslock_to_control: %u\n"
272 ".swap_lctl_lgui: %u\n"
273 ".swap_rctl_rgui: %u\n"
274 ".swap_lalt_lgui: %u\n"
275 ".swap_ralt_rgui: %u\n"
276 ".no_gui: %u\n"
277 ".swap_grave_esc: %u\n"
278 ".swap_backslash_backspace: %u\n"
279 ".nkro: %u\n"
280 ".swap_escape_capslock: %u\n"
281
282 , kc.raw
283 , kc.swap_control_capslock
284 , kc.capslock_to_control
285 , kc.swap_lctl_lgui
286 , kc.swap_rctl_rgui
287 , kc.swap_lalt_lgui
288 , kc.swap_ralt_rgui
289 , kc.no_gui
290 , kc.swap_grave_esc
291 , kc.swap_backslash_backspace
292 , kc.nkro
293 , kc.swap_escape_capslock
294 ); /* clang-format on */
295
296# ifdef BACKLIGHT_ENABLE
297
298 backlight_config_t bc;
299 bc.raw = eeconfig_read_backlight();
300 xprintf(/* clang-format off */
301 "backlight_config"
302
303 ".raw: %02X\n"
304 ".enable: %u\n"
305 ".level: %u\n"
306
307 , bc.raw
308 , bc.enable
309 , bc.level
310
311 ); /* clang-format on */
312
313# endif /* BACKLIGHT_ENABLE */
314}
315#endif /* !NO_PRINT && !USER_PRINT */
316
317static bool command_common(uint8_t code) {
318#ifdef KEYBOARD_LOCK_ENABLE
319 static host_driver_t *host_driver = 0;
320#endif
321
322 switch (code) {
323#ifdef SLEEP_LED_ENABLE
324
325 // test breathing sleep LED
326 case MAGIC_KC(MAGIC_KEY_SLEEP_LED):
327 print("Sleep LED Test\n");
328 sleep_led_toggle();
329 led_set(host_keyboard_leds());
330 break;
331#endif
332
333 // print stored eeprom config
334 case MAGIC_KC(MAGIC_KEY_EEPROM):
335#if !defined(NO_PRINT) && !defined(USER_PRINT)
336 print_eeconfig();
337#endif /* !NO_PRINT && !USER_PRINT */
338 break;
339
340 // clear eeprom
341 case MAGIC_KC(MAGIC_KEY_EEPROM_CLEAR):
342 print("Clearing EEPROM\n");
343 eeconfig_init();
344 break;
345
346#ifdef KEYBOARD_LOCK_ENABLE
347
348 // lock/unlock keyboard
349 case MAGIC_KC(MAGIC_KEY_LOCK):
350 if (host_get_driver()) {
351 host_driver = host_get_driver();
352 clear_keyboard();
353 host_set_driver(0);
354 print("Locked.\n");
355 } else {
356 host_set_driver(host_driver);
357 print("Unlocked.\n");
358 }
359 break;
360#endif
361
362 // print help
363 case MAGIC_KC(MAGIC_KEY_HELP):
364 case MAGIC_KC(MAGIC_KEY_HELP_ALT):
365 command_common_help();
366 break;
367
368 // activate console
369 case MAGIC_KC(MAGIC_KEY_CONSOLE):
370 debug_matrix = false;
371 debug_keyboard = false;
372 debug_mouse = false;
373 debug_enable = false;
374 command_console_help();
375 print("C> ");
376 command_state = CONSOLE;
377 break;
378
379 // jump to bootloader
380 case MAGIC_KC(MAGIC_KEY_BOOTLOADER):
381 case MAGIC_KC(MAGIC_KEY_BOOTLOADER_ALT):
382 print("\n\nJumping to bootloader... ");
383 reset_keyboard();
384 break;
385
386 // debug toggle
387 case MAGIC_KC(MAGIC_KEY_DEBUG):
388 debug_enable = !debug_enable;
389 if (debug_enable) {
390 print("\ndebug: on\n");
391 } else {
392 print("\ndebug: off\n");
393 debug_matrix = false;
394 debug_keyboard = false;
395 debug_mouse = false;
396 }
397 break;
398
399 // debug matrix toggle
400 case MAGIC_KC(MAGIC_KEY_DEBUG_MATRIX):
401 debug_matrix = !debug_matrix;
402 if (debug_matrix) {
403 print("\nmatrix: on\n");
404 debug_enable = true;
405 } else {
406 print("\nmatrix: off\n");
407 }
408 break;
409
410 // debug keyboard toggle
411 case MAGIC_KC(MAGIC_KEY_DEBUG_KBD):
412 debug_keyboard = !debug_keyboard;
413 if (debug_keyboard) {
414 print("\nkeyboard: on\n");
415 debug_enable = true;
416 } else {
417 print("\nkeyboard: off\n");
418 }
419 break;
420
421 // debug mouse toggle
422 case MAGIC_KC(MAGIC_KEY_DEBUG_MOUSE):
423 debug_mouse = !debug_mouse;
424 if (debug_mouse) {
425 print("\nmouse: on\n");
426 debug_enable = true;
427 } else {
428 print("\nmouse: off\n");
429 }
430 break;
431
432 // print version
433 case MAGIC_KC(MAGIC_KEY_VERSION):
434 print_version();
435 break;
436
437 // print status
438 case MAGIC_KC(MAGIC_KEY_STATUS):
439 print_status();
440 break;
441
442#ifdef NKRO_ENABLE
443
444 // NKRO toggle
445 case MAGIC_KC(MAGIC_KEY_NKRO):
446 clear_keyboard(); // clear to prevent stuck keys
447 keymap_config.nkro = !keymap_config.nkro;
448 if (keymap_config.nkro) {
449 print("NKRO: on\n");
450 } else {
451 print("NKRO: off\n");
452 }
453 break;
454#endif
455
456 // switch layers
457
458 case MAGIC_KC(MAGIC_KEY_LAYER0_ALT):
459 switch_default_layer(0);
460 break;
461
462#if MAGIC_KEY_SWITCH_LAYER_WITH_CUSTOM
463
464 case MAGIC_KC(MAGIC_KEY_LAYER0):
465 switch_default_layer(0);
466 break;
467
468 case MAGIC_KC(MAGIC_KEY_LAYER1):
469 switch_default_layer(1);
470 break;
471
472 case MAGIC_KC(MAGIC_KEY_LAYER2):
473 switch_default_layer(2);
474 break;
475
476 case MAGIC_KC(MAGIC_KEY_LAYER3):
477 switch_default_layer(3);
478 break;
479
480 case MAGIC_KC(MAGIC_KEY_LAYER4):
481 switch_default_layer(4);
482 break;
483
484 case MAGIC_KC(MAGIC_KEY_LAYER5):
485 switch_default_layer(5);
486 break;
487
488 case MAGIC_KC(MAGIC_KEY_LAYER6):
489 switch_default_layer(6);
490 break;
491
492 case MAGIC_KC(MAGIC_KEY_LAYER7):
493 switch_default_layer(7);
494 break;
495
496 case MAGIC_KC(MAGIC_KEY_LAYER8):
497 switch_default_layer(8);
498 break;
499
500 case MAGIC_KC(MAGIC_KEY_LAYER9):
501 switch_default_layer(9);
502 break;
503#endif
504
505#if MAGIC_KEY_SWITCH_LAYER_WITH_FKEYS
506
507 case KC_F1 ... KC_F9:
508 switch_default_layer((code - KC_F1) + 1);
509 break;
510 case KC_F10:
511 switch_default_layer(0);
512 break;
513#endif
514
515#if MAGIC_KEY_SWITCH_LAYER_WITH_NKEYS
516
517 case KC_1 ... KC_9:
518 switch_default_layer((code - KC_1) + 1);
519 break;
520 case KC_0:
521 switch_default_layer(0);
522 break;
523#endif
524
525 default:
526 print("?");
527 return false;
528 }
529 return true;
530}
531
532/***********************************************************
533 * Command console
534 ***********************************************************/
535static void command_console_help(void) {
536 print("\n\t- Console -\n"
537 "ESC/q: quit\n"
538#ifdef MOUSEKEY_ENABLE
539 "m: mousekey\n"
540#endif
541 );
542}
543
544static bool command_console(uint8_t code) {
545 switch (code) {
546 case KC_H:
547 case KC_SLASH: /* ? */
548 command_console_help();
549 print("C> ");
550 return true;
551 case KC_Q:
552 case KC_ESC:
553 command_state = ONESHOT;
554 return false;
555#if defined(MOUSEKEY_ENABLE)
556 case KC_M:
557 command_state = MOUSEKEY;
558 mousekey_console(KC_SLASH /* ? */);
559 return true;
560#endif
561 default:
562 print("?");
563 return false;
564 }
565}
566
567/***********************************************************
568 * Mousekey console
569 ***********************************************************/
570
571#if defined(MOUSEKEY_ENABLE)
572
573# if !defined(NO_PRINT) && !defined(USER_PRINT)
574static void mousekey_param_print(void) {
575 xprintf(/* clang-format off */
576
577#ifndef MK_3_SPEED
578 "1: delay(*10ms): %u\n"
579 "2: interval(ms): %u\n"
580 "3: max_speed: %u\n"
581 "4: time_to_max: %u\n"
582 "5: wheel_max_speed: %u\n"
583 "6: wheel_time_to_max: %u\n"
584
585 , mk_delay
586 , mk_interval
587 , mk_max_speed
588 , mk_time_to_max
589 , mk_wheel_max_speed
590 , mk_wheel_time_to_max
591#else
592 "no knobs sorry\n"
593#endif
594
595 ); /* clang-format on */
596}
597# endif /* !NO_PRINT && !USER_PRINT */
598
599# if !defined(NO_PRINT) && !defined(USER_PRINT)
600static void mousekey_console_help(void) {
601 mousekey_param_print();
602 xprintf(/* clang-format off */
603 "p: print values\n"
604 "d: set defaults\n"
605 "up: +1\n"
606 "dn: -1\n"
607 "lt: +10\n"
608 "rt: -10\n"
609 "ESC/q: quit\n"
610
611#ifndef MK_3_SPEED
612 "\n"
613 "speed = delta * max_speed * (repeat / time_to_max)\n"
614 "where delta: cursor=%d, wheel=%d\n"
615 "See http://en.wikipedia.org/wiki/Mouse_keys\n"
616 , MOUSEKEY_MOVE_DELTA, MOUSEKEY_WHEEL_DELTA
617#endif
618
619 ); /* clang-format on */
620}
621# endif /* !NO_PRINT && !USER_PRINT */
622
623/* Only used by `quantum/command.c` / `command_proc()`. To avoid
624 * any doubt: we return `false` to return to the main console,
625 * which differs from the `bool` that `command_proc()` returns. */
626bool mousekey_console(uint8_t code) {
627 static uint8_t param = 0;
628 static uint8_t *pp = NULL;
629 static char * desc = NULL;
630
631# if defined(NO_PRINT) || defined(USER_PRINT) /* -Wunused-parameter */
632 (void)desc;
633# endif
634
635 int8_t change = 0;
636
637 switch (code) {
638 case KC_H:
639 case KC_SLASH: /* ? */
640# if !defined(NO_PRINT) && !defined(USER_PRINT)
641 print("\n\t- Mousekey -\n");
642 mousekey_console_help();
643# endif
644 break;
645
646 case KC_Q:
647 case KC_ESC:
648 print("q\n");
649 if (!param) return false;
650 param = 0;
651 pp = NULL;
652 desc = NULL;
653 break;
654
655 case KC_P:
656# if !defined(NO_PRINT) && !defined(USER_PRINT)
657 print("\n\t- Values -\n");
658 mousekey_param_print();
659# endif
660 break;
661
662 case KC_1 ... KC_0: /* KC_0 gives param = 10 */
663 param = 1 + code - KC_1;
664 switch (param) { /* clang-format off */
665# define PARAM(n, v) case n: pp = &(v); desc = #v; break
666
667#ifndef MK_3_SPEED
668 PARAM(1, mk_delay);
669 PARAM(2, mk_interval);
670 PARAM(3, mk_max_speed);
671 PARAM(4, mk_time_to_max);
672 PARAM(5, mk_wheel_max_speed);
673 PARAM(6, mk_wheel_time_to_max);
674#endif /* MK_3_SPEED */
675
676# undef PARAM
677 default:
678 param = 0;
679 print("?\n");
680 break;
681 } /* clang-format on */
682 if (param) xprintf("%u\n", param);
683 break;
684
685 /* clang-format off */
686 case KC_UP: change = +1; break;
687 case KC_DOWN: change = -1; break;
688 case KC_LEFT: change = -10; break;
689 case KC_RIGHT: change = +10; break;
690 /* clang-format on */
691
692 case KC_D:
693
694# ifndef MK_3_SPEED
695 mk_delay = MOUSEKEY_DELAY / 10;
696 mk_interval = MOUSEKEY_INTERVAL;
697 mk_max_speed = MOUSEKEY_MAX_SPEED;
698 mk_time_to_max = MOUSEKEY_TIME_TO_MAX;
699 mk_wheel_max_speed = MOUSEKEY_WHEEL_MAX_SPEED;
700 mk_wheel_time_to_max = MOUSEKEY_WHEEL_TIME_TO_MAX;
701# endif /* MK_3_SPEED */
702
703 print("defaults\n");
704 break;
705
706 default:
707 print("?\n");
708 break;
709 }
710
711 if (change) {
712 if (pp) {
713 int16_t val = *pp + change;
714 if (val > (int16_t)UINT8_MAX)
715 *pp = UINT8_MAX;
716 else if (val < 0)
717 *pp = 0;
718 else
719 *pp = (uint8_t)val;
720 xprintf("= %u\n", *pp);
721 } else {
722 print("?\n");
723 }
724 }
725
726 if (param) {
727 xprintf("M%u:%s> ", param, desc ? desc : "???");
728 } else {
729 print("M> ");
730 }
731 return true;
732}
733
734#endif /* MOUSEKEY_ENABLE */
735
736/***********************************************************
737 * Utilities
738 ***********************************************************/
739
740static void switch_default_layer(uint8_t layer) {
741 xprintf("L%d\n", layer);
742 default_layer_set((layer_state_t)1 << layer);
743 clear_keyboard();
744}