Parent directory

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}