From 17a3dbc1591b6cdd96076b94a9d3648c19f7e2ab Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 3 Jul 2016 14:38:03 +0200 Subject: [PATCH 01/62] Integrate mouse keys into function layer, delete mouse layer. --- keyboards/ergodox_ez/keymaps/bepo/keymap.c | 64 +++++----------------- 1 file changed, 13 insertions(+), 51 deletions(-) diff --git a/keyboards/ergodox_ez/keymaps/bepo/keymap.c b/keyboards/ergodox_ez/keymaps/bepo/keymap.c index 921a94d63a..5c127ab78e 100644 --- a/keyboards/ergodox_ez/keymaps/bepo/keymap.c +++ b/keyboards/ergodox_ez/keymaps/bepo/keymap.c @@ -9,7 +9,6 @@ #define AQWER 3 // alted qwerty compat layer #define FNAV 4 // function / navigation keys #define NUM 5 // numeric keypad keys -#define MSE 6 // mouse keys #define KP_00 0 #define CA_Fx 1 @@ -26,7 +25,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | E_CIRC |A_GRAV| Y | X | . | K | | | | ' | Q | G | H | F | C_CEDIL| * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * |QWERTY| |LSuper| LCtrl| LAlt| |Escape| L_Mse| | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * |QWERTY| |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | CA_Fx| | | * | Space|LShift|------| |------|RShift|Enter | @@ -40,7 +39,7 @@ BP_PERCENT, BP_B, BP_E_ACUTE, BP_P, BP_O, BP_E_GRAVE, KC_BSPC, BP_W, BP_A, BP_U, BP_I, BP_E, BP_COMMA, BP_ECRC, BP_A_GRAVE, BP_Y, BP_X, BP_DOT, BP_K, KC_TAB, TG(QWER), KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, MO(MSE), + KC_ESC, KC_NO, MO(NUM), KC_SPC, KC_LSHIFT, MO(FNAV), // Right hand @@ -63,7 +62,7 @@ MO(FNAV), KC_RSHIFT, KC_ENTER), * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | e | a | y | x | . | k | | | | ' | q | g | h | f | c | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | BEPO | |LSuper| LCtrl| LAlt| |Escape| L_Mse| | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | | | | * | Space|LShift|------| |------|RShift|Enter | @@ -77,7 +76,7 @@ KC_PERCENT, KC_B, KC_E, KC_P, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, KC_E, KC_COMMA, KC_E, KC_A, KC_Y, KC_X, KC_DOT, KC_K, KC_TAB, KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, MO(MSE), + KC_ESC, KC_NO, MO(NUM), KC_SPC, MO(SQWER), MO(FNAV), // Right hand @@ -100,7 +99,7 @@ MO(FNAV), MO(SQWER), KC_ENTER), * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | E | A | Y | X | : | K | | | | ? | Q | G | H | F | C | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | BEPO | |LSuper| LCtrl| LAlt| |Escape| L_Mse| | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | | | | * | Space|LShift|------| |------|RShift|Enter | @@ -114,7 +113,7 @@ KC_GRV, S(KC_B), S(KC_E), S(KC_P), S(KC_O), S(KC_E), KC_TRNS, S(KC_W), S(KC_A), S(KC_U), S(KC_I), S(KC_E), KC_SCOLON, S(KC_E), S(KC_A), S(KC_Y), S(KC_X), KC_COLON, S(KC_K), S(KC_TAB), KC_TRNS, KC_TRNS, S(KC_LGUI), S(KC_LCTL), S(KC_LALT), - KC_TRNS, KC_TRNS, + KC_TRNS, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, // Right hand @@ -137,7 +136,7 @@ KC_TRNS, KC_TRNS, KC_TRNS), * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | e | \ | { | } | . | ~ | | | | ' | q | g | h | f | c | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | BEPO | |LSuper| LCtrl| LAlt| |Escape| L_Mse| | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | | | | * | _ |LShift|------| |------|RShift|Enter | @@ -151,7 +150,7 @@ KC_PERCENT, KC_PIPE, KC_E, KC_AMPR, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, RALT(KC_5), KC_COMMA, KC_E, KC_BSLASH, KC_LCBR, KC_RCBR, KC_DOT, KC_TILDE, KC_TAB, KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, MO(MSE), + KC_ESC, KC_NO, MO(NUM), KC_UNDS, MO(SQWER), MO(FNAV), // Right hand @@ -168,9 +167,9 @@ MO(FNAV), MO(SQWER), KC_ENTER), * ,--------------------------------------------------. ,--------------------------------------------------. * | | F1 | F2 | F3 | F4 | F5 |VolMut| | | F6 | F7 | F8 | F9 | F10 | | * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| - * | | | | | | |VolDwn| | | PgUp | Home | Up | End | F11 | | + * | | Next |LClick| Up |RClick| WhUp |VolDwn| | | PgUp | Home | Up | End | F11 | | * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| - * | | | | | | |------| |------| PgDn | Left | Down | Right| F12 | | + * | | Prev | Left | Down | Right|WhDown|------| |------| PgDn | Left | Down | Right| F12 | | * |--------+------+------+------+------+------| VolUp| | |------+------+------+------+------+--------| * | | Undo | Cut | Copy | Paste| | | | | | | | | | | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' @@ -184,8 +183,8 @@ MO(FNAV), MO(SQWER), KC_ENTER), [FNAV] = KEYMAP( // Left hand KC_NO, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_MUTE, -KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_VOLU, -KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, +KC_NO, KC_MS_BTN5, KC_MS_BTN1, KC_MS_UP, KC_MS_BTN2, KC_MS_WH_UP, KC_VOLU, +KC_NO, KC_MS_BTN4, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_MS_WH_DOWN, KC_NO, KC_UNDO, KC_CUT, KC_COPY, KC_PASTE, KC_NO, KC_VOLD, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO, KC_NO, @@ -236,44 +235,7 @@ KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_KP_0, M(KP_00), KC_KP_COMMA, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, -KC_NO, KC_TRNS, KC_KP_ENTER), -/* Keymap 6: mouse layer - * - * ,--------------------------------------------------. ,--------------------------------------------------. - * | | | | | | | | | | | | | | | | - * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| - * | | | | | | | | | | |LClick| Up |RClick| WhUp | | - * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| - * | | | | | | |------| |------| | Left | Down | Right|WhDown| | - * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------| - * | | | | | | | | | | | | | | | | - * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | | | | | | | | | | | | | | | | | | - * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | | | | | | - * | | |------| |------| | | - * | | | | | | | | - * `--------------------' `--------------------' - */ -[MSE] = KEYMAP( -// Left hand -KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, -KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, -KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, -KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, -KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, - KC_NO, KC_TRNS, - KC_NO, - KC_NO, KC_TRNS, KC_NO, -// Right hand - KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, - KC_NO, KC_NO, KC_MS_BTN1, KC_MS_UP, KC_MS_BTN2, KC_MS_WH_UP, KC_NO, - KC_NO, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_MS_WH_DOWN, KC_NO, - KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, - KC_TRNS, KC_TRNS, KC_TRNS, KC_NO, KC_NO, -KC_NO, KC_NO, -KC_NO, -KC_NO, KC_TRNS, KC_NO) +KC_NO, KC_TRNS, KC_KP_ENTER) }; const uint16_t PROGMEM fn_actions[] = { From 9aceaaed4cbdf49c12db85cf3ff40a9e762558a6 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 3 Jul 2016 15:51:55 +0200 Subject: [PATCH 02/62] Replace the "Ctrl+Alt+Fx" macro I was using to switch terminals without moving hands by a numeric layer switch key like on the left half, for consistency. --- keyboards/ergodox_ez/keymaps/bepo/keymap.c | 54 +++++++++------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/keyboards/ergodox_ez/keymaps/bepo/keymap.c b/keyboards/ergodox_ez/keymaps/bepo/keymap.c index 5c127ab78e..dd47357998 100644 --- a/keyboards/ergodox_ez/keymaps/bepo/keymap.c +++ b/keyboards/ergodox_ez/keymaps/bepo/keymap.c @@ -11,7 +11,6 @@ #define NUM 5 // numeric keypad keys #define KP_00 0 -#define CA_Fx 1 const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* Keymap 0: Base layer @@ -27,7 +26,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * |QWERTY| |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | CA_Fx| | | + * | | | L_Num| | L_Num| | | * | Space|LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' @@ -39,7 +38,7 @@ BP_PERCENT, BP_B, BP_E_ACUTE, BP_P, BP_O, BP_E_GRAVE, KC_BSPC, BP_W, BP_A, BP_U, BP_I, BP_E, BP_COMMA, BP_ECRC, BP_A_GRAVE, BP_Y, BP_X, BP_DOT, BP_K, KC_TAB, TG(QWER), KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, KC_NO, + KC_ESC, KC_TRNS, MO(NUM), KC_SPC, KC_LSHIFT, MO(FNAV), // Right hand @@ -48,8 +47,8 @@ TG(QWER), KC_NO, KC_LGUI, KC_LCTL, KC_LALT, BP_C, BP_T, BP_S, BP_R, BP_N, BP_M, KC_NUMLOCK, BP_APOS, BP_Q, BP_G, BP_H, BP_F, BP_CCED, BP_ALGR, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_NO, KC_INS, -M(CA_Fx), +KC_TRNS, KC_INS, +MO(NUM), MO(FNAV), KC_RSHIFT, KC_ENTER), /* Keymap 1: QWERTY system compatibility layer * @@ -64,7 +63,7 @@ MO(FNAV), KC_RSHIFT, KC_ENTER), * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | | | | + * | | | L_Num| | L_Num| | | * | Space|LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' @@ -76,7 +75,7 @@ KC_PERCENT, KC_B, KC_E, KC_P, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, KC_E, KC_COMMA, KC_E, KC_A, KC_Y, KC_X, KC_DOT, KC_K, KC_TAB, KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, KC_NO, + KC_ESC, KC_TRNS, MO(NUM), KC_SPC, MO(SQWER), MO(FNAV), // Right hand @@ -85,8 +84,8 @@ KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, MO(AQWER), KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_NO, KC_INS, -KC_TRNS, +KC_TRNS, KC_INS, +MO(NUM), MO(FNAV), MO(SQWER), KC_ENTER), /* Keymap 2: QWERTY shifted system compatibility layer * @@ -101,7 +100,7 @@ MO(FNAV), MO(SQWER), KC_ENTER), * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | | | | + * | | | L_Num| | L_Num| | | * | Space|LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' @@ -113,7 +112,7 @@ KC_GRV, S(KC_B), S(KC_E), S(KC_P), S(KC_O), S(KC_E), KC_TRNS, S(KC_W), S(KC_A), S(KC_U), S(KC_I), S(KC_E), KC_SCOLON, S(KC_E), S(KC_A), S(KC_Y), S(KC_X), KC_COLON, S(KC_K), S(KC_TAB), KC_TRNS, KC_TRNS, S(KC_LGUI), S(KC_LCTL), S(KC_LALT), - KC_TRNS, KC_NO, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, // Right hand @@ -138,7 +137,7 @@ KC_TRNS, KC_TRNS, KC_TRNS), * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | | | | + * | | | L_Num| | L_Num| | | * | _ |LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' @@ -150,7 +149,7 @@ KC_PERCENT, KC_PIPE, KC_E, KC_AMPR, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, RALT(KC_5), KC_COMMA, KC_E, KC_BSLASH, KC_LCBR, KC_RCBR, KC_DOT, KC_TILDE, KC_TAB, KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, KC_NO, + KC_ESC, KC_TRNS, MO(NUM), KC_UNDS, MO(SQWER), MO(FNAV), // Right hand @@ -159,8 +158,8 @@ KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, KC_TRNS, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_NO, KC_INS, -KC_TRNS, +KC_TRNS, KC_INS, +MO(NUM), MO(FNAV), MO(SQWER), KC_ENTER), /* Keymap 4: function / navigation layer * @@ -187,8 +186,8 @@ KC_NO, KC_MS_BTN5, KC_MS_BTN1, KC_MS_UP, KC_MS_BTN2, KC_MS_WH_UP, KC_VOLU, KC_NO, KC_MS_BTN4, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_MS_WH_DOWN, KC_NO, KC_UNDO, KC_CUT, KC_COPY, KC_PASTE, KC_NO, KC_VOLD, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, - KC_NO, KC_NO, - KC_NO, + KC_TRNS, KC_TRNS, + KC_TRNS, KC_NO, KC_TRNS, KC_TRNS, // Right hand KC_NO, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_NO, @@ -196,7 +195,7 @@ KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGDOWN, KC_LEFT, KC_DOWN, KC_RIGHT, KC_F12, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO, KC_NO, -KC_NO, KC_NO, +KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO), /* Keymap 5: numeric layer, sends keypad codes @@ -224,18 +223,18 @@ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, - KC_NO, KC_NO, + KC_TRNS, KC_TRNS, KC_TRNS, - KC_NO, KC_TRNS, KC_NO, + KC_NO, KC_TRNS, KC_TRNS, // Right hand KC_NO, KC_NO, KC_KP_PLUS, KC_KP_MINUS, KC_KP_SLASH, KC_KP_ASTERISK, KC_NO, KC_NO, KC_NO, KC_KP_7, KC_KP_8, KC_KP_9, KC_NO, KC_NO, KC_NO, KC_KP_4, KC_KP_5, KC_KP_6, KC_NO, KC_NO, KC_NO, KC_NO, KC_KP_1, KC_KP_2, KC_KP_3, KC_NO, KC_NO, KC_KP_0, M(KP_00), KC_KP_COMMA, KC_NO, KC_NO, -KC_NO, KC_NO, -KC_NO, -KC_NO, KC_TRNS, KC_KP_ENTER) +KC_TRNS, KC_TRNS, +KC_TRNS, +KC_TRNS, KC_TRNS, KC_KP_ENTER) }; const uint16_t PROGMEM fn_actions[] = { @@ -251,15 +250,6 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) return MACRO( U(KP_0), END ); } break; - case CA_Fx: - if (record->event.pressed) { - layer_on(FNAV); - return MACRO( D(LALT), D(LCTL), END ); - } else { - layer_off(FNAV); - return MACRO( U(LCTL), U(LALT), END ); - } - break; } return MACRO_NONE; }; From 6d195dc60c696d2e07bfe7d098b00598f36fe5a6 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 3 Jul 2016 16:27:08 +0200 Subject: [PATCH 03/62] Add a Makefile for the keymap to disable command mode (to keep the keyboard from going into command mode when both Shift keys are hold at the same time) and to allow issuing a simple "make" in the keymap folder to compile it. --- keyboards/ergodox_ez/keymaps/bepo/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 keyboards/ergodox_ez/keymaps/bepo/Makefile diff --git a/keyboards/ergodox_ez/keymaps/bepo/Makefile b/keyboards/ergodox_ez/keymaps/bepo/Makefile new file mode 100644 index 0000000000..b673c5ce52 --- /dev/null +++ b/keyboards/ergodox_ez/keymaps/bepo/Makefile @@ -0,0 +1,9 @@ +# Having a file like this allows you to override Makefile definitions +# for your own particular keymap + +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend +COMMAND_ENABLE = no # Commands for debug and configuration + +ifndef QUANTUM_DIR + include ../../../../Makefile +endif From 82edc37238a0f4239da0a6eee74d62773362a2d2 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 3 Jul 2016 16:44:57 +0200 Subject: [PATCH 04/62] Move Escape and Insert keys, Escape is now easier to reach (useful for vi). Change the layer switching used to keep a bepo layout on US keyboards. --- keyboards/ergodox_ez/keymaps/bepo/bepo.png | Bin 79747 -> 80838 bytes keyboards/ergodox_ez/keymaps/bepo/keymap.c | 28 ++++++++++---------- keyboards/ergodox_ez/keymaps/bepo/readme.md | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/keyboards/ergodox_ez/keymaps/bepo/bepo.png b/keyboards/ergodox_ez/keymaps/bepo/bepo.png index 3df7aa609f6300a48c36425320323935aeb435e3..bde2e2cfacb326e7934c5743aea2f303c8a42527 100644 GIT binary patch literal 80838 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%0AWcsmXzWE5KlyO(@CyZ4w=^{y>Z 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%0D`ojd*fJlCKgA-TFAi8|5S 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

Z9MY0`oat-sr%zCY^LfAn;EeA$0% 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 diff --git a/keyboards/ergodox_ez/keymaps/bepo/keymap.c b/keyboards/ergodox_ez/keymaps/bepo/keymap.c index dd47357998..7c30d58788 100644 --- a/keyboards/ergodox_ez/keymaps/bepo/keymap.c +++ b/keyboards/ergodox_ez/keymaps/bepo/keymap.c @@ -24,7 +24,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | E_CIRC |A_GRAV| Y | X | . | K | | | | ' | Q | G | H | F | C_CEDIL| * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * |QWERTY| |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | L_Num| | | * | Space|LShift|------| |------|RShift|Enter | @@ -37,8 +37,8 @@ BP_DOLLAR, BP_DQOT, BP_LGIL, BP_RGIL, BP_LPRN, BP_RPRN, KC_DEL, BP_PERCENT, BP_B, BP_E_ACUTE, BP_P, BP_O, BP_E_GRAVE, KC_BSPC, BP_W, BP_A, BP_U, BP_I, BP_E, BP_COMMA, BP_ECRC, BP_A_GRAVE, BP_Y, BP_X, BP_DOT, BP_K, KC_TAB, -TG(QWER), KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, KC_TRNS, +KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, + DF(BASE), DF(QWER), MO(NUM), KC_SPC, KC_LSHIFT, MO(FNAV), // Right hand @@ -47,7 +47,7 @@ TG(QWER), KC_NO, KC_LGUI, KC_LCTL, KC_LALT, BP_C, BP_T, BP_S, BP_R, BP_N, BP_M, KC_NUMLOCK, BP_APOS, BP_Q, BP_G, BP_H, BP_F, BP_CCED, BP_ALGR, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_TRNS, KC_INS, +DF(QWER), DF(BASE), MO(NUM), MO(FNAV), KC_RSHIFT, KC_ENTER), /* Keymap 1: QWERTY system compatibility layer @@ -61,7 +61,7 @@ MO(FNAV), KC_RSHIFT, KC_ENTER), * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | e | a | y | x | . | k | | | | ' | q | g | h | f | c | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | L_Num| | | * | Space|LShift|------| |------|RShift|Enter | @@ -74,8 +74,8 @@ KC_DOLLAR, S(KC_QUOT), S(KC_COMM), S(KC_DOT), KC_LPRN, KC_RPRN, KC_DEL, KC_PERCENT, KC_B, KC_E, KC_P, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, KC_E, KC_COMMA, KC_E, KC_A, KC_Y, KC_X, KC_DOT, KC_K, KC_TAB, -KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, KC_TRNS, +KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, + DF(BASE), DF(QWER), MO(NUM), KC_SPC, MO(SQWER), MO(FNAV), // Right hand @@ -84,7 +84,7 @@ KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, MO(AQWER), KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_TRNS, KC_INS, +DF(QWER), DF(BASE), MO(NUM), MO(FNAV), MO(SQWER), KC_ENTER), /* Keymap 2: QWERTY shifted system compatibility layer @@ -98,7 +98,7 @@ MO(FNAV), MO(SQWER), KC_ENTER), * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | E | A | Y | X | : | K | | | | ? | Q | G | H | F | C | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | L_Num| | | * | Space|LShift|------| |------|RShift|Enter | @@ -111,7 +111,7 @@ KC_HASH, KC_1, KC_2, KC_3, KC_4, KC_5, KC_TRNS, KC_GRV, S(KC_B), S(KC_E), S(KC_P), S(KC_O), S(KC_E), KC_TRNS, S(KC_W), S(KC_A), S(KC_U), S(KC_I), S(KC_E), KC_SCOLON, S(KC_E), S(KC_A), S(KC_Y), S(KC_X), KC_COLON, S(KC_K), S(KC_TAB), -KC_TRNS, KC_TRNS, S(KC_LGUI), S(KC_LCTL), S(KC_LALT), +S(KC_ESC), S(KC_INS), S(KC_LGUI), S(KC_LCTL), S(KC_LALT), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, @@ -135,7 +135,7 @@ KC_TRNS, KC_TRNS, KC_TRNS), * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| * | e | \ | { | } | . | ~ | | | | ' | q | g | h | f | c | * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * | BEPO | |LSuper| LCtrl| LAlt| |Escape| | | |Insert| | AltGr| RCtrl|RSuper|PrntSc| Pause| + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' * | | | L_Num| | L_Num| | | * | _ |LShift|------| |------|RShift|Enter | @@ -148,8 +148,8 @@ KC_DOLLAR, S(KC_QUOT), S(KC_COMM), S(KC_DOT), KC_LBRC, KC_RBRC, KC_DEL, KC_PERCENT, KC_PIPE, KC_E, KC_AMPR, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, RALT(KC_5), KC_COMMA, KC_E, KC_BSLASH, KC_LCBR, KC_RCBR, KC_DOT, KC_TILDE, KC_TAB, -KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, - KC_ESC, KC_TRNS, +KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, + KC_TRNS, KC_TRNS, MO(NUM), KC_UNDS, MO(SQWER), MO(FNAV), // Right hand @@ -158,7 +158,7 @@ KC_TRNS, KC_NO, KC_LGUI, KC_LCTL, KC_LALT, KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, KC_TRNS, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_TRNS, KC_INS, +KC_TRNS, KC_TRNS, MO(NUM), MO(FNAV), MO(SQWER), KC_ENTER), /* Keymap 4: function / navigation layer diff --git a/keyboards/ergodox_ez/keymaps/bepo/readme.md b/keyboards/ergodox_ez/keymaps/bepo/readme.md index 4a18cd80ff..207b675715 100644 --- a/keyboards/ergodox_ez/keymaps/bepo/readme.md +++ b/keyboards/ergodox_ez/keymaps/bepo/readme.md @@ -27,7 +27,7 @@ Touche de fonction permettant de saisir les touches F1 à F12, les touches F1 à Touche de fonction permettant l'accès au pavé numérique comme sur la TypeMatrix 2030, mais sans avoir à déplacer la main droite : avec les doigts sur la rangée de repos, possibilité de saisir les chiffres "4", "5" et "6" comme sur un pavé numérique classique. Le double "0" de la TypeMatrix a été conservé, et gagne une possibilité de répétition en simples "0". -L'appui sur une touche permet de basculer en mode BEPO sur un système configuré pour un clavier QWERTY. Cette compatibilité n'est pas parfaite (pas encore de gestion des accents mais ça devrait être faisable avec une disposition en qwerty international, et les combinaisons de touches ne sont pas toutes supportées puisque le clavier traduit déjà certaines touches en combinaisons) mais reste pratique pour une saisie de texte occasionnelle. +Touche permettant de basculer en mode BEPO sur un système configuré pour un clavier QWERTY. Cette compatibilité n'est pas parfaite (pas encore de gestion des accents mais ça devrait être faisable avec une disposition en qwerty international, et les combinaisons de touches ne sont pas toutes supportées puisque le clavier traduit déjà certaines touches en combinaisons) mais reste pratique pour une saisie de texte occasionnelle. TODO : couche de compatibilité pour utiliser la disposition BÉPO sur un système configuré pour un clavier AZERTY. From 4cfb262faab653247f4d66d44bf5f3339d82bd36 Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 4 Jul 2016 01:10:40 +0200 Subject: [PATCH 05/62] Spellchecking. --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index c24d951d8d..02207702c4 100644 --- a/readme.md +++ b/readme.md @@ -570,7 +570,7 @@ Enable the backlight from the Makefile. All of these functions are available in the `*_kb()` or `*_user()` variety. `kb` ones should only be used in the `/.c` file, and `user` ones should only be used in the `keymap.c`. The keyboard ones call the user ones - it's necessary to keep these calls to allow the keymap functions to work correctly. -## `void martix_init_*(void)` +## `void matrix_init_*(void)` This function gets called when the matrix is initiated, and can contain start-up code for your keyboard/keymap. From b5172e3afab515b1f93cd09c51b4c6c1b5174dc7 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 20 Aug 2016 18:19:03 +0200 Subject: [PATCH 06/62] Rename file following upstream folder rename. --- keyboards/{ergodox_ez => ergodox}/keymaps/bepo/Makefile | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename keyboards/{ergodox_ez => ergodox}/keymaps/bepo/Makefile (100%) diff --git a/keyboards/ergodox_ez/keymaps/bepo/Makefile b/keyboards/ergodox/keymaps/bepo/Makefile similarity index 100% rename from keyboards/ergodox_ez/keymaps/bepo/Makefile rename to keyboards/ergodox/keymaps/bepo/Makefile From b8679bbe045a2285d6ab6bbc420121b26f516b9a Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 5 Oct 2016 20:41:33 -0400 Subject: [PATCH 07/62] RGBW lights --- keyboards/ergodox/config.h | 2 ++ keyboards/ergodox/keymaps/jack/Makefile | 5 +++++ keyboards/ergodox/keymaps/jack/config.h | 14 ++++++++++++++ keyboards/ergodox/keymaps/jack/keymap.c | 4 ++-- quantum/rgblight.c | 18 +++++++++++++++--- quantum/rgblight.h | 1 + 6 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 keyboards/ergodox/keymaps/jack/Makefile create mode 100644 keyboards/ergodox/keymaps/jack/config.h diff --git a/keyboards/ergodox/config.h b/keyboards/ergodox/config.h index edc60caae1..049c707a56 100644 --- a/keyboards/ergodox/config.h +++ b/keyboards/ergodox/config.h @@ -1,6 +1,8 @@ #ifndef KEYBOARDS_ERGODOX_CONFIG_H_ #define KEYBOARDS_ERGODOX_CONFIG_H_ +#include "config_common.h" + #define MOUSEKEY_DELAY 100 #define MOUSEKEY_INTERVAL 20 #define MOUSEKEY_MAX_SPEED 3 diff --git a/keyboards/ergodox/keymaps/jack/Makefile b/keyboards/ergodox/keymaps/jack/Makefile new file mode 100644 index 0000000000..1e57612788 --- /dev/null +++ b/keyboards/ergodox/keymaps/jack/Makefile @@ -0,0 +1,5 @@ +RGBLIGHT_ENABLE = yes + +ifndef QUANTUM_DIR + include ../../../../Makefile +endif diff --git a/keyboards/ergodox/keymaps/jack/config.h b/keyboards/ergodox/keymaps/jack/config.h new file mode 100644 index 0000000000..01ccfb3a2a --- /dev/null +++ b/keyboards/ergodox/keymaps/jack/config.h @@ -0,0 +1,14 @@ +#ifndef CONFIG_USER_H +#define CONFIG_USER_H + +#include "../../config.h" + +/* ws2812 RGB LED */ +#define RGB_DI_PIN D7 +// #define RGBLIGHT_TIMER +#define RGBLED_NUM 20 // Number of LEDs +#define RGBLIGHT_HUE_STEP 8 +#define RGBLIGHT_SAT_STEP 8 +#define RGBLIGHT_VAL_STEP 8 + +#endif \ No newline at end of file diff --git a/keyboards/ergodox/keymaps/jack/keymap.c b/keyboards/ergodox/keymaps/jack/keymap.c index dda253fa45..1dd5a76187 100644 --- a/keyboards/ergodox/keymaps/jack/keymap.c +++ b/keyboards/ergodox/keymaps/jack/keymap.c @@ -24,7 +24,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NO, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_ENT, MO(1), KC_LEFT,KC_DOWN,KC_UP, KC_RGHT, - KC_NO, KC_NO, + RGB_TOG, RGB_HUI, KC_PGUP, KC_PGDN, KC_SPC,KC_SPC ), @@ -90,7 +90,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) // Runs just one time when the keyboard initializes. void matrix_init_user(void) { - + }; // Runs constantly in the background, in a loop. diff --git a/quantum/rgblight.c b/quantum/rgblight.c index f82e3ec558..801ca1d0d9 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -50,7 +50,11 @@ const uint8_t RGBLED_KNIGHT_INTERVALS[] PROGMEM = {100, 50, 20}; rgblight_config_t rgblight_config; rgblight_config_t inmem_config; -struct cRGB led[RGBLED_NUM]; +#ifdef RGBW + struct cRGBW led[RGBLED_NUM]; +#else + struct cRGB led[RGBLED_NUM]; +#endif uint8_t rgblight_inited = 0; @@ -334,14 +338,22 @@ void rgblight_setrgb(uint8_t r, uint8_t g, uint8_t b) { void rgblight_set(void) { if (rgblight_config.enable) { - ws2812_setleds(led, RGBLED_NUM); + #ifdef RGBW + ws2812_setleds_rgbw(led, RGBLED_NUM); + #else + ws2812_setleds(led, RGBLED_NUM); + #endif } else { for (uint8_t i = 0; i < RGBLED_NUM; i++) { led[i].r = 0; led[i].g = 0; led[i].b = 0; } - ws2812_setleds(led, RGBLED_NUM); + #ifdef RGBW + ws2812_setleds_rgbw(led, RGBLED_NUM); + #else + ws2812_setleds(led, RGBLED_NUM); + #endif } } diff --git a/quantum/rgblight.h b/quantum/rgblight.h index def26c428c..2a712d8be4 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h @@ -1,6 +1,7 @@ #ifndef RGBLIGHT_H #define RGBLIGHT_H +#define RGBW 1 #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) #define RGBLIGHT_MODES 23 From 99ca59baf8d508f3221df5dd89158241925aca14 Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Wed, 12 Oct 2016 12:03:54 -0400 Subject: [PATCH 08/62] I keep mis-using UPPER|LOWER/SLASH, and getting RESET. With RESET shifted to the UPPER+LOWER layer, it is now time to change that key to Alt-Slash, which, in Emacs, does automatic word completion --- keyboards/planck/keymaps/cbbrowne/keymap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/keyboards/planck/keymaps/cbbrowne/keymap.c b/keyboards/planck/keymaps/cbbrowne/keymap.c index 7f1601af75..4742ca5c06 100644 --- a/keyboards/planck/keymaps/cbbrowne/keymap.c +++ b/keyboards/planck/keymaps/cbbrowne/keymap.c @@ -94,6 +94,7 @@ enum macro_id { #define SHIFTQUOTE MT(MOD_RSFT, KC_QUOT) #define ALTRIGHT MT(MOD_LALT, KC_RGHT) #define MVERSION M(M_VERSION) +#define ALTSLASH LALT(KC_SLSH) /* Note that Planck has dimensions 4 rows x 12 columns */ @@ -109,13 +110,13 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [_RAISE] = { /* RAISE */ {KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC}, {_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS}, - {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, QWERTY, KEYPAD, KEYPAD, RESET, _______}, + {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, QWERTY, KEYPAD, KEYPAD, ALTSLASH,_______}, {_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} }, [_LOWER] = { /* LOWER */ {KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC}, {_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE}, - {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, QWERTY, KEYPAD, KEYPAD, RESET, _______}, + {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, QWERTY, KEYPAD, KEYPAD, ALTSLASH, _______}, {_______, KEYPAD, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} }, [_KEYPAD] = { /* Key Pad */ From 5f91fb413624781ac79db641549b9e08753c04b5 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sun, 16 Oct 2016 16:03:33 -0400 Subject: [PATCH 09/62] working with power limit --- build_keyboard.mk | 6 ++ keyboards/ergodox/keymaps/jack/config.h | 2 +- keyboards/ergodox/keymaps/jack/keymap.c | 4 +- quantum/keymap.h | 4 + quantum/light_ws2812.c | 137 +++++++++++++++++++++++- quantum/light_ws2812.h | 7 ++ quantum/quantum.c | 3 + quantum/quantum.h | 4 + 8 files changed, 163 insertions(+), 4 deletions(-) diff --git a/build_keyboard.mk b/build_keyboard.mk index 03a69b1464..cd9f44c7bd 100644 --- a/build_keyboard.mk +++ b/build_keyboard.mk @@ -169,6 +169,12 @@ ifeq ($(strip $(TAP_DANCE_ENABLE)), yes) SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c endif +ifeq ($(strip $(PRINTING_ENABLE)), yes) + OPT_DEFS += -DPRINTING_ENABLE + SRC += $(QUANTUM_DIR)/process_keycode/process_printer.c + SRC += $(TMK_DIR)/protocol/serial_uart.c +endif + ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes) SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC)) OPT_DEFS += $(SERIAL_DEFS) diff --git a/keyboards/ergodox/keymaps/jack/config.h b/keyboards/ergodox/keymaps/jack/config.h index 01ccfb3a2a..f0932084a0 100644 --- a/keyboards/ergodox/keymaps/jack/config.h +++ b/keyboards/ergodox/keymaps/jack/config.h @@ -6,7 +6,7 @@ /* ws2812 RGB LED */ #define RGB_DI_PIN D7 // #define RGBLIGHT_TIMER -#define RGBLED_NUM 20 // Number of LEDs +#define RGBLED_NUM 15 // Number of LEDs #define RGBLIGHT_HUE_STEP 8 #define RGBLIGHT_SAT_STEP 8 #define RGBLIGHT_VAL_STEP 8 diff --git a/keyboards/ergodox/keymaps/jack/keymap.c b/keyboards/ergodox/keymaps/jack/keymap.c index 1dd5a76187..fabd27a618 100644 --- a/keyboards/ergodox/keymaps/jack/keymap.c +++ b/keyboards/ergodox/keymaps/jack/keymap.c @@ -25,7 +25,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_NO, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH, KC_ENT, MO(1), KC_LEFT,KC_DOWN,KC_UP, KC_RGHT, RGB_TOG, RGB_HUI, - KC_PGUP, + RGB_MOD, KC_PGDN, KC_SPC,KC_SPC ), [SYMB] = KEYMAP( @@ -90,7 +90,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) // Runs just one time when the keyboard initializes. void matrix_init_user(void) { - + }; // Runs constantly in the background, in a loop. diff --git a/quantum/keymap.h b/quantum/keymap.h index 98ddfd0c53..41aa116228 100644 --- a/quantum/keymap.h +++ b/quantum/keymap.h @@ -174,6 +174,10 @@ enum quantum_keycodes { // Right shift, close paren KC_RSPC, + // Printing + PRINT_ON, + PRINT_OFF, + // always leave at the end SAFE_RANGE }; diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c index 401845e855..d38dac4c69 100755 --- a/quantum/light_ws2812.c +++ b/quantum/light_ws2812.c @@ -16,6 +16,122 @@ #include #include "debug.h" +#define RGBW_BB_TWI 1 + +#ifdef RGBW_BB_TWI + +// Port for the I2C +#define I2C_DDR DDRD +#define I2C_PIN PIND +#define I2C_PORT PORTD + +// Pins to be used in the bit banging +#define I2C_CLK 0 +#define I2C_DAT 1 + +#define I2C_DATA_HI()\ +I2C_DDR &= ~ (1 << I2C_DAT);\ +I2C_PORT |= (1 << I2C_DAT); +#define I2C_DATA_LO()\ +I2C_DDR |= (1 << I2C_DAT);\ +I2C_PORT &= ~ (1 << I2C_DAT); + +#define I2C_CLOCK_HI()\ +I2C_DDR &= ~ (1 << I2C_CLK);\ +I2C_PORT |= (1 << I2C_CLK); +#define I2C_CLOCK_LO()\ +I2C_DDR |= (1 << I2C_CLK);\ +I2C_PORT &= ~ (1 << I2C_CLK); + +#define I2C_DELAY 1 + +void I2C_WriteBit(unsigned char c) +{ + if (c > 0) + { + I2C_DATA_HI(); + } + else + { + I2C_DATA_LO(); + } + + I2C_CLOCK_HI(); + _delay_us(I2C_DELAY); + + I2C_CLOCK_LO(); + _delay_us(I2C_DELAY); + + if (c > 0) + { + I2C_DATA_LO(); + } + + _delay_us(I2C_DELAY); +} + +// Inits bitbanging port, must be called before using the functions below +// +void I2C_Init() +{ + I2C_PORT &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); + + I2C_CLOCK_HI(); + I2C_DATA_HI(); + + _delay_us(I2C_DELAY); +} + +// Send a START Condition +// +void I2C_Start() +{ + // set both to high at the same time + I2C_DDR &= ~ ((1 << I2C_DAT) | (1 << I2C_CLK)); + _delay_us(I2C_DELAY); + + I2C_DATA_LO(); + _delay_us(I2C_DELAY); + + I2C_CLOCK_LO(); + _delay_us(I2C_DELAY); +} + +// Send a STOP Condition +// +void I2C_Stop() +{ + I2C_CLOCK_HI(); + _delay_us(I2C_DELAY); + + I2C_DATA_HI(); + _delay_us(I2C_DELAY); +} + +// write a byte to the I2C slave device +// +unsigned char I2C_Write(unsigned char c) +{ + for (char i = 0; i < 8; i++) + { + I2C_WriteBit(c & 128); + + c <<= 1; + } + + + I2C_WriteBit(0); + _delay_us(I2C_DELAY); + _delay_us(I2C_DELAY); + + // _delay_us(I2C_DELAY); + //return I2C_ReadBit(); + return 0; +} + + +#endif + // Setleds for standard RGB void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) { @@ -41,6 +157,25 @@ void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) _SFR_IO8((RGB_DI_PIN >> 4) + 1) |= _BV(RGB_DI_PIN & 0xF); ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(RGB_DI_PIN & 0xF)); + + #ifdef RGBW_BB_TWI + cli(); + TWCR = 0; + I2C_Init(); + I2C_Start(); + I2C_Write(0x84); + uint16_t datlen = leds<<2; + uint8_t curbyte; + uint8_t * data = (uint8_t*)ledarray; + while (datlen--) { + curbyte=*data++; + I2C_Write(curbyte % 0x10); + } + I2C_Stop(); + sei(); + #endif + + _delay_us(80); } @@ -123,7 +258,7 @@ void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi) cli(); while (datlen--) { - curbyte=*data++; + curbyte=(*data++) % 0x10; asm volatile( " ldi %0,8 \n\t" diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h index 54eef22d9e..576c3bc483 100755 --- a/quantum/light_ws2812.h +++ b/quantum/light_ws2812.h @@ -16,6 +16,13 @@ #include #include //#include "ws2812_config.h" +#include "i2cmaster.h" + +#define LIGHT_I2C 1 +#define LIGHT_I2C_ADDR 0x84 +#define LIGHT_I2C_ADDR_WRITE ( (LIGHT_I2C_ADDR<<1) | I2C_WRITE ) +#define LIGHT_I2C_ADDR_READ ( (LIGHT_I2C_ADDR<<1) | I2C_READ ) + /* * Structure of the LED array diff --git a/quantum/quantum.c b/quantum/quantum.c index a16bd5443c..5fa5e66b32 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -128,6 +128,9 @@ bool process_record_quantum(keyrecord_t *record) { #endif #ifdef UCIS_ENABLE process_ucis(keycode, record) && + #endif + #ifdef PRINTING_ENABLE + process_printer(keycode, record) && #endif true)) { return false; diff --git a/quantum/quantum.h b/quantum/quantum.h index 0c60466495..06a2e049dc 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -59,6 +59,10 @@ extern uint32_t default_layer_state; #include "process_tap_dance.h" +#ifdef PRINTING_ENABLE + #include "process_printer.h" +#endif + #define SEND_STRING(str) send_string(PSTR(str)) void send_string(const char *str); From a889b899e2cf52b3b7807d8a7ad39f12e0761a10 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sun, 16 Oct 2016 16:03:56 -0400 Subject: [PATCH 10/62] working with power limit --- .../planck/keymaps/thermal_printer/Makefile | 26 ++ .../planck/keymaps/thermal_printer/config.h | 23 ++ .../planck/keymaps/thermal_printer/keymap.c | 314 ++++++++++++++++++ .../planck/keymaps/thermal_printer/readme.md | 2 + quantum/process_keycode/process_printer.c | 254 ++++++++++++++ quantum/process_keycode/process_printer.h | 8 + quantum/process_keycode/process_printer_bb.c | 260 +++++++++++++++ 7 files changed, 887 insertions(+) create mode 100644 keyboards/planck/keymaps/thermal_printer/Makefile create mode 100644 keyboards/planck/keymaps/thermal_printer/config.h create mode 100644 keyboards/planck/keymaps/thermal_printer/keymap.c create mode 100644 keyboards/planck/keymaps/thermal_printer/readme.md create mode 100644 quantum/process_keycode/process_printer.c create mode 100644 quantum/process_keycode/process_printer.h create mode 100644 quantum/process_keycode/process_printer_bb.c diff --git a/keyboards/planck/keymaps/thermal_printer/Makefile b/keyboards/planck/keymaps/thermal_printer/Makefile new file mode 100644 index 0000000000..3d1d11877f --- /dev/null +++ b/keyboards/planck/keymaps/thermal_printer/Makefile @@ -0,0 +1,26 @@ + + +# Build Options +# change to "no" to disable the options, or define them in the Makefile in +# the appropriate keymap folder that will get included automatically +# +BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) +MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +CONSOLE_ENABLE = no # Console for debug(+400) +COMMAND_ENABLE = yes # Commands for debug and configuration +NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work +BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality +MIDI_ENABLE = no # MIDI controls +AUDIO_ENABLE = yes # Audio output on port C6 +UNICODE_ENABLE = no # Unicode +BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID +RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +PRINTING_ENABLE = yes + +# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend + +ifndef QUANTUM_DIR + include ../../../../Makefile +endif diff --git a/keyboards/planck/keymaps/thermal_printer/config.h b/keyboards/planck/keymaps/thermal_printer/config.h new file mode 100644 index 0000000000..430b6493cf --- /dev/null +++ b/keyboards/planck/keymaps/thermal_printer/config.h @@ -0,0 +1,23 @@ +#ifndef CONFIG_USER_H +#define CONFIG_USER_H + +#include "../../config.h" + +# define SERIAL_UART_BAUD 19200 +# define SERIAL_UART_DATA UDR1 +# define SERIAL_UART_UBRR (F_CPU / (16UL * SERIAL_UART_BAUD) - 1) +# define SERIAL_UART_RXD_VECT USART1_RX_vect +# define SERIAL_UART_TXD_READY (UCSR1A & _BV(UDRE1)) +# define SERIAL_UART_INIT() do { \ + /* baud rate */ \ + UBRR1L = SERIAL_UART_UBRR; \ + /* baud rate */ \ + UBRR1H = SERIAL_UART_UBRR >> 8; \ + /* enable TX */ \ + UCSR1B = _BV(TXEN1); \ + /* 8-bit data */ \ + UCSR1C = _BV(UCSZ11) | _BV(UCSZ10); \ + sei(); \ + } while(0) + + #endif \ No newline at end of file diff --git a/keyboards/planck/keymaps/thermal_printer/keymap.c b/keyboards/planck/keymaps/thermal_printer/keymap.c new file mode 100644 index 0000000000..e880597319 --- /dev/null +++ b/keyboards/planck/keymaps/thermal_printer/keymap.c @@ -0,0 +1,314 @@ +// This is the canonical layout file for the Quantum project. If you want to add another keyboard, +// this is the style you want to emulate. + +#include "planck.h" +#include "action_layer.h" +#ifdef AUDIO_ENABLE + #include "audio.h" +#endif +#include "eeconfig.h" + +extern keymap_config_t keymap_config; + +// Each layer gets a name for readability, which is then used in the keymap matrix below. +// The underscores don't mean anything - you can have a layer called STUFF or any other name. +// Layer names don't all need to be of the same length, obviously, and you can also skip them +// entirely and just use numbers. +#define _QWERTY 0 +#define _COLEMAK 1 +#define _DVORAK 2 +#define _LOWER 3 +#define _RAISE 4 +#define _PLOVER 5 +#define _ADJUST 16 + +enum planck_keycodes { + QWERTY = SAFE_RANGE, + COLEMAK, + DVORAK, + PLOVER, + LOWER, + RAISE, + BACKLIT, + EXT_PLV +}; + +// Fillers to make layering more clear +#define _______ KC_TRNS +#define XXXXXXX KC_NO + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +/* Qwerty + * ,-----------------------------------------------------------------------------------. + * | Tab | Q | W | E | R | T | Y | U | I | O | P | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Esc | A | S | D | F | G | H | J | K | L | ; | " | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | Shift| Z | X | C | V | B | N | M | , | . | / |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | Brite| Ctrl | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right | + * `-----------------------------------------------------------------------------------' + */ +[_QWERTY] = { + {KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC}, + {KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT}, + {KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT }, + {BACKLIT, KC_LCTL, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT} +}, + +/* Colemak + * ,-----------------------------------------------------------------------------------. + * | Tab | Q | W | F | P | G | J | L | U | Y | ; | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Esc | A | R | S | T | D | H | N | E | I | O | " | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | Shift| Z | X | C | V | B | K | M | , | . | / |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | Brite| Ctrl | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right | + * `-----------------------------------------------------------------------------------' + */ +[_COLEMAK] = { + {KC_TAB, KC_Q, KC_W, KC_F, KC_P, KC_G, KC_J, KC_L, KC_U, KC_Y, KC_SCLN, KC_BSPC}, + {KC_ESC, KC_A, KC_R, KC_S, KC_T, KC_D, KC_H, KC_N, KC_E, KC_I, KC_O, KC_QUOT}, + {KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_K, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT }, + {BACKLIT, KC_LCTL, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT} +}, + +/* Dvorak + * ,-----------------------------------------------------------------------------------. + * | Tab | " | , | . | P | Y | F | G | C | R | L | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Esc | A | O | E | U | I | D | H | T | N | S | / | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | Shift| ; | Q | J | K | X | B | M | W | V | Z |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | Brite| Ctrl | Alt | GUI |Lower | Space |Raise | Left | Down | Up |Right | + * `-----------------------------------------------------------------------------------' + */ +[_DVORAK] = { + {KC_TAB, KC_QUOT, KC_COMM, KC_DOT, KC_P, KC_Y, KC_F, KC_G, KC_C, KC_R, KC_L, KC_BSPC}, + {KC_ESC, KC_A, KC_O, KC_E, KC_U, KC_I, KC_D, KC_H, KC_T, KC_N, KC_S, KC_SLSH}, + {KC_LSFT, KC_SCLN, KC_Q, KC_J, KC_K, KC_X, KC_B, KC_M, KC_W, KC_V, KC_Z, KC_ENT }, + {BACKLIT, KC_LCTL, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT} +}, + +/* Lower + * ,-----------------------------------------------------------------------------------. + * | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Del | F1 | F2 | F3 | F4 | F5 | F6 | _ | + | { | } | | | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | | F7 | F8 | F9 | F10 | F11 | F12 |ISO ~ |ISO | | | |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | | | | | | | | Next | Vol- | Vol+ | Play | + * `-----------------------------------------------------------------------------------' + */ +[_LOWER] = { + {KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC}, + {KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE}, + {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,S(KC_NUHS),S(KC_NUBS),_______, _______, _______}, + {_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} +}, + +/* Raise + * ,-----------------------------------------------------------------------------------. + * | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | Bksp | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | Del | F1 | F2 | F3 | F4 | F5 | F6 | - | = | [ | ] | \ | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | | F7 | F8 | F9 | F10 | F11 | F12 |ISO # |ISO / | | |Enter | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | | | | | | | | Next | Vol- | Vol+ | Play | + * `-----------------------------------------------------------------------------------' + */ +[_RAISE] = { + {KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC}, + {KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS}, + {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NUHS, KC_NUBS, _______, _______, _______}, + {_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} +}, + +/* Plover layer (http://opensteno.org) + * ,-----------------------------------------------------------------------------------. + * | # | # | # | # | # | # | # | # | # | # | # | # | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | | S | T | P | H | * | * | F | P | L | T | D | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * |TogOut| S | K | W | R | * | * | R | B | G | S | Z | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | Exit | | | A | O | | E | U | | | | + * `-----------------------------------------------------------------------------------' + */ + +[_PLOVER] = { + {KC_1, KC_1, KC_1, KC_1, KC_1, KC_1, KC_1, KC_1, KC_1, KC_1, KC_1, KC_1 }, + {XXXXXXX, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC}, + {XXXXXXX, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT}, + {EXT_PLV, XXXXXXX, XXXXXXX, KC_C, KC_V, XXXXXXX, XXXXXXX, KC_N, KC_M, XXXXXXX, XXXXXXX, XXXXXXX} +}, + +/* Adjust (Lower + Raise) + * ,-----------------------------------------------------------------------------------. + * | | Reset| | Print|no prnt | | | | | | | Del | + * |------+------+------+------+------+-------------+------+------+------+------+------| + * | | | |Aud on|Audoff|AGnorm|AGswap|Qwerty|Colemk|Dvorak|Plover| | + * |------+------+------+------+------+------|------+------+------+------+------+------| + * | |Voice-|Voice+|Mus on|Musoff|MIDIon|MIDIof| | | | | | + * |------+------+------+------+------+------+------+------+------+------+------+------| + * | | | | | | | | | | | | + * `-----------------------------------------------------------------------------------' + */ +[_ADJUST] = { + {_______, RESET, _______, PRINT_ON, PRINT_OFF, _______, _______, _______, _______, _______, _______, KC_DEL}, + {_______, _______, _______, AU_ON, AU_OFF, AG_NORM, AG_SWAP, QWERTY, COLEMAK, DVORAK, PLOVER, _______}, + {_______, MUV_DE, MUV_IN, MU_ON, MU_OFF, MI_ON, MI_OFF, _______, _______, _______, _______, _______}, + {_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______} +} + + +}; + +#ifdef AUDIO_ENABLE + +float tone_startup[][2] = SONG(STARTUP_SOUND); +float tone_qwerty[][2] = SONG(QWERTY_SOUND); +float tone_dvorak[][2] = SONG(DVORAK_SOUND); +float tone_colemak[][2] = SONG(COLEMAK_SOUND); +float tone_plover[][2] = SONG(PLOVER_SOUND); +float tone_plover_gb[][2] = SONG(PLOVER_GOODBYE_SOUND); +float music_scale[][2] = SONG(MUSIC_SCALE_SOUND); + +float tone_goodbye[][2] = SONG(GOODBYE_SOUND); +#endif + + +void persistant_default_layer_set(uint16_t default_layer) { + eeconfig_update_default_layer(default_layer); + default_layer_set(default_layer); +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + case QWERTY: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_qwerty, false, 0); + #endif + persistant_default_layer_set(1UL<<_QWERTY); + } + return false; + break; + case COLEMAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_colemak, false, 0); + #endif + persistant_default_layer_set(1UL<<_COLEMAK); + } + return false; + break; + case DVORAK: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_dvorak, false, 0); + #endif + persistant_default_layer_set(1UL<<_DVORAK); + } + return false; + break; + case LOWER: + if (record->event.pressed) { + layer_on(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_LOWER); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case RAISE: + if (record->event.pressed) { + layer_on(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } else { + layer_off(_RAISE); + update_tri_layer(_LOWER, _RAISE, _ADJUST); + } + return false; + break; + case BACKLIT: + if (record->event.pressed) { + register_code(KC_RSFT); + #ifdef BACKLIGHT_ENABLE + backlight_step(); + #endif + } else { + unregister_code(KC_RSFT); + } + return false; + break; + case PLOVER: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + stop_all_notes(); + PLAY_NOTE_ARRAY(tone_plover, false, 0); + #endif + layer_off(_RAISE); + layer_off(_LOWER); + layer_off(_ADJUST); + layer_on(_PLOVER); + if (!eeconfig_is_enabled()) { + eeconfig_init(); + } + keymap_config.raw = eeconfig_read_keymap(); + keymap_config.nkro = 1; + eeconfig_update_keymap(keymap_config.raw); + } + return false; + break; + case EXT_PLV: + if (record->event.pressed) { + #ifdef AUDIO_ENABLE + PLAY_NOTE_ARRAY(tone_plover_gb, false, 0); + #endif + layer_off(_PLOVER); + } + return false; + break; + } + return true; +} + +void matrix_init_user(void) { + #ifdef AUDIO_ENABLE + startup_user(); + #endif +} + +#ifdef AUDIO_ENABLE + +void startup_user() +{ + _delay_ms(20); // gets rid of tick + PLAY_NOTE_ARRAY(tone_startup, false, 0); +} + +void shutdown_user() +{ + PLAY_NOTE_ARRAY(tone_goodbye, false, 0); + _delay_ms(150); + stop_all_notes(); +} + +void music_on_user(void) +{ + music_scale_user(); +} + +void music_scale_user(void) +{ + PLAY_NOTE_ARRAY(music_scale, false, 0); +} + +#endif diff --git a/keyboards/planck/keymaps/thermal_printer/readme.md b/keyboards/planck/keymaps/thermal_printer/readme.md new file mode 100644 index 0000000000..de9680b498 --- /dev/null +++ b/keyboards/planck/keymaps/thermal_printer/readme.md @@ -0,0 +1,2 @@ +# The Default Planck Layout + diff --git a/quantum/process_keycode/process_printer.c b/quantum/process_keycode/process_printer.c new file mode 100644 index 0000000000..2e11dd366c --- /dev/null +++ b/quantum/process_keycode/process_printer.c @@ -0,0 +1,254 @@ +#include "process_printer.h" +#include "action_util.h" + +bool printing_enabled = false; +uint8_t character_shift = 0; + +void enabled_printing() { + printing_enabled = true; + serial_init(); +} + +void disable_printing() { + printing_enabled = false; +} + +uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29}; + +// uint8_t keycode_to_ascii[0xFF][2]; + +// keycode_to_ascii[KC_MINS] = {0x2D, 0x5F}; + +void print_char(char c) { + USB_Disable(); + serial_send(c); + USB_Init(); +} + +void print_box_string(uint8_t text[]) { + uint8_t len = strlen(text); + uint8_t out[len * 3 + 8]; + out[0] = 0xDA; + for (uint8_t i = 0; i < len; i++) { + out[i+1] = 0xC4; + } + out[len + 1] = 0xBF; + out[len + 2] = '\n'; + + out[len + 3] = 0xB3; + for (uint8_t i = 0; i < len; i++) { + out[len + 4 + i] = text[i]; + } + out[len * 2 + 4] = 0xB3; + out[len * 2 + 5] = '\n'; + + + out[len * 2 + 6] = 0xC0; + for (uint8_t i = 0; i < len; i++) { + out[len * 2 + 7 + i] = 0xC4; + } + out[len * 3 + 7] = 0xD9; + out[len * 3 + 8] = '\n'; + + print_string(out); +} + +void print_string(char c[]) { + for(uint8_t i = 0; i < strlen(c); i++) + print_char(c[i]); +} + +bool process_printer(uint16_t keycode, keyrecord_t *record) { + if (keycode == PRINT_ON) { + enabled_printing(); + return false; + } + if (keycode == PRINT_OFF) { + disable_printing(); + return false; + } + + if (printing_enabled) { + switch(keycode) { + case KC_EXLM ... KC_RPRN: + case KC_UNDS: + case KC_PLUS: + case KC_LCBR: + case KC_RCBR: + case KC_PIPE: + case KC_TILD: + keycode &= 0xFF; + case KC_LSFT: + case KC_RSFT: + if (record->event.pressed) { + character_shift++; + } else { + character_shift--; + } + return false; + break; + } + + switch(keycode) { + case KC_F1: + if (record->event.pressed) { + print_box_string("This is a line of text!"); + } + return false; + case KC_ESC: + if (record->event.pressed) { + print_char(0x1B); + } + return false; + break; + case KC_SPC: + if (record->event.pressed) { + print_char(0x20); + } + return false; + break; + case KC_A ... KC_Z: + if (record->event.pressed) { + if (character_shift) { + print_char(0x41 + (keycode - KC_A)); + } else { + print_char(0x61 + (keycode - KC_A)); + } + } + return false; + break; + case KC_1 ... KC_0: + if (record->event.pressed) { + if (character_shift) { + print_char(shifted_numbers[keycode - KC_1]); + } else { + print_char(0x30 + ((keycode - KC_1 + 1) % 10)); + } + } + return false; + break; + case KC_ENT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x0C); + } else { + print_char(0x0A); + } + } + return false; + break; + case KC_BSPC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x18); + } else { + print_char(0x1A); + } + } + return false; + break; + case KC_DOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3E); + } else { + print_char(0x2E); + } + } + return false; + break; + case KC_COMM: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3C); + } else { + print_char(0x2C); + } + } + return false; + break; + case KC_SLSH: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3F); + } else { + print_char(0x2F); + } + } + return false; + break; + case KC_QUOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x22); + } else { + print_char(0x27); + } + } + return false; + break; + case KC_GRV: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7E); + } else { + print_char(0x60); + } + } + return false; + break; + case KC_MINS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x5F); + } else { + print_char(0x2D); + } + } + return false; + break; + case KC_EQL: + if (record->event.pressed) { + if (character_shift) { + print_char(0x2B); + } else { + print_char(0x3D); + } + } + return false; + break; + case KC_LBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7B); + } else { + print_char(0x5B); + } + } + return false; + break; + case KC_RBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7D); + } else { + print_char(0x5D); + } + } + return false; + break; + case KC_BSLS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7C); + } else { + print_char(0x5C); + } + } + return false; + break; + } + } + return true; + +} \ No newline at end of file diff --git a/quantum/process_keycode/process_printer.h b/quantum/process_keycode/process_printer.h new file mode 100644 index 0000000000..fdd36d75a8 --- /dev/null +++ b/quantum/process_keycode/process_printer.h @@ -0,0 +1,8 @@ +#ifndef PROCESS_PRINTER_H +#define PROCESS_PRINTER_H + +#include "quantum.h" + +#include "protocol/serial.h" + +#endif \ No newline at end of file diff --git a/quantum/process_keycode/process_printer_bb.c b/quantum/process_keycode/process_printer_bb.c new file mode 100644 index 0000000000..1924d03774 --- /dev/null +++ b/quantum/process_keycode/process_printer_bb.c @@ -0,0 +1,260 @@ +#include "process_printer.h" +#include "action_util.h" + +bool printing_enabled = false; +uint8_t character_shift = 0; + +#define SERIAL_PIN_DDR DDRD +#define SERIAL_PIN_PORT PORTD +#define SERIAL_PIN_MASK _BV(PD3) +#define SERIAL_DELAY 52 + +inline static +void serial_delay(void) { + _delay_us(SERIAL_DELAY); +} + +inline static +void serial_high(void) { + SERIAL_PIN_PORT |= SERIAL_PIN_MASK; +} + +inline static +void serial_low(void) { + SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; +} + +inline static +void serial_output(void) { + SERIAL_PIN_DDR |= SERIAL_PIN_MASK; +} + + +void enabled_printing() { + printing_enabled = true; + serial_output(); + serial_high(); +} + +void disable_printing() { + printing_enabled = false; +} + +uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29}; + +// uint8_t keycode_to_ascii[0xFF][2]; + +// keycode_to_ascii[KC_MINS] = {0x2D, 0x5F}; + +void print_char(char c) { + uint8_t b = 8; + serial_output(); + while( b-- ) { + if(c & (1 << b)) { + serial_high(); + } else { + serial_low(); + } + serial_delay(); + } +} + +void print_string(char c[]) { + for(uint8_t i = 0; i < strlen(c); i++) + print_char(c[i]); +} + +bool process_printer(uint16_t keycode, keyrecord_t *record) { + if (keycode == PRINT_ON) { + enabled_printing(); + return false; + } + if (keycode == PRINT_OFF) { + disable_printing(); + return false; + } + + if (printing_enabled) { + switch(keycode) { + case KC_EXLM ... KC_RPRN: + case KC_UNDS: + case KC_PLUS: + case KC_LCBR: + case KC_RCBR: + case KC_PIPE: + case KC_TILD: + keycode &= 0xFF; + case KC_LSFT: + case KC_RSFT: + if (record->event.pressed) { + character_shift++; + } else { + character_shift--; + } + return false; + break; + } + + switch(keycode) { + case KC_F1: + if (record->event.pressed) { + print_string("This is a line of text!\n\n\n"); + } + return false; + case KC_ESC: + if (record->event.pressed) { + print_char(0x1B); + } + return false; + break; + case KC_SPC: + if (record->event.pressed) { + print_char(0x20); + } + return false; + break; + case KC_A ... KC_Z: + if (record->event.pressed) { + if (character_shift) { + print_char(0x41 + (keycode - KC_A)); + } else { + print_char(0x61 + (keycode - KC_A)); + } + } + return false; + break; + case KC_1 ... KC_0: + if (record->event.pressed) { + if (character_shift) { + print_char(shifted_numbers[keycode - KC_1]); + } else { + print_char(0x30 + ((keycode - KC_1 + 1) % 10)); + } + } + return false; + break; + case KC_ENT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x0C); + } else { + print_char(0x0A); + } + } + return false; + break; + case KC_BSPC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x18); + } else { + print_char(0x1A); + } + } + return false; + break; + case KC_DOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3E); + } else { + print_char(0x2E); + } + } + return false; + break; + case KC_COMM: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3C); + } else { + print_char(0x2C); + } + } + return false; + break; + case KC_SLSH: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3F); + } else { + print_char(0x2F); + } + } + return false; + break; + case KC_QUOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x22); + } else { + print_char(0x27); + } + } + return false; + break; + case KC_GRV: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7E); + } else { + print_char(0x60); + } + } + return false; + break; + case KC_MINS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x5F); + } else { + print_char(0x2D); + } + } + return false; + break; + case KC_EQL: + if (record->event.pressed) { + if (character_shift) { + print_char(0x2B); + } else { + print_char(0x3D); + } + } + return false; + break; + case KC_LBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7B); + } else { + print_char(0x5B); + } + } + return false; + break; + case KC_RBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7D); + } else { + print_char(0x5D); + } + } + return false; + break; + case KC_BSLS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7C); + } else { + print_char(0x5C); + } + } + return false; + break; + } + } + return true; + +} \ No newline at end of file From e9f748751808de2f1e85cf7fb670d78773bd5e76 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sun, 13 Nov 2016 23:02:38 -0500 Subject: [PATCH 11/62] mostly working --- keyboards/ergodox/ez/ez.c | 10 ++- keyboards/ergodox/ez/matrix.c | 2 +- keyboards/ergodox/keymaps/jack/Makefile | 1 + keyboards/ergodox/keymaps/jack/config.h | 4 +- quantum/light_ws2812.c | 21 +++-- quantum/light_ws2812.h | 14 +++- quantum/quantum.c | 1 + quantum/rgblight.c | 101 ++++++++++++------------ quantum/rgblight.h | 10 ++- tmk_core/protocol/lufa/lufa.c | 33 +++++++- 10 files changed, 125 insertions(+), 72 deletions(-) diff --git a/keyboards/ergodox/ez/ez.c b/keyboards/ergodox/ez/ez.c index ddb8ff0cf7..039e4c6bb1 100644 --- a/keyboards/ergodox/ez/ez.c +++ b/keyboards/ergodox/ez/ez.c @@ -16,10 +16,10 @@ void matrix_init_kb(void) { // unused pins - C7, D4, D5, D7, E6 // set as input with internal pull-ip enabled DDRC &= ~(1<<7); - DDRD &= ~(1<<7 | 1<<5 | 1<<4); + DDRD &= ~(1<<5 | 1<<4); DDRE &= ~(1<<6); PORTC |= (1<<7); - PORTD |= (1<<7 | 1<<5 | 1<<4); + PORTD |= (1<<5 | 1<<4); PORTE |= (1<<6); ergodox_blink_all_leds(); @@ -51,6 +51,10 @@ uint8_t init_mcp23018(void) { mcp23018_status = 0x20; // I2C subsystem + + uint8_t sreg_prev; + sreg_prev=SREG; + cli(); if (i2c_initialized == 0) { i2c_init(); // on pins D(1,0) i2c_initialized++; @@ -79,6 +83,8 @@ uint8_t init_mcp23018(void) { out: i2c_stop(); + SREG=sreg_prev; + return mcp23018_status; } diff --git a/keyboards/ergodox/ez/matrix.c b/keyboards/ergodox/ez/matrix.c index a19bab90b2..43f5152591 100644 --- a/keyboards/ergodox/ez/matrix.c +++ b/keyboards/ergodox/ez/matrix.c @@ -121,7 +121,7 @@ void matrix_init(void) matrix_scan_count = 0; #endif - matrix_init_kb(); + matrix_init_quantum(); } diff --git a/keyboards/ergodox/keymaps/jack/Makefile b/keyboards/ergodox/keymaps/jack/Makefile index 1e57612788..7c257af501 100644 --- a/keyboards/ergodox/keymaps/jack/Makefile +++ b/keyboards/ergodox/keymaps/jack/Makefile @@ -1,4 +1,5 @@ RGBLIGHT_ENABLE = yes +MIDI_ENABLE = yes ifndef QUANTUM_DIR include ../../../../Makefile diff --git a/keyboards/ergodox/keymaps/jack/config.h b/keyboards/ergodox/keymaps/jack/config.h index 1781563b84..5bf109c184 100644 --- a/keyboards/ergodox/keymaps/jack/config.h +++ b/keyboards/ergodox/keymaps/jack/config.h @@ -5,10 +5,12 @@ /* ws2812 RGB LED */ #define RGB_DI_PIN D7 -// #define RGBLIGHT_TIMER +#define RGBLIGHT_TIMER #define RGBLED_NUM 15 // Number of LEDs #define RGBLIGHT_HUE_STEP 12 #define RGBLIGHT_SAT_STEP 255 #define RGBLIGHT_VAL_STEP 12 +#define RGB_MIDI + #endif \ No newline at end of file diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c index 497543339b..6edbc0f2bd 100755 --- a/quantum/light_ws2812.c +++ b/quantum/light_ws2812.c @@ -133,13 +133,13 @@ unsigned char I2C_Write(unsigned char c) #endif // Setleds for standard RGB -void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds) +void inline ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) { // ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin)); ws2812_setleds_pin(ledarray,leds, _BV(RGB_DI_PIN & 0xF)); } -void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask) +void inline ws2812_setleds_pin(LED_TYPE *ledarray, uint16_t leds, uint8_t pinmask) { // ws2812_DDRREG |= pinmask; // Enable DDR // new universal format (DDR) @@ -150,12 +150,15 @@ void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pin } // Setleds for SK6812RGBW -void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds) +void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) { #ifdef RGBW_BB_TWI + uint8_t sreg_prev, twcr_prev; + sreg_prev=SREG; + twcr_prev=TWCR; cli(); - TWCR = 0; + TWCR &= ~(1<> 8) & 0xff; - OCR3AL = RGBLED_TIMER_TOP & 0xff; - SREG = sreg; + // static uint8_t rgblight_timer_is_init = 0; + // if (rgblight_timer_is_init) { + // return; + // } + // rgblight_timer_is_init = 1; + // /* Timer 3 setup */ + // TCCR3B = _BV(WGM32) // CTC mode OCR3A as TOP + // | _BV(CS30); // Clock selelct: clk/1 + // /* Set TOP value */ + // uint8_t sreg = SREG; + // cli(); + // OCR3AH = (RGBLED_TIMER_TOP >> 8) & 0xff; + // OCR3AL = RGBLED_TIMER_TOP & 0xff; + // SREG = sreg; + + rgblight_timer_enabled = true; } void rgblight_timer_enable(void) { - TIMSK3 |= _BV(OCIE3A); + rgblight_timer_enabled = true; dprintf("TIMER3 enabled.\n"); } void rgblight_timer_disable(void) { - TIMSK3 &= ~_BV(OCIE3A); + rgblight_timer_enabled = false; dprintf("TIMER3 disabled.\n"); } void rgblight_timer_toggle(void) { - TIMSK3 ^= _BV(OCIE3A); + rgblight_timer_enabled ^= rgblight_timer_enabled; dprintf("TIMER3 toggled.\n"); } -ISR(TIMER3_COMPA_vect) { - // mode = 1, static light, do nothing here - if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { - // mode = 2 to 5, breathing mode - rgblight_effect_breathing(rgblight_config.mode - 2); - } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) { - // mode = 6 to 8, rainbow mood mod - rgblight_effect_rainbow_mood(rgblight_config.mode - 6); - } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) { - // mode = 9 to 14, rainbow swirl mode - rgblight_effect_rainbow_swirl(rgblight_config.mode - 9); - } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) { - // mode = 15 to 20, snake mode - rgblight_effect_snake(rgblight_config.mode - 15); - } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) { - // mode = 21 to 23, knight mode - rgblight_effect_knight(rgblight_config.mode - 21); +void rgblight_task(void) { + if (rgblight_timer_enabled) { + // mode = 1, static light, do nothing here + if (rgblight_config.mode >= 2 && rgblight_config.mode <= 5) { + // mode = 2 to 5, breathing mode + rgblight_effect_breathing(rgblight_config.mode - 2); + } else if (rgblight_config.mode >= 6 && rgblight_config.mode <= 8) { + // mode = 6 to 8, rainbow mood mod + rgblight_effect_rainbow_mood(rgblight_config.mode - 6); + } else if (rgblight_config.mode >= 9 && rgblight_config.mode <= 14) { + // mode = 9 to 14, rainbow swirl mode + rgblight_effect_rainbow_swirl(rgblight_config.mode - 9); + } else if (rgblight_config.mode >= 15 && rgblight_config.mode <= 20) { + // mode = 15 to 20, snake mode + rgblight_effect_snake(rgblight_config.mode - 15); + } else if (rgblight_config.mode >= 21 && rgblight_config.mode <= 23) { + // mode = 21 to 23, knight mode + rgblight_effect_knight(rgblight_config.mode - 21); + } } } @@ -461,7 +462,7 @@ void rgblight_effect_rainbow_swirl(uint8_t interval) { last_timer = timer_read(); for (i = 0; i < RGBLED_NUM; i++) { hue = (360 / RGBLED_NUM * i + current_hue) % 360; - sethsv(hue, rgblight_config.sat, rgblight_config.val, &led[i]); + sethsv(hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&led[i]); } rgblight_set(); @@ -498,7 +499,7 @@ void rgblight_effect_snake(uint8_t interval) { k = k + RGBLED_NUM; } if (i == k) { - sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), &led[i]); + sethsv(rgblight_config.hue, rgblight_config.sat, (uint8_t)(rgblight_config.val*(RGBLIGHT_EFFECT_SNAKE_LENGTH-j)/RGBLIGHT_EFFECT_SNAKE_LENGTH), (LED_TYPE *)&led[i]); } } } @@ -518,7 +519,7 @@ void rgblight_effect_knight(uint8_t interval) { static uint16_t last_timer = 0; uint8_t i, j, cur; int8_t k; - struct cRGB preled[RGBLED_NUM]; + LED_TYPE preled[RGBLED_NUM]; static int8_t increment = -1; if (timer_elapsed(last_timer) < pgm_read_byte(&RGBLED_KNIGHT_INTERVALS[interval])) { return; @@ -537,7 +538,7 @@ void rgblight_effect_knight(uint8_t interval) { k = RGBLED_NUM - 1; } if (i == k) { - sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, &preled[i]); + sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val, (LED_TYPE *)&preled[i]); } } } diff --git a/quantum/rgblight.h b/quantum/rgblight.h index efc685f312..d16ba24e53 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h @@ -1,8 +1,6 @@ #ifndef RGBLIGHT_H #define RGBLIGHT_H -#define RGBW 1 - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) #define RGBLIGHT_MODES 23 #else @@ -35,6 +33,7 @@ #endif #define RGBLED_TIMER_TOP F_CPU/(256*64) +// #define RGBLED_TIMER_TOP 0xFF10 #include #include @@ -79,10 +78,13 @@ void eeconfig_update_rgblight(uint32_t val); void eeconfig_update_rgblight_default(void); void eeconfig_debug_rgblight(void); -void sethsv(uint16_t hue, uint8_t sat, uint8_t val, struct cRGB *led1); -void setrgb(uint8_t r, uint8_t g, uint8_t b, struct cRGB *led1); +void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1); +void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1); void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val); + +void rgblight_task(void); + void rgblight_timer_init(void); void rgblight_timer_enable(void); void rgblight_timer_disable(void); diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 01c0e45b0b..fe466f6047 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -71,6 +71,10 @@ #include "virtser.h" #endif +#ifdef RGB_MIDI + #include "rgblight.h" +#endif + uint8_t keyboard_idle = 0; /* 0: Boot Protocol, 1: Report Protocol(default) */ uint8_t keyboard_protocol = 1; @@ -1045,6 +1049,10 @@ int main(void) #endif keyboard_task(); +#ifdef RGBLIGHT_ENABLE + rgblight_task(); +#endif + #ifdef VIRTSER_ENABLE virtser_task(); CDC_Device_USBTask(&cdc_device); @@ -1077,15 +1085,34 @@ void fallthrough_callback(MidiDevice * device, #endif } +#ifdef RGB_MIDI + rgblight_config_t rgblight_config; +#endif + void cc_callback(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t val) { //sending it back on the next channel - midi_send_cc(device, (chan + 1) % 16, num, val); + // midi_send_cc(device, (chan + 1) % 16, num, val); + #ifdef RGB_MIDI + rgblight_config.raw = eeconfig_read_rgblight(); + switch (num) { + case 14: + rgblight_config.hue = val * 360 / 127; + break; + case 15: + rgblight_config.sat = val << 1; + break; + case 16: + rgblight_config.val = val << 1; + break; + } + rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); + #endif } void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) { - for (int i = 0; i < length; i++) - midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i)); + // for (int i = 0; i < length; i++) + // midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i)); } #endif From 702405f0391463cc5d0c8c8109304ac8d0ec844a Mon Sep 17 00:00:00 2001 From: Noah Andrews Date: Mon, 14 Nov 2016 10:03:18 -0500 Subject: [PATCH 12/62] Recommend WSL on Windows 10 At this point, I consider the batch scripts @IBNobody and I worked on to mostly be a failure. They've proven to be unreliable, too dependent on the environment they're being run in, and I've seen far too many examples of people having frustrating issues with them that I haven't been able to help them with. They can also produce misleading and confusing error messages. I've been pointing people to use the WSL for a while now. Eventually, I think we should make a proper replacement for the batch scripts, possibly with an environment in msys2. For now, the WSL method in Windows 10 is far more reliable, and is easy to set up. I also cleaned up some things in the WSL instructions themselves. --- readme.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/readme.md b/readme.md index d5a259ccb8..4eed2c776b 100644 --- a/readme.md +++ b/readme.md @@ -45,19 +45,19 @@ Before you are able to compile, you'll need to install an environment for AVR de ### Windows 10 -It's still recommended to use the method for Vista and later below. The reason for this is that the Windows 10 Subsystem for Linux lacks [USB support](https://wpdev.uservoice.com/forums/266908-command-prompt-console-bash-on-ubuntu-on-windo/suggestions/13355724-unable-to-access-usb-devices-from-bash), so it's not possible to flash the firmware to the keyboard. Please add your vote to the link! +Due to some issues with the "Windows (Vista and later)" instructions below, we now recommend following these instructions if you use Windows, which will allow you to use the Windows Subsystem for Linux to compile the firmware. If you are not using Windows 10 with the Anniversary Update installed (which came out in July 2016), you will need to use one of the other methods, such as Docker, Vagrant, or the instructions for Vista and later. -That said, it's still possible to use it for compilation. And recommended, if you need to compile much, since it's much faster than at least Cygwin (which is also supported, but currently lacking documentation). I haven't tried the method below, so I'm unable to tell. +If you use this method, you will need to use a standalone tool to flash the firmware to the keyboard after you compile it. We recommend the official [QMK Firmware Flasher](https://github.com/jackhumbert/qmk_firmware_flasher/releases). This is because the Windows 10 Subsystem for Linux lacks [libUSB support](https://wpdev.uservoice.com/forums/266908-command-prompt-console-bash-on-ubuntu-on-windo/suggestions/13355724-unable-to-access-usb-devices-from-bash), so it can't access the keyboard's microcontroller. Please add your vote for Microsoft to fix this issue using the link! Here are the steps 1. Install the Windows 10 subsystem for Linux, following [these instructions](http://www.howtogeek.com/249966/how-to-install-and-use-the-linux-bash-shell-on-windows-10/). -2. If you have previously cloned the repository using the normal Git bash, you will need to clean up the line endings. If you have cloned it after 20th of August 2016, you are likely fine. To clean up the line endings do the following - 1. Make sure that you have no changes you haven't committed by running `git status`, if you do commit them first - 2. From within the Git bash run `git rm --cached -r .` - 3. Followed by `git reset --hard` -3. Start the "Bash On Ubuntu On Windows" from the start menu -4. With the bash open, navigate to your Git checkout. The harddisk can be accessed from `/mnt` for example `/mnt/c` for the `c:\` drive. +2. If you have cloned the repository using git before August 20, 2016, clean up the line endings from wherever you currently access git: + 1. Make sure that you have no changes you haven't committed by running `git status`. ANY UNCOMMITTED CHANGES WILL BE PERMANENTLY LOST. + 2. Run `git rm --cached -r .` + 3. Run `git reset --hard` +3. Open "Bash On Ubuntu On Windows" from the start menu +4. With the bash window open, navigate to your copy of the [qmk_firmware repository](https://github.com/jackhumbert/qmk_firmware) using the `cd` command. The harddisks can be accessed from `/mnt/`. For example, your main hard drive (C:) can be accessed by executiing the command `cd /mnt/c`. If your username is John and the qmk_firmware folder is in your Downloads folder, you can move to it with the command `cd /mnt/c/Users/John/Downloads/qmk_firmware`. You can use the Tab key as you go to help you autocomplete the folder names. 5. Run `sudo util/install_dependencies.sh`. 6. After a while the installation will finish, and you are good to go @@ -1305,4 +1305,4 @@ This will add a traced variable named "layer" (the name is just for your informa In order to actually detect changes to the variables you should call `VERIFY_TRACED_VARIABLES` around the code that you think that modifies the variable. If a variable is modified it will tell you between which two `VERIFY_TRACED_VARIABLES` calls the modification happened. You can then add more calls to track it down further. I don't recommend spamming the codebase with calls. It's better to start with a few, and then keep adding them in a binary search fashion. You can also delete the ones you don't need, as each call need to store the file name and line number in the ROM, so you can run out of memory if you add too many calls. -Also remember to delete all the tracing code ones you have found the bug, as you wouldn't want to create a pull request with tracing code. \ No newline at end of file +Also remember to delete all the tracing code ones you have found the bug, as you wouldn't want to create a pull request with tracing code. From 530dd3377e4d409a7ca2fee7e47b60b735ebc0fa Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 15 Nov 2016 13:18:10 -0500 Subject: [PATCH 13/62] animations, midi, etc --- quantum/light_ws2812.c | 1 - tmk_core/protocol/lufa/lufa.c | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c index 6edbc0f2bd..aac058f534 100755 --- a/quantum/light_ws2812.c +++ b/quantum/light_ws2812.c @@ -171,7 +171,6 @@ void inline ws2812_setleds_rgbw(LED_TYPE *ledarray, uint16_t leds) } I2C_Stop(); SREG=sreg_prev; - // TWCR = (1< Date: Thu, 17 Nov 2016 17:42:14 -0500 Subject: [PATCH 14/62] rgb light through midi --- keyboards/amj60/config.h | 2 +- keyboards/clueboard/rev1/config.h | 2 +- keyboards/clueboard/rev2/config.h | 2 +- keyboards/cluecard/config.h | 2 +- .../cluecard/keymaps/rgb_effects/config.h | 2 +- keyboards/cluepad/config.h | 2 +- keyboards/ergodox/keymaps/jack/config.h | 3 +- keyboards/gh60/keymaps/robotmaxtron/config.h | 2 +- .../handwired/minorca/keymaps/rgb/config.h | 2 +- keyboards/jd40/config.h | 2 +- keyboards/kc60/keymaps/ws2812/config.h | 2 +- keyboards/lets_split/config.h | 2 +- keyboards/lets_split/keymaps/i2c/config.h | 2 +- keyboards/lets_split/keymaps/serial/config.h | 2 +- keyboards/phantom/config.h | 2 +- .../planck/keymaps/experimental/config.h | 2 +- keyboards/planck/keymaps/yang/config.h | 2 +- keyboards/preonic/config.h | 2 +- keyboards/preonic/keymaps/kinesis/config.h | 2 +- keyboards/satan/config.h | 2 +- keyboards/tada68/config.h | 2 +- quantum/light_ws2812.c | 2 - quantum/rgblight.c | 10 +- quantum/rgblight.h | 2 +- readme.md | 4 +- tmk_core/protocol/lufa/lufa.c | 96 +++++++++++++++++++ 26 files changed, 126 insertions(+), 31 deletions(-) diff --git a/keyboards/amj60/config.h b/keyboards/amj60/config.h index d98e0e9f2f..7c06f9a6c7 100644 --- a/keyboards/amj60/config.h +++ b/keyboards/amj60/config.h @@ -67,7 +67,7 @@ along with this program. If not, see . */ #define RGB_DI_PIN E2 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/clueboard/rev1/config.h b/keyboards/clueboard/rev1/config.h index 8c94972324..f40876ffbf 100644 --- a/keyboards/clueboard/rev1/config.h +++ b/keyboards/clueboard/rev1/config.h @@ -26,7 +26,7 @@ /* Underlight configuration */ #define RGB_DI_PIN B2 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 14 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/clueboard/rev2/config.h b/keyboards/clueboard/rev2/config.h index 15ca4ece86..8435fd02be 100644 --- a/keyboards/clueboard/rev2/config.h +++ b/keyboards/clueboard/rev2/config.h @@ -30,7 +30,7 @@ /* Underlight configuration */ #define RGB_DI_PIN D7 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 14 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/cluecard/config.h b/keyboards/cluecard/config.h index 765347b131..6520eb5574 100644 --- a/keyboards/cluecard/config.h +++ b/keyboards/cluecard/config.h @@ -140,7 +140,7 @@ along with this program. If not, see . /* Underlight configuration */ #define RGB_DI_PIN E6 -//#define RGBLIGHT_TIMER +//#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 4 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/cluecard/keymaps/rgb_effects/config.h b/keyboards/cluecard/keymaps/rgb_effects/config.h index e88847df4d..c6c9342c81 100644 --- a/keyboards/cluecard/keymaps/rgb_effects/config.h +++ b/keyboards/cluecard/keymaps/rgb_effects/config.h @@ -4,7 +4,7 @@ #include "../../config.h" // place overrides here -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLIGHT_EFFECT_SNAKE_LENGTH 3 #define RGBLIGHT_EFFECT_KNIGHT_LENGTH 2 #define RGBLIGHT_EFFECT_KNIGHT_OFFSET 2 diff --git a/keyboards/cluepad/config.h b/keyboards/cluepad/config.h index bae05fade3..bd64dfd27d 100644 --- a/keyboards/cluepad/config.h +++ b/keyboards/cluepad/config.h @@ -70,7 +70,7 @@ along with this program. If not, see . /* Underlight configuration */ #define RGB_DI_PIN F6 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 4 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/ergodox/keymaps/jack/config.h b/keyboards/ergodox/keymaps/jack/config.h index 5bf109c184..5c11652264 100644 --- a/keyboards/ergodox/keymaps/jack/config.h +++ b/keyboards/ergodox/keymaps/jack/config.h @@ -5,12 +5,13 @@ /* ws2812 RGB LED */ #define RGB_DI_PIN D7 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 15 // Number of LEDs #define RGBLIGHT_HUE_STEP 12 #define RGBLIGHT_SAT_STEP 255 #define RGBLIGHT_VAL_STEP 12 #define RGB_MIDI +#define RGBW_BB_TWI #endif \ No newline at end of file diff --git a/keyboards/gh60/keymaps/robotmaxtron/config.h b/keyboards/gh60/keymaps/robotmaxtron/config.h index 6a29e6b8c2..bcd7534617 100644 --- a/keyboards/gh60/keymaps/robotmaxtron/config.h +++ b/keyboards/gh60/keymaps/robotmaxtron/config.h @@ -182,7 +182,7 @@ along with this program. If not, see . #define ws2812_pin PF4 */ #define RGB_DI_PIN F4 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 8 #define RGBLIGHT_SAT_STEP 8 diff --git a/keyboards/handwired/minorca/keymaps/rgb/config.h b/keyboards/handwired/minorca/keymaps/rgb/config.h index deaac2e26f..43b3c59110 100644 --- a/keyboards/handwired/minorca/keymaps/rgb/config.h +++ b/keyboards/handwired/minorca/keymaps/rgb/config.h @@ -11,7 +11,7 @@ /* ws2812 RGB LED */ #define RGB_DI_PIN D5 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 13 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/jd40/config.h b/keyboards/jd40/config.h index e2594f4b37..047be5707b 100644 --- a/keyboards/jd40/config.h +++ b/keyboards/jd40/config.h @@ -70,7 +70,7 @@ along with this program. If not, see . ) #define RGB_DI_PIN D3 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 12 // Number of LEDs #define RGBLIGHT_HUE_STEP 8 #define RGBLIGHT_SAT_STEP 8 diff --git a/keyboards/kc60/keymaps/ws2812/config.h b/keyboards/kc60/keymaps/ws2812/config.h index 2f39ea8e55..43abf6228e 100644 --- a/keyboards/kc60/keymaps/ws2812/config.h +++ b/keyboards/kc60/keymaps/ws2812/config.h @@ -2,7 +2,7 @@ /* WS2812B RGB Underglow LED */ #define RGB_DI_PIN F5 // Based on wiring depicted in ws2812_wiring.jpg -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 16 // Number of LEDs. Change this to match your use case. #define RGBLIGHT_HUE_STEP 8 #define RGBLIGHT_SAT_STEP 8 diff --git a/keyboards/lets_split/config.h b/keyboards/lets_split/config.h index f4d900accb..b0ad522fcb 100644 --- a/keyboards/lets_split/config.h +++ b/keyboards/lets_split/config.h @@ -75,7 +75,7 @@ along with this program. If not, see . /* ws2812 RGB LED */ #define RGB_DI_PIN D4 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/lets_split/keymaps/i2c/config.h b/keyboards/lets_split/keymaps/i2c/config.h index 2671fabf6d..72e5ae66ba 100644 --- a/keyboards/lets_split/keymaps/i2c/config.h +++ b/keyboards/lets_split/keymaps/i2c/config.h @@ -75,7 +75,7 @@ along with this program. If not, see . /* ws2812 RGB LED */ #define RGB_DI_PIN D4 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/lets_split/keymaps/serial/config.h b/keyboards/lets_split/keymaps/serial/config.h index f4d900accb..b0ad522fcb 100644 --- a/keyboards/lets_split/keymaps/serial/config.h +++ b/keyboards/lets_split/keymaps/serial/config.h @@ -75,7 +75,7 @@ along with this program. If not, see . /* ws2812 RGB LED */ #define RGB_DI_PIN D4 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/phantom/config.h b/keyboards/phantom/config.h index 983a1d73f2..71a33498b4 100644 --- a/keyboards/phantom/config.h +++ b/keyboards/phantom/config.h @@ -63,7 +63,7 @@ along with this program. If not, see . /* Underlight configuration */ #define RGB_DI_PIN E2 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 20 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/planck/keymaps/experimental/config.h b/keyboards/planck/keymaps/experimental/config.h index 52acd1905e..cc093bee49 100644 --- a/keyboards/planck/keymaps/experimental/config.h +++ b/keyboards/planck/keymaps/experimental/config.h @@ -9,7 +9,7 @@ /* ws2812 RGB LED */ #define RGB_DI_PIN B1 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/planck/keymaps/yang/config.h b/keyboards/planck/keymaps/yang/config.h index feb5a11901..4ed19d76f9 100644 --- a/keyboards/planck/keymaps/yang/config.h +++ b/keyboards/planck/keymaps/yang/config.h @@ -5,7 +5,7 @@ /* ws2812 RGB LED */ #define RGB_DI_PIN D1 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 28 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/preonic/config.h b/keyboards/preonic/config.h index 3fb978c2f6..f88acf2111 100644 --- a/keyboards/preonic/config.h +++ b/keyboards/preonic/config.h @@ -63,7 +63,7 @@ along with this program. If not, see . /* ws2812 RGB LED */ #define RGB_DI_PIN D1 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 28 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/preonic/keymaps/kinesis/config.h b/keyboards/preonic/keymaps/kinesis/config.h index 086baa84ff..e6099ceb82 100644 --- a/keyboards/preonic/keymaps/kinesis/config.h +++ b/keyboards/preonic/keymaps/kinesis/config.h @@ -63,7 +63,7 @@ along with this program. If not, see . /* ws2812 RGB LED */ #define RGB_DI_PIN D1 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 28 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/satan/config.h b/keyboards/satan/config.h index 7e9f91cc82..eb357b39e0 100644 --- a/keyboards/satan/config.h +++ b/keyboards/satan/config.h @@ -67,7 +67,7 @@ along with this program. If not, see . */ #define RGB_DI_PIN E2 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 8 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/keyboards/tada68/config.h b/keyboards/tada68/config.h index 5d8757936d..19cf9c9b39 100644 --- a/keyboards/tada68/config.h +++ b/keyboards/tada68/config.h @@ -67,7 +67,7 @@ along with this program. If not, see . */ /*#define RGB_DI_PIN E2 -#define RGBLIGHT_TIMER +#define RGBLIGHT_ANIMATIONS #define RGBLED_NUM 2 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/quantum/light_ws2812.c b/quantum/light_ws2812.c index aac058f534..a883b13884 100755 --- a/quantum/light_ws2812.c +++ b/quantum/light_ws2812.c @@ -16,8 +16,6 @@ #include #include "debug.h" -#define RGBW_BB_TWI 1 - #ifdef RGBW_BB_TWI // Port for the I2C diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 1901010bf9..6b58f66547 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -174,7 +174,7 @@ void rgblight_init(void) { } eeconfig_debug_rgblight(); // display current eeprom values - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) + #ifdef RGBLIGHT_ANIMATIONS rgblight_timer_init(); // setup the timer #endif @@ -221,7 +221,7 @@ void rgblight_mode(uint8_t mode) { eeconfig_update_rgblight(rgblight_config.raw); xprintf("rgblight mode: %u\n", rgblight_config.mode); if (rgblight_config.mode == 1) { - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) + #ifdef RGBLIGHT_ANIMATIONS rgblight_timer_disable(); #endif } else if (rgblight_config.mode >= 2 && rgblight_config.mode <= 23) { @@ -231,7 +231,7 @@ void rgblight_mode(uint8_t mode) { // MODE 15-20, snake // MODE 21-23, knight - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) + #ifdef RGBLIGHT_ANIMATIONS rgblight_timer_enable(); #endif } @@ -245,7 +245,7 @@ void rgblight_toggle(void) { if (rgblight_config.enable) { rgblight_mode(rgblight_config.mode); } else { - #if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) + #ifdef RGBLIGHT_ANIMATIONS rgblight_timer_disable(); #endif _delay_ms(50); @@ -371,7 +371,7 @@ void rgblight_set(void) { } } -#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) +#ifdef RGBLIGHT_ANIMATIONS // Animation timer -- AVR Timer3 void rgblight_timer_init(void) { diff --git a/quantum/rgblight.h b/quantum/rgblight.h index d16ba24e53..330c2fe1ba 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h @@ -1,7 +1,7 @@ #ifndef RGBLIGHT_H #define RGBLIGHT_H -#if !defined(AUDIO_ENABLE) && defined(RGBLIGHT_TIMER) +#ifdef RGBLIGHT_ANIMATIONS #define RGBLIGHT_MODES 23 #else #define RGBLIGHT_MODES 1 diff --git a/readme.md b/readme.md index d5a259ccb8..2364b53010 100644 --- a/readme.md +++ b/readme.md @@ -1135,12 +1135,12 @@ For this mod, you need an unused pin wiring to DI of WS2812 strip. After wiring RGBLIGHT_ENABLE = yes -In order to use the underglow timer functions, you need to have `#define RGBLIGHT_TIMER` in your `config.h`, and have audio disabled (`AUDIO_ENABLE = no` in your Makefile). +In order to use the underglow animation functions, you need to have `#define RGBLIGHT_ANIMATIONS` in your `config.h`. Please add the following options into your config.h, and set them up according your hardware configuration. These settings are for the `F4` pin by default: #define RGB_DI_PIN F4 // The pin your RGB strip is wired to - #define RGBLIGHT_TIMER // Require for fancier stuff (not compatible with audio) + #define RGBLIGHT_ANIMATIONS // Require for fancier stuff (not compatible with audio) #define RGBLED_NUM 14 // Number of LEDs #define RGBLIGHT_HUE_STEP 10 #define RGBLIGHT_SAT_STEP 17 diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index b628cde370..7eb9be601e 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -51,6 +51,7 @@ #include "descriptor.h" #include "lufa.h" +#include "quantum.h" #ifdef NKRO_ENABLE #include "keycode_config.h" @@ -1111,9 +1112,104 @@ void cc_callback(MidiDevice * device, #endif } +void send_dword(uint32_t number) { + uint16_t word = (number >> 16); + send_word(word); + send_word(number & 0xFFFFUL); +} + +void send_word(uint16_t number) { + uint8_t byte = number >> 8; + send_byte(byte); + send_byte(number & 0xFF); +} + +void send_byte(uint8_t number) { + uint8_t nibble = number >> 4; + send_nibble(nibble); + send_nibble(number & 0xF); +} + +void send_nibble(uint8_t number) { + switch (number) { + case 0: + register_code(KC_0); + unregister_code(KC_0); + break; + case 1 ... 9: + register_code(KC_1 + (number - 1)); + unregister_code(KC_1 + (number - 1)); + break; + case 0xA ... 0xF: + register_code(KC_A + (number - 0xA)); + unregister_code(KC_A + (number - 0xA)); + break; + } +} + +uint8_t midi_buffer[16] = {0}; + void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) { // for (int i = 0; i < length; i++) // midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i)); + // if (start == 0x27) { + // SEND_STRING("\n"); + // send_word(start); + // SEND_STRING(": "); + for (uint8_t place = 0; place < length; place++) { + // send_byte(*data); + midi_buffer[start + place] = *data; + if (*data == 0xF7) + sysex_buffer_callback(start + place, &midi_buffer); + // SEND_STRING(" "); + data++; + } + // } + } + +void sysex_buffer_callback(uint8_t length, uint8_t * data) { + uint8_t * pointer_copy = data; + + if (*data++ != 0xF0) + return + data++; + data++; + data++; + data++; + + switch (*data++) { + case 0x27: ; // RGB LED functions + switch (*data++) + case 0x00: ; // Update HSV + uint32_t part1 = *data++; + uint32_t part2 = *data++; + uint32_t part3 = *data++; + uint32_t part4 = *data++; + uint32_t part5 = *data++; + uint32_t chunk = ((part1 & 0x1FUL) << 28) | (part2 << 21) | (part3 << 14) | (part4 << 7) | part5; + // SEND_STRING("\nCHUNK: "); + // send_dword(chunk); + rgblight_sethsv(((chunk >> 16) & 0xFFFF) % 360, (chunk >> 8) & 0xFF, chunk & 0xFF); + // SEND_STRING("\nHUE: "); + // send_word(((chunk >> 16) & 0xFFFF) % 360); + // SEND_STRING("\nSAT: "); + // send_word((chunk >> 8) & 0xFF); + // SEND_STRING("\nVAL: "); + // send_word(chunk & 0xFF); + break; + case 0x01: ; // Update RGB + break; + break; + } + + // SEND_STRING("\nDATA:\n"); + // while (*pointer_copy != 0xF7) { + // send_byte(*pointer_copy++); + // SEND_STRING(" "); + // } + +} + #endif From 9bbc9a7ce024edb4d80ce65d43c82456e3714928 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Thu, 17 Nov 2016 19:47:08 -0500 Subject: [PATCH 15/62] Initial Erez Experimental keymap tweaks --- keyboards/ergodox/keymaps/erez_experimental/Makefile | 2 ++ keyboards/ergodox/keymaps/erez_experimental/config.h | 11 +++++++++++ keyboards/ergodox/keymaps/erez_experimental/keymap.c | 12 ++++++------ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/keyboards/ergodox/keymaps/erez_experimental/Makefile b/keyboards/ergodox/keymaps/erez_experimental/Makefile index b673c5ce52..dbe89d1410 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/Makefile +++ b/keyboards/ergodox/keymaps/erez_experimental/Makefile @@ -3,6 +3,8 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend COMMAND_ENABLE = no # Commands for debug and configuration +RGBLIGHT_ENABLE = yes +MIDI_ENABLE = yes ifndef QUANTUM_DIR include ../../../../Makefile diff --git a/keyboards/ergodox/keymaps/erez_experimental/config.h b/keyboards/ergodox/keymaps/erez_experimental/config.h index e5d7fe1885..fbd12ab797 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/config.h +++ b/keyboards/ergodox/keymaps/erez_experimental/config.h @@ -8,5 +8,16 @@ #undef LEADER_TIMEOUT #define LEADER_TIMEOUT 300 + +/* ws2812 RGB LED */ +#define RGB_DI_PIN D7 +#define RGBLIGHT_ANIMATIONS +#define RGBLED_NUM 15 // Number of LEDs +#define RGBLIGHT_HUE_STEP 12 +#define RGBLIGHT_SAT_STEP 255 +#define RGBLIGHT_VAL_STEP 12 + +#define RGB_MIDI +#define RGBW_BB_TWI #endif diff --git a/keyboards/ergodox/keymaps/erez_experimental/keymap.c b/keyboards/ergodox/keymaps/erez_experimental/keymap.c index 4804959d63..b867d36013 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/keymap.c +++ b/keyboards/ergodox/keymaps/erez_experimental/keymap.c @@ -67,9 +67,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * ,-------------. ,-------------. * | | | | | | * ,------|------|------| |------+------+------. - * | | | | | | | | + * |VAI |VAD |HUI | |SAI |TOG |MOD | * | | |------| |------| | | - * | | | | | | | | + * | | |HUD | |SAD | | | * `--------------------' `--------------------' */ // SYMBOLS @@ -81,8 +81,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_6, KC_7, KC_8, KC_9, KC_0, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS,LCTL(KC_PGUP), LCTL(KC_PGDN), KC_TRNS,KC_TRNS, - KC_TRNS, - KC_TRNS,KC_TRNS,KC_TRNS, + RGB_HUI, + RGB_VAI,RGB_VAD,RGB_HUD, // right hand KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_F12, @@ -90,8 +90,8 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_TRNS, KC_PIPE, KC_AT, KC_EQL, KC_PERC, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, - KC_TRNS, KC_TRNS, KC_TRNS + RGB_SAI, + RGB_SAD, RGB_TOG, RGB_MOD ), /* Keymap 2: Media and mouse keys * From 285c5a91f23e972d9c579184283443111186329d Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Thu, 17 Nov 2016 20:56:36 -0500 Subject: [PATCH 16/62] Groundwork for dedicated color keycodes --- .../keymaps/erez_experimental/keymap.c | 24 ++++++++++++++++++- quantum/rgblight.c | 7 ++++++ quantum/rgblight.h | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/keyboards/ergodox/keymaps/erez_experimental/keymap.c b/keyboards/ergodox/keymaps/erez_experimental/keymap.c index b867d36013..4a23c7ac58 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/keymap.c +++ b/keyboards/ergodox/keymaps/erez_experimental/keymap.c @@ -7,6 +7,12 @@ #define SYMB 1 // symbols #define MDIA 2 // media keys +enum custom_keycodes { + PLACEHOLDER = SAFE_RANGE, // can always be here + RGB_FF00BB // always start with RGB_ +}; + + const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* Keymap 0: Basic layer * @@ -75,7 +81,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { // SYMBOLS [SYMB] = KEYMAP( // left hand - KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, + RGB_FF00BB, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS, KC_TRNS, KC_TRNS,KC_TRNS,KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_1, KC_2, KC_3, KC_4, KC_5, KC_TRNS, KC_6, KC_7, KC_8, KC_9, KC_0, KC_TRNS, @@ -152,6 +158,22 @@ void matrix_init_user(void) { }; + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + // dynamically generate these. + case RGB_FF00BB: + if (record->event.pressed) { + rgblight_enable(); + rgblight_mode(1); + rgblight_setrgb(0xff,0x00,0xbb); + } + return false; + break; + } + return true; +} + LEADER_EXTERNS(); // Runs constantly in the background, in a loop. diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 6b58f66547..00620da58e 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -253,6 +253,13 @@ void rgblight_toggle(void) { } } +void rgblight_enable(void) { + rgblight_config.enable = 1; + eeconfig_update_rgblight(rgblight_config.raw); + xprintf("rgblight enable: rgblight_config.enable = %u\n", rgblight_config.enable); + rgblight_mode(rgblight_config.mode); +} + void rgblight_increase_hue(void) { uint16_t hue; diff --git a/quantum/rgblight.h b/quantum/rgblight.h index 330c2fe1ba..a3673348e7 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h @@ -61,6 +61,7 @@ void rgblight_init(void); void rgblight_increase(void); void rgblight_decrease(void); void rgblight_toggle(void); +void rgblight_enable(void); void rgblight_step(void); void rgblight_mode(uint8_t mode); void rgblight_set(void); From 161bd5596b5d8199f2e56246a27ccbdb8c80bb36 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Fri, 18 Nov 2016 22:22:24 -0500 Subject: [PATCH 17/62] midi back and forth --- keyboards/ergodox/keymaps/jack/keymap.c | 7 ++- tmk_core/protocol/lufa/lufa.c | 62 ++++++++++++++++++------- tmk_core/protocol/lufa/lufa.h | 1 + 3 files changed, 52 insertions(+), 18 deletions(-) diff --git a/keyboards/ergodox/keymaps/jack/keymap.c b/keyboards/ergodox/keymaps/jack/keymap.c index 8721b9644a..eb41f12127 100644 --- a/keyboards/ergodox/keymaps/jack/keymap.c +++ b/keyboards/ergodox/keymaps/jack/keymap.c @@ -26,7 +26,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { MO(1), KC_LEFT,KC_DOWN,KC_UP, KC_RGHT, RGB_TOG, RGB_HUI, RGB_MOD, - KC_PGDN, KC_SPC,KC_SPC + M(2), KC_SPC,KC_SPC ), [SYMB] = KEYMAP( // left hand @@ -89,6 +89,11 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) eeconfig_init(); } break; + case 2: + if (record->event.pressed) { // For resetting EEPROM + send_unicode_midi(0x0CA0); + } + break; } return MACRO_NONE; }; diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 7eb9be601e..ae9cc2f962 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1161,7 +1161,7 @@ void sysex_callback(MidiDevice * device, // send_byte(*data); midi_buffer[start + place] = *data; if (*data == 0xF7) - sysex_buffer_callback(start + place, &midi_buffer); + sysex_buffer_callback(device, start + place, &midi_buffer); // SEND_STRING(" "); data++; } @@ -1169,7 +1169,24 @@ void sysex_callback(MidiDevice * device, } -void sysex_buffer_callback(uint8_t length, uint8_t * data) { +uint32_t decode_4byte_chunk(uint8_t * data) { + uint32_t part1 = *data++; + uint32_t part2 = *data++; + uint32_t part3 = *data++; + uint32_t part4 = *data++; + uint32_t part5 = *data++; + return ((part1 & 0x1FUL) << 28) | (part2 << 21) | (part3 << 14) | (part4 << 7) | part5; +} + +void encode_4byte_chunk(uint32_t data, uint8_t * pointer) { + *pointer++ = (data >> 28) & 0x7F; + *pointer++ = (data >> 21) & 0x7F; + *pointer++ = (data >> 14) & 0x7F; + *pointer++ = (data >> 7) & 0x7F; + *pointer++ = (data) & 0x7F; +} + +void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { uint8_t * pointer_copy = data; if (*data++ != 0xF0) @@ -1180,28 +1197,31 @@ void sysex_buffer_callback(uint8_t length, uint8_t * data) { data++; switch (*data++) { + case 0x13: ; // Get info from keyboard + switch (*data++) { + case 0x00: ; // Get layer state + // send_dword(layer_state); + uint8_t chunk[5]; + encode_4byte_chunk(layer_state | default_layer_state, &chunk); + + uint8_t array[] = {0xF0, 0x00, 0x00, 0x00, 0x00, chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], 0xF7}; + midi_send_array(&midi_device, 11, &array); + // midi_send_data(device, 3, 0x00, layer_state >> 24 & 0x7f, layer_state >> 16 & 0x7f); + // midi_send_data(device, 6, layer_state >> 8 & 0x7f, layer_state & 0x7f, 0xF7); + break; + } + #ifdef RGBLIGHT_ENABLE case 0x27: ; // RGB LED functions - switch (*data++) + switch (*data++) { case 0x00: ; // Update HSV - uint32_t part1 = *data++; - uint32_t part2 = *data++; - uint32_t part3 = *data++; - uint32_t part4 = *data++; - uint32_t part5 = *data++; - uint32_t chunk = ((part1 & 0x1FUL) << 28) | (part2 << 21) | (part3 << 14) | (part4 << 7) | part5; - // SEND_STRING("\nCHUNK: "); - // send_dword(chunk); + uint32_t chunk = decode_4byte_chunk(data); rgblight_sethsv(((chunk >> 16) & 0xFFFF) % 360, (chunk >> 8) & 0xFF, chunk & 0xFF); - // SEND_STRING("\nHUE: "); - // send_word(((chunk >> 16) & 0xFFFF) % 360); - // SEND_STRING("\nSAT: "); - // send_word((chunk >> 8) & 0xFF); - // SEND_STRING("\nVAL: "); - // send_word(chunk & 0xFF); break; case 0x01: ; // Update RGB break; + } break; + #endif } // SEND_STRING("\nDATA:\n"); @@ -1212,4 +1232,12 @@ void sysex_buffer_callback(uint8_t length, uint8_t * data) { } +void send_unicode_midi(uint32_t unicode) { + uint8_t chunk[5]; + encode_4byte_chunk(unicode, &chunk); + + uint8_t array[] = {0xF0, 0x00, 0x00, 0x00, 0x05, chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], 0xF7}; + midi_send_array(&midi_device, 11, &array); +} + #endif diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h index aad08d6407..3fec797b6c 100644 --- a/tmk_core/protocol/lufa/lufa.h +++ b/tmk_core/protocol/lufa/lufa.h @@ -70,6 +70,7 @@ typedef struct { #ifdef MIDI_ENABLE void MIDI_Task(void); MidiDevice midi_device; +void send_unicode_midi(uint32_t unicode); #endif // #if LUFA_VERSION_INTEGER < 0x120730 From b57cf3c0c851f2fb0e32c955b16fc6f0ad236e54 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 12:54:06 -0500 Subject: [PATCH 18/62] more structure to the package --- tmk_core/protocol/lufa/lufa.c | 109 +++++++++++++++++++++++++++------- tmk_core/protocol/lufa/lufa.h | 15 ++++- 2 files changed, 101 insertions(+), 23 deletions(-) diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index ae9cc2f962..cc00b3b89b 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1147,10 +1147,9 @@ void send_nibble(uint8_t number) { } } -uint8_t midi_buffer[16] = {0}; +uint8_t midi_buffer[MIDI_SYSEX_BUFFER] = {0}; -void sysex_callback(MidiDevice * device, - uint16_t start, uint8_t length, uint8_t * data) { +void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) { // for (int i = 0; i < length; i++) // midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i)); // if (start == 0x27) { @@ -1169,7 +1168,7 @@ void sysex_callback(MidiDevice * device, } -uint32_t decode_4byte_chunk(uint8_t * data) { +uint32_t decode_uint32_chunk(uint8_t * data) { uint32_t part1 = *data++; uint32_t part2 = *data++; uint32_t part3 = *data++; @@ -1178,7 +1177,13 @@ uint32_t decode_4byte_chunk(uint8_t * data) { return ((part1 & 0x1FUL) << 28) | (part2 << 21) | (part3 << 14) | (part4 << 7) | part5; } -void encode_4byte_chunk(uint32_t data, uint8_t * pointer) { +uint32_t decode_uint8_chunk(uint8_t * data) { + uint32_t part4 = *data++; + uint32_t part5 = *data++; + return (part4 << 7) | part5; +} + +void encode_uint32_chunk(uint32_t data, uint8_t * pointer) { *pointer++ = (data >> 28) & 0x7F; *pointer++ = (data >> 21) & 0x7F; *pointer++ = (data >> 14) & 0x7F; @@ -1186,6 +1191,11 @@ void encode_4byte_chunk(uint32_t data, uint8_t * pointer) { *pointer++ = (data) & 0x7F; } +void encode_uint8_chunk(uint8_t data, uint8_t * pointer) { + *pointer++ = (data >> 7) & 0x7F; + *pointer++ = (data) & 0x7F; +} + void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { uint8_t * pointer_copy = data; @@ -1197,28 +1207,77 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) data++; switch (*data++) { - case 0x13: ; // Get info from keyboard + case 0x12: ; // Set info on keyboard switch (*data++) { - case 0x00: ; // Get layer state - // send_dword(layer_state); - uint8_t chunk[5]; - encode_4byte_chunk(layer_state | default_layer_state, &chunk); - - uint8_t array[] = {0xF0, 0x00, 0x00, 0x00, 0x00, chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], 0xF7}; - midi_send_array(&midi_device, 11, &array); - // midi_send_data(device, 3, 0x00, layer_state >> 24 & 0x7f, layer_state >> 16 & 0x7f); - // midi_send_data(device, 6, layer_state >> 8 & 0x7f, layer_state & 0x7f, 0xF7); + case 0x02: ; // set default layer + uint8_t default_layer = decode_uint8_chunk(data); + eeconfig_update_default_layer(default_layer); + default_layer_set((uint32_t)default_layer); + break; + case 0x08: ; // set keymap options + uint8_t keymap_options = decode_uint8_chunk(data); + eeconfig_update_keymap(keymap_options); break; } + break; + case 0x13: ; // Get info from keyboard + switch (*data++) { + case 0x00: ; // Handshake + send_bytes_sysex(0x00, NULL, 0); + break; + case 0x01: ; // Get debug state + uint8_t debug[2]; + encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEBUG), &debug); + send_bytes_sysex(0x01, &debug, 2); + break; + case 0x02: ; // Get default layer + uint8_t default_layer[2]; + encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEFAULT_LAYER), &default_layer); + send_bytes_sysex(0x02, &default_layer, 2); + break; + #ifdef AUDIO_ENABLE + case 0x03: ; // Get backlight state + uint8_t audio[2]; + encode_uint8_chunk(eeprom_read_byte(EECONFIG_AUDIO), &audio); + send_bytes_sysex(0x03, &audio, 2); + #endif + case 0x04: ; // Get layer state + uint8_t layers[5]; + encode_uint32_chunk(layer_state, &layers); + send_bytes_sysex(0x04, &layers, 5); + break; + #ifdef BACKLIGHT_ENABLE + case 0x06: ; // Get backlight state + uint8_t backlight[2]; + encode_uint8_chunk(eeprom_read_byte(EECONFIG_BACKLIGHT), &backlight); + send_bytes_sysex(0x06, &backlight, 2); + #endif + #ifdef RGBLIGHT_ENABLE + case 0x07: ; // Get rgblight state + uint8_t rgblight[2]; + encode_uint32_chunk(eeprom_read_dword(EECONFIG_RGBLIGHT), &rgblight); + send_bytes_sysex(0x07, &rgblight, 5); + #endif + case 0x08: ; // Keymap options + uint8_t keymap_options[2]; + encode_uint8_chunk(eeconfig_read_keymap(), &keymap_options); + send_bytes_sysex(0x08, &keymap_options, 2); + break; + } + break; #ifdef RGBLIGHT_ENABLE case 0x27: ; // RGB LED functions switch (*data++) { case 0x00: ; // Update HSV - uint32_t chunk = decode_4byte_chunk(data); - rgblight_sethsv(((chunk >> 16) & 0xFFFF) % 360, (chunk >> 8) & 0xFF, chunk & 0xFF); + uint32_t hsv = decode_uint32_chunk(data); + rgblight_sethsv(((hsv >> 16) & 0xFFFF) % 360, (hsv >> 8) & 0xFF, hsv & 0xFF); break; case 0x01: ; // Update RGB break; + case 0x02: ; // Update mode + uint8_t rgb_mode = decode_uint8_chunk(data); + rgblight_mode(rgb_mode); + break; } break; #endif @@ -1234,10 +1293,20 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) void send_unicode_midi(uint32_t unicode) { uint8_t chunk[5]; - encode_4byte_chunk(unicode, &chunk); + encode_uint32_chunk(unicode, &chunk); + send_bytes_sysex(0x05, &chunk, 5); +} - uint8_t array[] = {0xF0, 0x00, 0x00, 0x00, 0x05, chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], 0xF7}; - midi_send_array(&midi_device, 11, &array); +void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length) { + uint8_t * array = malloc(sizeof(uint8_t) * (length + 6)); + array[0] = 0xF0; + array[1] = 0x00; + array[2] = 0x00; + array[3] = 0x00; + array[4] = type; + array[length + 5] = 0xF7; + memcpy(array + 5, bytes, length); + midi_send_array(&midi_device, length + 6, array); } #endif diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h index 3fec797b6c..198964f901 100644 --- a/tmk_core/protocol/lufa/lufa.h +++ b/tmk_core/protocol/lufa/lufa.h @@ -68,9 +68,18 @@ typedef struct { } __attribute__ ((packed)) report_extra_t; #ifdef MIDI_ENABLE -void MIDI_Task(void); -MidiDevice midi_device; -void send_unicode_midi(uint32_t unicode); + #define MIDI_SYSEX_BUFFER 16 + void MIDI_Task(void); + MidiDevice midi_device; + + void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data); + uint32_t decode_uint32_chunk(uint8_t * data); + uint32_t decode_uint8_chunk(uint8_t * data); + void encode_uint32_chunk(uint32_t data, uint8_t * pointer); + void encode_uint8_chunk(uint8_t data, uint8_t * pointer); + void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data); + void send_unicode_midi(uint32_t unicode); + void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length); #endif // #if LUFA_VERSION_INTEGER < 0x120730 From c1037b1dc060d14a09a59f697fefe2b5b91bf373 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 18:05:06 -0500 Subject: [PATCH 19/62] working with helper, qmk_helper_windows@05b0105 --- keyboards/planck/keymaps/default/Makefile | 8 ++++---- keyboards/planck/keymaps/default/keymap.c | 4 ++-- tmk_core/protocol/lufa/lufa.c | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/keyboards/planck/keymaps/default/Makefile b/keyboards/planck/keymaps/default/Makefile index 0f4953888d..267a087ea9 100644 --- a/keyboards/planck/keymaps/default/Makefile +++ b/keyboards/planck/keymaps/default/Makefile @@ -5,17 +5,17 @@ # the appropriate keymap folder that will get included automatically # BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE = yes # Mouse keys(+4700) +MOUSEKEY_ENABLE = no # Mouse keys(+4700) EXTRAKEY_ENABLE = yes # Audio control and System control(+450) CONSOLE_ENABLE = no # Console for debug(+400) -COMMAND_ENABLE = yes # Commands for debug and configuration +COMMAND_ENABLE = no # Commands for debug and configuration NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality -MIDI_ENABLE = no # MIDI controls +MIDI_ENABLE = yes # MIDI controls AUDIO_ENABLE = yes # Audio output on port C6 UNICODE_ENABLE = no # Unicode BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID -RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend diff --git a/keyboards/planck/keymaps/default/keymap.c b/keyboards/planck/keymaps/default/keymap.c index 5f71ae7d19..ddbe4d7b27 100644 --- a/keyboards/planck/keymaps/default/keymap.c +++ b/keyboards/planck/keymaps/default/keymap.c @@ -107,7 +107,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [_LOWER] = { {KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC}, {KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE}, - {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,S(KC_NUHS),S(KC_NUBS),_______, _______, _______}, + {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,S(KC_NUHS),S(KC_NUBS),KC_HOME, KC_END, _______}, {_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} }, @@ -125,7 +125,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [_RAISE] = { {KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC}, {KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS}, - {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NUHS, KC_NUBS, _______, _______, _______}, + {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NUHS, KC_NUBS, KC_PGUP, KC_PGDN, _______}, {_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} }, diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index cc00b3b89b..35739e3211 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1207,6 +1207,12 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) data++; switch (*data++) { + case 0x07: ; // Quantum action + break; + case 0x08: ; // Keyboard acion + break; + case 0x09: ; // User action + break; case 0x12: ; // Set info on keyboard switch (*data++) { case 0x02: ; // set default layer From 664c0a036b3d7c3ed39f4a7a78d97f4a9cc7d20c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 19:50:55 -0500 Subject: [PATCH 20/62] cleaning up new code --- quantum/light_ws2812.h | 2 +- quantum/quantum.c | 40 ++++++++++++++++ quantum/quantum.h | 5 ++ tmk_core/protocol/lufa/lufa.c | 90 +++++++++++------------------------ 4 files changed, 73 insertions(+), 64 deletions(-) diff --git a/quantum/light_ws2812.h b/quantum/light_ws2812.h index 0bef93d5ec..9498e550e9 100755 --- a/quantum/light_ws2812.h +++ b/quantum/light_ws2812.h @@ -16,7 +16,7 @@ #include #include //#include "ws2812_config.h" -#include "i2cmaster.h" +//#include "i2cmaster.h" #define LIGHT_I2C 1 #define LIGHT_I2C_ADDR 0x84 diff --git a/quantum/quantum.c b/quantum/quantum.c index 9fd9a6ef72..8b2fefef65 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -802,6 +802,46 @@ void backlight_set(uint8_t level) #endif // backlight +// Functions for spitting out values +// + +void send_dword(uint32_t number) { // this might not actually work + uint16_t word = (number >> 16); + send_word(word); + send_word(number & 0xFFFFUL); +} + +void send_word(uint16_t number) { + uint8_t byte = number >> 8; + send_byte(byte); + send_byte(number & 0xFF); +} + +void send_byte(uint8_t number) { + uint8_t nibble = number >> 4; + send_nibble(nibble); + send_nibble(number & 0xF); +} + +void send_nibble(uint8_t number) { + switch (number) { + case 0: + register_code(KC_0); + unregister_code(KC_0); + break; + case 1 ... 9: + register_code(KC_1 + (number - 1)); + unregister_code(KC_1 + (number - 1)); + break; + case 0xA ... 0xF: + register_code(KC_A + (number - 0xA)); + unregister_code(KC_A + (number - 0xA)); + break; + } +} + + + __attribute__ ((weak)) void led_set_user(uint8_t usb_led) { diff --git a/quantum/quantum.h b/quantum/quantum.h index 06a2e049dc..3d35f11fad 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -110,6 +110,11 @@ void breathing_speed_dec(uint8_t value); #endif #endif +void send_dword(uint32_t number); +void send_word(uint16_t number); +void send_byte(uint8_t number); +void send_nibble(uint8_t number); + void led_set_user(uint8_t usb_led); void led_set_kb(uint8_t usb_led); diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 35739e3211..14da3b8039 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -84,9 +84,9 @@ static uint8_t keyboard_led_stats = 0; static report_keyboard_t keyboard_report_sent; #ifdef MIDI_ENABLE -void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); -void usb_get_midi(MidiDevice * device); -void midi_usb_init(MidiDevice * device); +static void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2); +static void usb_get_midi(MidiDevice * device); +static void midi_usb_init(MidiDevice * device); #endif /* Host driver */ @@ -714,7 +714,7 @@ int8_t sendchar(uint8_t c) ******************************************************************************/ #ifdef MIDI_ENABLE -void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { +static void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byte1, uint8_t byte2) { MIDI_EventPacket_t event; event.Data1 = byte0; event.Data2 = byte1; @@ -774,7 +774,7 @@ void usb_send_func(MidiDevice * device, uint16_t cnt, uint8_t byte0, uint8_t byt USB_USBTask(); } -void usb_get_midi(MidiDevice * device) { +static void usb_get_midi(MidiDevice * device) { MIDI_EventPacket_t event; while (MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, &event)) { @@ -804,12 +804,12 @@ void usb_get_midi(MidiDevice * device) { USB_USBTask(); } -void midi_usb_init(MidiDevice * device){ +static void midi_usb_init(MidiDevice * device){ midi_device_init(device); midi_device_set_send_func(device, usb_send_func); midi_device_set_pre_input_process_func(device, usb_get_midi); - SetupHardware(); + // SetupHardware(); sei(); } @@ -1112,41 +1112,6 @@ void cc_callback(MidiDevice * device, #endif } -void send_dword(uint32_t number) { - uint16_t word = (number >> 16); - send_word(word); - send_word(number & 0xFFFFUL); -} - -void send_word(uint16_t number) { - uint8_t byte = number >> 8; - send_byte(byte); - send_byte(number & 0xFF); -} - -void send_byte(uint8_t number) { - uint8_t nibble = number >> 4; - send_nibble(nibble); - send_nibble(number & 0xF); -} - -void send_nibble(uint8_t number) { - switch (number) { - case 0: - register_code(KC_0); - unregister_code(KC_0); - break; - case 1 ... 9: - register_code(KC_1 + (number - 1)); - unregister_code(KC_1 + (number - 1)); - break; - case 0xA ... 0xF: - register_code(KC_A + (number - 0xA)); - unregister_code(KC_A + (number - 0xA)); - break; - } -} - uint8_t midi_buffer[MIDI_SYSEX_BUFFER] = {0}; void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) { @@ -1159,8 +1124,8 @@ void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t for (uint8_t place = 0; place < length; place++) { // send_byte(*data); midi_buffer[start + place] = *data; - if (*data == 0xF7) - sysex_buffer_callback(device, start + place, &midi_buffer); + if (*data == 0xF7 && midi_buffer[0] == 0xF0) + sysex_buffer_callback(device, start + place, midi_buffer); // SEND_STRING(" "); data++; } @@ -1197,10 +1162,9 @@ void encode_uint8_chunk(uint8_t data, uint8_t * pointer) { } void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { - uint8_t * pointer_copy = data; + // uint8_t * pointer_copy = data; // use for debugging - if (*data++ != 0xF0) - return + //data++; // i'm 98% sure there's a better way to do this data++; data++; data++; @@ -1233,41 +1197,41 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) break; case 0x01: ; // Get debug state uint8_t debug[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEBUG), &debug); - send_bytes_sysex(0x01, &debug, 2); + encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEBUG), debug); + send_bytes_sysex(0x01, debug, 2); break; case 0x02: ; // Get default layer uint8_t default_layer[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEFAULT_LAYER), &default_layer); - send_bytes_sysex(0x02, &default_layer, 2); + encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEFAULT_LAYER), default_layer); + send_bytes_sysex(0x02, default_layer, 2); break; #ifdef AUDIO_ENABLE case 0x03: ; // Get backlight state uint8_t audio[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_AUDIO), &audio); - send_bytes_sysex(0x03, &audio, 2); + encode_uint8_chunk(eeprom_read_byte(EECONFIG_AUDIO), audio); + send_bytes_sysex(0x03, audio, 2); #endif case 0x04: ; // Get layer state uint8_t layers[5]; - encode_uint32_chunk(layer_state, &layers); - send_bytes_sysex(0x04, &layers, 5); + encode_uint32_chunk(layer_state, layers); + send_bytes_sysex(0x04, layers, 5); break; #ifdef BACKLIGHT_ENABLE case 0x06: ; // Get backlight state uint8_t backlight[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_BACKLIGHT), &backlight); - send_bytes_sysex(0x06, &backlight, 2); + encode_uint8_chunk(eeprom_read_byte(EECONFIG_BACKLIGHT), backlight); + send_bytes_sysex(0x06, backlight, 2); #endif #ifdef RGBLIGHT_ENABLE case 0x07: ; // Get rgblight state uint8_t rgblight[2]; - encode_uint32_chunk(eeprom_read_dword(EECONFIG_RGBLIGHT), &rgblight); - send_bytes_sysex(0x07, &rgblight, 5); + encode_uint32_chunk(eeprom_read_dword(EECONFIG_RGBLIGHT), rgblight); + send_bytes_sysex(0x07, rgblight, 5); #endif case 0x08: ; // Keymap options uint8_t keymap_options[2]; - encode_uint8_chunk(eeconfig_read_keymap(), &keymap_options); - send_bytes_sysex(0x08, &keymap_options, 2); + encode_uint8_chunk(eeconfig_read_keymap(), keymap_options); + send_bytes_sysex(0x08, keymap_options, 2); break; } break; @@ -1299,8 +1263,8 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) void send_unicode_midi(uint32_t unicode) { uint8_t chunk[5]; - encode_uint32_chunk(unicode, &chunk); - send_bytes_sysex(0x05, &chunk, 5); + encode_uint32_chunk(unicode, chunk); + send_bytes_sysex(0x05, chunk, 5); } void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length) { From 6390033e8688550826a4bd3004a2e76568600657 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 20:14:16 -0500 Subject: [PATCH 21/62] cleaning up midid --- quantum/config_common.h | 99 ++++++++++++++++++----------------- tmk_core/common/host_driver.h | 9 +++- tmk_core/protocol/lufa/lufa.c | 2 +- 3 files changed, 59 insertions(+), 51 deletions(-) diff --git a/quantum/config_common.h b/quantum/config_common.h index 8ed5f4a106..f3897dc2ce 100644 --- a/quantum/config_common.h +++ b/quantum/config_common.h @@ -5,55 +5,56 @@ #define COL2ROW 0 #define ROW2COL 1 /* I/O pins */ -#define B0 0x30 -#define B1 0x31 -#define B2 0x32 -#define B3 0x33 -#define B4 0x34 -#define B5 0x35 -#define B6 0x36 -#define B7 0x37 -#define C0 0x60 -#define C1 0x61 -#define C2 0x62 -#define C3 0x63 -#define C4 0x64 -#define C5 0x65 -#define C6 0x66 -#define C7 0x67 -#define D0 0x90 -#define D1 0x91 -#define D2 0x92 -#define D3 0x93 -#define D4 0x94 -#define D5 0x95 -#define D6 0x96 -#define D7 0x97 -#define E0 0xC0 -#define E1 0xC1 -#define E2 0xC2 -#define E3 0xC3 -#define E4 0xC4 -#define E5 0xC5 -#define E6 0xC6 -#define E7 0xC7 -#define F0 0xF0 -#define F1 0xF1 -#define F2 0xF2 -#define F3 0xF3 -#define F4 0xF4 -#define F5 0xF5 -#define F6 0xF6 -#define F7 0xF7 -#define A0 0x00 -#define A1 0x01 -#define A2 0x02 -#define A3 0x03 -#define A4 0x04 -#define A5 0x05 -#define A6 0x06 -#define A7 0x07 - +#ifndef F0 + #define B0 0x30 + #define B1 0x31 + #define B2 0x32 + #define B3 0x33 + #define B4 0x34 + #define B5 0x35 + #define B6 0x36 + #define B7 0x37 + #define C0 0x60 + #define C1 0x61 + #define C2 0x62 + #define C3 0x63 + #define C4 0x64 + #define C5 0x65 + #define C6 0x66 + #define C7 0x67 + #define D0 0x90 + #define D1 0x91 + #define D2 0x92 + #define D3 0x93 + #define D4 0x94 + #define D5 0x95 + #define D6 0x96 + #define D7 0x97 + #define E0 0xC0 + #define E1 0xC1 + #define E2 0xC2 + #define E3 0xC3 + #define E4 0xC4 + #define E5 0xC5 + #define E6 0xC6 + #define E7 0xC7 + #define F0 0xF0 + #define F1 0xF1 + #define F2 0xF2 + #define F3 0xF3 + #define F4 0xF4 + #define F5 0xF5 + #define F6 0xF6 + #define F7 0xF7 + #define A0 0x00 + #define A1 0x01 + #define A2 0x02 + #define A3 0x03 + #define A4 0x04 + #define A5 0x05 + #define A6 0x06 + #define A7 0x07 +#endif /* USART configuration */ #ifdef BLUETOOTH_ENABLE diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h index edb9e5dd9c..588d1c0be8 100644 --- a/tmk_core/common/host_driver.h +++ b/tmk_core/common/host_driver.h @@ -20,7 +20,9 @@ along with this program. If not, see . #include #include "report.h" - +#ifdef MIDI_ENABLE + #include "midi.h" +#endif typedef struct { uint8_t (*keyboard_leds)(void); @@ -28,6 +30,11 @@ typedef struct { void (*send_mouse)(report_mouse_t *); void (*send_system)(uint16_t); void (*send_consumer)(uint16_t); +#ifdef MIDI_ENABLE + void (*usb_send_func)(MidiDevice *, uint16_t, uint8_t, uint8_t, uint8_t); + void (*usb_get_midi)(MidiDevice *); + void (*midi_usb_init)(MidiDevice *); +#endif } host_driver_t; #endif diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 14da3b8039..a33a16599e 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1051,7 +1051,7 @@ int main(void) // MIDI_Task(); #endif -#ifdef RGBLIGHT_ENABLE +#ifdef RGBLIGHT_ANIMATIONS rgblight_task(); #endif From 06a2677b7eedbf58532fa1a673ba1277e756174d Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 20:17:32 -0500 Subject: [PATCH 22/62] fix infinity --- keyboards/ergodox/config.h | 2 -- keyboards/ergodox/ez/config.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/keyboards/ergodox/config.h b/keyboards/ergodox/config.h index 049c707a56..edc60caae1 100644 --- a/keyboards/ergodox/config.h +++ b/keyboards/ergodox/config.h @@ -1,8 +1,6 @@ #ifndef KEYBOARDS_ERGODOX_CONFIG_H_ #define KEYBOARDS_ERGODOX_CONFIG_H_ -#include "config_common.h" - #define MOUSEKEY_DELAY 100 #define MOUSEKEY_INTERVAL 20 #define MOUSEKEY_MAX_SPEED 3 diff --git a/keyboards/ergodox/ez/config.h b/keyboards/ergodox/ez/config.h index 084a044ee1..67a856e511 100644 --- a/keyboards/ergodox/ez/config.h +++ b/keyboards/ergodox/ez/config.h @@ -21,6 +21,8 @@ along with this program. If not, see . #include "../config.h" +#include "config_common.h" + /* USB Device descriptor parameter */ #define VENDOR_ID 0xFEED #define PRODUCT_ID 0x1307 From 3d7aaa31e41a9c96e785b0c089d74dfda525dfbe Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 00:30:06 -0500 Subject: [PATCH 23/62] converted to 8bit messages --- Dockerfile | 3 +- tmk_core/protocol/lufa/lufa.c | 119 +++++++++++++++++++--------------- tmk_core/protocol/midi.mk | 1 + 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/Dockerfile b/Dockerfile index 744ded8579..c42bbeb32a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,5 +25,4 @@ ENV subproject=ez ENV keymap=default VOLUME /qmk -WORKDIR /qmk -CMD make clean ; make keyboard=${keyboard} subproject=${subproject} keymap=${keymap} +WORKDIR /qmk \ No newline at end of file diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index a33a16599e..c4531c8d73 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -76,6 +76,10 @@ #include "rgblight.h" #endif +#ifdef MIDI_ENABLE + #include "sysex_tools.h" +#endif + uint8_t keyboard_idle = 0; /* 0: Boot Protocol, 1: Report Protocol(default) */ uint8_t keyboard_protocol = 1; @@ -1124,8 +1128,16 @@ void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t for (uint8_t place = 0; place < length; place++) { // send_byte(*data); midi_buffer[start + place] = *data; - if (*data == 0xF7 && midi_buffer[0] == 0xF0) - sysex_buffer_callback(device, start + place, midi_buffer); + if (*data == 0xF7) { + // SEND_STRING("\nRD: "); + // for (uint8_t i = 0; i < start + place + 1; i++){ + // send_byte(midi_buffer[i]); + // SEND_STRING(" "); + // } + uint8_t * decoded = malloc(sizeof(uint8_t) * (sysex_decoded_length(start + place - 4))); + uint16_t decode_length = sysex_decode(decoded, midi_buffer + 4, start + place - 4); + sysex_buffer_callback(device, decode_length, decoded); + } // SEND_STRING(" "); data++; } @@ -1161,32 +1173,35 @@ void encode_uint8_chunk(uint8_t data, uint8_t * pointer) { *pointer++ = (data) & 0x7F; } -void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { - // uint8_t * pointer_copy = data; // use for debugging +void dword_to_bytes(uint8_t * bytes, uint32_t dword) { + bytes[0] = (dword >> 24) & 0xFF; + bytes[1] = (dword >> 16) & 0xFF; + bytes[2] = (dword >> 8) & 0xFF; + bytes[3] = (dword >> 0) & 0xFF; +} - //data++; // i'm 98% sure there's a better way to do this - data++; - data++; - data++; - data++; +void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { + // SEND_STRING("\nRX: "); + // for (uint8_t i = 0; i < length; i++) { + // send_byte(data[i]); + // SEND_STRING(" "); + // } switch (*data++) { case 0x07: ; // Quantum action break; - case 0x08: ; // Keyboard acion + case 0x08: ; // Keyboard action break; case 0x09: ; // User action break; case 0x12: ; // Set info on keyboard switch (*data++) { case 0x02: ; // set default layer - uint8_t default_layer = decode_uint8_chunk(data); - eeconfig_update_default_layer(default_layer); - default_layer_set((uint32_t)default_layer); + eeconfig_update_default_layer(data[0] << 8 | data[1]); + default_layer_set((uint32_t)(data[0] << 8 | data[1])); break; case 0x08: ; // set keymap options - uint8_t keymap_options = decode_uint8_chunk(data); - eeconfig_update_keymap(keymap_options); + eeconfig_update_keymap(data[0]); break; } break; @@ -1196,42 +1211,37 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) send_bytes_sysex(0x00, NULL, 0); break; case 0x01: ; // Get debug state - uint8_t debug[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEBUG), debug); - send_bytes_sysex(0x01, debug, 2); + uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) }; + send_bytes_sysex(0x01, debug_bytes, 1); break; case 0x02: ; // Get default layer - uint8_t default_layer[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_DEFAULT_LAYER), default_layer); - send_bytes_sysex(0x02, default_layer, 2); + uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) }; + send_bytes_sysex(0x02, default_bytes, 1); break; #ifdef AUDIO_ENABLE case 0x03: ; // Get backlight state - uint8_t audio[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_AUDIO), audio); - send_bytes_sysex(0x03, audio, 2); + uint8_t audio_bytes[1] = { eeprom_read_byte(EECONFIG_AUDIO) }; + send_bytes_sysex(0x03, audio_bytes, 1); #endif case 0x04: ; // Get layer state - uint8_t layers[5]; - encode_uint32_chunk(layer_state, layers); - send_bytes_sysex(0x04, layers, 5); + uint8_t layer_state_bytes[4]; + dword_to_bytes(layer_state_bytes, layer_state); + send_bytes_sysex(0x04, layer_state_bytes, 4); break; #ifdef BACKLIGHT_ENABLE case 0x06: ; // Get backlight state - uint8_t backlight[2]; - encode_uint8_chunk(eeprom_read_byte(EECONFIG_BACKLIGHT), backlight); - send_bytes_sysex(0x06, backlight, 2); + uint8_t backlight_bytes[1] = { eeprom_read_byte(EECONFIG_BACKLIGHT) }; + send_bytes_sysex(0x06, backlight_bytes, 1); #endif #ifdef RGBLIGHT_ENABLE case 0x07: ; // Get rgblight state - uint8_t rgblight[2]; - encode_uint32_chunk(eeprom_read_dword(EECONFIG_RGBLIGHT), rgblight); - send_bytes_sysex(0x07, rgblight, 5); + uint8_t rgblight_bytes[4]; + dword_to_bytes(rgblight_bytes, eeprom_read_dword(EECONFIG_RGBLIGHT)); + send_bytes_sysex(0x07, rgblight_bytes, 4); #endif case 0x08: ; // Keymap options - uint8_t keymap_options[2]; - encode_uint8_chunk(eeconfig_read_keymap(), keymap_options); - send_bytes_sysex(0x08, keymap_options, 2); + uint8_t keymap_bytes[1] = { eeconfig_read_keymap() }; + send_bytes_sysex(0x08, keymap_bytes, 1); break; } break; @@ -1239,26 +1249,18 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) case 0x27: ; // RGB LED functions switch (*data++) { case 0x00: ; // Update HSV - uint32_t hsv = decode_uint32_chunk(data); - rgblight_sethsv(((hsv >> 16) & 0xFFFF) % 360, (hsv >> 8) & 0xFF, hsv & 0xFF); + rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]); break; case 0x01: ; // Update RGB break; case 0x02: ; // Update mode - uint8_t rgb_mode = decode_uint8_chunk(data); - rgblight_mode(rgb_mode); + rgblight_mode(data[0]); break; } break; #endif } - // SEND_STRING("\nDATA:\n"); - // while (*pointer_copy != 0xF7) { - // send_byte(*pointer_copy++); - // SEND_STRING(" "); - // } - } void send_unicode_midi(uint32_t unicode) { @@ -1268,15 +1270,30 @@ void send_unicode_midi(uint32_t unicode) { } void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length) { - uint8_t * array = malloc(sizeof(uint8_t) * (length + 6)); + // SEND_STRING("\nTX: "); + // for (uint8_t i = 0; i < length; i++) { + // send_byte(bytes[i]); + // SEND_STRING(" "); + // } + uint8_t * precode = malloc(sizeof(uint8_t) * (length + 1)); + precode[0] = type; + memcpy(precode + 1, bytes, length); + uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 1))); + uint16_t encoded_length = sysex_encode(encoded, precode, length + 1); + uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5)); array[0] = 0xF0; array[1] = 0x00; array[2] = 0x00; array[3] = 0x00; - array[4] = type; - array[length + 5] = 0xF7; - memcpy(array + 5, bytes, length); - midi_send_array(&midi_device, length + 6, array); + array[encoded_length + 4] = 0xF7; + memcpy(array + 4, encoded, encoded_length); + midi_send_array(&midi_device, encoded_length + 5, array); + + // SEND_STRING("\nTD: "); + // for (uint8_t i = 0; i < encoded_length + 5; i++) { + // send_byte(array[i]); + // SEND_STRING(" "); + // } } #endif diff --git a/tmk_core/protocol/midi.mk b/tmk_core/protocol/midi.mk index c85ae42ff2..4855b23d30 100644 --- a/tmk_core/protocol/midi.mk +++ b/tmk_core/protocol/midi.mk @@ -4,6 +4,7 @@ SRC += midi.c \ midi_device.c \ bytequeue/bytequeue.c \ bytequeue/interrupt_setting.c \ + sysex_tools.c \ $(LUFA_SRC_USBCLASS) VPATH += $(TMK_PATH)/$(MIDI_DIR) \ No newline at end of file From 2e23689b8e3222982082c1f5a4f8ce7686f9658b Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 18:52:02 -0500 Subject: [PATCH 24/62] converted to new format --- quantum/rgblight.c | 13 ++ quantum/rgblight.h | 1 + tmk_core/protocol/lufa/lufa.c | 313 +++++++++++++++++++++------------- tmk_core/protocol/lufa/lufa.h | 16 +- 4 files changed, 217 insertions(+), 126 deletions(-) diff --git a/quantum/rgblight.c b/quantum/rgblight.c index 00620da58e..bb03d6e913 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -183,6 +183,19 @@ void rgblight_init(void) { } } +void rgblight_update_dword(uint32_t dword) { + rgblight_config.raw = dword; + eeconfig_update_rgblight(rgblight_config.raw); + if (rgblight_config.enable) + rgblight_mode(rgblight_config.mode); + else { + #ifdef RGBLIGHT_ANIMATIONS + rgblight_timer_disable(); + #endif + rgblight_set(); + } +} + void rgblight_increase(void) { uint8_t mode = 0; if (rgblight_config.mode < RGBLIGHT_MODES) { diff --git a/quantum/rgblight.h b/quantum/rgblight.h index a3673348e7..28a410e480 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h @@ -65,6 +65,7 @@ void rgblight_enable(void); void rgblight_step(void); void rgblight_mode(uint8_t mode); void rgblight_set(void); +void rgblight_update_dword(uint32_t dword); void rgblight_increase_hue(void); void rgblight_decrease_hue(void); void rgblight_increase_sat(void); diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index c4531c8d73..c3234b8ce5 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1145,141 +1145,58 @@ void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t } -uint32_t decode_uint32_chunk(uint8_t * data) { - uint32_t part1 = *data++; - uint32_t part2 = *data++; - uint32_t part3 = *data++; - uint32_t part4 = *data++; - uint32_t part5 = *data++; - return ((part1 & 0x1FUL) << 28) | (part2 << 21) | (part3 << 14) | (part4 << 7) | part5; -} - -uint32_t decode_uint8_chunk(uint8_t * data) { - uint32_t part4 = *data++; - uint32_t part5 = *data++; - return (part4 << 7) | part5; -} - -void encode_uint32_chunk(uint32_t data, uint8_t * pointer) { - *pointer++ = (data >> 28) & 0x7F; - *pointer++ = (data >> 21) & 0x7F; - *pointer++ = (data >> 14) & 0x7F; - *pointer++ = (data >> 7) & 0x7F; - *pointer++ = (data) & 0x7F; -} - -void encode_uint8_chunk(uint8_t data, uint8_t * pointer) { - *pointer++ = (data >> 7) & 0x7F; - *pointer++ = (data) & 0x7F; -} - -void dword_to_bytes(uint8_t * bytes, uint32_t dword) { +void dword_to_bytes(uint32_t dword, uint8_t * bytes) { bytes[0] = (dword >> 24) & 0xFF; bytes[1] = (dword >> 16) & 0xFF; bytes[2] = (dword >> 8) & 0xFF; bytes[3] = (dword >> 0) & 0xFF; } -void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { - // SEND_STRING("\nRX: "); - // for (uint8_t i = 0; i < length; i++) { - // send_byte(data[i]); - // SEND_STRING(" "); - // } - - switch (*data++) { - case 0x07: ; // Quantum action - break; - case 0x08: ; // Keyboard action - break; - case 0x09: ; // User action - break; - case 0x12: ; // Set info on keyboard - switch (*data++) { - case 0x02: ; // set default layer - eeconfig_update_default_layer(data[0] << 8 | data[1]); - default_layer_set((uint32_t)(data[0] << 8 | data[1])); - break; - case 0x08: ; // set keymap options - eeconfig_update_keymap(data[0]); - break; - } - break; - case 0x13: ; // Get info from keyboard - switch (*data++) { - case 0x00: ; // Handshake - send_bytes_sysex(0x00, NULL, 0); - break; - case 0x01: ; // Get debug state - uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) }; - send_bytes_sysex(0x01, debug_bytes, 1); - break; - case 0x02: ; // Get default layer - uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) }; - send_bytes_sysex(0x02, default_bytes, 1); - break; - #ifdef AUDIO_ENABLE - case 0x03: ; // Get backlight state - uint8_t audio_bytes[1] = { eeprom_read_byte(EECONFIG_AUDIO) }; - send_bytes_sysex(0x03, audio_bytes, 1); - #endif - case 0x04: ; // Get layer state - uint8_t layer_state_bytes[4]; - dword_to_bytes(layer_state_bytes, layer_state); - send_bytes_sysex(0x04, layer_state_bytes, 4); - break; - #ifdef BACKLIGHT_ENABLE - case 0x06: ; // Get backlight state - uint8_t backlight_bytes[1] = { eeprom_read_byte(EECONFIG_BACKLIGHT) }; - send_bytes_sysex(0x06, backlight_bytes, 1); - #endif - #ifdef RGBLIGHT_ENABLE - case 0x07: ; // Get rgblight state - uint8_t rgblight_bytes[4]; - dword_to_bytes(rgblight_bytes, eeprom_read_dword(EECONFIG_RGBLIGHT)); - send_bytes_sysex(0x07, rgblight_bytes, 4); - #endif - case 0x08: ; // Keymap options - uint8_t keymap_bytes[1] = { eeconfig_read_keymap() }; - send_bytes_sysex(0x08, keymap_bytes, 1); - break; - } - break; - #ifdef RGBLIGHT_ENABLE - case 0x27: ; // RGB LED functions - switch (*data++) { - case 0x00: ; // Update HSV - rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]); - break; - case 0x01: ; // Update RGB - break; - case 0x02: ; // Update mode - rgblight_mode(data[0]); - break; - } - break; - #endif - } - +uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index) { + return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3]; } -void send_unicode_midi(uint32_t unicode) { - uint8_t chunk[5]; - encode_uint32_chunk(unicode, chunk); - send_bytes_sysex(0x05, chunk, 5); -} +enum MESSAGE_TYPE { + MT_GET_DATA = 0x10, // Get data from keyboard + MT_GET_DATA_ACK = 0x11, // returned data to process (ACK) + MT_SET_DATA = 0x20, // Set data on keyboard + MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK) + MT_SEND_DATA = 0x30, // Sending data/action from keyboard + MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK) + MT_EXE_ACTION = 0x40, // executing actions on keyboard + MT_EXE_ACTION_ACK =0x41, // return confirmation/value (ACK) + MT_TYPE_ERROR = 0x80 // type not recofgnised (ACK) +}; -void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length) { +enum DATA_TYPE { + DT_NONE = 0x00, + DT_HANDSHAKE, + DT_DEFAULT_LAYER, + DT_CURRENT_LAYER, + DT_KEYMAP_OPTIONS, + DT_BACKLIGHT, + DT_RGBLIGHT, + DT_UNICODE, + DT_DEBUG, + DT_AUDIO, + DT_QUANTUM_ACTION, + DT_KEYBOARD_ACTION, + DT_USER_ACTION, + +}; + +void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint8_t length) { // SEND_STRING("\nTX: "); // for (uint8_t i = 0; i < length; i++) { // send_byte(bytes[i]); // SEND_STRING(" "); // } - uint8_t * precode = malloc(sizeof(uint8_t) * (length + 1)); - precode[0] = type; - memcpy(precode + 1, bytes, length); - uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 1))); - uint16_t encoded_length = sysex_encode(encoded, precode, length + 1); + uint8_t * precode = malloc(sizeof(uint8_t) * (length + 2)); + precode[0] = message_type; + precode[1] = data_type; + memcpy(precode + 2, bytes, length); + uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 2))); + uint16_t encoded_length = sysex_encode(encoded, precode, length + 2); uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5)); array[0] = 0xF0; array[1] = 0x00; @@ -1296,4 +1213,158 @@ void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length) { // } } +#define MT_GET_DATA(data_type, data, length) send_bytes_sysex(MT_GET_DATA, data_type, data, length) +#define MT_GET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_GET_DATA_ACK, data_type, data, length) +#define MT_SET_DATA(data_type, data, length) send_bytes_sysex(MT_SET_DATA, data_type, data, length) +#define MT_SET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SET_DATA_ACK, data_type, data, length) +#define MT_SEND_DATA(data_type, data, length) send_bytes_sysex(MT_SEND_DATA, data_type, data, length) +#define MT_SEND_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SEND_DATA_ACK, data_type, data, length) +#define MT_EXE_ACTION(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION, data_type, data, length) +#define MT_EXE_ACTION_ACK(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION_ACK, data_type, data, length) + +__attribute__ ((weak)) +bool sysex_process_quantum(uint8_t length, uint8_t * data) { + return sysex_process_keyboard(length, data); +} + +__attribute__ ((weak)) +bool sysex_process_keyboard(uint8_t length, uint8_t * data) { + return sysex_process_user(length, data); +} + +__attribute__ ((weak)) +bool sysex_process_user(uint8_t length, uint8_t * data) { + return true; +} + +void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { + // SEND_STRING("\nRX: "); + // for (uint8_t i = 0; i < length; i++) { + // send_byte(data[i]); + // SEND_STRING(" "); + // } + if (!sysex_process_quantum(length, data)) + return; + + switch (data[0]) { + case MT_SET_DATA: + switch (data[1]) { + case DT_DEFAULT_LAYER: { + eeconfig_update_default_layer(data[2]); + default_layer_set((uint32_t)(data[2])); + break; + } + case DT_KEYMAP_OPTIONS: { + eeconfig_update_keymap(data[2]); + break; + } + case DT_RGBLIGHT: { + #ifdef RGBLIGHT_ENABLE + uint32_t rgblight = bytes_to_dword(data, 2); + rgblight_update_dword(rgblight); + #endif + break; + } + } + case MT_GET_DATA: + switch (data[1]) { + case DT_HANDSHAKE: { + MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0); + break; + } + case DT_DEBUG: { + uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) }; + MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1); + break; + } + case DT_DEFAULT_LAYER: { + uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) }; + MT_GET_DATA_ACK(DT_DEFAULT_LAYER, default_bytes, 1); + break; + } + case DT_CURRENT_LAYER: { + uint8_t layer_state_bytes[4]; + dword_to_bytes(layer_state, layer_state_bytes); + MT_GET_DATA_ACK(DT_CURRENT_LAYER, layer_state_bytes, 4); + break; + } + case DT_AUDIO: { + #ifdef AUDIO_ENABLE + uint8_t audio_bytes[1] = { eeprom_read_byte(EECONFIG_AUDIO) }; + MT_GET_DATA_ACK(DT_AUDIO, audio_bytes, 1); + #else + MT_GET_DATA_ACK(DT_AUDIO, NULL, 0); + #endif + break; + } + case DT_BACKLIGHT: { + #ifdef BACKLIGHT_ENABLE + uint8_t backlight_bytes[1] = { eeprom_read_byte(EECONFIG_BACKLIGHT) }; + MT_GET_DATA_ACK(DT_BACKLIGHT, backlight_bytes, 1); + #else + MT_GET_DATA_ACK(DT_BACKLIGHT, NULL, 0); + #endif + break; + } + case DT_RGBLIGHT: { + #ifdef RGBLIGHT_ENABLE + uint8_t rgblight_bytes[4]; + dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes); + MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4); + #else + MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0) + #endif + break; + } + case DT_KEYMAP_OPTIONS: { + uint8_t keymap_bytes[1] = { eeconfig_read_keymap() }; + MT_GET_DATA_ACK(DT_KEYMAP_OPTIONS, keymap_bytes, 1); + break; + } + default: + break; + } + break; + case MT_SET_DATA_ACK: + case MT_GET_DATA_ACK: + break; + case MT_SEND_DATA: + break; + case MT_SEND_DATA_ACK: + break; + case MT_EXE_ACTION: + break; + case MT_EXE_ACTION_ACK: + break; + case MT_TYPE_ERROR: + break; + default: ; // command not recognised + send_bytes_sysex(MT_TYPE_ERROR, DT_NONE, data, length); + break; + + // #ifdef RGBLIGHT_ENABLE + // case 0x27: ; // RGB LED functions + // switch (*data++) { + // case 0x00: ; // Update HSV + // rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]); + // break; + // case 0x01: ; // Update RGB + // break; + // case 0x02: ; // Update mode + // rgblight_mode(data[0]); + // break; + // } + // break; + // #endif + } + +} + +void send_unicode_midi(uint32_t unicode) { + uint8_t chunk[4]; + dword_to_bytes(unicode, chunk); + MT_SEND_DATA(DT_UNICODE, chunk, 5); +} + + #endif diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h index 198964f901..99b089f42b 100644 --- a/tmk_core/protocol/lufa/lufa.h +++ b/tmk_core/protocol/lufa/lufa.h @@ -73,13 +73,19 @@ typedef struct { MidiDevice midi_device; void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data); - uint32_t decode_uint32_chunk(uint8_t * data); - uint32_t decode_uint8_chunk(uint8_t * data); - void encode_uint32_chunk(uint32_t data, uint8_t * pointer); - void encode_uint8_chunk(uint8_t data, uint8_t * pointer); void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data); void send_unicode_midi(uint32_t unicode); - void send_bytes_sysex(uint8_t type, uint8_t * bytes, uint8_t length); + void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint8_t length); + + __attribute__ ((weak)) + bool sysex_process_quantum(uint8_t length, uint8_t * data); + + __attribute__ ((weak)) + bool sysex_process_keyboard(uint8_t length, uint8_t * data); + + __attribute__ ((weak)) + bool sysex_process_user(uint8_t length, uint8_t * data); + #endif // #if LUFA_VERSION_INTEGER < 0x120730 From cefa8468fb5f28bd67a0c02d371a4aef0964e20c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 20:16:38 -0500 Subject: [PATCH 25/62] travis pls --- keyboards/ergodox/infinity/rules.mk | 2 + keyboards/ergodox/keymaps/jack/Makefile | 4 +- quantum/quantum.c | 9 ++++- quantum/quantum.h | 2 + tmk_core/protocol/lufa/lufa.c | 49 +------------------------ tmk_core/protocol/lufa/lufa.h | 42 ++++++++++++++++++++- 6 files changed, 56 insertions(+), 52 deletions(-) diff --git a/keyboards/ergodox/infinity/rules.mk b/keyboards/ergodox/infinity/rules.mk index ccb735a485..473a6dfec6 100644 --- a/keyboards/ergodox/infinity/rules.mk +++ b/keyboards/ergodox/infinity/rules.mk @@ -63,6 +63,8 @@ VISUALIZER_ENABLE ?= no #temporarily disabled to make everything compile LCD_ENABLE ?= yes LED_ENABLE ?= yes LCD_BACKLIGHT_ENABLE ?= yes +MIDI_ENABLE = no +RGBLIGHT_ENABLE = no ifndef QUANTUM_DIR include ../../../Makefile diff --git a/keyboards/ergodox/keymaps/jack/Makefile b/keyboards/ergodox/keymaps/jack/Makefile index 7c257af501..3ca69bb923 100644 --- a/keyboards/ergodox/keymaps/jack/Makefile +++ b/keyboards/ergodox/keymaps/jack/Makefile @@ -1,5 +1,5 @@ -RGBLIGHT_ENABLE = yes -MIDI_ENABLE = yes +RGBLIGHT_ENABLE ?= yes +MIDI_ENABLE ?= yes ifndef QUANTUM_DIR include ../../../../Makefile diff --git a/quantum/quantum.c b/quantum/quantum.c index f9f1ef22d0..8372a7adc5 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -847,8 +847,13 @@ void send_nibble(uint8_t number) { } } - - +void send_unicode_midi(uint32_t unicode) { + #ifdef MIDI_ENABLE + uint8_t chunk[4]; + dword_to_bytes(unicode, chunk); + MT_SEND_DATA(DT_UNICODE, chunk, 5); + #endif +} __attribute__ ((weak)) void led_set_user(uint8_t usb_led) { diff --git a/quantum/quantum.h b/quantum/quantum.h index 3d35f11fad..316da15b9a 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -119,4 +119,6 @@ void send_nibble(uint8_t number); void led_set_user(uint8_t usb_led); void led_set_kb(uint8_t usb_led); +void send_unicode_midi(uint32_t unicode); + #endif diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index c3234b8ce5..eae3e8f298 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -72,7 +72,7 @@ #include "virtser.h" #endif -#ifdef RGB_MIDI +#if (defined(RGB_MIDI) | defined(RGBLIGHT_ANIMATIONS)) & defined(RGBLIGHT_ENABLE) #include "rgblight.h" #endif @@ -1156,35 +1156,6 @@ uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index) { return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3]; } -enum MESSAGE_TYPE { - MT_GET_DATA = 0x10, // Get data from keyboard - MT_GET_DATA_ACK = 0x11, // returned data to process (ACK) - MT_SET_DATA = 0x20, // Set data on keyboard - MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK) - MT_SEND_DATA = 0x30, // Sending data/action from keyboard - MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK) - MT_EXE_ACTION = 0x40, // executing actions on keyboard - MT_EXE_ACTION_ACK =0x41, // return confirmation/value (ACK) - MT_TYPE_ERROR = 0x80 // type not recofgnised (ACK) -}; - -enum DATA_TYPE { - DT_NONE = 0x00, - DT_HANDSHAKE, - DT_DEFAULT_LAYER, - DT_CURRENT_LAYER, - DT_KEYMAP_OPTIONS, - DT_BACKLIGHT, - DT_RGBLIGHT, - DT_UNICODE, - DT_DEBUG, - DT_AUDIO, - DT_QUANTUM_ACTION, - DT_KEYBOARD_ACTION, - DT_USER_ACTION, - -}; - void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint8_t length) { // SEND_STRING("\nTX: "); // for (uint8_t i = 0; i < length; i++) { @@ -1213,15 +1184,6 @@ void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, // } } -#define MT_GET_DATA(data_type, data, length) send_bytes_sysex(MT_GET_DATA, data_type, data, length) -#define MT_GET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_GET_DATA_ACK, data_type, data, length) -#define MT_SET_DATA(data_type, data, length) send_bytes_sysex(MT_SET_DATA, data_type, data, length) -#define MT_SET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SET_DATA_ACK, data_type, data, length) -#define MT_SEND_DATA(data_type, data, length) send_bytes_sysex(MT_SEND_DATA, data_type, data, length) -#define MT_SEND_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SEND_DATA_ACK, data_type, data, length) -#define MT_EXE_ACTION(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION, data_type, data, length) -#define MT_EXE_ACTION_ACK(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION_ACK, data_type, data, length) - __attribute__ ((weak)) bool sysex_process_quantum(uint8_t length, uint8_t * data) { return sysex_process_keyboard(length, data); @@ -1312,7 +1274,7 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes); MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4); #else - MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0) + MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0); #endif break; } @@ -1360,11 +1322,4 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) } -void send_unicode_midi(uint32_t unicode) { - uint8_t chunk[4]; - dword_to_bytes(unicode, chunk); - MT_SEND_DATA(DT_UNICODE, chunk, 5); -} - - #endif diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h index 99b089f42b..0962dda8d8 100644 --- a/tmk_core/protocol/lufa/lufa.h +++ b/tmk_core/protocol/lufa/lufa.h @@ -74,8 +74,9 @@ typedef struct { void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data); void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data); - void send_unicode_midi(uint32_t unicode); void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint8_t length); + void dword_to_bytes(uint32_t dword, uint8_t * bytes); + uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index); __attribute__ ((weak)) bool sysex_process_quantum(uint8_t length, uint8_t * data); @@ -86,6 +87,45 @@ typedef struct { __attribute__ ((weak)) bool sysex_process_user(uint8_t length, uint8_t * data); + enum MESSAGE_TYPE { + MT_GET_DATA = 0x10, // Get data from keyboard + MT_GET_DATA_ACK = 0x11, // returned data to process (ACK) + MT_SET_DATA = 0x20, // Set data on keyboard + MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK) + MT_SEND_DATA = 0x30, // Sending data/action from keyboard + MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK) + MT_EXE_ACTION = 0x40, // executing actions on keyboard + MT_EXE_ACTION_ACK =0x41, // return confirmation/value (ACK) + MT_TYPE_ERROR = 0x80 // type not recofgnised (ACK) + }; + + enum DATA_TYPE { + DT_NONE = 0x00, + DT_HANDSHAKE, + DT_DEFAULT_LAYER, + DT_CURRENT_LAYER, + DT_KEYMAP_OPTIONS, + DT_BACKLIGHT, + DT_RGBLIGHT, + DT_UNICODE, + DT_DEBUG, + DT_AUDIO, + DT_QUANTUM_ACTION, + DT_KEYBOARD_ACTION, + DT_USER_ACTION, + + }; + + + #define MT_GET_DATA(data_type, data, length) send_bytes_sysex(MT_GET_DATA, data_type, data, length) + #define MT_GET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_GET_DATA_ACK, data_type, data, length) + #define MT_SET_DATA(data_type, data, length) send_bytes_sysex(MT_SET_DATA, data_type, data, length) + #define MT_SET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SET_DATA_ACK, data_type, data, length) + #define MT_SEND_DATA(data_type, data, length) send_bytes_sysex(MT_SEND_DATA, data_type, data, length) + #define MT_SEND_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SEND_DATA_ACK, data_type, data, length) + #define MT_EXE_ACTION(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION, data_type, data, length) + #define MT_EXE_ACTION_ACK(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION_ACK, data_type, data, length) + #endif // #if LUFA_VERSION_INTEGER < 0x120730 From f25596b8dc2f15f620c07164d871023d9284618c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 21:28:12 -0500 Subject: [PATCH 26/62] rgblight fixes --- keyboards/ergodox/keymaps/erez_experimental/Makefile | 4 ++-- keyboards/ergodox/keymaps/erez_experimental/keymap.c | 8 +++++--- tmk_core/protocol/lufa/lufa.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/keyboards/ergodox/keymaps/erez_experimental/Makefile b/keyboards/ergodox/keymaps/erez_experimental/Makefile index dbe89d1410..51a0c74c54 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/Makefile +++ b/keyboards/ergodox/keymaps/erez_experimental/Makefile @@ -3,8 +3,8 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend COMMAND_ENABLE = no # Commands for debug and configuration -RGBLIGHT_ENABLE = yes -MIDI_ENABLE = yes +RGBLIGHT_ENABLE ?= yes +MIDI_ENABLE ?= yes ifndef QUANTUM_DIR include ../../../../Makefile diff --git a/keyboards/ergodox/keymaps/erez_experimental/keymap.c b/keyboards/ergodox/keymaps/erez_experimental/keymap.c index 4a23c7ac58..0c0e3c4e39 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/keymap.c +++ b/keyboards/ergodox/keymaps/erez_experimental/keymap.c @@ -164,9 +164,11 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { // dynamically generate these. case RGB_FF00BB: if (record->event.pressed) { - rgblight_enable(); - rgblight_mode(1); - rgblight_setrgb(0xff,0x00,0xbb); + #ifdef RGBLIGHT_ENABLE + rgblight_enable(); + rgblight_mode(1); + rgblight_setrgb(0xff,0x00,0xbb); + #endif } return false; break; diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index eae3e8f298..aa2e781c80 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1055,7 +1055,7 @@ int main(void) // MIDI_Task(); #endif -#ifdef RGBLIGHT_ANIMATIONS +#if defined(RGBLIGHT_ANIMATIONS) & defined(RGBLIGHT_ENABLE) rgblight_task(); #endif From 6fee7e178f7c949213a124d78de60bc30267d367 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Sat, 26 Nov 2016 23:53:15 +0700 Subject: [PATCH 27/62] fix strict-prototypes warning --- quantum/process_keycode/process_unicode.h | 1 + 1 file changed, 1 insertion(+) diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h index 065eeb5f6a..f17cfa6cf2 100644 --- a/quantum/process_keycode/process_unicode.h +++ b/quantum/process_keycode/process_unicode.h @@ -22,6 +22,7 @@ void register_hex(uint16_t hex); bool process_unicode(uint16_t keycode, keyrecord_t *record); #ifdef UNICODEMAP_ENABLE +void unicode_map_input_error(void); bool process_unicode_map(uint16_t keycode, keyrecord_t *record); #endif From a182cbc0319d54122e12dfa48e782e8e122c7df6 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Sun, 27 Nov 2016 00:34:29 +0700 Subject: [PATCH 28/62] Update Unicode documentation --- readme.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 3eb67882ab..cd65e0e69e 100644 --- a/readme.md +++ b/readme.md @@ -911,7 +911,33 @@ In `quantum/keymap_extras/`, you'll see various language files - these work the ## Unicode support -You can currently send 4 hex digits with your OS-specific modifier key (RALT for OSX with the "Unicode Hex Input" layout, see [this article](http://www.poynton.com/notes/misc/mac-unicode-hex-input.html) to learn more) - this is currently limited to supporting one OS at a time, and requires a recompile for switching. 8 digit hex codes are being worked on. The keycode function is `UC(n)`, where *n* is a 4 digit hexidecimal. Enable from the Makefile. +There are three Unicode keymap definition method available in QMK: + +### UNICODE_ENABLE + +Supports Unicode input up to 0xFFFF. The keycode function is `UC(n)` in +keymap file, where *n* is a 4 digit hexadecimal. + +### UNICODEMAP_ENABLE + +Supports Unicode up to 0xFFFFFFFF. You need to maintain a separate mapping +table `const uint32_t PROGMEM unicode_map[] = {...}` in your keymap file. +The keycode function is `X(n)` where *n* is the array index of the mapping +table. + +### UCIS_ENABLE + +TBD + +Unicode input in QMK works by inputing a sequence of characters to the OS, +sort of like macro. Unfortunately, each OS has different ideas on how Unicode is inputted. + +This is the current list of Unicode input method in QMK: + +* UC_OSX: MacOS Unicode Hex Input support. Works only up to 0xFFFF. Disabled by default. To enable: go to System Preferences -> Keyboard -> Input Sources, and enable Unicode Hex. +* UC_LNX: Unicode input method under Linux. Works up to 0xFFFFF. Should work almost anywhere on ibus enabled distros. Without ibus, this works under GTK apps, but rarely anywhere else. +* UC_WIN: (not recommended) Windows built-in Unicode input. To enable: create registry key under `HKEY_CURRENT_USER\Control Panel\Input Method\EnableHexNumpad` of type `REG_SZ` called `EnableHexNumpad`, set its value to 1, and reboot. This method is not recommended because of reliability and compatibility issue, use WinCompose method below instead. +* UC_WINC: Windows Unicode input using WinCompose. Requires [WinCompose](https://github.com/samhocevar/wincompose). Works reliably under many (all?) variations of Windows. ## Backlight Breathing From 7edac212c8ed8442bf4207e70dc8194631b2bf27 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sat, 26 Nov 2016 15:37:46 -0500 Subject: [PATCH 29/62] separated into api files/folder --- build_keyboard.mk | 8 + common.mk | 1 + keyboards/ergodox/keymaps/jack/keymap.c | 2 +- keyboards/ergodox/rules.mk | 1 - keyboards/planck/rules.mk | 1 + keyboards/preonic/keymaps/default/Makefile | 22 --- keyboards/preonic/rules.mk | 3 +- quantum/api.c | 178 ++++++++++++++++++ quantum/api.h | 59 ++++++ quantum/api/api_sysex.c | 29 +++ quantum/api/api_sysex.h | 10 + quantum/quantum.c | 6 +- quantum/quantum.h | 2 +- tmk_core/protocol/lufa/lufa.c | 203 +-------------------- tmk_core/protocol/lufa/lufa.h | 61 +------ 15 files changed, 303 insertions(+), 283 deletions(-) create mode 100644 quantum/api.c create mode 100644 quantum/api.h create mode 100644 quantum/api/api_sysex.c create mode 100644 quantum/api/api_sysex.h diff --git a/build_keyboard.mk b/build_keyboard.mk index 42f8f8ac7b..c1e5540039 100644 --- a/build_keyboard.mk +++ b/build_keyboard.mk @@ -131,6 +131,14 @@ ifndef CUSTOM_MATRIX SRC += $(QUANTUM_DIR)/matrix.c endif +ifeq ($(strip $(API_SYSEX_ENABLE)), yes) + OPT_DEFS += -DAPI_SYSEX_ENABLE + SRC += $(QUANTUM_DIR)/api/api_sysex.c + OPT_DEFS += -DAPI_ENABLE + SRC += $(QUANTUM_DIR)/api.c + MIDI_ENABLE=yes +endif + ifeq ($(strip $(MIDI_ENABLE)), yes) OPT_DEFS += -DMIDI_ENABLE SRC += $(QUANTUM_DIR)/process_keycode/process_midi.c diff --git a/common.mk b/common.mk index 18751cd5ac..c4b9394a24 100644 --- a/common.mk +++ b/common.mk @@ -23,4 +23,5 @@ COMMON_VPATH += $(QUANTUM_PATH) COMMON_VPATH += $(QUANTUM_PATH)/keymap_extras COMMON_VPATH += $(QUANTUM_PATH)/audio COMMON_VPATH += $(QUANTUM_PATH)/process_keycode +COMMON_VPATH += $(QUANTUM_PATH)/api COMMON_VPATH += $(SERIAL_PATH) \ No newline at end of file diff --git a/keyboards/ergodox/keymaps/jack/keymap.c b/keyboards/ergodox/keymaps/jack/keymap.c index eb41f12127..9cb80c59d1 100644 --- a/keyboards/ergodox/keymaps/jack/keymap.c +++ b/keyboards/ergodox/keymaps/jack/keymap.c @@ -91,7 +91,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) break; case 2: if (record->event.pressed) { // For resetting EEPROM - send_unicode_midi(0x0CA0); + api_send_unicode(0x0CA0); } break; } diff --git a/keyboards/ergodox/rules.mk b/keyboards/ergodox/rules.mk index add64ec76f..2e501e81b2 100644 --- a/keyboards/ergodox/rules.mk +++ b/keyboards/ergodox/rules.mk @@ -24,6 +24,5 @@ COMMAND_ENABLE ?= yes # Commands for debug and configuration CUSTOM_MATRIX ?= yes # Custom matrix file for the ErgoDox EZ SLEEP_LED_ENABLE ?= yes # Breathing sleep LED during USB suspend NKRO_ENABLE ?= yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work -MIDI_ENABLE ?= no # MIDI controls UNICODE_ENABLE ?= yes # Unicode ONEHAND_ENABLE ?= yes # Allow swapping hands of keyboard diff --git a/keyboards/planck/rules.mk b/keyboards/planck/rules.mk index 25db53a315..ccee972715 100644 --- a/keyboards/planck/rules.mk +++ b/keyboards/planck/rules.mk @@ -62,6 +62,7 @@ AUDIO_ENABLE ?= no # Audio output on port C6 UNICODE_ENABLE ?= no # Unicode BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID RGBLIGHT_ENABLE ?= no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +API_SYSEX_ENABLE = yes # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend \ No newline at end of file diff --git a/keyboards/preonic/keymaps/default/Makefile b/keyboards/preonic/keymaps/default/Makefile index 581e08cd02..3d4659ceb9 100644 --- a/keyboards/preonic/keymaps/default/Makefile +++ b/keyboards/preonic/keymaps/default/Makefile @@ -1,25 +1,3 @@ - - -# Build Options -# change to "no" to disable the options, or define them in the Makefile in -# the appropriate keymap folder that will get included automatically -# -BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE = yes # Mouse keys(+4700) -EXTRAKEY_ENABLE = yes # Audio control and System control(+450) -CONSOLE_ENABLE = no # Console for debug(+400) -COMMAND_ENABLE = yes # Commands for debug and configuration -NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work -BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality -MIDI_ENABLE = no # MIDI controls -AUDIO_ENABLE = yes # Audio output on port C6 -UNICODE_ENABLE = no # Unicode -BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID -RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. - -# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE -SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend - ifndef QUANTUM_DIR include ../../../../Makefile endif \ No newline at end of file diff --git a/keyboards/preonic/rules.mk b/keyboards/preonic/rules.mk index d0f3a3a1c0..c4ce2aacca 100644 --- a/keyboards/preonic/rules.mk +++ b/keyboards/preonic/rules.mk @@ -53,7 +53,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 # the appropriate keymap folder that will get included automatically # BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE ?= yes # Mouse keys(+4700) +MOUSEKEY_ENABLE ?= no # Mouse keys(+4700) EXTRAKEY_ENABLE ?= yes # Audio control and System control(+450) CONSOLE_ENABLE ?= no # Console for debug(+400) COMMAND_ENABLE ?= yes # Commands for debug and configuration @@ -64,6 +64,7 @@ AUDIO_ENABLE ?= no # Audio output on port C6 UNICODE_ENABLE ?= no # Unicode BLUETOOTH_ENABLE ?= no # Enable Bluetooth with the Adafruit EZ-Key HID RGBLIGHT_ENABLE ?= no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +API_SYSEX_ENABLE ?= yes # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE SLEEP_LED_ENABLE ?= no # Breathing sleep LED during USB suspend \ No newline at end of file diff --git a/quantum/api.c b/quantum/api.c new file mode 100644 index 0000000000..4ca3b96762 --- /dev/null +++ b/quantum/api.c @@ -0,0 +1,178 @@ +#include "api.h" +#include "quantum.h" + +void dword_to_bytes(uint32_t dword, uint8_t * bytes) { + bytes[0] = (dword >> 24) & 0xFF; + bytes[1] = (dword >> 16) & 0xFF; + bytes[2] = (dword >> 8) & 0xFF; + bytes[3] = (dword >> 0) & 0xFF; +} + +uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index) { + return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3]; +} + +__attribute__ ((weak)) +bool process_api_quantum(uint8_t length, uint8_t * data) { + return process_api_keyboard(length, data); +} + +__attribute__ ((weak)) +bool process_api_keyboard(uint8_t length, uint8_t * data) { + return process_api_user(length, data); +} + +__attribute__ ((weak)) +bool process_api_user(uint8_t length, uint8_t * data) { + return true; +} + +void process_api(uint16_t length, uint8_t * data) { + // SEND_STRING("\nRX: "); + // for (uint8_t i = 0; i < length; i++) { + // send_byte(data[i]); + // SEND_STRING(" "); + // } + if (!process_api_quantum(length, data)) + return; + + switch (data[0]) { + case MT_SET_DATA: + switch (data[1]) { + case DT_DEFAULT_LAYER: { + eeconfig_update_default_layer(data[2]); + default_layer_set((uint32_t)(data[2])); + break; + } + case DT_KEYMAP_OPTIONS: { + eeconfig_update_keymap(data[2]); + break; + } + case DT_RGBLIGHT: { + #ifdef RGBLIGHT_ENABLE + uint32_t rgblight = bytes_to_dword(data, 2); + rgblight_update_dword(rgblight); + #endif + break; + } + } + case MT_GET_DATA: + switch (data[1]) { + case DT_HANDSHAKE: { + MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0); + break; + } + case DT_DEBUG: { + uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) }; + MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1); + break; + } + case DT_DEFAULT_LAYER: { + uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) }; + MT_GET_DATA_ACK(DT_DEFAULT_LAYER, default_bytes, 1); + break; + } + case DT_CURRENT_LAYER: { + uint8_t layer_state_bytes[4]; + dword_to_bytes(layer_state, layer_state_bytes); + MT_GET_DATA_ACK(DT_CURRENT_LAYER, layer_state_bytes, 4); + break; + } + case DT_AUDIO: { + #ifdef AUDIO_ENABLE + uint8_t audio_bytes[1] = { eeprom_read_byte(EECONFIG_AUDIO) }; + MT_GET_DATA_ACK(DT_AUDIO, audio_bytes, 1); + #else + MT_GET_DATA_ACK(DT_AUDIO, NULL, 0); + #endif + break; + } + case DT_BACKLIGHT: { + #ifdef BACKLIGHT_ENABLE + uint8_t backlight_bytes[1] = { eeprom_read_byte(EECONFIG_BACKLIGHT) }; + MT_GET_DATA_ACK(DT_BACKLIGHT, backlight_bytes, 1); + #else + MT_GET_DATA_ACK(DT_BACKLIGHT, NULL, 0); + #endif + break; + } + case DT_RGBLIGHT: { + #ifdef RGBLIGHT_ENABLE + uint8_t rgblight_bytes[4]; + dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes); + MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4); + #else + MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0); + #endif + break; + } + case DT_KEYMAP_OPTIONS: { + uint8_t keymap_bytes[1] = { eeconfig_read_keymap() }; + MT_GET_DATA_ACK(DT_KEYMAP_OPTIONS, keymap_bytes, 1); + break; + } + case DT_KEYMAP_SIZE: { + uint8_t keymap_size[2] = {MATRIX_ROWS, MATRIX_COLS}; + MT_GET_DATA_ACK(DT_KEYMAP_SIZE, keymap_size, 2); + break; + } + case DT_KEYMAP: { + uint8_t keymap_data[MATRIX_ROWS * MATRIX_COLS * 4 + 3]; + keymap_data[0] = data[2]; + keymap_data[1] = MATRIX_ROWS; + keymap_data[2] = MATRIX_COLS; + for (int i = 0; i < MATRIX_ROWS; i++) { + for (int j = 0; j < MATRIX_COLS; j++) { + keymap_data[3 + (i*MATRIX_COLS*2) + (j*2)] = pgm_read_word(&keymaps[data[2]][i][j]) >> 8; + keymap_data[3 + (i*MATRIX_COLS*2) + (j*2) + 1] = pgm_read_word(&keymaps[data[2]][i][j]) & 0xFF; + } + } + MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, MATRIX_ROWS * MATRIX_COLS * 4 + 3); + // uint8_t keymap_data[5]; + // keymap_data[0] = data[2]; + // keymap_data[1] = data[3]; + // keymap_data[2] = data[4]; + // keymap_data[3] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) >> 8; + // keymap_data[4] = pgm_read_word(&keymaps[data[2]][data[3]][data[4]]) & 0xFF; + + // MT_GET_DATA_ACK(DT_KEYMAP, keymap_data, 5); + break; + } + default: + break; + } + break; + case MT_SET_DATA_ACK: + case MT_GET_DATA_ACK: + break; + case MT_SEND_DATA: + break; + case MT_SEND_DATA_ACK: + break; + case MT_EXE_ACTION: + break; + case MT_EXE_ACTION_ACK: + break; + case MT_TYPE_ERROR: + break; + default: ; // command not recognised + SEND_BYTES(MT_TYPE_ERROR, DT_NONE, data, length); + break; + + // #ifdef RGBLIGHT_ENABLE + // case 0x27: ; // RGB LED functions + // switch (*data++) { + // case 0x00: ; // Update HSV + // rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]); + // break; + // case 0x01: ; // Update RGB + // break; + // case 0x02: ; // Update mode + // rgblight_mode(data[0]); + // break; + // } + // break; + // #endif + } + +} \ No newline at end of file diff --git a/quantum/api.h b/quantum/api.h new file mode 100644 index 0000000000..00dcdb8954 --- /dev/null +++ b/quantum/api.h @@ -0,0 +1,59 @@ +#ifndef _API_H_ +#define _API_H_ + +#include "lufa.h" + +enum MESSAGE_TYPE { + MT_GET_DATA = 0x10, // Get data from keyboard + MT_GET_DATA_ACK = 0x11, // returned data to process (ACK) + MT_SET_DATA = 0x20, // Set data on keyboard + MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK) + MT_SEND_DATA = 0x30, // Sending data/action from keyboard + MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK) + MT_EXE_ACTION = 0x40, // executing actions on keyboard + MT_EXE_ACTION_ACK =0x41, // return confirmation/value (ACK) + MT_TYPE_ERROR = 0x80 // type not recofgnised (ACK) +}; + +enum DATA_TYPE { + DT_NONE = 0x00, + DT_HANDSHAKE, + DT_DEFAULT_LAYER, + DT_CURRENT_LAYER, + DT_KEYMAP_OPTIONS, + DT_BACKLIGHT, + DT_RGBLIGHT, + DT_UNICODE, + DT_DEBUG, + DT_AUDIO, + DT_QUANTUM_ACTION, + DT_KEYBOARD_ACTION, + DT_USER_ACTION, + DT_KEYMAP_SIZE, + DT_KEYMAP +}; + +void dword_to_bytes(uint32_t dword, uint8_t * bytes); +uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index); + +#define MT_GET_DATA(data_type, data, length) SEND_BYTES(MT_GET_DATA, data_type, data, length) +#define MT_GET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_GET_DATA_ACK, data_type, data, length) +#define MT_SET_DATA(data_type, data, length) SEND_BYTES(MT_SET_DATA, data_type, data, length) +#define MT_SET_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SET_DATA_ACK, data_type, data, length) +#define MT_SEND_DATA(data_type, data, length) SEND_BYTES(MT_SEND_DATA, data_type, data, length) +#define MT_SEND_DATA_ACK(data_type, data, length) SEND_BYTES(MT_SEND_DATA_ACK, data_type, data, length) +#define MT_EXE_ACTION(data_type, data, length) SEND_BYTES(MT_EXE_ACTION, data_type, data, length) +#define MT_EXE_ACTION_ACK(data_type, data, length) SEND_BYTES(MT_EXE_ACTION_ACK, data_type, data, length) + +void process_api(uint16_t length, uint8_t * data); + +__attribute__ ((weak)) +bool process_api_quantum(uint8_t length, uint8_t * data); + +__attribute__ ((weak)) +bool process_api_keyboard(uint8_t length, uint8_t * data); + +__attribute__ ((weak)) +bool process_api_user(uint8_t length, uint8_t * data); + +#endif \ No newline at end of file diff --git a/quantum/api/api_sysex.c b/quantum/api/api_sysex.c new file mode 100644 index 0000000000..a4a554e764 --- /dev/null +++ b/quantum/api/api_sysex.c @@ -0,0 +1,29 @@ +#include "api_sysex.h" + +void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint16_t length) { + // SEND_STRING("\nTX: "); + // for (uint8_t i = 0; i < length; i++) { + // send_byte(bytes[i]); + // SEND_STRING(" "); + // } + uint8_t * precode = malloc(sizeof(uint8_t) * (length + 2)); + precode[0] = message_type; + precode[1] = data_type; + memcpy(precode + 2, bytes, length); + uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 2))); + uint16_t encoded_length = sysex_encode(encoded, precode, length + 2); + uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5)); + array[0] = 0xF0; + array[1] = 0x00; + array[2] = 0x00; + array[3] = 0x00; + array[encoded_length + 4] = 0xF7; + memcpy(array + 4, encoded, encoded_length); + midi_send_array(&midi_device, encoded_length + 5, array); + + // SEND_STRING("\nTD: "); + // for (uint8_t i = 0; i < encoded_length + 5; i++) { + // send_byte(array[i]); + // SEND_STRING(" "); + // } +} \ No newline at end of file diff --git a/quantum/api/api_sysex.h b/quantum/api/api_sysex.h new file mode 100644 index 0000000000..b947b60e54 --- /dev/null +++ b/quantum/api/api_sysex.h @@ -0,0 +1,10 @@ +#ifndef _API_SYSEX_H_ +#define _API_SYSEX_H_ + +#include "api.h" + +void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint16_t length); + +#define SEND_BYTES(mt, dt, b, l) send_bytes_sysex(mt, dt, b, l) + +#endif \ No newline at end of file diff --git a/quantum/quantum.c b/quantum/quantum.c index 8372a7adc5..f653564a67 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -847,12 +847,12 @@ void send_nibble(uint8_t number) { } } -void send_unicode_midi(uint32_t unicode) { - #ifdef MIDI_ENABLE +void api_send_unicode(uint32_t unicode) { +#ifdef API_ENABLE uint8_t chunk[4]; dword_to_bytes(unicode, chunk); MT_SEND_DATA(DT_UNICODE, chunk, 5); - #endif +#endif } __attribute__ ((weak)) diff --git a/quantum/quantum.h b/quantum/quantum.h index 316da15b9a..e6adf974ab 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -119,6 +119,6 @@ void send_nibble(uint8_t number); void led_set_user(uint8_t usb_led); void led_set_kb(uint8_t usb_led); -void send_unicode_midi(uint32_t unicode); +void api_send_unicode(uint32_t unicode); #endif diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index aa2e781c80..39d4824b6b 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1091,37 +1091,17 @@ void fallthrough_callback(MidiDevice * device, #endif } -#ifdef RGB_MIDI - rgblight_config_t rgblight_config; -#endif void cc_callback(MidiDevice * device, uint8_t chan, uint8_t num, uint8_t val) { //sending it back on the next channel // midi_send_cc(device, (chan + 1) % 16, num, val); - #ifdef RGB_MIDI - rgblight_config.raw = eeconfig_read_rgblight(); - switch (num) { - case 14: - rgblight_config.hue = val * 360 / 127; - break; - case 15: - rgblight_config.sat = val << 1; - break; - case 16: - rgblight_config.val = val << 1; - break; - } - rgblight_sethsv(rgblight_config.hue, rgblight_config.sat, rgblight_config.val); - #endif } uint8_t midi_buffer[MIDI_SYSEX_BUFFER] = {0}; void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data) { - // for (int i = 0; i < length; i++) - // midi_send_cc(device, 15, 0x7F & data[i], 0x7F & (start + i)); - // if (start == 0x27) { + #ifdef API_SYSEX_ENABLE // SEND_STRING("\n"); // send_word(start); // SEND_STRING(": "); @@ -1136,190 +1116,13 @@ void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t // } uint8_t * decoded = malloc(sizeof(uint8_t) * (sysex_decoded_length(start + place - 4))); uint16_t decode_length = sysex_decode(decoded, midi_buffer + 4, start + place - 4); - sysex_buffer_callback(device, decode_length, decoded); + process_api(decode_length, decoded); } // SEND_STRING(" "); data++; } - // } - + #endif } -void dword_to_bytes(uint32_t dword, uint8_t * bytes) { - bytes[0] = (dword >> 24) & 0xFF; - bytes[1] = (dword >> 16) & 0xFF; - bytes[2] = (dword >> 8) & 0xFF; - bytes[3] = (dword >> 0) & 0xFF; -} - -uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index) { - return ((uint32_t)bytes[index + 0] << 24) | ((uint32_t)bytes[index + 1] << 16) | ((uint32_t)bytes[index + 2] << 8) | (uint32_t)bytes[index + 3]; -} - -void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint8_t length) { - // SEND_STRING("\nTX: "); - // for (uint8_t i = 0; i < length; i++) { - // send_byte(bytes[i]); - // SEND_STRING(" "); - // } - uint8_t * precode = malloc(sizeof(uint8_t) * (length + 2)); - precode[0] = message_type; - precode[1] = data_type; - memcpy(precode + 2, bytes, length); - uint8_t * encoded = malloc(sizeof(uint8_t) * (sysex_encoded_length(length + 2))); - uint16_t encoded_length = sysex_encode(encoded, precode, length + 2); - uint8_t * array = malloc(sizeof(uint8_t) * (encoded_length + 5)); - array[0] = 0xF0; - array[1] = 0x00; - array[2] = 0x00; - array[3] = 0x00; - array[encoded_length + 4] = 0xF7; - memcpy(array + 4, encoded, encoded_length); - midi_send_array(&midi_device, encoded_length + 5, array); - - // SEND_STRING("\nTD: "); - // for (uint8_t i = 0; i < encoded_length + 5; i++) { - // send_byte(array[i]); - // SEND_STRING(" "); - // } -} - -__attribute__ ((weak)) -bool sysex_process_quantum(uint8_t length, uint8_t * data) { - return sysex_process_keyboard(length, data); -} - -__attribute__ ((weak)) -bool sysex_process_keyboard(uint8_t length, uint8_t * data) { - return sysex_process_user(length, data); -} - -__attribute__ ((weak)) -bool sysex_process_user(uint8_t length, uint8_t * data) { - return true; -} - -void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) { - // SEND_STRING("\nRX: "); - // for (uint8_t i = 0; i < length; i++) { - // send_byte(data[i]); - // SEND_STRING(" "); - // } - if (!sysex_process_quantum(length, data)) - return; - - switch (data[0]) { - case MT_SET_DATA: - switch (data[1]) { - case DT_DEFAULT_LAYER: { - eeconfig_update_default_layer(data[2]); - default_layer_set((uint32_t)(data[2])); - break; - } - case DT_KEYMAP_OPTIONS: { - eeconfig_update_keymap(data[2]); - break; - } - case DT_RGBLIGHT: { - #ifdef RGBLIGHT_ENABLE - uint32_t rgblight = bytes_to_dword(data, 2); - rgblight_update_dword(rgblight); - #endif - break; - } - } - case MT_GET_DATA: - switch (data[1]) { - case DT_HANDSHAKE: { - MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0); - break; - } - case DT_DEBUG: { - uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) }; - MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1); - break; - } - case DT_DEFAULT_LAYER: { - uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) }; - MT_GET_DATA_ACK(DT_DEFAULT_LAYER, default_bytes, 1); - break; - } - case DT_CURRENT_LAYER: { - uint8_t layer_state_bytes[4]; - dword_to_bytes(layer_state, layer_state_bytes); - MT_GET_DATA_ACK(DT_CURRENT_LAYER, layer_state_bytes, 4); - break; - } - case DT_AUDIO: { - #ifdef AUDIO_ENABLE - uint8_t audio_bytes[1] = { eeprom_read_byte(EECONFIG_AUDIO) }; - MT_GET_DATA_ACK(DT_AUDIO, audio_bytes, 1); - #else - MT_GET_DATA_ACK(DT_AUDIO, NULL, 0); - #endif - break; - } - case DT_BACKLIGHT: { - #ifdef BACKLIGHT_ENABLE - uint8_t backlight_bytes[1] = { eeprom_read_byte(EECONFIG_BACKLIGHT) }; - MT_GET_DATA_ACK(DT_BACKLIGHT, backlight_bytes, 1); - #else - MT_GET_DATA_ACK(DT_BACKLIGHT, NULL, 0); - #endif - break; - } - case DT_RGBLIGHT: { - #ifdef RGBLIGHT_ENABLE - uint8_t rgblight_bytes[4]; - dword_to_bytes(eeconfig_read_rgblight(), rgblight_bytes); - MT_GET_DATA_ACK(DT_RGBLIGHT, rgblight_bytes, 4); - #else - MT_GET_DATA_ACK(DT_RGBLIGHT, NULL, 0); - #endif - break; - } - case DT_KEYMAP_OPTIONS: { - uint8_t keymap_bytes[1] = { eeconfig_read_keymap() }; - MT_GET_DATA_ACK(DT_KEYMAP_OPTIONS, keymap_bytes, 1); - break; - } - default: - break; - } - break; - case MT_SET_DATA_ACK: - case MT_GET_DATA_ACK: - break; - case MT_SEND_DATA: - break; - case MT_SEND_DATA_ACK: - break; - case MT_EXE_ACTION: - break; - case MT_EXE_ACTION_ACK: - break; - case MT_TYPE_ERROR: - break; - default: ; // command not recognised - send_bytes_sysex(MT_TYPE_ERROR, DT_NONE, data, length); - break; - - // #ifdef RGBLIGHT_ENABLE - // case 0x27: ; // RGB LED functions - // switch (*data++) { - // case 0x00: ; // Update HSV - // rgblight_sethsv((data[0] << 8 | data[1]) % 360, data[2], data[3]); - // break; - // case 0x01: ; // Update RGB - // break; - // case 0x02: ; // Update mode - // rgblight_mode(data[0]); - // break; - // } - // break; - // #endif - } - -} #endif diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h index 0962dda8d8..b11854101d 100644 --- a/tmk_core/protocol/lufa/lufa.h +++ b/tmk_core/protocol/lufa/lufa.h @@ -68,64 +68,17 @@ typedef struct { } __attribute__ ((packed)) report_extra_t; #ifdef MIDI_ENABLE - #define MIDI_SYSEX_BUFFER 16 void MIDI_Task(void); MidiDevice midi_device; + #define MIDI_SYSEX_BUFFER 32 +#endif - void sysex_callback(MidiDevice * device, uint16_t start, uint8_t length, uint8_t * data); - void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data); - void send_bytes_sysex(uint8_t message_type, uint8_t data_type, uint8_t * bytes, uint8_t length); - void dword_to_bytes(uint32_t dword, uint8_t * bytes); - uint32_t bytes_to_dword(uint8_t * bytes, uint8_t index); - - __attribute__ ((weak)) - bool sysex_process_quantum(uint8_t length, uint8_t * data); - - __attribute__ ((weak)) - bool sysex_process_keyboard(uint8_t length, uint8_t * data); - - __attribute__ ((weak)) - bool sysex_process_user(uint8_t length, uint8_t * data); - - enum MESSAGE_TYPE { - MT_GET_DATA = 0x10, // Get data from keyboard - MT_GET_DATA_ACK = 0x11, // returned data to process (ACK) - MT_SET_DATA = 0x20, // Set data on keyboard - MT_SET_DATA_ACK = 0x21, // returned data to confirm (ACK) - MT_SEND_DATA = 0x30, // Sending data/action from keyboard - MT_SEND_DATA_ACK = 0x31, // returned data/action confirmation (ACK) - MT_EXE_ACTION = 0x40, // executing actions on keyboard - MT_EXE_ACTION_ACK =0x41, // return confirmation/value (ACK) - MT_TYPE_ERROR = 0x80 // type not recofgnised (ACK) - }; - - enum DATA_TYPE { - DT_NONE = 0x00, - DT_HANDSHAKE, - DT_DEFAULT_LAYER, - DT_CURRENT_LAYER, - DT_KEYMAP_OPTIONS, - DT_BACKLIGHT, - DT_RGBLIGHT, - DT_UNICODE, - DT_DEBUG, - DT_AUDIO, - DT_QUANTUM_ACTION, - DT_KEYBOARD_ACTION, - DT_USER_ACTION, - - }; - - - #define MT_GET_DATA(data_type, data, length) send_bytes_sysex(MT_GET_DATA, data_type, data, length) - #define MT_GET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_GET_DATA_ACK, data_type, data, length) - #define MT_SET_DATA(data_type, data, length) send_bytes_sysex(MT_SET_DATA, data_type, data, length) - #define MT_SET_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SET_DATA_ACK, data_type, data, length) - #define MT_SEND_DATA(data_type, data, length) send_bytes_sysex(MT_SEND_DATA, data_type, data, length) - #define MT_SEND_DATA_ACK(data_type, data, length) send_bytes_sysex(MT_SEND_DATA_ACK, data_type, data, length) - #define MT_EXE_ACTION(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION, data_type, data, length) - #define MT_EXE_ACTION_ACK(data_type, data, length) send_bytes_sysex(MT_EXE_ACTION_ACK, data_type, data, length) +#ifdef API_ENABLE + #include "api.h" +#endif +#ifdef API_SYSEX_ENABLE + #include "api_sysex.h" #endif // #if LUFA_VERSION_INTEGER < 0x120730 From be4e75423a232d9d328bb23835e0fa5152292c95 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:41:22 -0800 Subject: [PATCH 30/62] Tidy up atomicity in timer.c and ring_buffer.h Adopt the macros for saving/restoring the interrupt state that are provided by the avr gcc environment. Removing intialization of the timer value; this shaves off a few bytes because globals are default initialized to zero. --- tmk_core/common/avr/timer.c | 36 ++++++++++++++++-------------------- tmk_core/ring_buffer.h | 26 ++++++++++++-------------- 2 files changed, 28 insertions(+), 34 deletions(-) diff --git a/tmk_core/common/avr/timer.c b/tmk_core/common/avr/timer.c index 292b41c3a6..84af444885 100644 --- a/tmk_core/common/avr/timer.c +++ b/tmk_core/common/avr/timer.c @@ -17,6 +17,7 @@ along with this program. If not, see . #include #include +#include #include #include "timer_avr.h" #include "timer.h" @@ -24,7 +25,7 @@ along with this program. If not, see . // counter resolution 1ms // NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }} -volatile uint32_t timer_count = 0; +volatile uint32_t timer_count; void timer_init(void) { @@ -52,10 +53,9 @@ void timer_init(void) inline void timer_clear(void) { - uint8_t sreg = SREG; - cli(); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; - SREG = sreg; + } } inline @@ -63,10 +63,9 @@ uint16_t timer_read(void) { uint32_t t; - uint8_t sreg = SREG; - cli(); - t = timer_count; - SREG = sreg; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + t = timer_count; + } return (t & 0xFFFF); } @@ -76,10 +75,9 @@ uint32_t timer_read32(void) { uint32_t t; - uint8_t sreg = SREG; - cli(); - t = timer_count; - SREG = sreg; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + t = timer_count; + } return t; } @@ -89,10 +87,9 @@ uint16_t timer_elapsed(uint16_t last) { uint32_t t; - uint8_t sreg = SREG; - cli(); - t = timer_count; - SREG = sreg; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + t = timer_count; + } return TIMER_DIFF_16((t & 0xFFFF), last); } @@ -102,10 +99,9 @@ uint32_t timer_elapsed32(uint32_t last) { uint32_t t; - uint8_t sreg = SREG; - cli(); - t = timer_count; - SREG = sreg; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + t = timer_count; + } return TIMER_DIFF_32(t, last); } diff --git a/tmk_core/ring_buffer.h b/tmk_core/ring_buffer.h index 7bdebbcf34..005d1be613 100644 --- a/tmk_core/ring_buffer.h +++ b/tmk_core/ring_buffer.h @@ -4,13 +4,13 @@ * Ring buffer to store scan codes from keyboard *------------------------------------------------------------------*/ #define RBUF_SIZE 32 +#include static uint8_t rbuf[RBUF_SIZE]; static uint8_t rbuf_head = 0; static uint8_t rbuf_tail = 0; static inline void rbuf_enqueue(uint8_t data) { - uint8_t sreg = SREG; - cli(); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { uint8_t next = (rbuf_head + 1) % RBUF_SIZE; if (next != rbuf_tail) { rbuf[rbuf_head] = data; @@ -18,36 +18,34 @@ static inline void rbuf_enqueue(uint8_t data) } else { print("rbuf: full\n"); } - SREG = sreg; + } } static inline uint8_t rbuf_dequeue(void) { uint8_t val = 0; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - uint8_t sreg = SREG; - cli(); if (rbuf_head != rbuf_tail) { val = rbuf[rbuf_tail]; rbuf_tail = (rbuf_tail + 1) % RBUF_SIZE; } - SREG = sreg; + } return val; } static inline bool rbuf_has_data(void) { - uint8_t sreg = SREG; - cli(); - bool has_data = (rbuf_head != rbuf_tail); - SREG = sreg; - return has_data; + bool has_data; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + has_data = (rbuf_head != rbuf_tail); + } + return has_data; } static inline void rbuf_clear(void) { - uint8_t sreg = SREG; - cli(); + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { rbuf_head = rbuf_tail = 0; - SREG = sreg; + } } #endif /* RING_BUFFER_H */ From 8485bb34d2e291db5b6c81f892850da1cdca37ba Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:43:11 -0800 Subject: [PATCH 31/62] Add arduino-alike GPIO pin control helpers Unlike the arduino functions, these don't take abstract pin numbers, they take pin labels like `B0`. Also, rather than taking very generic parameter names, these take slightly more descriptive enum values. These improve the clarity of code that would otherwise be inscrutable bit manipulation in tersely named port register names. --- quantum/pincontrol.h | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 quantum/pincontrol.h diff --git a/quantum/pincontrol.h b/quantum/pincontrol.h new file mode 100644 index 0000000000..36ce29ef22 --- /dev/null +++ b/quantum/pincontrol.h @@ -0,0 +1,37 @@ +#pragma once +// Some helpers for controlling gpio pins +#include + +enum { + PinDirectionInput = 0, + PinDirectionOutput = 1, + PinLevelHigh = 1, + PinLevelLow = 0, +}; + +// ex: pinMode(B0, PinDirectionOutput); +static inline void pinMode(uint8_t pin, int mode) { + uint8_t bv = _BV(pin & 0xf); + if (mode == PinDirectionOutput) { + _SFR_IO8((pin >> 4) + 1) |= bv; + } else { + _SFR_IO8((pin >> 4) + 1) &= ~bv; + _SFR_IO8((pin >> 4) + 2) &= ~bv; + } +} + +// ex: digitalWrite(B0, PinLevelHigh); +static inline void digitalWrite(uint8_t pin, int mode) { + uint8_t bv = _BV(pin & 0xf); + if (mode == PinLevelHigh) { + _SFR_IO8((pin >> 4) + 2) |= bv; + } else { + _SFR_IO8((pin >> 4) + 2) &= ~bv; + } +} + +// Return true if the pin is HIGH +// digitalRead(B0) +static inline bool digitalRead(uint8_t pin) { + return _SFR_IO8(pin >> 4) & _BV(pin & 0xf); +} From 712476cd288505cabb2ad6163d1c1ba13a7a1cca Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:48:04 -0800 Subject: [PATCH 32/62] Add support for Adafruit BLE modules This implements some helper functions that allow sending key reports to an SPI based Bluetooth Low Energy module, such as the Adafruit Feather 32u4 Bluefruit LE. There is some plumbing required in lufa.c to enable this; that is in a follow-on commit. --- tmk_core/common.mk | 6 +- tmk_core/protocol/lufa.mk | 4 + tmk_core/protocol/lufa/adafruit_ble.cpp | 805 ++++++++++++++++++++++++ tmk_core/protocol/lufa/adafruit_ble.h | 60 ++ tmk_core/protocol/lufa/ringbuffer.hpp | 66 ++ 5 files changed, 940 insertions(+), 1 deletion(-) create mode 100644 tmk_core/protocol/lufa/adafruit_ble.cpp create mode 100644 tmk_core/protocol/lufa/adafruit_ble.h create mode 100644 tmk_core/protocol/lufa/ringbuffer.hpp diff --git a/tmk_core/common.mk b/tmk_core/common.mk index f826a7b540..c32a12bb6f 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -81,6 +81,10 @@ ifeq ($(strip $(BACKLIGHT_ENABLE)), yes) TMK_COMMON_DEFS += -DBACKLIGHT_ENABLE endif +ifeq ($(strip $(ADAFRUIT_BLE_ENABLE)), yes) + TMK_COMMON_DEFS += -DADAFRUIT_BLE_ENABLE +endif + ifeq ($(strip $(BLUETOOTH_ENABLE)), yes) TMK_COMMON_DEFS += -DBLUETOOTH_ENABLE endif @@ -110,4 +114,4 @@ endif VPATH += $(TMK_PATH)/$(COMMON_DIR) ifeq ($(PLATFORM),CHIBIOS) VPATH += $(TMK_PATH)/$(COMMON_DIR)/chibios -endif \ No newline at end of file +endif diff --git a/tmk_core/protocol/lufa.mk b/tmk_core/protocol/lufa.mk index 5b1e3d19d0..151d26cbc8 100644 --- a/tmk_core/protocol/lufa.mk +++ b/tmk_core/protocol/lufa.mk @@ -21,6 +21,10 @@ ifeq ($(strip $(MIDI_ENABLE)), yes) include $(TMK_PATH)/protocol/midi.mk endif +ifeq ($(strip $(ADAFRUIT_BLE_ENABLE)), yes) + LUFA_SRC += $(LUFA_DIR)/adafruit_ble.cpp +endif + ifeq ($(strip $(BLUETOOTH_ENABLE)), yes) LUFA_SRC += $(LUFA_DIR)/bluetooth.c \ $(TMK_DIR)/protocol/serial_uart.c diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp new file mode 100644 index 0000000000..37194e77a9 --- /dev/null +++ b/tmk_core/protocol/lufa/adafruit_ble.cpp @@ -0,0 +1,805 @@ +#include "adafruit_ble.h" +#include +#include +#include +#include +#include +#include "debug.h" +#include "pincontrol.h" +#include "timer.h" +#include "action_util.h" +#include "ringbuffer.hpp" +#include + +// These are the pin assignments for the 32u4 boards. +// You may define them to something else in your config.h +// if yours is wired up differently. +#ifndef AdafruitBleResetPin +#define AdafruitBleResetPin D4 +#endif + +#ifndef AdafruitBleCSPin +#define AdafruitBleCSPin B4 +#endif + +#ifndef AdafruitBleIRQPin +#define AdafruitBleIRQPin E6 +#endif + + +#define SAMPLE_BATTERY +#define ConnectionUpdateInterval 1000 /* milliseconds */ + +static struct { + bool is_connected; + bool initialized; + bool configured; + +#define ProbedEvents 1 +#define UsingEvents 2 + bool event_flags; + +#ifdef SAMPLE_BATTERY + uint16_t last_battery_update; + uint32_t vbat; +#endif + uint16_t last_connection_update; +} state; + +// Commands are encoded using SDEP and sent via SPI +// https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/blob/master/SDEP.md + +#define SdepMaxPayload 16 +struct sdep_msg { + uint8_t type; + uint8_t cmd_low; + uint8_t cmd_high; + struct __attribute__((packed)) { + uint8_t len:7; + uint8_t more:1; + }; + uint8_t payload[SdepMaxPayload]; +} __attribute__((packed)); + +// The recv latency is relatively high, so when we're hammering keys quickly, +// we want to avoid waiting for the responses in the matrix loop. We maintain +// a short queue for that. Since there is quite a lot of space overhead for +// the AT command representation wrapped up in SDEP, we queue the minimal +// information here. + +enum queue_type { + QTKeyReport, // 1-byte modifier + 6-byte key report + QTConsumer, // 16-bit key code +#ifdef MOUSE_ENABLE + QTMouseMove, // 4-byte mouse report +#endif +}; + +struct queue_item { + enum queue_type queue_type; + uint16_t added; + union __attribute__((packed)) { + struct __attribute__((packed)) { + uint8_t modifier; + uint8_t keys[6]; + } key; + + uint16_t consumer; + struct __attribute__((packed)) { + uint8_t x, y, scroll, pan; + } mousemove; + }; +}; + +// Items that we wish to send +static RingBuffer send_buf; +// Pending response; while pending, we can't send any more requests. +// This records the time at which we sent the command for which we +// are expecting a response. +static RingBuffer resp_buf; + +static bool process_queue_item(struct queue_item *item, uint16_t timeout); + +enum sdep_type { + SdepCommand = 0x10, + SdepResponse = 0x20, + SdepAlert = 0x40, + SdepError = 0x80, + SdepSlaveNotReady = 0xfe, // Try again later + SdepSlaveOverflow = 0xff, // You read more data than is available +}; + +enum ble_cmd { + BleInitialize = 0xbeef, + BleAtWrapper = 0x0a00, + BleUartTx = 0x0a01, + BleUartRx = 0x0a02, +}; + +enum ble_system_event_bits { + BleSystemConnected = 0, + BleSystemDisconnected = 1, + BleSystemUartRx = 8, + BleSystemMidiRx = 10, +}; + +// The SDEP.md file says 2MHz but the web page and the sample driver +// both use 4MHz +#define SpiBusSpeed 4000000 + +#define SdepTimeout 150 /* milliseconds */ +#define SdepShortTimeout 10 /* milliseconds */ +#define SdepBackOff 25 /* microseconds */ +#define BatteryUpdateInterval 10000 /* milliseconds */ + +static bool at_command(const char *cmd, char *resp, uint16_t resplen, + bool verbose, uint16_t timeout = SdepTimeout); +static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, + bool verbose = false); + +struct SPI_Settings { + uint8_t spcr, spsr; +}; + +static struct SPI_Settings spi; + +// Initialize 4Mhz MSBFIRST MODE0 +void SPI_init(struct SPI_Settings *spi) { + spi->spcr = _BV(SPE) | _BV(MSTR); + spi->spsr = _BV(SPI2X); + + static_assert(SpiBusSpeed == F_CPU / 2, "hard coded at 4Mhz"); + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + // Ensure that SS is OUTPUT High + digitalWrite(B0, PinLevelHigh); + pinMode(B0, PinDirectionOutput); + + SPCR |= _BV(MSTR); + SPCR |= _BV(SPE); + pinMode(B1 /* SCK */, PinDirectionOutput); + pinMode(B2 /* MOSI */, PinDirectionOutput); + } +} + +static inline void SPI_begin(struct SPI_Settings*spi) { + SPCR = spi->spcr; + SPSR = spi->spsr; +} + +static inline uint8_t SPI_TransferByte(uint8_t data) { + SPDR = data; + asm volatile("nop"); + while (!(SPSR & _BV(SPIF))) { + ; // wait + } + return SPDR; +} + +static inline void spi_send_bytes(const uint8_t *buf, uint8_t len) { + if (len == 0) return; + const uint8_t *end = buf + len; + while (buf < end) { + SPDR = *buf; + while (!(SPSR & _BV(SPIF))) { + ; // wait + } + ++buf; + } +} + +static inline uint16_t spi_read_byte(void) { + return SPI_TransferByte(0x00 /* dummy */); +} + +static inline void spi_recv_bytes(uint8_t *buf, uint8_t len) { + const uint8_t *end = buf + len; + if (len == 0) return; + while (buf < end) { + SPDR = 0; // write a dummy to initiate read + while (!(SPSR & _BV(SPIF))) { + ; // wait + } + *buf = SPDR; + ++buf; + } +} + +#if 0 +static void dump_pkt(const struct sdep_msg *msg) { + print("pkt: type="); + print_hex8(msg->type); + print(" cmd="); + print_hex8(msg->cmd_high); + print_hex8(msg->cmd_low); + print(" len="); + print_hex8(msg->len); + print(" more="); + print_hex8(msg->more); + print("\n"); +} +#endif + +// Send a single SDEP packet +static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) { + SPI_begin(&spi); + + digitalWrite(AdafruitBleCSPin, PinLevelLow); + uint16_t timerStart = timer_read(); + bool success = false; + bool ready = false; + + do { + ready = SPI_TransferByte(msg->type) != SdepSlaveNotReady; + if (ready) { + break; + } + + // Release it and let it initialize + digitalWrite(AdafruitBleCSPin, PinLevelHigh); + _delay_us(SdepBackOff); + digitalWrite(AdafruitBleCSPin, PinLevelLow); + } while (timer_elapsed(timerStart) < timeout); + + if (ready) { + // Slave is ready; send the rest of the packet + spi_send_bytes(&msg->cmd_low, + sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len); + success = true; + } + + digitalWrite(AdafruitBleCSPin, PinLevelHigh); + + return success; +} + +static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, + const uint8_t *payload, uint8_t len, + bool moredata) { + msg->type = SdepCommand; + msg->cmd_low = command & 0xff; + msg->cmd_high = command >> 8; + msg->len = len; + msg->more = (moredata && len == SdepMaxPayload) ? 1 : 0; + + static_assert(sizeof(*msg) == 20, "msg is correctly packed"); + + memcpy(msg->payload, payload, len); +} + +// Read a single SDEP packet +static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) { + bool success = false; + uint16_t timerStart = timer_read(); + bool ready = false; + + do { + ready = digitalRead(AdafruitBleIRQPin); + if (ready) { + break; + } + _delay_us(1); + } while (timer_elapsed(timerStart) < timeout); + + if (ready) { + SPI_begin(&spi); + + digitalWrite(AdafruitBleCSPin, PinLevelLow); + + do { + // Read the command type, waiting for the data to be ready + msg->type = spi_read_byte(); + if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) { + // Release it and let it initialize + digitalWrite(AdafruitBleCSPin, PinLevelHigh); + _delay_us(SdepBackOff); + digitalWrite(AdafruitBleCSPin, PinLevelLow); + continue; + } + + // Read the rest of the header + spi_recv_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload))); + + // and get the payload if there is any + if (msg->len <= SdepMaxPayload) { + spi_recv_bytes(msg->payload, msg->len); + } + success = true; + break; + } while (timer_elapsed(timerStart) < timeout); + + digitalWrite(AdafruitBleCSPin, PinLevelHigh); + } + return success; +} + +static void resp_buf_read_one(bool greedy) { + uint16_t last_send; + if (!resp_buf.peek(last_send)) { + return; + } + + if (digitalRead(AdafruitBleIRQPin)) { + struct sdep_msg msg; + +again: + if (sdep_recv_pkt(&msg, SdepTimeout)) { + if (!msg.more) { + // We got it; consume this entry + resp_buf.get(last_send); + dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send)); + } + + if (greedy && resp_buf.peek(last_send) && digitalRead(AdafruitBleIRQPin)) { + goto again; + } + } + + } else if (timer_elapsed(last_send) > SdepTimeout * 2) { + dprintf("waiting_for_result: timeout, resp_buf size %d\n", + (int)resp_buf.size()); + + // Timed out: consume this entry + resp_buf.get(last_send); + } +} + +static void send_buf_send_one(uint16_t timeout = SdepTimeout) { + struct queue_item item; + + // Don't send anything more until we get an ACK + if (!resp_buf.empty()) { + return; + } + + if (!send_buf.peek(item)) { + return; + } + if (process_queue_item(&item, timeout)) { + // commit that peek + send_buf.get(item); + dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size()); + } else { + dprint("failed to send, will retry\n"); + _delay_ms(SdepTimeout); + resp_buf_read_one(true); + } +} + +static void resp_buf_wait(const char *cmd) { + bool didPrint = false; + while (!resp_buf.empty()) { + if (!didPrint) { + dprintf("wait on buf for %s\n", cmd); + didPrint = true; + } + resp_buf_read_one(true); + } +} + +static bool ble_init(void) { + state.initialized = false; + state.configured = false; + state.is_connected = false; + + pinMode(AdafruitBleIRQPin, PinDirectionInput); + pinMode(AdafruitBleCSPin, PinDirectionOutput); + digitalWrite(AdafruitBleCSPin, PinLevelHigh); + + SPI_init(&spi); + + // Perform a hardware reset + pinMode(AdafruitBleResetPin, PinDirectionOutput); + digitalWrite(AdafruitBleResetPin, PinLevelHigh); + digitalWrite(AdafruitBleResetPin, PinLevelLow); + _delay_ms(10); + digitalWrite(AdafruitBleResetPin, PinLevelHigh); + + _delay_ms(1000); // Give it a second to initialize + + state.initialized = true; + return state.initialized; +} + +static inline uint8_t min(uint8_t a, uint8_t b) { + return a < b ? a : b; +} + +static bool read_response(char *resp, uint16_t resplen, bool verbose) { + char *dest = resp; + char *end = dest + resplen; + + while (true) { + struct sdep_msg msg; + + if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) { + dprint("sdep_recv_pkt failed\n"); + return false; + } + + if (msg.type != SdepResponse) { + *resp = 0; + return false; + } + + uint8_t len = min(msg.len, end - dest); + if (len > 0) { + memcpy(dest, msg.payload, len); + dest += len; + } + + if (!msg.more) { + // No more data is expected! + break; + } + } + + // Ensure the response is NUL terminated + *dest = 0; + + // "Parse" the result text; we want to snip off the trailing OK or ERROR line + // Rewind past the possible trailing CRLF so that we can strip it + --dest; + while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) { + *dest = 0; + --dest; + } + + // Look back for start of preceeding line + char *last_line = strrchr(resp, '\n'); + if (last_line) { + ++last_line; + } else { + last_line = resp; + } + + bool success = false; + static const char kOK[] PROGMEM = "OK"; + + success = !strcmp_P(last_line, kOK ); + + if (verbose || !success) { + dprintf("result: %s\n", resp); + } + return success; +} + +static bool at_command(const char *cmd, char *resp, uint16_t resplen, + bool verbose, uint16_t timeout) { + const char *end = cmd + strlen(cmd); + struct sdep_msg msg; + + if (verbose) { + dprintf("ble send: %s\n", cmd); + } + + if (resp) { + // They want to decode the response, so we need to flush and wait + // for all pending I/O to finish before we start this one, so + // that we don't confuse the results + resp_buf_wait(cmd); + *resp = 0; + } + + // Fragment the command into a series of SDEP packets + while (end - cmd > SdepMaxPayload) { + sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true); + if (!sdep_send_pkt(&msg, timeout)) { + return false; + } + cmd += SdepMaxPayload; + } + + sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false); + if (!sdep_send_pkt(&msg, timeout)) { + return false; + } + + if (resp == NULL) { + auto now = timer_read(); + while (!resp_buf.enqueue(now)) { + resp_buf_read_one(false); + } + auto later = timer_read(); + if (TIMER_DIFF_16(later, now) > 0) { + dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now)); + } + return true; + } + + return read_response(resp, resplen, verbose); +} + +bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) { + auto cmdbuf = (char *)alloca(strlen_P(cmd) + 1); + strcpy_P(cmdbuf, cmd); + return at_command(cmdbuf, resp, resplen, verbose); +} + +bool adafruit_ble_is_connected(void) { + return state.is_connected; +} + +bool adafruit_ble_enable_keyboard(void) { + char resbuf[128]; + + if (!state.initialized && !ble_init()) { + return false; + } + + state.configured = false; + + // Disable command echo + static const char kEcho[] PROGMEM = "ATE=0"; + // Make the advertised name match the keyboard + static const char kGapDevName[] PROGMEM = + "AT+GAPDEVNAME=" STR(PRODUCT) " " STR(DESCRIPTION); + // Turn on keyboard support + static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1"; + + // Adjust intervals to improve latency. This causes the "central" + // system (computer/tablet) to poll us every 10-30 ms. We can't + // set a smaller value than 10ms, and 30ms seems to be the natural + // processing time on my macbook. Keeping it constrained to that + // feels reasonable to type to. + static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,"; + + // Reset the device so that it picks up the above changes + static const char kATZ[] PROGMEM = "ATZ"; + + // Turn down the power level a bit + static const char kPower[] PROGMEM = "AT+BLEPOWERLEVEL=-12"; + static PGM_P const configure_commands[] PROGMEM = { + kEcho, + kGapIntervals, + kGapDevName, + kHidEnOn, + kPower, + kATZ, + }; + + uint8_t i; + for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); + ++i) { + PGM_P cmd; + memcpy_P(&cmd, configure_commands + i, sizeof(cmd)); + + if (!at_command_P(cmd, resbuf, sizeof(resbuf))) { + dprintf("failed BLE command: %S: %s\n", cmd, resbuf); + goto fail; + } + } + + state.configured = true; + + // Check connection status in a little while; allow the ATZ time + // to kick in. + state.last_connection_update = timer_read(); +fail: + return state.configured; +} + +static void set_connected(bool connected) { + if (connected != state.is_connected) { + if (connected) { + print("****** BLE CONNECT!!!!\n"); + } else { + print("****** BLE DISCONNECT!!!!\n"); + } + state.is_connected = connected; + + // TODO: if modifiers are down on the USB interface and + // we cut over to BLE or vice versa, they will remain stuck. + // This feels like a good point to do something like clearing + // the keyboard and/or generating a fake all keys up message. + // However, I've noticed that it takes a couple of seconds + // for macOS to to start recognizing key presses after BLE + // is in the connected state, so I worry that doing that + // here may not be good enough. + } +} + +void adafruit_ble_task(void) { + char resbuf[48]; + + if (!state.configured && !adafruit_ble_enable_keyboard()) { + return; + } + resp_buf_read_one(true); + send_buf_send_one(SdepShortTimeout); + + if (resp_buf.empty() && (state.event_flags & UsingEvents) && + digitalRead(AdafruitBleIRQPin)) { + // Must be an event update + if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) { + uint32_t mask = strtoul(resbuf, NULL, 16); + + if (mask & BleSystemConnected) { + set_connected(true); + } else if (mask & BleSystemDisconnected) { + set_connected(false); + } + } + } + + if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) { + bool shouldPoll = true; + if (!(state.event_flags & ProbedEvents)) { + // Request notifications about connection status changes. + // This only works in SPIFRIEND firmware > 0.6.7, which is why + // we check for this conditionally here. + // Note that at the time of writing, HID reports only work correctly + // with Apple products on firmware version 0.6.7! + // https://forums.adafruit.com/viewtopic.php?f=8&t=104052 + if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) { + at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf)); + state.event_flags |= UsingEvents; + } + state.event_flags |= ProbedEvents; + + // leave shouldPoll == true so that we check at least once + // before relying solely on events + } else { + shouldPoll = false; + } + + static const char kGetConn[] PROGMEM = "AT+GAPGETCONN"; + state.last_connection_update = timer_read(); + + if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) { + set_connected(atoi(resbuf)); + } + } + +#ifdef SAMPLE_BATTERY + // I don't know if this really does anything useful yet; the reported + // voltage level always seems to be around 3200mV. We may want to just rip + // this code out. + if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && + resp_buf.empty()) { + state.last_battery_update = timer_read(); + + if (at_command_P(PSTR("AT+HWVBAT"), resbuf, sizeof(resbuf))) { + state.vbat = atoi(resbuf); + } + } +#endif +} + +static bool process_queue_item(struct queue_item *item, uint16_t timeout) { + char cmdbuf[48]; + char fmtbuf[64]; + + // Arrange to re-check connection after keys have settled + state.last_connection_update = timer_read(); + +#if 1 + if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) { + dprintf("send latency %dms\n", + TIMER_DIFF_16(state.last_connection_update, item->added)); + } +#endif + + switch (item->queue_type) { + case QTKeyReport: + strcpy_P(fmtbuf, + PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x")); + snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->key.modifier, + item->key.keys[0], item->key.keys[1], item->key.keys[2], + item->key.keys[3], item->key.keys[4], item->key.keys[5]); + return at_command(cmdbuf, NULL, 0, true, timeout); + + case QTConsumer: + strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x")); + snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer); + return at_command(cmdbuf, NULL, 0, true, timeout); + +#ifdef MOUSE_ENABLE + case QTMouseMove: + strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d")); + snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, + item->mousemove.y, item->mousemove.scroll, item->mousemove.pan); + return at_command(cmdbuf, NULL, 0, true, timeout); +#endif + default: + return true; + } +} + +bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, + uint8_t nkeys) { + struct queue_item item; + bool didWait = false; + + item.queue_type = QTKeyReport; + item.key.modifier = hid_modifier_mask; + item.added = timer_read(); + + while (nkeys >= 0) { + item.key.keys[0] = keys[0]; + item.key.keys[1] = nkeys >= 1 ? keys[1] : 0; + item.key.keys[2] = nkeys >= 2 ? keys[2] : 0; + item.key.keys[3] = nkeys >= 3 ? keys[3] : 0; + item.key.keys[4] = nkeys >= 4 ? keys[4] : 0; + item.key.keys[5] = nkeys >= 5 ? keys[5] : 0; + + if (!send_buf.enqueue(item)) { + if (!didWait) { + dprint("wait for buf space\n"); + didWait = true; + } + send_buf_send_one(); + continue; + } + + if (nkeys <= 6) { + return true; + } + + nkeys -= 6; + keys += 6; + } + + return true; +} + +bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration) { + struct queue_item item; + + item.queue_type = QTConsumer; + item.consumer = keycode; + + while (!send_buf.enqueue(item)) { + send_buf_send_one(); + } + return true; +} + +#ifdef MOUSE_ENABLE +bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, + int8_t pan) { + struct queue_item item; + + item.queue_type = QTMouseMove; + item.mousemove.x = x; + item.mousemove.y = y; + item.mousemove.scroll = scroll; + item.mousemove.pan = pan; + + while (!send_buf.enqueue(item)) { + send_buf_send_one(); + } + return true; +} +#endif + +uint32_t adafruit_ble_read_battery_voltage(void) { + return state.vbat; +} + +bool adafruit_ble_set_mode_leds(bool on) { + if (!state.configured) { + return false; + } + + // The "mode" led is the red blinky one + at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0); + + // Pin 19 is the blue "connected" LED; turn that off too. + // When turning LEDs back on, don't turn that LED on if we're + // not connected, as that would be confusing. + at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") + : PSTR("AT+HWGPIO=19,0"), + NULL, 0); + return true; +} + +// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel +bool adafruit_ble_set_power_level(int8_t level) { + char cmd[46]; + if (!state.configured) { + return false; + } + snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level); + return at_command(cmd, NULL, 0, false); +} diff --git a/tmk_core/protocol/lufa/adafruit_ble.h b/tmk_core/protocol/lufa/adafruit_ble.h new file mode 100644 index 0000000000..351fd55ae9 --- /dev/null +++ b/tmk_core/protocol/lufa/adafruit_ble.h @@ -0,0 +1,60 @@ +/* Bluetooth Low Energy Protocol for QMK. + * Author: Wez Furlong, 2016 + * Supports the Adafruit BLE board built around the nRF51822 chip. + */ +#pragma once +#ifdef ADAFRUIT_BLE_ENABLE +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Instruct the module to enable HID keyboard support and reset */ +extern bool adafruit_ble_enable_keyboard(void); + +/* Query to see if the BLE module is connected */ +extern bool adafruit_ble_query_is_connected(void); + +/* Returns true if we believe that the BLE module is connected. + * This uses our cached understanding that is maintained by + * calling ble_task() periodically. */ +extern bool adafruit_ble_is_connected(void); + +/* Call this periodically to process BLE-originated things */ +extern void adafruit_ble_task(void); + +/* Generates keypress events for a set of keys. + * The hid modifier mask specifies the state of the modifier keys for + * this set of keys. + * Also sends a key release indicator, so that the keys do not remain + * held down. */ +extern bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, + uint8_t nkeys); + +/* Send a consumer keycode, holding it down for the specified duration + * (milliseconds) */ +extern bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration); + +#ifdef MOUSE_ENABLE +/* Send a mouse/wheel movement report. + * The parameters are signed and indicate positive of negative direction + * change. */ +extern bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, + int8_t pan); +#endif + +/* Compute battery voltage by reading an analog pin. + * Returns the integer number of millivolts */ +extern uint32_t adafruit_ble_read_battery_voltage(void); + +extern bool adafruit_ble_set_mode_leds(bool on); +extern bool adafruit_ble_set_power_level(int8_t level); + +#ifdef __cplusplus +} +#endif + +#endif // ADAFRUIT_BLE_ENABLE diff --git a/tmk_core/protocol/lufa/ringbuffer.hpp b/tmk_core/protocol/lufa/ringbuffer.hpp new file mode 100644 index 0000000000..70a3c4881d --- /dev/null +++ b/tmk_core/protocol/lufa/ringbuffer.hpp @@ -0,0 +1,66 @@ +#pragma once +// A simple ringbuffer holding Size elements of type T +template +class RingBuffer { + protected: + T buf_[Size]; + uint8_t head_{0}, tail_{0}; + public: + inline uint8_t nextPosition(uint8_t position) { + return (position + 1) % Size; + } + + inline uint8_t prevPosition(uint8_t position) { + if (position == 0) { + return Size - 1; + } + return position - 1; + } + + inline bool enqueue(const T &item) { + static_assert(Size > 1, "RingBuffer size must be > 1"); + uint8_t next = nextPosition(head_); + if (next == tail_) { + // Full + return false; + } + + buf_[head_] = item; + head_ = next; + return true; + } + + inline bool get(T &dest, bool commit = true) { + auto tail = tail_; + if (tail == head_) { + // No more data + return false; + } + + dest = buf_[tail]; + tail = nextPosition(tail); + + if (commit) { + tail_ = tail; + } + return true; + } + + inline bool empty() const { return head_ == tail_; } + + inline uint8_t size() const { + int diff = head_ - tail_; + if (diff >= 0) { + return diff; + } + return Size + diff; + } + + inline T& front() { + return buf_[tail_]; + } + + inline bool peek(T &item) { + return get(item, false); + } +}; From e26a80508f2247d27e431a7415df1ff3405f598a Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 28 Nov 2016 11:20:00 +0100 Subject: [PATCH 33/62] Reorganize the numeric keypad layer more like a traditional numeric keypad. --- keyboards/ergodox/keymaps/bepo/bepo.png | Bin 80838 -> 80249 bytes keyboards/ergodox/keymaps/bepo/keymap.c | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/keyboards/ergodox/keymaps/bepo/bepo.png b/keyboards/ergodox/keymaps/bepo/bepo.png index bde2e2cfacb326e7934c5743aea2f303c8a42527..54992f5ae54c6c38b29221a78c45224af611573f 100644 GIT binary patch literal 80249 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

-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ℑ1Hf=epn57pS$h+hEY=X%Z>>Az^#= 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 z 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%0AWcsmXzWE5KlyO(@CyZ4w=^{y>Z zy3fwd?Upo7Q_#}t`hMtU_?d|Qb{p;7hf4a&;kVUa3Cs*gp zOk?)Y&`{Y^#eRN%Ywq2b>t(He&G_TR&2w(oAAOHsy)yl^%bu1WJ|+4=Ro7m3fHr)U z90N^irKUCsoIG>JrKYB)oqe`I>D_FdEz7kvG&qWO?zx&$^zxFbin=;?m-lqN$i3lP zqj=-v<8y9r>n)x5>D#wsox56H| zi-2ppKuaT>+xa4|E)CI|IAOwp-Shg6yuPr|`NM|~6V_~0xLUC`ax+_FW8)sv+!$dA ziH_9M(>NDpZa-@AWH)$Mgwu&Y&`{dPj}J}UJ-332zXW4GUo~OS?v%OK z_>i!6^;YG&mN(~Sf)AOAEPZ|@%Tz{2MkQOv!!*u3@6G|xuw~+5wtG_M>o~Z$nx;<| zH<9X9m{k_t;|$p*cA&g(SIti&5iZs~S?gn&eUq|$L5K6C$vk`Z?9j!Ff?Kz4owi=G z*9}yvU%mRqe%A%L7%A>=V(YhXXwEN+^cc2X^r{A5dF@L*FsvWWj z+VPa-sd-slH>w%7X^Y*td)Ki3U(J$b%WnDTPe0bQ_o(+7k4RWgWcDke>fpruV@)?6 zU!7vVB}%ucx%uJy_x+%8rLL2c)sv6+$(CK-BFv&#w`AVp70Wo-^{QrrrfohxI{M=N ze)~Ij?rcaoDfHyYlY*-GcN0OOmgIH{5hMOVNLng~fav!=98hW+jT=C`j>0xUk z4*rhsw)%X1siJdR!iNV3wxFoqRIeavl_f zd-A6zCw1%I?I?T<+REhj&hTT7u3E+OggN16=l;Z9*4@?OmHw?yz&PmI(Pd&B*CIZA z_^@FY^Qs6=ZtiBMg%j53ZS(Y3o2+PUz5C|%x*reOS9`{Bc%Hx43)*W3>Sr6xTqF7Y zc!0*PX}ZzZUh&=2)YSCw@ez^n^z>Z&?vS*EM2BhiHIHp8A3&0Q(AmImF~MrSvr<<6 z?Ca}0Th+K{kIlKd|KXQQ*8E#^UM()CL{wDt;YD}(qvrQ(Kuc#Nc-W2{Idb6Y)v1$3 zxqVgUt#$n(U%uN{{IEemdHMDuE7Q-<1I-+QmVY-jG0i@=a7*`BgPB(AKwGxKWhuwC zh#UKAt>;z0v%FV7Ge&Xx>5a9&%fK^tyN(^2svTZ&{ZQET21aH9QPHc9Ot*s97=HOu za%V@Oa{y>T;l_;{!|uLau|ng^+uPxre61nn%mh#uljt~oht5{@Uj_pok_%H64_t9$gc{{Eh&-qUY= zxo6L(|;^pn8&>on0qt3rE!2uuHp6LG==^C$%-ZiR zJOMcyW67+=E0&ogtrq3Jx&6xwOU3QCLE8qSCAhce-#_-{<>ig}_w8oi`LG@wr;zXeDLT|*Dt$T zI&5D(+Px1ntsQhWaLH=HXi09K!wSErG4k@J=oF;te0g=1+t1JM#ogWJGP1IUrLRI} zoPATjf9}I;yw1x@OrP?vv=#P@4Uguy6=6~Igk#R!xuCJU2@?dsOCI-De@{9$$8y5S z6pN}aDM-z$BZo)uSe^Af1E`*ET4e^=|7Gd?Gt z7XA5h`G5NRJC7Hwy7vEm{2rT!PbCsgF6~RGJn-oD1hGUlIsMF;ld7~feF$5jnHe=r z<>|#{$t=~_kV!p{MSVUVo4B*VxWU*!L8B`oZbEm@9k+?64UB(({q^VHhvPEtX$j2L zH>%f1*6;a$!`R~8d7JZ9^U`fMe~a4B88ki4|Jj_5l-O9s8^@Z0R)TgAPn9XQc z7cVcanAq5bAzGbRkD9%xtgc?XV8MY`Tl4q*WGjAlMlj_<@i!G$Y3`8e%B3IYrfZ0B znNN^f+_L2LkN4#p(x<w^?2DR>Xo`GAp~^+c+-_*wJ`J;;L+{r>AGd&!^KL zK6};%nn?Zqe*g0n&RzQsw*1&(RU=a=EPrmTQ%#I)Uf9;JnSKjg?fmOnoy3u?U|Zs$L)+;7vgV1Yv1^o)xtS4)!@{;k~m+tbriaI2o;qn=$q z&KZkvwMu*R2IiFJ-rXhI*w`4b`f5gAo?Bd;oLi4XrbCO%d74;=Rs`u=G%ziIqC*FiUG7*?ep{V(Y5a$9&Q&D6T9~M_hoa5jj7JMi^M__ zFYcatW79%0bM4<{N1G-r*mdH%>#I2)Z+6{y!gSG8ti`Uw!`7@XB$mgyd8hHKQ>RXW z)@HqrnsYa<=D8$S>mlAH$281#`OURr?R0tc;rEkbupuk-_9>S7U74z9wzI)Z?1jRj zT`Tlfc{5ln*4y`)r`72pTTrrybgXsxyCd1__deV3+jypgNLKWR&)Z9H?Agbb{&`lS zLCN0oX5(iftGp`$VxPQ7n#`S%+-N0z)wMJ*mT7_du1l9MCmPMH*#CXrt4G%712jbP z6inSVp442qa;1c6R!IB#+^noa2bl8zZcz@TWZqI6b=C#V3 z1FOMLiY)W)?mGH=@9o8_R&jB)E(-VTa$3kCACxRIdrnYbV57TSCCk#KOT*^Rg=|JB zEHYv_Y+zCL!tC4oW&KV8u_4n13fw>`e}yzRx0ud>MXudC*Lit)L7SQV?f<4!`mPOI zT>t-HMox}MOW>}@Icb|E|NZ;-;p0cg=;-UxUprie#)7sjqp{pw@^8Eb#_7E-Cyu7^ilSEpb1nrg_)7WPDv|E3lLqLGQr%#^}3?x9~ za-A+szO&6bwU%3W^D4Nk(7U}W@7|uyy1&07&%Tv-cF${}X7I9-pa1>&_cne!AA8vT z-Q%wpj86YfGj4V*)++qF>fo#Usb24s&VAw9W44Xw^!@dRwra1P^GZu!-+h1G-wi1z zC-HsXlXKJP%j@g>*Vn}gPuY9p2~(iCSlRn~y`WRDifX^S2n20?-JEuI)1Gg4%kP8s zpEMbIl{Ynqtp*k1pfhtcM7S=pvoCZiwVc1sv6)S&WYVr!8y?cC|2w_qOi; z^Hjg$&Bo&ak&&5|d#!t0?e!#c_Jyy=b-c4bOF(O9+SP~^J5!IWPCixeFNfPljjdW( z+Mqm4^-S8klBv_DgJMX+EN4dO90RFd(6CMeBXdUbLj6fs{<`g~`l|Ko>+AHNPYZv3 zdivv0x4uEj2>}V7?=mVjHZq{|0eb>>3Cr01d?M`P?w)*hmTAPEij6Otn*$c^n&W?c zWAgC{)2AQbJ?-8rA>%C@9TrYtUTJvhX7N&ig}df>Uq3tB98{W3)ecv(vAOffO1!sq zZzu1KO$)^)$M49y8WEuNF6roRbKUD~&61Cs*FD^J@5sz`pFS1s*ts+D*O!-J_HyZ| zsSmG)$Aju=h?AR}Uz}8*f298Z?|1{A<^u;DM8w6DudE0>aq1N4@CCaXi%XX;vnGpd z+vTGsTvJ4^O5TcC5OAXLip0}5JA*npLc`aTFh6_SyWvCbGclzS%Uf}8ds}aB&p&+q zx_D-0W`abX6!+Ubh9BEPlNY{R$N7tG@zY%j+a(`fK4lrd5p+K6-QDHMFE1^fc0GJu z3}}t^t%w(^RlYt@h}w|A2pa4E^r;B6o6unP*&lB3ZqgTc$BPi&*Rb{Zv17>fiS}Gj5bl%+l9G z_Ck(j>#HIedHKk`SGTWbhF2$zeP-# zx8Yv-`-8`vtkaB{r#{j35!SHVw3{wKAG@=&_@Dt#ijm~89!c=_sxvbTn~b=kV^2@hJ-ooN`N7MVoc{j) zJQ4;B++sQcr3C_7A>vn6Su&CvofdY81|?6~{8VJsX+wz~HXW-UjAwfO3OgNHv0DF4 zX+3DKbMmt@GdueF%3gG_wk0meH&9HQ%J;rC^ue8*V&_0klxRD+CG+xxnKL{0?6CnY zCFMDM;h0mr>PmL@i&s~NKYaJD&$9Sg!uNM~6J}JWv+v%yQ_;vsXny^_oeO#nxlKQq z&;U94QD^;J>vBFhIk}9yJh5DuBdsn!efO?!%9JU3+=&|}Oq<50udja(UJIqOf;>y0Z=3u}5KaRGAy{zY6o>Qp$bW+_g;Q+(x z)CZs~J#0J@4U^UVxlU>1l+3j%Z)jCv*&bDgbrvIl#$V-@34l4YnI=_UB9N;Xa94V^GN#6o?7ADWo9xq)eP}Vk9Nd` z$KQB;5Y(`~v8z;@jbHA~hGR}{zhd|NFH?<*J`-k<)X&_X0 z;=!DEJd0Sl#U8v|K7U))+uQm3kAl``w6(E0O1Ac{YvmSywE4W<>km7%!`2*_V_EEi zV4i7VGVe>%Vg+hJ}UY!1e3mpP!#U{^{vySI_|~4`09TUa&wxL{#+Sykrd#uI&>f z7JHo43<Vh>c4JB)~sIsEvvs9v{>N!`r}VdPX2hw zTfehQGk96TEmo{Mp{KCgsIilP26Z z$GXSjsQIGnM-6!LOz$01`*}TL(jE?JzrWm}zqFJ}N?VOzB~4}qH9Teqzwq+(bSx?| zD%|C<<@(3R$3dr;E!?w5MpsuCw16NkZr+R1ugBu5_R6`sx=xE{7T1qE^Lu@@?N8GS z_wUQs)zy_8WomU&P&uX%R17*(@2p$R*ZcY(|NZM*zOXa&`blo}4SxzmrpZQiz4xzg z|Fx{@;%g)0G#B~*GM3?+FQ(-je(&18Ay7)YDmDkyy7jl%Xcja(u|6Z{vG07o{^c^7@{RQcdtYnXozxS>FcmXetZ$EeSsN&HAkDIiyJW6{4k!d2N|&6h{JyMm!m?#*875LILbNX4%sx3u z6*RO0noioV!JwtJRngWq_DkJ~wsR$}Zf>{k7RIi=s-&&$UGU_|6NlATZ|!;h;X{Fo ztLw*ku-=BpSxu*Fp%(-CUI=Fg)b5_O`54pMn=;Lx&R_mvR?J;@?jPs;CF_oCpBcSy z_hRKk{JRfHg4*<3Hag7h&4}&G(s}ayx%1K>N43eI6DXRTw5B?(47s%@f8lNK_1722 z@2?AUUpwhR`(D}jxVShEZ|~P1=D96yjL~y1EHw1;_GUf$^Ye4X$tM?F%&@vs9u*~Z z=kDD~x<57ep$r7Y=-yX10oR$R^Ulj2TtJMrz;gJ%8@9}e>?o0y1PUgql@5+Wj4_hQAz zr2!fNv9V`=@4fB3{Ia9o^zt3~y>86n;^OeK6jTZ9D_t6E)A|32YGa~=pETIOpqOdN zpKE6aNcFItxo`JxN@>m4F!9+j4$|CLZgyOoI(KgG#^mEs>-uFZous*$ zwuv7$0Ie(pHL@1{xe)kR+tyZAZF1-L>h0|(Q=F=*st`@j^wXL(uWwEKYb+-FhoPIV zuHgjp`{aA~I6!sLza6DJ!*?C&nea9=Br>IR*U`PnCeIh1yr7bW?t;>HcP#&WU0?4S z87Vny)+~e4S0T3|3O4NJleM~{8TS%ikbcUF&4O!Brx+!koTMsYl)?d8zb9i+!0`Fm+1Fe343$%=x88p9di{RztUPEB z@vkp0Gcqy+w#rYk+SlXuyE<{h#iQl(76xeCQ2=G4H>GT#a*eP0Z{TP4Yx6peZE}`R z+WbiRipjlARq=1?JYM~H)d{oNGGuy;o_lSr?fdU}{kLvKok%g-y(=ar=FPh++HSk5 z@h_1hjTUt4N0Q{u{1iRvZL&Yok3Vb_%#uRUUu)-z_DRny5h>oyHx zG^i&r#Y^?n>C=JH(b^iI(br#JGUr$pA6vI>!UTbwdwXVne{x9l_V#>t4-bxwV4J3| zoAh~Yh3yue*J1aYE@m8?#=F&E_U`pC`!c}xWkBtd$vEpa56M19N5(5zrl2{XRwqRb z&=J^StKZ)H?#yr7vSf+Mk6*u>76yEnmr&&$7A9t6V>4mS9G^9N=j7IW-MTKmZpHCs z`q>7mPpq6&uW!ivx>vP-(-t=o@ogp1;*h9q4oDJNxpDjYlFq$s3ruGhEHIU>1oc;M zMJzb?EFd;%S*^g@*xh3H?%e|&4e(URdTCJSjvW>i)z!&=e|??Xr*HVU=keUAsVgJ~%l!O+5eB7Znu+gohvhJwqt^PDk9r!+&my%1UwXv^;wu#r)s{*_J^Srq^~~f(Cq?;% zM>X7!-(xTC5?E*|z4m5Hk3hDxd%yn1*Wf<-!OppBZGTi%Rwn-Y^Yg@s69-;gT>SCJ z5?*ze-53oo>mPl#f^Fw0k_By{scDRa;&3cUrrtm>uPHm9F|1R86; zx;nh@`8nA?pXdK?S-o2ON|q@P8?)X2KgB*Xjas*^+pxg^v|nrwyY{+>ty!Xn4j&d2 z5^DPK;|JgS=g*%zuMAPLwUu4&H&;l+XeQ5c|M_lpb#?8(?`_MKc5-s+*gAdh$E6oD z6sDgJjELyCbSY>}>~1k}{W#D<;P-Rv>*a!0itOCEv#DR2e^LI6U*gu_K9u_k!&8B# zx0@|pJvN-wTyl+JOPVly?A4ql$3XMOpn;Hso^#)xn`^yd%^H@&1{ryI#}>JE3y6uO zRqo%oQLx|U6UUh}W9?Y4r9#c@{BB7}O79t0Z+~-pJ3okSPLp|YHnP?bY8^18cP)+PSC>Y>G5@vadB}IJXFH2T))1#Y}=G6B0F~O zRJ5^?0Ug}o<0Aqpe2!bc-vg@A-rV26KiGcC$&`$&O?xBf3S{KwwuWde{iejAc$9bD zV?{_Q04m_G%vp5ZI-J)b+w9-VzP%p3(n;5kf|7jGWUJ_$9G$q@uc4>U{U|IfjM$Pf z@#)`f+ss5nMN4nr?CR>;kakvzg`GY5$%%=JlD@pS2y$&#S69b(=k(3fX9xz}DVQQ3 zq#;u1oYkXbx_ry+vyoX08-FWqo&G`KaLoC@x*L*PHa=K#?%PrE_=J0VDh+1(SX6)0 zX=-YE@b+!*=JfN6cJ7okG&G!HQ(3fqj_>lzpf1z8b?d-84`pO@wEq14`|#1Drj8Dd z7bR8)eOu05ZB*-qOZfA#T$2R`3~jGelqV~)d8cTlp(N=w)E*j9No9ovO+DrhtAtWkF>V4eb{S$@4%Uv zpxX;rgk_{&^+xOtYL|SRAF=n}x!0m)|9#UB9=!QRHEoWqXP}12Lr6GTMDr??*_W7A zU)(v*0MrCql&zDJmIgZcbWi=yZyK7Kj%jIW+vobe*_D)(q%hIr4cp{Bdu&!*&2pSL zeR}%mI8!NJ&_;*E!)#%mTI%ZTpd_1_x$^1O+2;A+41032diCGC_gCc|ezo-Kj>wzW z7EToS)-U~|uvpgY*p-B2A6}vQybXJfF>i)pXc|UuGi|fTzHAR)$F}T?9`P)#b?JT>^jyIwz}16 zVMEZ$7PrNMB3e_qigw<4m$zrGwwl+0YKfjo@HR|5( zLjI)pXA;cLsg=ck>-!;CRDLeS=;5WM-e$XtrFz-)^z_zD4oOZ{{`2?m$JgukKLQ;w z^!4jjtH8zPXJ+2}SlFK2{_a6UkAjVEk<+}Y@d z$3zVc4LP{DoFXG7vAF&ifBu~vjQsrld{(|{!k~FCZgD-1bNqA9#<8+KnkPJQRkyF6 zKx(q%nhAgQ%(IPs`SPW~OrJgM7S$!CNBqmXmYzA|!y{`Ya=4w}Jt|5n{risxkNNli zi|G%K*K+nO)IN2Z$2Lo6LY6+EZtLlHCzpu5g|-1yj%%c!(o9;uX6aVs(xFv$a>eAG-DMZPPaaplbH+ZH*7R`+4_1~u;MeH z^#=~B>^-|*^jF{3_HQpgUcP3vJ7vzU+qu5#MqOIG-IZ85B(YI^9-z}eETfOb+FUV0i6IyTFhzNWoq;+nGrPfNMrq2>K z+i1|4d7PatO@WKu6z%NhZT?-oVWWW7&SS6gTjwotQoU|a{D^mjNVzpA*Ot{JT*=g_ zQx!EdI1CL9_w;w)TW~Q0G~TCZU~nO^S|=ntT-nM>il_K}lX+Eyr;iV4 z;Be!v8!UVM?S8T>cI$1rn6ZV+$~gVpo3ET)Zi^+?@2QZTd1?2Km`hztKd+iF<-*3D z3#QyZ8b1HkhxO<47Op*e#?!!jrVr@cBfEb;l22!Ahp%(V$jD${8{-g^ywEsKI=XFD zSKn^q@@3jaMwj04-HTc)78x1Yq^z!f{GHyOhYufibafSV>|GbTyG=8A*?|X z%-OSPpeWo?u@7{P#=2`A*N;t$3{!g{?en87S=UcyU-PL?W+yI5S#m!Eovqf!FW(0` ztSnR3uEqkiMd@6#$;sZ<-}mSLIaGRPZYXDM^Vd4jxi3F``s5T971jRTM2h!Gk!4qR zcVJYMmIi41#7v*G&AaDLo5ogNUfymd<~PTpvF`7$gJ;k3`rCe;B3f8j$fv6XE&8jZ z7spjT6@7DW@9mm;UsKSe9cY=r&SG|P{kS8bldwUT1F$tOJpYPy+qb0Er*q66Z@*vX zTu@+OV`F1b^(6yz{sE|Y=;YL-QQEn2qXW|HsMTD);%8?L-q@I&%T~HkVftyq!bdJ= zW|?+p#O5^re0aG1;menuyLMSg^t#!6zf=6!t{2XTnU=Vq#(h1O*xA`nhje_pYQf{mhI;QSGpV=jY~v z#tm=XveGMmNd9BY5=ac`$NsJL4b7uDM@7Uo#>=-#WAM~lQ_c3<+E9AaLwGDPdj z)vK0I{@pMU^HF2d7QcIB+4`)irQR>xjb{3&Em^+&`%3w1SFSv`oxgu;jJTNCx1I8z z=7NSb&A*trO`Sgd@ZrPEy1Ke6R;@ae+;7`9ZJL;hnp#wto&ituv}s~HcJ4fwVzh9_ z4vBg5=1sft@4;5(;-$ta;xpIk>a*wXZ*Aqiyxjk}tMuBNIj@D1lO5Nq7yG$v zTDMN1B-wHO{_WE5PfgV}tooACBV!p90&2<~=C|MS=8*TMb?;a{Ylp7`EuV63=W{J9 zGkflMCS}+0jn3s8Dr3>3#bO-{k!FC2OO%^LbCx+4%D&S1Z$bo6kL<%3z%oH^2QKgP7P@-9JzD>jgpn zP|x>s*|qMRKuL1q{e86s#l_AQ6&Bm_@An-!;u0t*FW-N2bNb<{S4Dq+f3F@DUf%q3 zRp@Gq_hr|wOMZN+Zsk++&uUpq%<)g(S8sUyyGo~OyUhM-CJ9UXz73>&sCrt{_H<<4r88xtjR?(e&sRh+)~ zV#lOOLNm^$iHM6kD@}~JSN&nuv3vKx=eb5i%s6}g-`nl?KfGGKzAI>YK;bn}Zk2PL z9@nmlHs$JQO!WdyYHDg~n#l(FELpMywDH4h>7u9J`Ee1niel4r zUi??^>t8LusQwwp#*~muh;K)%gE4>SeC5(@Zjq? zb7aE$KUpTfNnQN<(b4V?A3hxDl{VK|FKbgFpsK3+<0~Kc-uRbm%fpt}H(Nw2=0#HUjIS-C@1ygbEDOJs z?yf(bn!Iq|KDocYzB+>zTyLE;NeDE7_v3v1Kjo}yPC-zueWJZvBGqj6N6>8;KR-PU zTQ6^0CDPc~Sn=heyJ6+06wtgK&*jqO#<$N7#~itLdAYx`h6aao8_&TRhRFrr-b6Yc zkK4A(?)MvGP)T{>s58v1Sw~mU6a#`)&VUe8Nc*Rl>+;lo#tjj3KCp`i=6Z3_zs2?=pn8l8C|IcJBs<0@GoG8{e~;HLxZS%oBhTpepWVmYCO?(%nzh90`qLA^igHi>J#$QdUwAiSN6}NRKY#vwIIX|G z<6fLoi8i$t*V7?8+@$x6h9~-t}GFvwveiTwLG&|9{{A_;_4?<=%=5(BVqZl=|Y;n>K;2 zYM2(REQ2qt=Sq|NmoLxXWYf^cy7;t<*uAT0s2>)`k2^c745z zcU7_TK0CK`_1=vEQBhq7z*n@jmHVE{(uWSp1SN-*m(Dz!rW3h|gb(dK9v+v72nn}dsiU_yFFKcpVoL4TtKk)(dn~@cyK8sVp_uEcYRC$`qLPg# zSzS!T_++hGzTd0nm#_UIxbNpPX^CF9gHo+)*X`P6_2>8f|Des>4bj{43hVm6mbzWJ zdgu2%uC2N^1Zugt@2@(rsWQ~#&rU|(ud@4{(`8&jrhj;_YU78;{q~14Op@;GDD3F$ z6x^$)_v7<<`@*lULJfGD*R0V2#TDOGXh1$VW4Uzht5;c|je;xIu6-IiIiLtMn-~aL z!qSnU!@+B4ar+_jc0s$fGPAE=zhU$3{nradbF6PGS%K!dUOn==-aOlUn?3*R*|W8? zVq-vU-6xa%ADx=2{p0WV`+~BvZv$Y1l(xNrM~@zzVUWmVmVd7&a&sE!$hem;UnWSf z-Mo2o+G5q)kAr`M?s9N)cK!$&r#RHY30fvdSD@uO;1FGuuTxP~_2^-{eB0{Pt3^R;JeHuWSlKw|Q}_Vd5XoDBC{xNC);`^!zH*QKpWR=g-R z5=1C3)gvP1jL?OdO8er;Hi>{iOBrAUn?_83me@Q zA6yZ*I3PIKS(;mftJQRGrjE_WBf`^OcZ=&gDNSrh+?A)pBW-pjsNwjLBMEPBZJoAX z)+{HYJ^8zgY_+KrFB20}#c4&SGnygdSC57!Hy+t}@7mgEK?w(to~1o``ZV!K zhahOB?GngG)`b0LXmafc7YB|EMS zi#8QwVrJHTU;FdvbkKp3I@kB@+gE!pLO=?-4&mUob-Q+1fw}(1eJeq|jU zp9zq@slbBGhG+IF+oP^5$;i!p8!Y?q@+rfQKVQ#zC8U&e{p-#2`Jgo{veW!JW5ri~ zTeJ(b#6gkQ-Bj$Be0PEbn|q(k!d}){!7i({*XxL{?yv1qJ=y(XtB#l`uc*t5SKQST zEv{RazM2yHMwn~M#)QW^XDd3laa_~L0iD3y($dn9`0nji0SSqYEnBwOT~5d_eLPis zee$&@(jfa)Ud%E`WYUY-;V?%p=&ft%MbNOlP+x`)=+xu-zpvv1!@}B@EmQNEYqizA zw{^~(Iey=x3y$6JF8!+e)%R<}9GTA3+w~5om_0nw`nbbxBU{?DdV7w}!0`B+r?182 z-``ie=-Sre=YD&>-OAo`d$~0zaFnFDmy~XlXgjzm^)%=#fQqWBLzgduw&5RWV&%5j zfBn_$T!SrTcT`f&uVZWRT9=sY!@GP}3kT<}Lx&FO%#N721Ui52uy6uPcyFusbiKr* zU7`sysqIswI=6u~q8$JYa^>H%G4Q$G+j?_zy7T($&505`QYI@d|AzYDmUL8& z?(K}7dB$54|J~b}k&`R3b=|&A;+@5NmEHRiuB-@@wcEaOB_}(-+?&s#uW~>o?v{-T z4(Y}cJRd%Na`N=-e7d#x`MHCK4>O-Vdv?y<^xR&-d_T?Oua;iDaCcAnujY#xZlCJE z%=q!A)Tip9)w)eWkwCn=b^1;!q7KC|mgkK|ADEk9m-Pd%Z1TG?&-;K9bc%@QYy}Y^Kh(^e8kw)?;VhdaAU zyEVYo#3E23sp8Qa7&85X!0L6!uDShLaI5Wne|_8O?OxV<^uuCn6ZM0nxzjdF-mm>G z3t9pXx^VZy_wUD#^-6=r1U*126kkYlJGHQ}uUfs{vhWd$le6=}>#sX6xvtu~LJ!m& z^8hUdDCOige3fOqHSuo!{v-K2cVA4~WSc3nSTE@9)$6;yRN1=qN?m<8F>T>X@cfVC zgL7&s9v4C*B03fm?=b*jsY zQ@WQQoZccK(ZiFQO{n3qN~eF9cr1i3vcdX9_I z#Gk$GRamxhLd`dYXK#C79JqUJ_o8c|OV_(RY5X3zbp4^Z)2u&=;)jZ+S#Ec$an?%WDU0KUrcTbg}s zO=N(E$lhz9OQNQFvCi~q3tsN`@l^Huz3t!cRi7`?o$9qPL@W2+_8V_pSIGy(f~Or> zK=bU6`1Pc@omSnHYiXI~TdmALk^TPhuEX*R_pO|#VGmkq-~yXHo#Pf>RAl7j>|FT# z+}ya=LdHoO!O5ajA2y4yXxESC)5n@-2zKwi)suVThca`vf1TqL&?I}+BDiZ8doK-2 zys{!AX=Vm&EkNLk)vLi1^%XW8@sC8J|o%j$G4!EY09s?rak?Y_c|7|7Q$`v zL)+n1c9h>! zHvTTG;RkL(zXlzWz9w>W#dXIh&{Fe{?T={slI;h5h z&XO1Hl==EqR@gG$=0?PdwQE~_)Hbg^ee~$jcYb@5TozwEaP+9F$+xNr>)t%gdF=fL zwu)Uwbg|jV{cWH8mp=Vf@zLoLdg?b&0Kb8E}WaI4ly!AIgiGqVvFX7%dC<`gl4mNONv03BSZ zG1Y6z^y!PYZJSmOTIl)WMaGpYR~D>V#RWRBXr^)cn^#<%oClwson7g#7X#YS)6&w? zaV+lp;bU=5a`A6Zr~d!(nBRbhd1Xk~vuA0``=n!@b}w3_)Y97e@c+N}{~tVh#H6pU z@8asZaLt;Y?=fx*KlJ)7clPn&VPazXaKV{B@yCaU9UUDGfq{bQ|JxTQO?fj(b?uhDLRS91=mHD;}>r%e4BMv5EP6zo-jefpOuw0VD(jt+FvFjT&(XwHx>x1`?=KA*ccfbFC?^D zLPx6lF28g&XJyUVS*F~_`(&Hfuh$2SdTzg8C!MzW=E}!x;yaaWZDsTF@<5{zeX`bU zOM^P6Oc4QHwIwGf*U{hq+;)DTM$N|5(_)}apf)x#nwpvcT2n!1Hz+A9KYaD7Yq5KO z(Wn0wT5ebGu08tbiN_Yn+X44O`j={YUr5V2{Loeky?*lMRkPJkojPTZaDV|c zmhCHsv|lW1F1im45wr9(E^hXKz5lG>SZMt_szBM+I#DNg7>jBk?^_fhYco7KlSnSOqSF4XPi+Bd8M70 z_HJ!NhuuGitD5_hXU~!z9B3@7pLpv0`S!5YTVt|Kq)vZ&KVyc(ixR7QpJiGPiCWF& zn_u@!6J&s>C~L1<^2ge>VcmcJ)XaYDvNQ-Z)V_1)&b`0>%StZRk~;PA<3!Pj$`sa~ zG-Zi4N8iV~I@Vtl*IkcqznF4l<7fAe@4tMVw*UQ_jRilirJ8IrvnmAza>jS}sLh=6 zC@WWH*L*n0o{^F9Vym9vWxI}R>*Mny!^-P7s)@ae58Ix2m~FXF5Og}QUwhr-wi~5i z)!ac#aaM<|-SqQjWMt%o(@#O@WJ=g<_od60fv#`-@cHv*tvebb8;kziab;#^ip8Hl zcdpGx&DqV3ZAp;krcIl2`li2lk|X=i@?`H}TUUH{~(uT7t7YU=(N z*UZ=?5r5h&s&D7(RU1G2`^Rb#UU_b1vi?fbhB*IhvyBSNECs`n@_gFl!|nW!4>U5b zDc!kyx3k{#&vGkvIO$D~Haq+A+qZ4e6FNDkda>r`=c}lz3uo(BKlav}{`lJ3=so?~ z)ghswH}B@G+Pp)tEY|ic|H+dlCG2W;oIM}9`YPzu;ox9li8jaDTH8&VH!Ds*J#qHz z?4P^$R)0Tq|GvDVqho;9)IHB_xR&k)#q*yZA3uEky7gANioQO-q@-lP%8(W7*0CKn z$jHfQfo^m%TzoMDbY0=iXA6RoblUI%M^ z-Aui=r!ph&-~E~A=e`WmnhLu340N^#f5hI@`}=A^+@j**hmRg56>G-+F21X)tGnm+ zOUGHWW-Yjym1|eME@N+6*4DD)Z6{Mehd!nlNp9M_S+{kL+hWIx3X5Og-}mp>VX^B!lk0>R zC002%H?h8Z_l|>~fBTUifBw{*UNz^@qa+C)w%y4O?(8fs`>rZ!o+p!(lvGuczvP%k zQ0YYQYN#I@R^Du}P_GgQdRBG!B6z_JQ>oc*&_Iiaw|DZ}98FD4=qUZ8$B!q@n4zHs z8m%wCSIMrYr*~t2ef{z}jmalp1l=IzJ zUv*j-ut7^kT3TB7@sEGS+k%6G4KpvP{P_7(QB$+?yN$=fEtBWW;gOe@?~yh?ck2Ju ztgWe{Ota@)xpIZ2)hV&~(ac%1xXR1Rr%anx_WPelZ{U(wmtN0Z&9=Z)`hUssIHx(n zwj7$pd*8t}hs}=7%Ff=Hb8}OkWprSmAZRG$!Gi?w%t?=&t<>r1`rD)Ubk(ZAs#sWb z?>)lv@@Q^3sGd(rS#tLL=@TaoOw|tGW$IR9B|F7S)yUX*tyaVIDEH)mkC8}{@8DPvm3Pg5!|eK zJ*E79t+?CbiBmVfEU`LWmk zvvK;l7Qf}nW)>E+!QrSI?d0UNMlIs|;iG(Sb#-+u%HPQ>30ise+|Qz&G9bn6?d*>p zKdwCAEAr{)rc`dwO^|YOd0T~R%F4`^1Zj44cUS*iQxO_E^=|Al^SnD93l=QMyK4;2 zndibl%|wX}Tc-y+cX>O(?0WKQ&|;9-WYB5;)AeE>{XMotU%hpwKJm_u!VjN6zrMP$Mx@JjNswkuO^w1tj|sD8Wr;pc zF_J7QDzd2civg`*U;TJvjZ`n&zkmPk-b!yl6r7yx_ilK|-z}Y=4qAd!S66pqb9%pTEcjH+u5#JC7eV)6 zmD;yZ-F*65k- zO!)fh>I{?2NoUUotqjr7(<@tXzI5Avr~m){zWm2MMQ-usm!N}ozr4RM9~c-oZN{AW z^ZVDV(K(S~6tk~pr+an#hNVlEuy`%K^z6qhlT0Ddk|Qr}aN>a!>wJ4RhC4RyfNrIA zxfvm#tzy4E-9NmlYL|2OqI;LF3feCLC5xrk@85Q{RZw8qw{PDJ`+B=+`tf>N&(6>1 zkB^UMVP%c{tK_$8-8wbxckkYr&DT78`gF6?!WWaDi%LsN7rwh=dAjJ!w`vbx-=k+{ z8b5sg-2Hp}f|73C=xqm%A7_8~@L|}$xpU|8&h%+}^yrbDrQG=h1BZnHH)6KUnKq5h z+}!-yasNqDi#@Kmg1Zcf7lW%iB`1|`Jjo2&#c+1vE)U*kA=3>?A z{Wf#OjSY#+mo8tCw`8|h_kSV^^-=9>RytnB3>xq*mGw+Pa`}#W2%Zp1z zh?9wlY1i6`k77KQ27#`3SDKjc{@z|O`AZol6HY$`O_|l!*3SR+_3G;Ii4!L#7SC~Y zbuE4U!!syZBy*R?TE-Q64=)PGCbgx+<`gkNI&FGE&2m>&ePU~l>vEOL*j8=1{8%+q zOH}{g^?wyDK`XcXtY}%kUSCN`2~<66zq{|QsHb=C(doW>?u~2xSBGe=xGLK}|4N3* zhfkjlU0m#5`JYeoj$;bMO7q z^&DJWhpw%S&b<|-Hu>wXij((}jAjNzMRCpaXQ(PW zg0dM_c~^W%dCy_!yh+b&qw9v=)`kX#+13lXK$pz5w6qAU?!L0Xy_AzbJqt8V47v>w zRD68>+PZwX`kz04HWWYiyZ8R=#6KSn^KwX z!!t9Dr~UTv^*y>J^YVk|&)ZvCSnll)_PW10`?}tbA3qXqZOIJ#tue>4n9XP=Pit#y z?WTUFXe;YFBMXZeKWbgd-ri!hx3>okC11ZT{`h!*yNi}ZR7(%9hc;N%xvEQlNl&kZi#0qpMQS$M=tvi)> zfKHa2VNs}*c6OHQ7D%GBnX_=?g3B)-Jbs*Ps<~5s(){QBU0sLX+}xb|%C7d8iI=x` z<#)&G4R`AskDQcz8W*giq{IZe-F{c;Yn{5)SF;L#eaX}i;hHja>c@A>=LQA^HCDS3O9~9?M?)B zs^7iitFNzTVQ25|N}pdVrl+UZ(b2KN%R}XrlIe@U*h7aUrMOpzuRpfLbMh{pUsAnn zpsO1|jlLg0DlUreb9HqsC@yY}(c8Y#R9SiP<;SYGZ`}eNzIw0rN{Ufr-|{{6&U?zL zfByU_c$H_-o!jh7|Nc1f+gv7e_0u^u)6zTf?MCY<)2H9gdAIfVyB^6prymY6+#`gO&1_x!W6v_Ro^=~B==(*nkorVLkAZ9t3F&vtrTzbe_3rvq9S zpO*)^Ht+bix3|HK-A9if8&-eI*|BR^(*J*dU0y4hzTkA7zIwIx#9cB|mmKkNaba1s zXi-kqnNz2lV)Wb-6BUh&j3&&SnQ5BY+uaRnFs7ZEp|~slNWYvdSAKr}Y-`QcSF@fx zc~bI9e0%4x-_j>qjPV6xz~Hk%1N_j24 zv}w++zm;{ZPKlo@>&(r~18vXS*Ze4$UG4Sc`EzHr$qTn_+vdF=beL^fnc1n+rz^i- zE(2XOJ!j4wzFqe!pUWOOdi3MJy}?!fF)=dBd}m)fc1K?5Q*cO@aQuck{wNnVUzC9?f#~tgEw|;-#8mB)KkbZ`Q@Tmo9+CuwzeyzmO9fmpo z{~z@dD_My)$HGEG(B_7-v(1yQt%>B|-~bIgNwgi5&ff!?%yv|oxM0Bo2E-ylhgnPH zE*vet^Ga7yQL)TiaPr9%v+_y#nVAQ77C%=2b#*tu+so|_`a8ROdtD1Q{C%v-&1E%z zPH1T8!{zhqobvMY{{48&ucE5@@X^ukJ-=VgwJukf>XqwvF75oh-XA|IJeCIS`TOlQ zXx<6bxeyR=_*1wjDfRR;U67}o`E6Ok!^3^%+sU3hd9tIs`>^%9%*n|KzPIfEvwt7ID?C2dd$^5Px?;O$__t3VJ~&iV?6|sE_U6r- z6TFsc=;^t6dv~9$NO~VQp;y{mNkgNfJa=!anb?|zrn4WT7TTa=R(Rf|pPSPdw9+Ls zR1|cbl&h;NYlzm=v+>KH6j|Q6d$;qdYu1I=o$I*8^&WgYF7NK?$q72TV!{Lgki(|y z#~)kVZ^yMZtb5utG0=Un@Av&)r|QWoV{u{9jJn@%&3k06w>cZ-{on07+pKiwliQM$ zMeY}_Hh*(#>*=758?$1vO=kJ+pMLC^TgKK~e9~<9_Wy4Zn65v4>eR#s2O7<+f4>#p ze6DZ0$?UTh1rHd`&9~35eA{pT@4&ymzbn6o_PQmPCp~-lvU93-_@Udkr9t-*#^|*N ztvvGW?QPav{d5X!qxh8Nk6~c4~BX3=9L{^7qlO-=go;UQ=x zUZLyaiw=6zmDSakpZ>G*YF2JvY_D7Mg9izL?^73FFTNjfV_U9t8?Q8|N!cT5%r;#w zmg#VWx!Ak;1-G+a6a<2LQx)*4>4?}tGqE?kN;7@f_RjnNZoloT*RS7}?Xu?PTk=Y% z8WaPddG8-zF8k|VcXf3QSQ!G^(ypYeth+uuJUscr0!M?HJ{o#@$AtZD5-Z<7I@&$K zLuK0Q-;<{-U#{+>7Cis85SNOXSc#P^Xq(@R85zZ(StQVotFZh2m6euLyi(i$iYFx} zKYaVPcl*66?||R>F0QVL@9yk0%bhiI=FO-2tHt$V4!pa&d+oIH_)o22#CzUoXFUm31P;X!b6%ygMD~^D5bx+4;6qGqnZ0ed;43DypcX!*lQ6 zy&HQfH~U5}Te|e%>C@bx?c_DE z2h_OKvzV}|J8=j9vu-inL)&t1TkZMxa{2tEzrVhQt>=|8;V?Bd)zH)1=H;cTs#-Sr z%I5QSr@QqQIwU1OyzFm(^!57vdBLFbE<8Oww;z9fb#*vsvvP>m#QF2{XKrwFcLyD2 z($UlNt*#?STx6`v&b<1n?B4g_&CSgTGpbL|x_s$U z!KWvlDJdxnHf#{sx^?dR>jzjtJ*-VmQ@vRE`T0SMhoZOVZO!~#cI)laSFf}-7zhZ^PZ0W9h=a2PD8zvp;@cZr_xH4pon)u$OYuECs`_DV_e*gczmKK(j z^z>%%2LIEWdUo5ofpT|M?Q_?4CsQ`7Gmh zl}y|B|DQBTXpUX&tz~D`eP^|RdYA83+qRyTTCj8H%}wpn%~_!xo0G(yt8>B8rL=HO_S;)qL8rLrTz`Ik{_&HO)j_i&I&ph$e5&&G zQqDhj%i!)*5v&=`Y;$Xvg5){8f86l`s61sx1l{H*6` zF=((W_m&B0uuD;~(flo_#Gmgx<@D3of4gp6xdNI*Og=x)HX|dW;bh98na1fG($C9D z@UX?~F5}(*=M%SH+@6lr;p-o5zh8HFs&=@{yT#$_VmAKP&QD2EiK}?Xy1Rd`h{&Da zty}j>s;E?3GDmOAY3%RkKXmx;+CJr)3u@ml@3X1<^5SAgPtTU0=8}?4;?!6Moxca zfQH4)o-5a{D_dJj7wx>W%H!Vda{WJl{|btTTzS6VN=;Q2G@)l!`uxe0lAX(s{GBp& zs-mHxAZSG+pR5(j-njm4+ssr{R6vL6PV02_^z2M6D*gQ}S42##NX|bhDoSDc>0G^q zdGmWf2kgARw^#Pw`Sa&Nhq|X2Ns4f>8W|a_c>@}yx%bA^DrlvMP$$d3fB(X^UCb~! zapDB%y0aKPcTjtq?J%gQc=oIfbb{2%l`CcMoj-lL*+=d5)y+@&KfPYRKg#w}a70AM zj~^8#CMFSatJkeNroaDB)3s}1Z|?7xfBEv|j>5-mPl_!26fqjDx%1e`C?hZkRGf zgoTy$;jv!n1PL}zPtQeJ;L-_vAeL}6=vac;!Jy@O{mLb8@9Y!?U21V*p)=@cWN*Wr z_5bTY2Y;MC&AmD8tW#;Jsl>A6NxMp33WcqSNZdKkw%QC7zfDa{tM^NrWK6hQE!ea- zBY9zQpPVfhKR^F$@3pt5`xmEne|xMs)obb5$C|aZwSt0z7t{A2`1#{U$*$!t(_7J{rteUx3?cYe|}xP|J8<#;ZX7%N=1tD- zsHg6V`lFIsN-RqXT)2`x! zf|!0>Pvz%liEnOffxjlcQKGC8?$vi{nz?8<$2 z5)2&HhCK$gM=L8WwY0TAUiP;K1>B02D-Ui=KCWYTTiR-NjjEa&=nScX;^NJ_6BnQPA@yASI=@i*e22h}HW`udKQv*}hFVZ@Kq&*_m@?qn2;ox^?S~l`r0T zWPjv+?Y&0ydQ$Yt3E~!tis}MfB1aP(gLS34O+G2HO^Uhx{X2X0IhBHQiVl+|Klu5$ zIQAH`;`hpPpP%e}|9s#6a#z;msy$vyom^a4mif=`J9NnDSmoQ*-zMAI+JYwQK?{s) ze}7xJawVtU^#`24-Q{baY&;g!*!uC`*<;7t1XvDQMNkl?p(T?B0 zep$@T(QC1tz2UfB{Xd%{NgrDz*C#k}=&&e$e|*?1YB%U4{GXqnFJ8Qu`F_o3Ub&hN zjxoDRGLN|Ce|mDVu#mlxM!-H_SF^>*?#FZE}fO>1dyufF0OeC66Tr?p|fRbuaC zZGCiNqVk5DIT8{Q4%OAx@9ykmUVgc=-~Qi>vLi8i;(2#=H2T~9Ou17(S;g~3iPbSf zUk?w5pdg{u%UYt=wjE94-1Tu*#~iCtE<-~@4}bsf6@0vG%u~Env$C@-Uw_gS<6iyD zAumtw+1c5kL9b)4tMveX-+> z+br^j-l!&aX?1ikYhh^FpEmHDW8U)%nl40`e%r{yix(_g#wOLv7Pa=;>TMI0mmWWU z^r)hyCg=J+pH6Lf9deCnYS3A?;$q{uM(>JvxlGH-%P+6zm$7KrUH*R2{{8Z9iv`vF z<}Ap*V{L5>y7WCHH1y%?_4~iQ)U1n+mR@e~^4Hhb&3Suj9LvkiWsgW?l@}HoDk&>F zull=W!*)))7Tay#A3u%jx^(AGPyD}6(<|O?y$(8B`OhQq{SK9tmh9NYGof}e_i+h!$w{@L9Is6TL>DsU$tu0hi|v@LHk0DW}abQr7IA= zTRw5mvGi~QO{dR$^D4dl{P>KFjV0fL?wR-Y_I8*rx@zA3MT?p?&a1z*CG*CH#KSxM zl~12OZ5jPZkmcd$X*KU|aesez_wYjJ_76Xw&#(T&qq^;R(asNN&F?=rGt(Hf_y6sR z%HsbfQoPyTb`w2J&R8yz@V@E2;8^yegpCm!5)ZS1&Sbv5E%(db^=sFz@%ep{0b9}Y0{ zUuZhNI(&Vbk6QEHyyItQn}6*8|D%6L?QgSmw__fW;{P^vzcwyRWiDnFyRj*B$0ol$ zTTjp4>dK*WC%rpv!;P(>Q&><(C^WE-L+cZuj>~aKEd* zu5RzXwC%SIOJ9Y6F7nmT(K%9l-qt-{T0+91xY&4(-}4UC9L3Aa%PY`*bPXSS@Z8!3 z8*abN$jNc3tlZhov?pw}tD75}i;^H07uT_z>Zqt$?Ta7qISTBk`noFq?d6vx8rs^; zP76O|_^%AmNZ5Y+B~Sb5>H3dPP1Uw2deRZj=i}|o{ao|ipP!%q27NQSRMFbr-k-h4 zNw)s_)7|~|11?>@3|e7y|KGRmJ=e9hv@DoA%HQ8Rda#*2Ff!6Je@6X}hwL)eWjwvT zy(`wQKmPCUZ`(~0B3!I_cXlvNfBoLkq<+qe?c26(;+pdA#zyAi=jV7&eU#GYYiAY} z742~po$AH9F+#@ZrqiK&$G-Deuzi@HUKH>nJGG@}Xm2<$ZSA3{@XYhjF6v9u z$#tNuG5vPGGZgCPSA;RA08gg$jLe4U-wBkLPzY&w{J;5KRuP}zQ@dO({SGI zHxDy2^NG`^5C8f3`C)-Y!Pi%zF7ED+SFhjKbT{w#?)Uq=|IZVM_^=*U?(ueu>&q3- ztzGcq-8;A3T-_;NOOLDVTC#-Y<;#~dEQ_D5xP4mIs)WO6X3xcUyR81Ri-FFU0v)ns zYiqls>Z=y0dgZtOBLM0l^4tGu*tgFPG(a1+dg{Nq$BrEne9jVDey*e_HYkW`qQ{f( zo5bsT!dDc3dlPx&$Pooq)z*!A^Hok3-v55@Ufi{f`g(e89x6^QE=Oh@pO+>7a^Bgb ztx<(9E-2o3TQ+1_Ft@|L>ee_UOk^dx>6z~npQYDX{ za<7ZseJt|RlzH>c{oeeZ_u!`OAGgiBJ2&C(X49?py}I#xy!PkqOg$EFS6zt|Pj^m> z->Z1c3o5F8(Jcp>d$!d>dl)Yudc5C zc)^(;RB@lT|8Mi|?r!$>!;Ru`6^#70Uj&{MS^CYh>Fkv@za(66v`aK%a~kiWMT>b7!TA4?5N7eb{w3F(pMMx!SXwy-9&%za{_Py?f;vx!Vsn&YLIqt28-T zdEbvm-2L|#&aq$jeeL@7>9$+_JUtz=vb3^qp7vONZJ*rwtE8G=v7L3YO12Csc5&DZqlB((9qUjzpAc%Uv|rV7kBTjnC4iy zTeoi~Zolm~NdJ^itK+p1TB3!LZmzVi|_9|Am@Ypm?hL7E2 z(vvIKIa(Fw>3?TX_nUKIP2^_KDPo|lfF*96(X~G!UfsOQdChkAvrTN(tM4t3FTel# z*k<*Aynf3kf1YLkX4Z@9Hyhc&@wDk+d|6?w+Pa*Cb!UXP<%q6ZBb@*CQ(CSd6L+0L zg!tZo?XN*QZo!CY zTvPgut@)sSs{THS^#Mn+wkoNsvrks@{d9uEXr|AFtgQiBQ|(0AO84K-dHFGFt(c&o z;GADlT2s4}Q|>G}^YUDwdj z;pzM~dEYJOm>mU-8#itQ9V65$Z9ZYzw6@yc-wLm__b&w}^4m3q4~s=4`7W(zmtnrK z;zmPUwf^(12^+Pie7lj%tFs|Bg@;$CVshZ?)d!evr$0Ky_Ux2R;_0x5r>s6+)62gm zrnun&`;RyowN!orcK<3hBi#?L+cu_t`R#_a2QQBQB#_Qoy0?6@*y(aM!4*JplFUV8le zJX`6Yl~YWEPueax%5v52)1#x^CBIKBT<-JlNYcgz1&)4)s~&rPKAU~w%$XFK_0H{l zAFbl{HAHQnnd9&851J&ZoG%{pBa0t2LhslyR2bT@OlJ8y&Y!U$TpThx65AyXSkb8Q;Bocgu+-CsP)^1zk7qqIB@u+UWM1 z`wJht9lKT?bLGkvhqYnOtFN-@On!W6sW<2-d(c4S9Q*ot|BTX_PH`ptdb4xqPSE1u zM~@y!tbhHrDr$m$z~iG!_D`5JscEKhdSCR>`TD0$pEfLi7jq)TNJE6{mf0kgg+VJ9 zTz`G>=FOMit9_OpH=g@s_xAZIT%hgpE3Rf8+ZHb}ckbL9+w=?V)F7ZT(V5 zY1sk}@%(*1)y(qlSmc}m%};l_G(A4vUwwzU*RA>0t5*#@)Ac1h$=U|?@POTd8N%1tgUB%EdIUgoSlG$4BwTjy!IQlb#+@K zbmYR0|G!uLKJo6Z(#1tS8tu(RIV+~za=2lBDRaZ!y!NQIZ5K0SzRe8P0-ygSDtdH< zW?*!5_oq*v8mt2N+L^DfidZI7hyh+jR*3{8)@$um~bm)+TvGksoY{?rVm=-O3P{eC>_UqTL0a{bn zNLngytovI9TK;r*hJjSC^0k}&rm9o?Z{5BvX@0f--{<)gr%!)g z$gd;Dz07Ckqrz1-Qa)hJsr$S6`SGm@(|-TCjdS(YF3|MZrza zAHLO?n3-+bmgwW}@1B(fy5&$}eRxR7f}J~OUVnb;VF9QI=CxEPG&EFB(sOa++av$h z*Z3c3y`DmuFG_qSZoRTjI; z-acBx|9n+Ce@V1k{N-yGyRM(#+xGw07yrXeN-@`)?ymc&aKp6l&8M{7nFfum@1Ak5 z`1>{M&fmV>YTK88m7Xy#N?eHl_Rr7H6~(%lzZv+>vx%JH5_c;!F7Dh+wX^26wY3`h z`upD>10}%DEn7@LcN%>({=NI$z4}(iPtBUh&28KEFI>o&nwn}+^TXgs zlHsRMpWL1<*%2HZ+}zd01zH~RE;>J7KSWFP@yRVt3mYPI+B{S~t&m*~+PD$5_SxPy zOLy;{{m})~&;niAc4nqAXcODL=Y7^SuQe)|uU2hYwk++&jp#=Lsu8N;;k}n1(GzoFs-JH&U>eQ(O6RDSmG5cyP@6~)ho47wXG?aDo%`>lW^iKWu ztt_mzH~027(Co~f^Rn@8HtxK!zux}Q4YjqkbG|-|`TFKx)@hA5H-8+C z-`9LH<_?SP324#zt7RgI-Of@xo~d%?bdzYCjNfd7L@St+uPeKR;~K<+u4Ql z4M!vE`?rhye(&17yYl}Z=a+BavU*Nhqn<8Yx#vgR_O_xgF9NSwRnPSk-(Xc8?`#?1 z!{-qfCuf#-hr??@?!7&g9v&W`@QKlD579b0$FeveCg#o7%|;^MrK)D16$`kXotV5Ig zt+X#YmtKxMKi~Q7`tZXa{);V6{XM(j+xNxGze-=R-O3mK?VaPpy87jP zjQz@nkDc|dUz7V6{rkS(`Tf;{9yiv0`n+S$MM@2zZpvAX@N z?JDoDf6tyje|)mPU1#Lxw1sQd@aRqF{`>dukHhl+8eY7}0G)6T>eg0gm`I(OZQgJ9 zav{s2wr_%QyUTRtDjqPNNHMym|NVEN(8ilj?;U#c=jUff*UC!E$DW`58pPGCkA4@i zHtfieBL&xP-p*+(?W%PR4i;Ws{CD>KKWP#1Rjckk?2$B9n0{JNTH5-}mr9cvK5Dl# z`L1M^y1TPa@ls9h`tk1WZqOkjCr)@=+a%tkP@(@=g6rzMq8FK_rg1?lMWoGgIClJN zx|!pamZqkptPHxuuzzQ8WF%*=+hNU$6VLx%$=cfEXXQDmqpz38S11g$)> zHhTM?f0j3Qwe^Ti^=d7BeeGi7;f0S~C#i68b1P2u`uJw^`AucV9&UEY*mEPtEUdP7 z(IO?E*=D*gPIWhx@;_L=t>@4@U4tC`YU%e=a=-tukN?e=Q`dX?>7hZ(G}n?0>o3TcfKe8?mAMUR&bN z^K04OrgvSu{EK(hrDqHO z`WVjPW7lD~b8-Hb(A{VE+V{of;ETmOS^M_c#nhEs>;3;KyCbH#k@fE4lP`8z++aKM z>#4Yb?N&a&Hs3}2nYbT5eE5aA?#T&3ov1Awdeg!8#{c>G`QpWkjrse2vhmyfP|%Cr z)q-uH@!7|^ceO38J*@BFa;2($s`$7!Z|CO9&uQnZelJ_5cJKYuhzCL|wY9XILPA88 zl$0Wv*;G80tgWRJ6B9jreO)6WB#MfQ-Pc_2Y9-4cy$^lnf0gZhoUG z!1p+!&_c#w_SwU)Ua$N(%ck;^!CRhsP}2`|wEoPQGfO6j z^G>JjGC5TEUhdu9O?>};zl+`SH&eZ_UB~};j-{)U`xpUDXC7aJ@jK949^7X5uj@aRc z1qR;)#hADcO%GYoFMj{ESnJK4V^cJPEndHAzG?WVN%!scb?f>zue}$rqUzs_84_pa z+sg;76#4n{XL8-TzianjxOVN>tvDlfb@r1dPtMVNw=n42qjmcqyekQMt9kkI<-cXW zvbIKn)^JXlBGSJzI5^n3UT$Bh$ez}y0UkM?_kE)@cg!!T zrAwD`aC0}`%z5^Accw{oj@^gw=wktCO7CyFWs6Ub|9mYvAJmdxcl_do3l8#+cKo(3 ze}8YOw^CJA)rU*o`jsU*iJ!Or$qY9rjAs|qVgG(`!ym&L^P-+N{%!Y*Iaken-CwKi z?uLUw9r4wBmN9YrwKGq1{{7+VvE?9q@yDTJxyIIK;kM%2cimsxzINZaeE!=P4mABf zeD}^BpZ(izzpZ$`_d6(R&djkC{`vFgj`H_%_v(JQsP;=6)RUZ9!&U9kfouX`t8llj;^jli(I>p#mEJQ zn^!z~ovl74OaJ5(lNBLaEv>DNI%3tK-yW4%UA%AsbTPuCGc%3t*8cpWdVO7NbI{5! z8(LL7L8tVbIC=8p={+Y;o=iORDNt*wW8^o7!oR;tXZWb~|KEJ`#^uMNT&&Cd=AN2$ zGucFHVbIDNv6?sU-YqNTIktE)Xm0n*mlDtjjix3iXk7aDf^DFS8yZXhO;+(_myfS} zIyLdSubS|ctkM%)x3+EF>bUr#!L507=k|Vmef{&lyC$=2&E$Wq)=kzhp7=dy@z(Cs z>ns2Ld=Bm(>^Hu0Us6H>H1!7B`ZQ@$ldAW$4cnYbzr!Q!*8lG!QQP)=?k}^Fd9m{n z+w{wwtL69gua+0PaJ_2Z&Ys&=Zw)@WeZRgvB-Oz7Z}ykFdl;vmZk_$y?lXtZ75m?3 z?*9*~x99nvZ}=|m_qBZf+1ndi-|zd)7q(gyG!QGnGs8HY@7x^AX3!1s-|rO5OqP`-TV| zi=rnSI%3`d%Nm4P40UFJu1$BBt309~$=z@B>BNQuQ!i$)I122!&)t30>H0&yr?0NA zwy6E}WyAmcyu4>V{r=wGhr2|zCDseG7``jgT(xhXz-YTR?DVUI;41DM-3rf1ERF(-GcTG>+IMVA=H-HKZzAvQU%cmT^5<6j zTSje0!jf|C8l8E$_Vjr_h|ge}8;i+?-MI@BV|Lofk?MavoFvCtAKf-ub^Q zsM_nzK5qYrM<>R9rNia=eH_aVH|~>un^E)8GUmiz<(PE`4>*P1vMI^XW;d4Z;#=^p z{PoL8UDmu`U+ho*{POU#+=PdFzu!B&xZkd8-8#LJva+Oyhgw0c?{#r|yI#D=sQG#| ze8cUx72ofce>@%kZ_>xVAR`am-Ch2$sPdbr+;%S^a(2b!X>p*t=wR#Z2o)p|sEJX`5$;zO^$p7UmYyNf1q29CT>q z_ax!I;FTc}yUTQsBpFVcJXugu(sJFmDOi^v}j@TiiVflB@J|bt4jT!(7XHk|9zD?_Qg_L z{ns@;j2A!r=UbS?o9`CP+~4Hu93FF@Z;aU}@^$}z*?ren1Z;n}{l~u7OBOQ1)&e-S zMn8Ri@ymSuM^5kL6MtMky5j#|wl7<1o%i?K*^17+YBk?3C#Df}a>_&h`d`8^>l_WY zUR@pjcwxJoQ%Q*lXnFju`1dzAr%#+RrKMfIPU7@5-NnHhW-@WVzP9!-$dlKvKff4W zVKdod{q<%A4$u-FSy@>}*Xn9(Ep2VvUpx4>YU}Fe#+2Sa=$4qMcSYX9bH{bK5CyeZYy{Sc`X&H z+BF4Hv?p*=R z8~Md&Yd9q&HnE8@9bNnBv%&tKv%>AG?d@`6UZ%4(Gftg4HDL8sN6=c*^t~_p>%J(1 zmWl+eoD#Z4cgl)YtDI6&RQ%>znI<0ZK5u$DX`_OX(WK4i_N`vs{k_sg?A7bnkd9$W zYN}z}_h(-=?%gZP;<#YZqC2 zoTaXL{=F32+?(5SrG7918P7W??jx7yJ7`17}AB>2sww}T7vgpCnR zMg6j`;BoYQw!g@$GR{U;c_kLHcjtGR%|6=(D$|8JS**+7@thQ~Zc^A#{M^q&MF_O! zSUFG2Npv4Gx22`!n$mAmr%pAPeRj|JhZ`?kG@NnDW2=10a_H#x*Gp{8j8eVFw0$|Z zeaYSTMO=oDoulc&l_?XvmfqM~ZT|Rvpw`qEFFsuH-BI#Vs880q?c6!PlCrW#pi%eG zP|=um2PZ#kX6HZjvgFaZxz-jnKQ_eQ<||4xo1JOfvoIwsE$Q>Kvvo6_XPf7{xw)}D zzQ1vLWTHAQrWh?;wTjDYsgSO& zuH4)IJD!0J1CY~3Iy3=nL zxZ?KHv$vF3#9G?Vt}kmfdN=vSfktKzZ|`Ogl|^rPMb-T0^&IUMe|%+S@b{z3n)s!p zq$2#I+ppbhm$I7MXE=4Dil>K)kcygG701qzUbQW#2lMuPrS-Y|XYarg`r+|G8GJ!s>nx z9vo~g>GW`R2CdDgs;*ubpb-!f($X!if9R={&td+MD2wo$-A)S~Qc{-O_lsT|roGH} z_OY3A@-NoRmp0FP@b~-u<5RW6LF1XHkN3+jj}K1%{;*yC(T|Uh*St3ls;Vg}GD^S3 zAFM9feUzz50o0lgH=j|fJkbNx<`5MHU6$H^Mq#cW`_iD!Wy_WY+PBBdOK@kX$4-0vl1kbr!OP3*xcxX^YKv`jMxp&LmxXzd5nus1v;DV3PkpFm(#z3u zO5X#zxbDuKm}BRchOJKA7*R2Qe{$m~g@jGnmzVh>#=%Q=6=r(f$T6Fs!a3FJY2l;D zm>8a!K5Q#PKnrD6R8$P6&9CUbm;qYO;zvG=dvzYPrx9QNyJYk$6Q3^X;`Cu`ldZ=c<+l&6o5cK>+L z%rCLkC1%~h2Fa_Yi7R5cTARceQ!i^4@?R<~D|1?Z-Fa!y#%*O^*uV>c+J5|~ICA{B zv)W|Gg#j0?ul%|E`s?F50?!L9940MspK#&tUtu93g~=x)uKV}83151x9vz^nuFk$X ze7)E=20NDGFbtjVo4Yg!y)E+GKPiXL0zJ@^-C$i7GAcsqUaV z#EW*yY}~llpt@9){pu_$b^+nSr7@1B{dd2X)tbMf@<)o)V2zq`vA zxMh3P+8L(VV)`#X?%lf=v|0ny9;*HQ?PBBnb?fwGED8=ht^}>L;^OAEHR9~*?zTMM zx_Yyhn;TnDaPY>Ai%Q2{vo$knP2~dJy&1GJMbzbU8|Xrhn4Lm_fq|ekC(HW|Wf=F( z*l_cPDLbFMUC+wkg32_7nP%P$?0Q!x3?aHyiUb`R4_ z;o9$a%k66SCw%$Za^R4J+C`Vr1I~BXX$CLb;P%W}&}%`@`^pFUEgwJ0ZcaO!v}W`2 zISUq+ep|>CKDXA*jqTEcTe11BZ0lopyLFrFifNXf*VM#h)esOG z%DVVs$K~bzmm61Vhpz*b2RkZ0D&4wutKi8A!DC;3d|YrfD{}6F6DK_8*jAe<6t7yd zhUenNi)&^v|MTkq|EOC(qwwtQ?fH*CJUsj*?MjBpqAgpd{EJ+E`Q^l`4~ljML`9v_ z40%;x5fB)7@JCJ1!CfyeFYjN?%q2dhujzNq$#dt@t^^v)J{y<0xWYR*S(&3L;ZKbB zbUoLsEUnf1+)`6j^?yn2YtW9EK7W3H(*TP`5EYxg_$#F$}OEx{r#P5OpMHQhN^pzo9a-u<{Xx;r4P|emY(5-do^Ued$JO<9uK#zhTL(J#7<6bNXrtDdS*F~n zsj11EPR~vc<p6U6ZX7G$xZ<^<> zTc>wT_}Js){g*Ru`$#fv-MY2z@)XdriQ3w~8-#C9nk2L)W~UJ73K9EyyCp#@eH zf|qZde4eV$%*+frIR7uG+OnwoV==ex{{8#?%Ds!wps_sg00HCC_I+*Z3;x?lcvV$dmA$*8`G)aW z=Z17{-4!3XToOQ6!qoqL9S_WFPQk}-PXJZ#KK$;qJmNlQvg zLH**6zP_~De7l;xudlCveBAz@;a)%Zz}jmcN$xAQ3z|6H`(zF-a_v5rGTr?ADuIX( z%-@p}8WlKfemrP?ysDHBd|*7ge2swH;)&nEnN7-Gtef@W!-wBP<-hIPwSW8cCq=(% zYA4xEId{%)SINP>A#O2zi>91a8z4-d8 z@b3Xq?vL8rGNxgXA+t|oxVq#LU$KT(-|9bsop;^gA zze2P`k0cqMNh@}E9`5YSyv%3jA&EVUN(_$)@5#!~KdwH%rfJb4rKtT*3j-Y1Uw2*@ za3IAfF(H9LZ8GQm`v0~u>kgg~GF!{IjE7Cl&8vTTQ~16jB`+_p3G?Rl&6pvfqN?hs zHMJ_m1vEXp_@cw=tH1U#J4Z)Ln@I6KetzcMxnrO+C%>BBiQd{Kw0G~`HNT{e9zDvz z&(B}++cS}0Aj;{OpMR=CT$H3 zhrqx<56}+B<@2hzCad`#Ixb&-=C{lT^FtNA{h)h^($b91b#`@eotyF^q0Q@V>Za`P z@9uW=_sbV&+r$fL{A~qCTZ(tE`Ai=Tef{r|H%|vV-@0wvG{67bZ@&dy8@Ib$f9|25 zSHt5UetCKM!t1X;e!X4~N_PEy!pax#+&MFA*}kHuUiYFN@BQ=XG^o$|__-2C(wV1b zQoU^RYd&$_x_uk80Bpa1ZLKY6R_EQjykF^}T&?amyVf6@e)gh{j!sL6R;!1KRQPI} zwPD?7&iHh=D4lp(1X@;GlD`tX3NY2-XsRq9d-_h_k`fakVPVP5y-s`oKJn0v*}Qpk ztF1%FTgH};QvWMhl{OfppOg9Z^>+UL-WM-2PNW#|@B9C+8gxcG=up)9ZF~3HzF^{J zW@f&zuh#nR)U1<}RO491?l5znJ$u$EAyLWlf$&wmtUI7t>C)F>I`R8tGBYz3k3Kru zy|MChT3oaPt5o8iV{I2RTq-Jl?0EI2S#(?P{;<`qDJd%H)t+`{|M=ROeSLicw5DEo zSt9p~d*;lUpfS}LJ@DeaZZlUd#FQj)ATJ%a<=bJUtV6V~QMEuPG@hff|&8 zf{ka+_*AVe64%Pj%HsNARr>mx?zNx^vesn^c6RfE<3S50R0>{ZYt-^?+Zw7P_POYh z-Wx`z?oP9~Mh=}F))!k_TS2!&ytvNH%$$*z*LL~kk!8NKZH&aSva_4@HUz}P^z1Bt zeo3{;yWpzMdvEb;s2yBi!7BKK4nrqA8GTOvT?;;mb!qS8TghfkiQoC|sS zam#cW{kwPXmJ}SW{Tvq*)U?!lx{{h2Tk-RAtsz>eZ!8YDd3tiXC<(eK2_|bhyvpy} zDm#CB%&rnnS65fiG7HeSWA*oU2cJsW)Lzdp`EovXcNs4`zub|Nlhq49J~}FB9ReCJ zc%Y`D^5DWk=RN1P{{8)Zvt6;(+`J=Se#qDTU<942_wVoTjrsTYB}S@(684%f?Z3D3 zwl}MI*8KbV++e29i}&xppRTx-V;07~d&dq5rHLGZf`W^+o@(mow74ia1_cQ%TC`}w zym{{?u1q$Nc;UlocY4bWueBbNT)e!vo}Hcjyu6mz4z#?()^_gq_hyWZ4ni*u9J;zX zTu@fFcm2L!TxGjuL5CRD{X89i=&2Ns(f=>Y?OSi=xaH^T8yOkdFmYGymD`?we_8zJ zhp*q>+{_NT0QbNF1|2bOx%xkapc(Xic9ow}tQ!3ORxdelDC5niG#_WZ4FPd+a#z$F z%XZ5?efo59-3_O^di&;!Gd4ODzPh4$=+kCzY85?#GxR)kJlgie~R zt)8|vH&>zQ>Z@Fk<#B~v`_s?Md8i11P8$de46OL`@%Ub?ehvUQgO=(|ndMMBk2aW^ zn$`)oe>LZ8XIAlaT7TV`E%ec&M-|!jnhFQl|9$Ihv%0D`ojd*fJlCKgA-TFAi8|5S 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

Z9MY0`oat-sr%zCY^LfAn;EeA$0% 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 Date: Mon, 28 Nov 2016 11:21:23 +0100 Subject: [PATCH 34/62] Adjust comment. --- keyboards/ergodox/keymaps/bepo/readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyboards/ergodox/keymaps/bepo/readme.md b/keyboards/ergodox/keymaps/bepo/readme.md index 207b675715..51a5069851 100644 --- a/keyboards/ergodox/keymaps/bepo/readme.md +++ b/keyboards/ergodox/keymaps/bepo/readme.md @@ -23,7 +23,7 @@ La touche "Tab" est placée comme sur la TypeMatrix 2020. Meilleure symétrie et accessibilité que la TypeMatrix 2030 : les touches "W" et "%" ont dû être déplacées du côté gauche en raison du nombre de touches de l'ErgoDox, mais l'auriculaire droit ne gère maintenant que deux colonnes de touches au lieu de trois. La touche "Ê" redevient accessible sur la même rangée que les autres lettres, comme sur un clavier classique en disposition bépo. Les lettres, chiffres et symboles sont tous regroupés sur 4 lignes et 6 colonnes pour chaque main, et la première rangée de lettres à la main gauche conserve une identité visuelle "BÉPO". -Touche de fonction permettant de saisir les touches F1 à F12, les touches F1 à F10 sont placées de façon logique par rapport aux chiffres 1 à 0. Cette même touche permet l'accès aux touches directionnelles sans déplacer la main droite. Les touches "Home" et "End" sont placées de la même façon que sur une TypeMatrix 2030 par rapport aux touches directionnelles. Les touches "Page Up" et "Page Down" sont également accessibles facilement sans déplacer la main droite. Les fonctions "VolUp" et "VolDown" sont placées comme sur la TypeMatrix 2030, avec la fonction "Mute" juste au dessus. Les fonctions "Undo", "Cut", "Copy" et "Paste" sont placées côte à côte comme elles le seraient sur un clavier QWERTY en combinaison avec la touche "Ctrl" (à l'emplacement des lettres "Z", "X", "C" et "V"). Par rapport au layout "SpaceFN", l'utilisation d'une touche de fonction dédiée au pouce permet de ne pas ajouter de latence, et la touche espace reste compatible avec les jeux (action au moment de l'appui et possibilité d'appui long). +Touche de fonction permettant de saisir les touches F1 à F12, les touches F1 à F10 sont placées de façon logique par rapport aux chiffres 1 à 0. Cette même touche permet l'accès aux touches directionnelles sans déplacer la main droite et d'effectuer des actions souris avec uniquement la main gauche. Les touches "Home" et "End" sont placées de la même façon que sur une TypeMatrix 2030 par rapport aux touches directionnelles. Les touches "Page Up" et "Page Down" sont également accessibles facilement sans déplacer la main droite. Les fonctions "VolUp" et "VolDown" sont placées comme sur la TypeMatrix 2030, avec la fonction "Mute" juste au dessus. Les fonctions "Undo", "Cut", "Copy" et "Paste" sont placées côte à côte comme elles le seraient sur un clavier QWERTY en combinaison avec la touche "Ctrl" (à l'emplacement des lettres "Z", "X", "C" et "V"). Par rapport au layout "SpaceFN", l'utilisation d'une touche de fonction dédiée au pouce permet de ne pas ajouter de latence, et la touche espace reste compatible avec les jeux (action au moment de l'appui et possibilité d'appui long). Touche de fonction permettant l'accès au pavé numérique comme sur la TypeMatrix 2030, mais sans avoir à déplacer la main droite : avec les doigts sur la rangée de repos, possibilité de saisir les chiffres "4", "5" et "6" comme sur un pavé numérique classique. Le double "0" de la TypeMatrix a été conservé, et gagne une possibilité de répétition en simples "0". From 2d0ada01902a0103dc4f4f54a416f0666c641b5b Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Mon, 28 Nov 2016 07:55:02 -0500 Subject: [PATCH 35/62] Pulls LED config into common config for EZ --- keyboards/ergodox/ez/config.h | 11 +++++++++++ keyboards/ergodox/keymaps/erez_experimental/config.h | 10 ---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/keyboards/ergodox/ez/config.h b/keyboards/ergodox/ez/config.h index 67a856e511..0b7e8b2ee1 100644 --- a/keyboards/ergodox/ez/config.h +++ b/keyboards/ergodox/ez/config.h @@ -45,6 +45,17 @@ along with this program. If not, see . /* Set 0 if debouncing isn't needed */ #define DEBOUNCE 5 +/* ws2812 RGB LED */ +#define RGB_DI_PIN D7 +#define RGBLIGHT_ANIMATIONS +#define RGBLED_NUM 15 // Number of LEDs +#define RGBLIGHT_HUE_STEP 12 +#define RGBLIGHT_SAT_STEP 255 +#define RGBLIGHT_VAL_STEP 12 + +#define RGB_MIDI +#define RGBW_BB_TWI + /* * Feature disable options * These options are also useful to firmware size reduction. diff --git a/keyboards/ergodox/keymaps/erez_experimental/config.h b/keyboards/ergodox/keymaps/erez_experimental/config.h index fbd12ab797..4da18c65aa 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/config.h +++ b/keyboards/ergodox/keymaps/erez_experimental/config.h @@ -9,15 +9,5 @@ #undef LEADER_TIMEOUT #define LEADER_TIMEOUT 300 -/* ws2812 RGB LED */ -#define RGB_DI_PIN D7 -#define RGBLIGHT_ANIMATIONS -#define RGBLED_NUM 15 // Number of LEDs -#define RGBLIGHT_HUE_STEP 12 -#define RGBLIGHT_SAT_STEP 255 -#define RGBLIGHT_VAL_STEP 12 - -#define RGB_MIDI -#define RGBW_BB_TWI #endif From 9caf866618840ca38f4ceb1166ad679174c752c3 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Mon, 28 Nov 2016 07:59:01 -0500 Subject: [PATCH 36/62] Tweaks EZ Makefile --- keyboards/ergodox/ez/Makefile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/keyboards/ergodox/ez/Makefile b/keyboards/ergodox/ez/Makefile index 191c6bb664..9b6121e2c2 100644 --- a/keyboards/ergodox/ez/Makefile +++ b/keyboards/ergodox/ez/Makefile @@ -1,3 +1,8 @@ +SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend +COMMAND_ENABLE = no # Commands for debug and configuration +RGBLIGHT_ENABLE ?= yes +MIDI_ENABLE ?= yes + ifndef MAKEFILE_INCLUDED include ../../../Makefile -endif \ No newline at end of file +endif From d2b6438e391743544d437ca8c2998de6ab631894 Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 28 Nov 2016 14:10:31 +0100 Subject: [PATCH 37/62] A little cleanup, add some comments, change others. --- keyboards/ergodox/keymaps/bepo/keymap.c | 42 ++++++++++--------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/keyboards/ergodox/keymaps/bepo/keymap.c b/keyboards/ergodox/keymaps/bepo/keymap.c index c1a8ae21d9..8f068e238d 100644 --- a/keyboards/ergodox/keymaps/bepo/keymap.c +++ b/keyboards/ergodox/keymaps/bepo/keymap.c @@ -1,19 +1,19 @@ #include "ergodox.h" -#include "debug.h" -#include "action_layer.h" #include "keymap_bepo.h" -#define BASE 0 // default layer -#define QWER 1 // qwerty compat layer -#define SQWER 2 // shifted qwerty compat layer -#define AQWER 3 // alted qwerty compat layer -#define FNAV 4 // function / navigation keys -#define NUM 5 // numeric keypad keys +// keymaps +#define BASE 0 // default layer, for bepo compatible systems +#define QWER 1 // bepo to qwerty base compat layer, for qwerty systems +#define SQWER 2 // bepo with shift key to qwerty compat layer +#define AQWER 3 // bepo with altgr key to qwerty compat layer +#define FNAV 4 // function / navigation / mouse layer +#define NUM 5 // numeric keypad layer -#define KP_00 0 +// macros +#define KP_00 0 // keypad "double 0" const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { -/* Keymap 0: Base layer +/* Keymap 0: default layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | $ | " | < | > | ( | ) |Delete| |ScroLo| @ | + | - | / | * | = | @@ -50,7 +50,7 @@ KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, DF(QWER), DF(BASE), MO(NUM), MO(FNAV), KC_RSHIFT, KC_ENTER), -/* Keymap 1: QWERTY system compatibility layer +/* Keymap 1: bepo to qwerty base compat layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | $ | " | < | > | ( | ) |Delete| |ScroLo| @ | + | - | / | * | = | @@ -87,7 +87,7 @@ KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, DF(QWER), DF(BASE), MO(NUM), MO(FNAV), MO(SQWER), KC_ENTER), -/* Keymap 2: QWERTY shifted system compatibility layer +/* Keymap 2: bepo with shift key to qwerty compat layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | # | 1 | 2 | 3 | 4 | 5 |Delete| |ScroLo| 6 | 7 | 8 | 9 | 0 | = | @@ -124,7 +124,7 @@ S(KC_ESC), S(KC_INS), S(KC_LGUI), S(KC_LCTL), S(KC_LALT), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), -/* Keymap 3: QWERTY alted system compatibility layer +/* Keymap 3: bepo with altgr key to qwerty compat layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | $ | " | < | > | [ | ] |Delete| |ScroLo| @ | + | - | / | * | = | @@ -161,7 +161,7 @@ KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, KC_TRNS, KC_TRNS, MO(NUM), MO(FNAV), MO(SQWER), KC_ENTER), -/* Keymap 4: function / navigation layer +/* Keymap 4: function / navigation / mouse layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | | F1 | F2 | F3 | F4 | F5 |VolMut| | | F6 | F7 | F8 | F9 | F10 | | @@ -198,7 +198,7 @@ KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO), -/* Keymap 5: numeric layer, sends keypad codes +/* Keymap 5: numeric keypad layer, sends keypad codes * * ,--------------------------------------------------. ,--------------------------------------------------. * | | | | | | | | | | | NumLo| / | * | - | | @@ -237,12 +237,10 @@ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS) }; -const uint16_t PROGMEM fn_actions[] = { -}; - const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) { switch(id) { + // keypad "double 0" case KP_00: if (record->event.pressed) { return MACRO( T(KP_0), D(KP_0), END ); @@ -253,11 +251,3 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) } return MACRO_NONE; }; - -// Runs just one time when the keyboard initializes. -void matrix_init_user(void) { -}; - -// Runs constantly in the background, in a loop. -void matrix_scan_user(void) { -}; From 84735836e309fe9e2c45ed991a58820ae2bb9123 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Mon, 28 Nov 2016 08:13:32 -0500 Subject: [PATCH 38/62] Tweaks position of TOG not to conflict with MO --- keyboards/ergodox/keymaps/erez_experimental/keymap.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/keyboards/ergodox/keymaps/erez_experimental/keymap.c b/keyboards/ergodox/keymaps/erez_experimental/keymap.c index 0c0e3c4e39..2963c40e31 100644 --- a/keyboards/ergodox/keymaps/erez_experimental/keymap.c +++ b/keyboards/ergodox/keymaps/erez_experimental/keymap.c @@ -71,7 +71,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * | | | |NxtTab|PrvTab| | | | | | | * `----------------------------------' `----------------------------------' * ,-------------. ,-------------. - * | | | | | | + * | | | |TOG | * ,------|------|------| |------+------+------. * |VAI |VAD |HUI | |SAI |TOG |MOD | * | | |------| |------| | | @@ -95,9 +95,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { KC_AMPR, KC_UNDS, KC_MINS, CM_SCLN, KC_PLUS, KC_TRNS, KC_TRNS, KC_PIPE, KC_AT, KC_EQL, KC_PERC, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, - KC_TRNS, KC_TRNS, + RGB_TOG, KC_TRNS, RGB_SAI, - RGB_SAD, RGB_TOG, RGB_MOD + RGB_SAD, KC_TRNS, RGB_MOD ), /* Keymap 2: Media and mouse keys * From f02eccbb29ee6a8cf421895dcef2e55a76c1bdcb Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 28 Nov 2016 14:16:42 +0100 Subject: [PATCH 39/62] Change layer names (cosmetic change) and reorder them so that the "shift" layer can be accessed from the "alt" layer when in QWERTY compat mode. --- keyboards/ergodox/keymaps/bepo/keymap.c | 124 ++++++++++++------------ 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/keyboards/ergodox/keymaps/bepo/keymap.c b/keyboards/ergodox/keymaps/bepo/keymap.c index 8f068e238d..c19ab0d48d 100644 --- a/keyboards/ergodox/keymaps/bepo/keymap.c +++ b/keyboards/ergodox/keymaps/bepo/keymap.c @@ -2,12 +2,12 @@ #include "keymap_bepo.h" // keymaps -#define BASE 0 // default layer, for bepo compatible systems -#define QWER 1 // bepo to qwerty base compat layer, for qwerty systems -#define SQWER 2 // bepo with shift key to qwerty compat layer -#define AQWER 3 // bepo with altgr key to qwerty compat layer +#define BEPO 0 // default layer, for bepo compatible systems +#define QW_B 1 // bepo to qwerty base compat layer, for qwerty systems +#define QW_A 2 // bepo with altgr key to qwerty compat layer +#define QW_S 3 // bepo with shift key to qwerty compat layer #define FNAV 4 // function / navigation / mouse layer -#define NUM 5 // numeric keypad layer +#define NUMK 5 // numeric keypad layer // macros #define KP_00 0 // keypad "double 0" @@ -26,20 +26,20 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | L_Num| | | + * | | |L_NumK| |L_NumK| | | * | Space|LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' */ -[BASE] = KEYMAP( +[BEPO] = KEYMAP( // Left hand BP_DOLLAR, BP_DQOT, BP_LGIL, BP_RGIL, BP_LPRN, BP_RPRN, KC_DEL, BP_PERCENT, BP_B, BP_E_ACUTE, BP_P, BP_O, BP_E_GRAVE, KC_BSPC, BP_W, BP_A, BP_U, BP_I, BP_E, BP_COMMA, BP_ECRC, BP_A_GRAVE, BP_Y, BP_X, BP_DOT, BP_K, KC_TAB, KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, - DF(BASE), DF(QWER), - MO(NUM), + DF(BEPO), DF(QW_B), + MO(NUMK), KC_SPC, KC_LSHIFT, MO(FNAV), // Right hand KC_SLCK, BP_AT, BP_PLUS, BP_MINUS, BP_SLASH, BP_ASTR, BP_EQUAL, @@ -47,8 +47,8 @@ KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, BP_C, BP_T, BP_S, BP_R, BP_N, BP_M, KC_NUMLOCK, BP_APOS, BP_Q, BP_G, BP_H, BP_F, BP_CCED, BP_ALGR, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -DF(QWER), DF(BASE), -MO(NUM), +DF(QW_B), DF(BEPO), +MO(NUMK), MO(FNAV), KC_RSHIFT, KC_ENTER), /* Keymap 1: bepo to qwerty base compat layer * @@ -63,31 +63,68 @@ MO(FNAV), KC_RSHIFT, KC_ENTER), * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | L_Num| | | + * | | |L_NumK| |L_NumK| | | * | Space|LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' */ -[QWER] = KEYMAP( +[QW_B] = KEYMAP( // Left hand KC_DOLLAR, S(KC_QUOT), S(KC_COMM), S(KC_DOT), KC_LPRN, KC_RPRN, KC_DEL, KC_PERCENT, KC_B, KC_E, KC_P, KC_O, KC_E, KC_BSPC, KC_W, KC_A, KC_U, KC_I, KC_E, KC_COMMA, KC_E, KC_A, KC_Y, KC_X, KC_DOT, KC_K, KC_TAB, KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, - DF(BASE), DF(QWER), - MO(NUM), - KC_SPC, MO(SQWER), MO(FNAV), + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_SPC, MO(QW_S), KC_TRNS, // Right hand KC_SLCK, KC_AT, KC_PLUS, KC_MINUS, KC_SLASH, KC_ASTR, KC_EQUAL, KC_CAPSLOCK, KC_CIRC, KC_V, KC_D, KC_L, KC_J, KC_Z, KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, - MO(AQWER), KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -DF(QWER), DF(BASE), -MO(NUM), -MO(FNAV), MO(SQWER), KC_ENTER), -/* Keymap 2: bepo with shift key to qwerty compat layer + MO(QW_A), KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, +KC_TRNS, KC_TRNS, +KC_TRNS, +KC_TRNS, MO(QW_S), KC_ENTER), +/* Keymap 2: bepo with altgr key to qwerty compat layer + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | $ | " | < | > | [ | ] |Delete| |ScroLo| @ | + | - | / | * | = | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | % | | | e | & | o | e |Backsp| |CapsLo| ^ | v | d | l | j | z | + * |--------+------+------+------+------+------| ace | | |------+------+------+------+------+--------| + * | w | a | u | i | € | , |------| |------| c | t | s | r | n | m | + * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| + * | e | \ | { | } | . | ~ | | | | ' | q | g | h | f | c | + * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| + * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' + * | | |L_NumK| |L_NumK| | | + * | _ |LShift|------| |------|RShift|Enter | + * | | |L_FNav| |L_FNav| | | + * `--------------------' `--------------------' + */ +[QW_A] = KEYMAP( +// Left hand +KC_DOLLAR, S(KC_QUOT), S(KC_COMM), S(KC_DOT), KC_LBRC, KC_RBRC, KC_DEL, +KC_PERCENT, KC_PIPE, KC_E, KC_AMPR, KC_O, KC_E, KC_BSPC, +KC_W, KC_A, KC_U, KC_I, RALT(KC_5), KC_COMMA, +KC_E, KC_BSLASH, KC_LCBR, KC_RCBR, KC_DOT, KC_TILDE, KC_TAB, +KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_UNDS, MO(QW_S), KC_TRNS, +// Right hand + KC_SLCK, KC_AT, KC_PLUS, KC_MINUS, KC_SLASH, KC_ASTR, KC_EQUAL, + KC_CAPSLOCK, KC_CIRC, KC_V, KC_D, KC_L, KC_J, KC_Z, + KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, + KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, + KC_TRNS, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, +KC_TRNS, KC_TRNS, +KC_TRNS, +KC_TRNS, MO(QW_S), KC_ENTER), +/* Keymap 3: bepo with shift key to qwerty compat layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | # | 1 | 2 | 3 | 4 | 5 |Delete| |ScroLo| 6 | 7 | 8 | 9 | 0 | = | @@ -100,12 +137,12 @@ MO(FNAV), MO(SQWER), KC_ENTER), * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | L_Num| | | + * | | |L_NumK| |L_NumK| | | * | Space|LShift|------| |------|RShift|Enter | * | | |L_FNav| |L_FNav| | | * `--------------------' `--------------------' */ -[SQWER] = KEYMAP( +[QW_S] = KEYMAP( // Left hand KC_HASH, KC_1, KC_2, KC_3, KC_4, KC_5, KC_TRNS, KC_GRV, S(KC_B), S(KC_E), S(KC_P), S(KC_O), S(KC_E), KC_TRNS, @@ -124,43 +161,6 @@ S(KC_ESC), S(KC_INS), S(KC_LGUI), S(KC_LCTL), S(KC_LALT), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), -/* Keymap 3: bepo with altgr key to qwerty compat layer - * - * ,--------------------------------------------------. ,--------------------------------------------------. - * | $ | " | < | > | [ | ] |Delete| |ScroLo| @ | + | - | / | * | = | - * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| - * | % | | | e | & | o | e |Backsp| |CapsLo| ^ | v | d | l | j | z | - * |--------+------+------+------+------+------| ace | | |------+------+------+------+------+--------| - * | w | a | u | i | € | , |------| |------| c | t | s | r | n | m | - * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| - * | e | \ | { | } | . | ~ | | | | ' | q | g | h | f | c | - * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' - * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| - * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' - * | | | L_Num| | L_Num| | | - * | _ |LShift|------| |------|RShift|Enter | - * | | |L_FNav| |L_FNav| | | - * `--------------------' `--------------------' - */ -[AQWER] = KEYMAP( -// Left hand -KC_DOLLAR, S(KC_QUOT), S(KC_COMM), S(KC_DOT), KC_LBRC, KC_RBRC, KC_DEL, -KC_PERCENT, KC_PIPE, KC_E, KC_AMPR, KC_O, KC_E, KC_BSPC, -KC_W, KC_A, KC_U, KC_I, RALT(KC_5), KC_COMMA, -KC_E, KC_BSLASH, KC_LCBR, KC_RCBR, KC_DOT, KC_TILDE, KC_TAB, -KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, - KC_TRNS, KC_TRNS, - MO(NUM), - KC_UNDS, MO(SQWER), MO(FNAV), -// Right hand - KC_SLCK, KC_AT, KC_PLUS, KC_MINUS, KC_SLASH, KC_ASTR, KC_EQUAL, - KC_CAPSLOCK, KC_CIRC, KC_V, KC_D, KC_L, KC_J, KC_Z, - KC_C, KC_T, KC_S, KC_R, KC_N, KC_M, - KC_NUMLOCK, KC_QUOT, KC_Q, KC_G, KC_H, KC_F, KC_C, - KC_TRNS, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -KC_TRNS, KC_TRNS, -MO(NUM), -MO(FNAV), MO(SQWER), KC_ENTER), /* Keymap 4: function / navigation / mouse layer * * ,--------------------------------------------------. ,--------------------------------------------------. @@ -216,7 +216,7 @@ KC_TRNS, KC_TRNS, KC_NO), * | | | | | | | | * `--------------------' `--------------------' */ -[NUM] = KEYMAP( +[NUMK] = KEYMAP( // Left hand KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, @@ -234,7 +234,7 @@ KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_KP_0, M(KP_00), KC_KP_COMMA, KC_KP_ENTER, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, -KC_TRNS, KC_TRNS, KC_TRNS) +KC_TRNS, KC_TRNS, KC_NO) }; const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) From 5a2501d90fb9d2ea1a60d42dfd664d899865e6b5 Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 28 Nov 2016 16:38:03 +0100 Subject: [PATCH 40/62] Add the AZERTY compatibility layer. --- keyboards/ergodox/keymaps/bepo/keymap.c | 125 ++++++++++++++++++++++- keyboards/ergodox/keymaps/bepo/readme.md | 4 +- 2 files changed, 122 insertions(+), 7 deletions(-) diff --git a/keyboards/ergodox/keymaps/bepo/keymap.c b/keyboards/ergodox/keymaps/bepo/keymap.c index c19ab0d48d..05250ee6a7 100644 --- a/keyboards/ergodox/keymaps/bepo/keymap.c +++ b/keyboards/ergodox/keymaps/bepo/keymap.c @@ -1,13 +1,17 @@ #include "ergodox.h" #include "keymap_bepo.h" +#include "keymap_french.h" // keymaps #define BEPO 0 // default layer, for bepo compatible systems #define QW_B 1 // bepo to qwerty base compat layer, for qwerty systems #define QW_A 2 // bepo with altgr key to qwerty compat layer #define QW_S 3 // bepo with shift key to qwerty compat layer -#define FNAV 4 // function / navigation / mouse layer -#define NUMK 5 // numeric keypad layer +#define AZ_B 4 // bepo to azerty base compat layer, for azerty systems +#define AZ_A 5 // bepo with altgr key to azerty compat layer +#define AZ_S 6 // bepo with shift key to azerty compat layer +#define FNAV 7 // function / navigation / mouse layer +#define NUMK 8 // numeric keypad layer // macros #define KP_00 0 // keypad "double 0" @@ -47,7 +51,7 @@ KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, BP_C, BP_T, BP_S, BP_R, BP_N, BP_M, KC_NUMLOCK, BP_APOS, BP_Q, BP_G, BP_H, BP_F, BP_CCED, BP_ALGR, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, -DF(QW_B), DF(BEPO), +DF(AZ_B), DF(BEPO), MO(NUMK), MO(FNAV), KC_RSHIFT, KC_ENTER), /* Keymap 1: bepo to qwerty base compat layer @@ -161,7 +165,118 @@ S(KC_ESC), S(KC_INS), S(KC_LGUI), S(KC_LCTL), S(KC_LALT), KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), -/* Keymap 4: function / navigation / mouse layer +/* Keymap 4: bepo to azerty base compat layer + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | $ | " | < | > | ( | ) |Delete| |ScroLo| @ | + | - | / | * | = | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | % | b |e_acut| p | o |e_grav|Backsp| |CapsLo| ^ | v | d | l | j | z | + * |--------+------+------+------+------+------| ace | | |------+------+------+------+------+--------| + * | w | a | u | i | e | , |------| |------| c | t | s | r | n | m | + * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| + * | e |a_grav| y | x | . | k | | | | ' | q | g | h | f | c_cedil| + * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| + * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' + * | | |L_NumK| |L_NumK| | | + * | Space|LShift|------| |------|RShift|Enter | + * | | |L_FNav| |L_FNav| | | + * `--------------------' `--------------------' + */ +[AZ_B] = KEYMAP( +// Left hand +FR_DLR, FR_QUOT, FR_LESS, FR_GRTR, FR_LPRN, FR_RPRN, KC_DEL, +FR_PERC, KC_B, FR_EACU, KC_P, KC_O, FR_EGRV, KC_BSPC, +FR_W, FR_A, KC_U, KC_I, KC_E, FR_COMM, +KC_E, FR_AGRV, KC_Y, KC_X, FR_DOT, KC_K, KC_TAB, +KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_SPC, MO(AZ_S), KC_TRNS, +// Right hand + KC_SLCK, FR_AT, FR_PLUS, FR_MINS, FR_SLSH, FR_ASTR, FR_EQL, + KC_CAPSLOCK, KC_LBRC, KC_V, KC_D, KC_L, KC_J, FR_Z, + KC_C, KC_T, KC_S, KC_R, KC_N, FR_M, + KC_NUMLOCK, FR_APOS, FR_Q, KC_G, KC_H, KC_F, FR_CCED, + MO(AZ_A), KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, +KC_TRNS, KC_TRNS, +KC_TRNS, +KC_TRNS, MO(AZ_S), KC_ENTER), +/* Keymap 5: bepo with altgr key to azerty compat layer + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | $ | " | < | > | [ | ] |Delete| |ScroLo| @ | + | - | / | * | = | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | % | | | e | & | o | e |Backsp| |CapsLo| ^ | v | d | l | j | z | + * |--------+------+------+------+------+------| ace | | |------+------+------+------+------+--------| + * | w | a |u_grav| trem | € | , |------| |------| c | t | s | r | n | m | + * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| + * | / | \ | { | } | . | ~ | | | | ' | q | g | h | f | c | + * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| + * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' + * | | |L_NumK| |L_NumK| | | + * | _ |LShift|------| |------|RShift|Enter | + * | | |L_FNav| |L_FNav| | | + * `--------------------' `--------------------' + */ +[AZ_A] = KEYMAP( +// Left hand +FR_DLR, FR_QUOT, FR_LESS, FR_GRTR, FR_LBRC, FR_RBRC, KC_DEL, +FR_PERC, FR_PIPE, FR_EACU, FR_AMP, KC_O, FR_EGRV, KC_BSPC, +FR_W, FR_A, FR_UGRV, S(KC_LBRC), FR_EURO, FR_COMM, +FR_SLSH, FR_BSLS, FR_LCBR, FR_RCBR, FR_DOT, FR_TILD, KC_TAB, +KC_ESC, KC_INS, KC_LGUI, KC_LCTL, KC_LALT, + KC_TRNS, KC_TRNS, + KC_TRNS, + FR_UNDS, MO(AZ_S), KC_TRNS, +// Right hand + KC_SLCK, FR_AT, FR_PLUS, FR_MINS, FR_SLSH, FR_ASTR, FR_EQL, + KC_CAPSLOCK, KC_LBRC, KC_V, KC_D, KC_L, KC_J, FR_Z, + KC_C, KC_T, KC_S, KC_R, KC_N, FR_M, + KC_NUMLOCK, FR_APOS, FR_Q, KC_G, KC_H, KC_F, FR_CCED, + KC_TRNS, KC_RCTL, KC_RGUI, KC_PSCREEN, KC_PAUSE, +KC_TRNS, KC_TRNS, +KC_TRNS, +KC_TRNS, MO(AZ_S), KC_ENTER), +/* Keymap 6: bepo with shift key to azerty compat layer + * + * ,--------------------------------------------------. ,--------------------------------------------------. + * | # | 1 | 2 | 3 | 4 | 5 |Delete| |ScroLo| 6 | 7 | 8 | 9 | 0 | ° | + * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------| + * | ` | B | E | P | O | E |Backsp| |CapsLo| ! | V | D | L | J | Z | + * |--------+------+------+------+------+------| ace | | |------+------+------+------+------+--------| + * | W | A | U | I | E | ; |------| |------| C | T | S | R | N | M | + * |--------+------+------+------+------+------| Tab | | NumLo|------+------+------+------+------+--------| + * | E | A | Y | X | : | K | | | | ? | Q | G | H | F | C | + * `--------+------+------+------+------+-------------,-------------. ,-------------`-------------+------+------+------+------+--------' + * |Escape|Insert|LSuper| LCtrl| LAlt| | BEPO |QWERTY| |AZERTY| BEPO | | AltGr| RCtrl|RSuper|PrntSc| Pause| + * `----------------------------------' ,------|------|------| |------+------+------. `----------------------------------' + * | | |L_NumK| |L_NumK| | | + * | Space|LShift|------| |------|RShift|Enter | + * | | |L_FNav| |L_FNav| | | + * `--------------------' `--------------------' + */ +[AZ_S] = KEYMAP( +// Left hand +FR_HASH, FR_1, FR_2, FR_3, FR_4, FR_5, KC_TRNS, +FR_GRV, S(KC_B), S(KC_E), S(KC_P), S(KC_O), S(KC_E), KC_TRNS, +S(FR_W), S(FR_A), S(KC_U), S(KC_I), S(KC_E), FR_SCLN, +S(KC_E), S(FR_A), S(KC_Y), S(KC_X), FR_COLN, S(KC_K), S(KC_TAB), +S(KC_ESC), S(KC_INS), S(KC_LGUI), S(KC_LCTL), S(KC_LALT), + KC_TRNS, KC_TRNS, + KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, +// Right hand + KC_TRNS, FR_6, FR_7, FR_8, FR_9, FR_0, FR_OVRR, + KC_TRNS, FR_EXLM, S(KC_V), S(KC_D), S(KC_L), S(KC_J), S(FR_Z), + S(KC_C), S(KC_T), S(KC_S), S(KC_R), S(KC_N), S(FR_M), + KC_TRNS, FR_QUES, S(FR_Q), S(KC_G), S(KC_H), S(KC_F), S(KC_C), + S(KC_RALT), S(KC_RCTL), S(KC_RGUI), KC_TRNS, KC_TRNS, +KC_TRNS, KC_TRNS, +KC_TRNS, +KC_TRNS, KC_TRNS, KC_TRNS), +/* Keymap 7: function / navigation / mouse layer * * ,--------------------------------------------------. ,--------------------------------------------------. * | | F1 | F2 | F3 | F4 | F5 |VolMut| | | F6 | F7 | F8 | F9 | F10 | | @@ -198,7 +313,7 @@ KC_NO, KC_NO, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_NO), -/* Keymap 5: numeric keypad layer, sends keypad codes +/* Keymap 8: numeric keypad layer, sends keypad codes * * ,--------------------------------------------------. ,--------------------------------------------------. * | | | | | | | | | | | NumLo| / | * | - | | diff --git a/keyboards/ergodox/keymaps/bepo/readme.md b/keyboards/ergodox/keymaps/bepo/readme.md index 51a5069851..2959ac8298 100644 --- a/keyboards/ergodox/keymaps/bepo/readme.md +++ b/keyboards/ergodox/keymaps/bepo/readme.md @@ -27,8 +27,8 @@ Touche de fonction permettant de saisir les touches F1 à F12, les touches F1 à Touche de fonction permettant l'accès au pavé numérique comme sur la TypeMatrix 2030, mais sans avoir à déplacer la main droite : avec les doigts sur la rangée de repos, possibilité de saisir les chiffres "4", "5" et "6" comme sur un pavé numérique classique. Le double "0" de la TypeMatrix a été conservé, et gagne une possibilité de répétition en simples "0". -Touche permettant de basculer en mode BEPO sur un système configuré pour un clavier QWERTY. Cette compatibilité n'est pas parfaite (pas encore de gestion des accents mais ça devrait être faisable avec une disposition en qwerty international, et les combinaisons de touches ne sont pas toutes supportées puisque le clavier traduit déjà certaines touches en combinaisons) mais reste pratique pour une saisie de texte occasionnelle. +Touche permettant de basculer en mode BEPO sur un système configuré pour un clavier QWERTY. Cette compatibilité n'est pas parfaite (pas encore de gestion des accents mais ça devrait être faisable avec une disposition en qwerty international, et les combinaisons de touches ne sont pas toutes supportées puisque le clavier traduit déjà certaines touches en combinaisons) mais reste pratique pour une saisie de texte occasionnelle et pour des accès BIOS ou console en QWERTY. -TODO : couche de compatibilité pour utiliser la disposition BÉPO sur un système configuré pour un clavier AZERTY. +Touche permettant de basculer en mode BEPO sur un système configuré pour un clavier AZERTY. Cette compatibilité n'est pas parfaite (pas de gestion des caractères non présents sur le clavier AZERTY, et les combinaisons de touches ne sont pas toutes supportées puisque le clavier traduit déjà certaines touches en combinaisons) mais reste pratique pour une saisie de texte occasionnelle et pour faire du bureau à distance vers un système Windows sans BEPO. > Olivier Smedts From 06f18e95d4670a055ca349da7d653e0bcb37d83a Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 29 Nov 2016 00:06:12 -0500 Subject: [PATCH 41/62] enable api sysex for ez --- keyboards/ergodox/ez/rules.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/keyboards/ergodox/ez/rules.mk b/keyboards/ergodox/ez/rules.mk index a9715beb85..f570061fe4 100644 --- a/keyboards/ergodox/ez/rules.mk +++ b/keyboards/ergodox/ez/rules.mk @@ -72,6 +72,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=512 # SLEEP_LED_ENABLE = no +API_SYSEX_ENABLE ?= yes ifndef QUANTUM_DIR include ../../../Makefile From d0cefef946660865dae80877886fcce610920a27 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 29 Nov 2016 00:09:56 -0500 Subject: [PATCH 42/62] enable rgblight by default for ez --- keyboards/ergodox/ez/config.h | 11 +++++++++++ keyboards/ergodox/ez/rules.mk | 1 + 2 files changed, 12 insertions(+) diff --git a/keyboards/ergodox/ez/config.h b/keyboards/ergodox/ez/config.h index 67a856e511..c2750a321f 100644 --- a/keyboards/ergodox/ez/config.h +++ b/keyboards/ergodox/ez/config.h @@ -41,6 +41,17 @@ along with this program. If not, see . #define LED_BRIGHTNESS_LO 15 #define LED_BRIGHTNESS_HI 255 +/* ws2812 RGB LED */ +#define RGB_DI_PIN D7 +#define RGBLIGHT_ANIMATIONS +#define RGBLED_NUM 15 // Number of LEDs +#define RGBLIGHT_HUE_STEP 12 +#define RGBLIGHT_SAT_STEP 255 +#define RGBLIGHT_VAL_STEP 12 + +#define RGB_MIDI +#define RGBW_BB_TWI + /* Set 0 if debouncing isn't needed */ #define DEBOUNCE 5 diff --git a/keyboards/ergodox/ez/rules.mk b/keyboards/ergodox/ez/rules.mk index f570061fe4..893cfa7a84 100644 --- a/keyboards/ergodox/ez/rules.mk +++ b/keyboards/ergodox/ez/rules.mk @@ -73,6 +73,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=512 SLEEP_LED_ENABLE = no API_SYSEX_ENABLE ?= yes +RGBLIGHT_ENABLE ?= yes ifndef QUANTUM_DIR include ../../../Makefile From f946d830f98da0161753d37da9659caa7469cf4f Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 29 Nov 2016 00:11:11 -0500 Subject: [PATCH 43/62] guess i didnt pull --- keyboards/ergodox/ez/config.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/keyboards/ergodox/ez/config.h b/keyboards/ergodox/ez/config.h index f3e1020bdb..c2750a321f 100644 --- a/keyboards/ergodox/ez/config.h +++ b/keyboards/ergodox/ez/config.h @@ -56,17 +56,6 @@ along with this program. If not, see . /* Set 0 if debouncing isn't needed */ #define DEBOUNCE 5 -/* ws2812 RGB LED */ -#define RGB_DI_PIN D7 -#define RGBLIGHT_ANIMATIONS -#define RGBLED_NUM 15 // Number of LEDs -#define RGBLIGHT_HUE_STEP 12 -#define RGBLIGHT_SAT_STEP 255 -#define RGBLIGHT_VAL_STEP 12 - -#define RGB_MIDI -#define RGBW_BB_TWI - /* * Feature disable options * These options are also useful to firmware size reduction. From 4094544d41450617bc21ab58646603b8964eae0e Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Tue, 29 Nov 2016 09:23:16 -0500 Subject: [PATCH 44/62] Test layout for ErgoDox EZ manufacturing robot --- .../keymaps/robot_test_layout/keymap.c | 130 ++++++++++++++++++ .../keymaps/robot_test_layout/readme.md | 5 + quantum/rgblight.c | 6 + quantum/rgblight.h | 2 + 4 files changed, 143 insertions(+) create mode 100644 keyboards/ergodox/keymaps/robot_test_layout/keymap.c create mode 100644 keyboards/ergodox/keymaps/robot_test_layout/readme.md diff --git a/keyboards/ergodox/keymaps/robot_test_layout/keymap.c b/keyboards/ergodox/keymaps/robot_test_layout/keymap.c new file mode 100644 index 0000000000..0363eedc2b --- /dev/null +++ b/keyboards/ergodox/keymaps/robot_test_layout/keymap.c @@ -0,0 +1,130 @@ +#include "ergodox.h" +#include "debug.h" +#include "action_layer.h" +#include "version.h" + +enum custom_keycodes { + PLACEHOLDER = SAFE_RANGE, // can always be here + RGB_FF0000, + RGB_00FF00, + RGB_0000FF, + RGB_FFFFFF, + RGB_TOGGLE +}; + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[0] = KEYMAP( + RGB_TOGGLE,RGB_FF0000,RGB_00FF00,RGB_0000FF,RGB_FFFFFF,RGB_TOGGLE,KC_6, + KC_A,KC_Q,KC_W,KC_E,KC_R,KC_T,KC_E,KC_A,KC_A,KC_S,KC_D,KC_F,KC_G,KC_A,KC_Z,KC_X,KC_C,KC_V,KC_B,KC_L,KC_Z,KC_QUOTE,KC_N,KC_U,KC_C,KC_E,KC_8,KC_9,KC_Y,KC_COMMA,KC_6,KC_7,KC_6,KC_7,KC_8,KC_9,KC_0,KC_MINUS,KC_J,KC_Y,KC_U,KC_I,KC_O,KC_P,KC_BSLASH,KC_H,KC_J,KC_K,KC_L,KC_J,KC_K,KC_Z,KC_N,KC_M,KC_COMMA,KC_DOT,KC_E,KC_QUOTE,KC_8,KC_7,KC_LBRACKET,KC_RBRACKET,KC_H,KC_9,KC_7,KC_8,KC_7,KC_6,KC_9), +}; + +const uint16_t PROGMEM fn_actions[] = { + [1] = ACTION_LAYER_TAP_TOGGLE(1) +}; + +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + switch(id) { + case 0: + if (record->event.pressed) { + SEND_STRING (QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION); + } + break; + } + return MACRO_NONE; +}; + + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + switch (keycode) { + // dynamically generate these. + case RGB_FF0000: + if (record->event.pressed) { + #ifdef RGBLIGHT_ENABLE + EZ_RGB(0xff0000); + register_code(KC_A); unregister_code(KC_A); + #endif + } + return false; + break; + case RGB_00FF00: + if (record->event.pressed) { + #ifdef RGBLIGHT_ENABLE + EZ_RGB(0x00ff00); + register_code(KC_B); unregister_code(KC_B); + #endif + } + return false; + break; + case RGB_0000FF: + if (record->event.pressed) { + #ifdef RGBLIGHT_ENABLE + EZ_RGB(0x0000ff); + register_code(KC_C); unregister_code(KC_C); + #endif + } + return false; + break; + case RGB_FFFFFF: + if (record->event.pressed) { + #ifdef RGBLIGHT_ENABLE + EZ_RGB(0xffffff); + register_code(KC_D); unregister_code(KC_D); + #endif + } + return false; + break; + case RGB_TOGGLE: + if (record->event.pressed) { + #ifdef RGBLIGHT_ENABLE + rgblight_toggle(); + register_code(KC_F); unregister_code(KC_F); + #endif + } + return false; + break; + } + return true; +} + +void matrix_scan_user(void) { + + uint8_t layer = biton32(layer_state); + + ergodox_board_led_off(); + ergodox_right_led_1_off(); + ergodox_right_led_2_off(); + ergodox_right_led_3_off(); + switch (layer) { + case 1: + ergodox_right_led_1_on(); + break; + case 2: + ergodox_right_led_2_on(); + break; + case 3: + ergodox_right_led_3_on(); + break; + case 4: + ergodox_right_led_1_on(); + ergodox_right_led_2_on(); + break; + case 5: + ergodox_right_led_1_on(); + ergodox_right_led_3_on(); + break; + case 6: + ergodox_right_led_2_on(); + ergodox_right_led_3_on(); + break; + case 7: + ergodox_right_led_1_on(); + ergodox_right_led_2_on(); + ergodox_right_led_3_on(); + break; + default: + break; + } + +}; diff --git a/keyboards/ergodox/keymaps/robot_test_layout/readme.md b/keyboards/ergodox/keymaps/robot_test_layout/readme.md new file mode 100644 index 0000000000..45dc2aa76c --- /dev/null +++ b/keyboards/ergodox/keymaps/robot_test_layout/readme.md @@ -0,0 +1,5 @@ +# Robot test layout + +Use this layout if you like to pretend you're [Norman](https://www.youtube.com/watch?v=-sbxFBay-tg), the ErgoDox EZ manufacturing robot. + +It's really meant just for internal use, but we're posting it on GitHub anyway, because hurray to open source. :) diff --git a/quantum/rgblight.c b/quantum/rgblight.c index bb03d6e913..625971e0fe 100644 --- a/quantum/rgblight.c +++ b/quantum/rgblight.c @@ -425,6 +425,12 @@ void rgblight_timer_toggle(void) { dprintf("TIMER3 toggled.\n"); } +void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b) { + rgblight_enable(); + rgblight_mode(1); + rgblight_setrgb(r, g, b); +} + void rgblight_task(void) { if (rgblight_timer_enabled) { // mode = 1, static light, do nothing here diff --git a/quantum/rgblight.h b/quantum/rgblight.h index 28a410e480..aa1d026e0e 100644 --- a/quantum/rgblight.h +++ b/quantum/rgblight.h @@ -84,6 +84,8 @@ void sethsv(uint16_t hue, uint8_t sat, uint8_t val, LED_TYPE *led1); void setrgb(uint8_t r, uint8_t g, uint8_t b, LED_TYPE *led1); void rgblight_sethsv_noeeprom(uint16_t hue, uint8_t sat, uint8_t val); +#define EZ_RGB(val) rgblight_show_solid_color((val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF) +void rgblight_show_solid_color(uint8_t r, uint8_t g, uint8_t b); void rgblight_task(void); From 66b13a66e93c50ba6258fcde548ab946fd8db683 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Wed, 30 Nov 2016 22:22:57 -0500 Subject: [PATCH 45/62] Better layout --- .../keymaps/robot_test_layout/keymap.c | 121 ++++++++++-------- 1 file changed, 71 insertions(+), 50 deletions(-) diff --git a/keyboards/ergodox/keymaps/robot_test_layout/keymap.c b/keyboards/ergodox/keymaps/robot_test_layout/keymap.c index 0363eedc2b..480be177f0 100644 --- a/keyboards/ergodox/keymaps/robot_test_layout/keymap.c +++ b/keyboards/ergodox/keymaps/robot_test_layout/keymap.c @@ -9,16 +9,42 @@ enum custom_keycodes { RGB_00FF00, RGB_0000FF, RGB_FFFFFF, - RGB_TOGGLE + RGB_TOGGLE, + LED1, + LED2, + LED3 }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [0] = KEYMAP( - RGB_TOGGLE,RGB_FF0000,RGB_00FF00,RGB_0000FF,RGB_FFFFFF,RGB_TOGGLE,KC_6, - KC_A,KC_Q,KC_W,KC_E,KC_R,KC_T,KC_E,KC_A,KC_A,KC_S,KC_D,KC_F,KC_G,KC_A,KC_Z,KC_X,KC_C,KC_V,KC_B,KC_L,KC_Z,KC_QUOTE,KC_N,KC_U,KC_C,KC_E,KC_8,KC_9,KC_Y,KC_COMMA,KC_6,KC_7,KC_6,KC_7,KC_8,KC_9,KC_0,KC_MINUS,KC_J,KC_Y,KC_U,KC_I,KC_O,KC_P,KC_BSLASH,KC_H,KC_J,KC_K,KC_L,KC_J,KC_K,KC_Z,KC_N,KC_M,KC_COMMA,KC_DOT,KC_E,KC_QUOTE,KC_8,KC_7,KC_LBRACKET,KC_RBRACKET,KC_H,KC_9,KC_7,KC_8,KC_7,KC_6,KC_9), + RGB_TOGGLE, RGB_FF0000, RGB_00FF00, RGB_0000FF, RGB_FFFFFF, KC_5, KC_LPRN, + KC_GRAVE, KC_A, KC_B, KC_C, KC_D, KC_E, KC_EXLM, + KC_HASH, KC_J, KC_K, KC_L, KC_M, KC_N, + KC_AMPR, KC_T, KC_U, KC_V, KC_W, KC_X, KC_DLR, + KC_PIPE, KC_R, KC_PLUS, KC_LCBR, KC_RCBR, + + KC_F, KC_G, + KC_H, + KC_P, KC_O, KC_I, + + + + // RIGHT HAND + KC_RPRN, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, + KC_AT, KC_F, KC_G, KC_H, KC_I, KC_COLN, KC_BSLS, + KC_O, KC_P, KC_Q, KC_R, KC_S, KC_QUOT, + LSFT(KC_COMM), KC_Y, KC_Z, KC_COMM, KC_DOT, KC_SLSH, KC_ASTR, + KC_A, KC_B, KC_C, KC_D, KC_PIPE, + + LED1, KC_E, + LED2, + LED3, KC_J, KC_K + ) }; + + const uint16_t PROGMEM fn_actions[] = { [1] = ACTION_LAYER_TAP_TOGGLE(1) }; @@ -35,7 +61,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) return MACRO_NONE; }; - +bool status_led1_on = false, status_led2_on = false, status_led3_on = false; bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { // dynamically generate these. @@ -43,7 +69,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { #ifdef RGBLIGHT_ENABLE EZ_RGB(0xff0000); - register_code(KC_A); unregister_code(KC_A); + register_code(KC_1); unregister_code(KC_1); #endif } return false; @@ -52,7 +78,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { #ifdef RGBLIGHT_ENABLE EZ_RGB(0x00ff00); - register_code(KC_B); unregister_code(KC_B); + register_code(KC_2); unregister_code(KC_2); #endif } return false; @@ -61,7 +87,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { #ifdef RGBLIGHT_ENABLE EZ_RGB(0x0000ff); - register_code(KC_C); unregister_code(KC_C); + register_code(KC_3); unregister_code(KC_3); #endif } return false; @@ -70,7 +96,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { #ifdef RGBLIGHT_ENABLE EZ_RGB(0xffffff); - register_code(KC_D); unregister_code(KC_D); + register_code(KC_4); unregister_code(KC_4); #endif } return false; @@ -79,52 +105,47 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { #ifdef RGBLIGHT_ENABLE rgblight_toggle(); - register_code(KC_F); unregister_code(KC_F); + register_code(KC_EQL); unregister_code(KC_EQL); #endif } return false; break; + case LED1: + if (record->event.pressed) { + if(status_led1_on) { + ergodox_right_led_1_off(); + status_led1_on = false; + } else { + ergodox_right_led_1_on(); + status_led1_on = true; + } + } + return false; + break; + case LED2: + if (record->event.pressed) { + if(status_led2_on) { + ergodox_right_led_2_off(); + status_led2_on = false; + } else { + ergodox_right_led_2_on(); + status_led2_on = true; + } + } + return false; + break; + case LED3: + if (record->event.pressed) { + if(status_led3_on) { + ergodox_right_led_3_off(); + status_led3_on = false; + } else { + ergodox_right_led_3_on(); + status_led3_on = true; + } + } + return false; + break; } return true; } - -void matrix_scan_user(void) { - - uint8_t layer = biton32(layer_state); - - ergodox_board_led_off(); - ergodox_right_led_1_off(); - ergodox_right_led_2_off(); - ergodox_right_led_3_off(); - switch (layer) { - case 1: - ergodox_right_led_1_on(); - break; - case 2: - ergodox_right_led_2_on(); - break; - case 3: - ergodox_right_led_3_on(); - break; - case 4: - ergodox_right_led_1_on(); - ergodox_right_led_2_on(); - break; - case 5: - ergodox_right_led_1_on(); - ergodox_right_led_3_on(); - break; - case 6: - ergodox_right_led_2_on(); - ergodox_right_led_3_on(); - break; - case 7: - ergodox_right_led_1_on(); - ergodox_right_led_2_on(); - ergodox_right_led_3_on(); - break; - default: - break; - } - -}; From 1f290f6213c7c3bf001a85242cfae4f9b5a14942 Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Thu, 1 Dec 2016 16:21:15 -0500 Subject: [PATCH 46/62] Make my builds smaller --- keyboards/planck/keymaps/cbbrowne/Makefile | 7 ++++--- keyboards/planck/keymaps/cbbrowne/config.h | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/keyboards/planck/keymaps/cbbrowne/Makefile b/keyboards/planck/keymaps/cbbrowne/Makefile index 581e08cd02..3c20da84be 100644 --- a/keyboards/planck/keymaps/cbbrowne/Makefile +++ b/keyboards/planck/keymaps/cbbrowne/Makefile @@ -5,8 +5,8 @@ # the appropriate keymap folder that will get included automatically # BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000) -MOUSEKEY_ENABLE = yes # Mouse keys(+4700) -EXTRAKEY_ENABLE = yes # Audio control and System control(+450) +MOUSEKEY_ENABLE = no # Mouse keys(+4700) +EXTRAKEY_ENABLE = no # Audio control and System control(+450) CONSOLE_ENABLE = no # Console for debug(+400) COMMAND_ENABLE = yes # Commands for debug and configuration NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work @@ -16,10 +16,11 @@ AUDIO_ENABLE = yes # Audio output on port C6 UNICODE_ENABLE = no # Unicode BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. +API_SYSEX_ENABLE = no # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/cbbrowne/config.h b/keyboards/planck/keymaps/cbbrowne/config.h index 1e04ba61d7..bd15fd5a22 100644 --- a/keyboards/planck/keymaps/cbbrowne/config.h +++ b/keyboards/planck/keymaps/cbbrowne/config.h @@ -1,6 +1,9 @@ #ifndef CONFIG_USER_H #define CONFIG_USER_H +#define NO_DEBUG +#define NO_PRINT + #include "../../config.h" #define LEADER_TIMEOUT 300 From b787ed9dc6c81f47215c48d47240717afa3cd440 Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Thu, 1 Dec 2016 16:24:03 -0500 Subject: [PATCH 47/62] More notes on .hex size protection --- readme.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index a92ae4c1dc..5c82efcddd 100644 --- a/readme.md +++ b/readme.md @@ -1318,14 +1318,27 @@ You probably don't want to "brick" your keyboard, making it impossible to rewrite firmware onto it. Here are some of the parameters to show what things are (and likely aren't) too risky. -- If a keyboard map does not include RESET, then, to get into DFU +- If your keyboard map does not include RESET, then, to get into DFU mode, you will need to press the reset button on the PCB, which - requires unscrewing some bits. + requires unscrewing the bottom. - Messing with tmk_core / common files might make the keyboard inoperable - Too large a .hex file is trouble; `make dfu` will erase the block, test the size (oops, wrong order!), which errors out, failing to - flash the keyboard + flash the keyboard, leaving it in DFU mode. + - To this end, note that the maximum .hex file size on Planck is + 7000h (28672 decimal) +```Linking: .build/planck_rev4_cbbrowne.elf [OK] +Creating load file for Flash: .build/planck_rev4_cbbrowne.hex [OK] + +Size after: + text data bss dec hex filename + 0 22396 0 22396 577c planck_rev4_cbbrowne.hex +``` + - The above file is of size 22396/577ch, which is less than + 28672/7000h + - As long as you have a suitable alternative .hex file around, you + can retry, loading that one - DFU tools do /not/ allow you to write into the bootloader (unless you throw in extra fruitsalad of options), so there is little risk there. From af4c44deef55a300113b4a65f8d3ab37bf2ef97d Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Thu, 1 Dec 2016 16:31:30 -0500 Subject: [PATCH 48/62] Improve docs on SYSEX bit --- keyboards/planck/keymaps/cbbrowne/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyboards/planck/keymaps/cbbrowne/Makefile b/keyboards/planck/keymaps/cbbrowne/Makefile index 3c20da84be..b1c70ace70 100644 --- a/keyboards/planck/keymaps/cbbrowne/Makefile +++ b/keyboards/planck/keymaps/cbbrowne/Makefile @@ -16,7 +16,7 @@ AUDIO_ENABLE = yes # Audio output on port C6 UNICODE_ENABLE = no # Unicode BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight. Do not enable this with audio at the same time. -API_SYSEX_ENABLE = no +API_SYSEX_ENABLE = yes # Enable SYSEX API (+5390) # Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend From 95a160bf92ebc5b92ef360f1649e2bd5e3ac2000 Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Thu, 1 Dec 2016 16:31:51 -0500 Subject: [PATCH 49/62] Improve docs on memory usage --- readme.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/readme.md b/readme.md index 5c82efcddd..afdb03ba54 100644 --- a/readme.md +++ b/readme.md @@ -348,6 +348,10 @@ This allows you output audio on the C6 pin (needs abstracting). See the [audio s Use this to debug changes to variable values, see the [tracing variables](#tracing-variables) section for more information. +`API_SYSEX_ENABLE` + +This enables using the Quantum SYSEX API to send strings (somewhere?) + ### Customizing Makefile options on a per-keymap basis If your keymap directory has a file called `Makefile` (note the filename), any Makefile options you set in that file will take precedence over other Makefile options for your particular keyboard. @@ -1339,6 +1343,9 @@ Size after: 28672/7000h - As long as you have a suitable alternative .hex file around, you can retry, loading that one + - Some of the options you might specify in your keyboard's Makefile + consume extra memory; watch out for BOOTMAGIC_ENABLE, + MOUSEKEY_ENABLE, EXTRAKEY_ENABLE, CONSOLE_ENABLE, API_SYSEX_ENABLE - DFU tools do /not/ allow you to write into the bootloader (unless you throw in extra fruitsalad of options), so there is little risk there. From 570e784140becd8621c4d05e8e36c8b0f8402b3b Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Fri, 2 Dec 2016 12:31:43 -0500 Subject: [PATCH 50/62] I want page-down/page-up - put those on LOWER-Left/Right near bottom corner --- keyboards/planck/keymaps/cbbrowne/keymap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/keyboards/planck/keymaps/cbbrowne/keymap.c b/keyboards/planck/keymaps/cbbrowne/keymap.c index 4742ca5c06..717f4b2351 100644 --- a/keyboards/planck/keymaps/cbbrowne/keymap.c +++ b/keyboards/planck/keymaps/cbbrowne/keymap.c @@ -62,6 +62,7 @@ - How about Alt-F1 thru Alt-F8? - What's the keystroke to get from X to console these days? - A layer for doing console switching would not be a bad idea + - I haven't got page-up/page-down, let's have that... */ enum layers { @@ -117,7 +118,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { {KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC}, {_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE}, {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, QWERTY, KEYPAD, KEYPAD, ALTSLASH, _______}, - {_______, KEYPAD, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} + {_______, KEYPAD, _______, _______, _______, _______, _______, _______, KC_PGDN, KC_VOLD, KC_VOLU, KC_PGUP} }, [_KEYPAD] = { /* Key Pad */ {KC_ESC, USERNAME, MVERSION, KC_F10, KC_F11, KC_F12, KC_PGUP, KC_KP_ENTER, KC_7, KC_8, KC_9, KC_BSPC}, From f6e86cd2c904cc3951b2341b9c73a535dbf28f03 Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Fri, 2 Dec 2016 12:35:03 -0500 Subject: [PATCH 51/62] I also want page-down/page-up on UPPER layer --- keyboards/planck/keymaps/cbbrowne/keymap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyboards/planck/keymaps/cbbrowne/keymap.c b/keyboards/planck/keymaps/cbbrowne/keymap.c index 717f4b2351..2be4dab4b1 100644 --- a/keyboards/planck/keymaps/cbbrowne/keymap.c +++ b/keyboards/planck/keymaps/cbbrowne/keymap.c @@ -112,7 +112,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { {KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC}, {_______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS}, {_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, QWERTY, KEYPAD, KEYPAD, ALTSLASH,_______}, - {_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY} + {_______, _______, _______, _______, _______, _______, _______, _______, KC_PGDN, KC_VOLD, KC_VOLU, KC_PGUP} }, [_LOWER] = { /* LOWER */ {KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC}, From 5d43a2aecf2fcb9ed9a25ddc0924c66e544bcdf8 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Fri, 2 Dec 2016 12:53:18 -0500 Subject: [PATCH 52/62] Kristian's keymap --- keyboards/ergodox/keymaps/kristian/keymap.c | 79 +++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 keyboards/ergodox/keymaps/kristian/keymap.c diff --git a/keyboards/ergodox/keymaps/kristian/keymap.c b/keyboards/ergodox/keymaps/kristian/keymap.c new file mode 100644 index 0000000000..2238590917 --- /dev/null +++ b/keyboards/ergodox/keymaps/kristian/keymap.c @@ -0,0 +1,79 @@ +#include "ergodox.h" +#include "debug.h" +#include "action_layer.h" +#include "version.h" +#include "keymap_fr_ch.h" +#include "keymap_french.h" +#include "keymap_german.h" +#include "keymap_german_ch.h" +#include "keymap_nordic.h" +#include "keymap_norwegian.h" +#include "keymap_spanish.h" + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + + +[0] = KEYMAP(NO_LESS,KC_1,KC_2,KC_3,KC_4,KC_5,KC_BSPACE,KC_TAB,KC_Q,KC_W,KC_E,KC_R,KC_T,TG(1),KC_BSPACE,KC_A,KC_S,KC_D,KC_F,KC_G,SFT_T(NO_QUOT),CTL_T(KC_Z),KC_X,KC_C,KC_V,KC_B,SFT_T(KC_EQUAL),MO(1),CTL_T(KC_GRAVE),KC_LGUI,KC_LEFT,KC_RIGHT,KC_ESCAPE,KC_CAPSLOCK,KC_HOME,KC_SPACE,KC_LGUI,KC_LALT,KC_DELETE,KC_6,KC_7,KC_8,KC_9,KC_0,NO_PLUS,TG(1),KC_Y,KC_U,KC_I,KC_O,KC_P,NO_AM,KC_H,KC_J,KC_K,KC_L,LT(2,NO_OSLH),NO_AE,SFT_T(KC_RBRC),KC_N,KC_M,KC_COMMA,KC_DOT,CTL_T(KC_SLASH),SFT_T(NO_QUOT),KC_DOWN,KC_UP,NO_LPRN,NO_RPRN,MO(1),NO_QUOT,CTL_T(KC_ESCAPE),NO_APOS,KC_LALT,KC_LGUI,KC_ENTER), + +[1] = KEYMAP(M(0),KC_F1,KC_F2,KC_F3,KC_F4,KC_F5,KC_BSPACE,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_BSPACE,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LSHIFT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LCTL,KC_LGUI,KC_LEFT,KC_RIGHT,KC_ESCAPE,KC_TRANSPARENT,KC_HOME,KC_SPACE,KC_LGUI,KC_LALT,KC_DELETE,KC_F6,KC_F7,KC_F8,KC_F9,KC_F10,KC_F11,KC_TRANSPARENT,KC_7,KC_8,KC_9,KC_TRANSPARENT,KC_TRANSPARENT,KC_F12,KC_4,KC_5,KC_6,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_0,KC_1,KC_2,KC_3,NO_LBRC,NO_RBRC,KC_LSHIFT,KC_COMMA,KC_DOT,LSFT(NO_LBRC),LSFT(NO_RBRC),KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LALT,KC_LGUI,KC_ENTER), + +[2] = KEYMAP(KC_ESCAPE,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_MS_UP,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_MS_LEFT,KC_MS_DOWN,KC_MS_RIGHT,KC_TRANSPARENT,KC_LSHIFT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LCTL,KC_LALT,KC_LGUI,KC_MS_BTN1,KC_MS_BTN2,KC_ESCAPE,KC_TRANSPARENT,KC_TRANSPARENT,KC_SPACE,KC_LGUI,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_MEDIA_PREV_TRACK,KC_MEDIA_PLAY_PAUSE,KC_MEDIA_NEXT_TRACK,KC_TRANSPARENT,KC_TRANSPARENT,KC_AUDIO_VOL_UP,KC_AUDIO_VOL_DOWN,KC_AUDIO_MUTE,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_ESCAPE,KC_MS_WH_UP,KC_MS_WH_DOWN,KC_MS_ACCEL0,KC_MS_ACCEL1), + +}; + +const uint16_t PROGMEM fn_actions[] = { + [1] = ACTION_LAYER_TAP_TOGGLE(1) +}; + +const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) +{ + switch(id) { + case 0: + if (record->event.pressed) { + SEND_STRING (QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION); + } + break; + } + return MACRO_NONE; +}; + +void matrix_scan_user(void) { + + uint8_t layer = biton32(layer_state); + + ergodox_board_led_off(); + ergodox_right_led_1_off(); + ergodox_right_led_2_off(); + ergodox_right_led_3_off(); + switch (layer) { + case 1: + ergodox_right_led_1_on(); + break; + case 2: + ergodox_right_led_2_on(); + break; + case 3: + ergodox_right_led_3_on(); + break; + case 4: + ergodox_right_led_1_on(); + ergodox_right_led_2_on(); + break; + case 5: + ergodox_right_led_1_on(); + ergodox_right_led_3_on(); + break; + case 6: + ergodox_right_led_2_on(); + ergodox_right_led_3_on(); + break; + case 7: + ergodox_right_led_1_on(); + ergodox_right_led_2_on(); + ergodox_right_led_3_on(); + break; + default: + break; + } + +}; From aa70aa3962f0c148916412eb40924e108b6b5c07 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Fri, 2 Dec 2016 13:03:39 -0500 Subject: [PATCH 53/62] Tweaks Kristian's layout again --- keyboards/ergodox/keymaps/kristian/keymap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keyboards/ergodox/keymaps/kristian/keymap.c b/keyboards/ergodox/keymaps/kristian/keymap.c index 2238590917..e7e4243255 100644 --- a/keyboards/ergodox/keymaps/kristian/keymap.c +++ b/keyboards/ergodox/keymaps/kristian/keymap.c @@ -13,7 +13,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { -[0] = KEYMAP(NO_LESS,KC_1,KC_2,KC_3,KC_4,KC_5,KC_BSPACE,KC_TAB,KC_Q,KC_W,KC_E,KC_R,KC_T,TG(1),KC_BSPACE,KC_A,KC_S,KC_D,KC_F,KC_G,SFT_T(NO_QUOT),CTL_T(KC_Z),KC_X,KC_C,KC_V,KC_B,SFT_T(KC_EQUAL),MO(1),CTL_T(KC_GRAVE),KC_LGUI,KC_LEFT,KC_RIGHT,KC_ESCAPE,KC_CAPSLOCK,KC_HOME,KC_SPACE,KC_LGUI,KC_LALT,KC_DELETE,KC_6,KC_7,KC_8,KC_9,KC_0,NO_PLUS,TG(1),KC_Y,KC_U,KC_I,KC_O,KC_P,NO_AM,KC_H,KC_J,KC_K,KC_L,LT(2,NO_OSLH),NO_AE,SFT_T(KC_RBRC),KC_N,KC_M,KC_COMMA,KC_DOT,CTL_T(KC_SLASH),SFT_T(NO_QUOT),KC_DOWN,KC_UP,NO_LPRN,NO_RPRN,MO(1),NO_QUOT,CTL_T(KC_ESCAPE),NO_APOS,KC_LALT,KC_LGUI,KC_ENTER), +[0] = KEYMAP(NO_LESS,KC_1,KC_2,KC_3,KC_4,KC_5,KC_BSPACE,KC_TAB,KC_Q,KC_W,KC_E,KC_R,KC_T,TG(1),KC_BSPACE,KC_A,KC_S,KC_D,KC_F,KC_G,SFT_T(NO_APOS),CTL_T(KC_Z),KC_X,KC_C,KC_V,KC_B,SFT_T(KC_EQUAL),MO(1),CTL_T(KC_GRAVE),KC_LGUI,KC_LEFT,KC_RIGHT,KC_ESCAPE,KC_CAPSLOCK,KC_HOME,KC_SPACE,KC_LGUI,KC_LALT,KC_DELETE,KC_6,KC_7,KC_8,KC_9,KC_0,NO_PLUS,TG(1),KC_Y,KC_U,KC_I,KC_O,KC_P,NO_AM,KC_H,KC_J,KC_K,KC_L,LT(2,NO_OSLH),NO_AE,SFT_T(KC_RBRC),KC_N,KC_M,KC_COMMA,KC_DOT,CTL_T(KC_SLASH),SFT_T(NO_APOS),KC_DOWN,KC_UP,NO_LPRN,NO_RPRN,MO(1),NO_QUOT,CTL_T(KC_ESCAPE),NO_APOS,KC_LALT,KC_LGUI,KC_ENTER), [1] = KEYMAP(M(0),KC_F1,KC_F2,KC_F3,KC_F4,KC_F5,KC_BSPACE,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_BSPACE,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LSHIFT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LCTL,KC_LGUI,KC_LEFT,KC_RIGHT,KC_ESCAPE,KC_TRANSPARENT,KC_HOME,KC_SPACE,KC_LGUI,KC_LALT,KC_DELETE,KC_F6,KC_F7,KC_F8,KC_F9,KC_F10,KC_F11,KC_TRANSPARENT,KC_7,KC_8,KC_9,KC_TRANSPARENT,KC_TRANSPARENT,KC_F12,KC_4,KC_5,KC_6,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_0,KC_1,KC_2,KC_3,NO_LBRC,NO_RBRC,KC_LSHIFT,KC_COMMA,KC_DOT,LSFT(NO_LBRC),LSFT(NO_RBRC),KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_TRANSPARENT,KC_LALT,KC_LGUI,KC_ENTER), From 555e41d9e5f8d393637898e2c77c64066b648245 Mon Sep 17 00:00:00 2001 From: Erez Zukerman Date: Fri, 2 Dec 2016 13:03:51 -0500 Subject: [PATCH 54/62] Annotates nordic --- quantum/keymap_extras/keymap_nordic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/keymap_extras/keymap_nordic.h b/quantum/keymap_extras/keymap_nordic.h index da5c829757..9b0ef35ca9 100644 --- a/quantum/keymap_extras/keymap_nordic.h +++ b/quantum/keymap_extras/keymap_nordic.h @@ -13,7 +13,7 @@ #define NO_ACUT KC_EQL #define NO_AM KC_LBRC -#define NO_QUOT KC_RBRC +#define NO_QUOT KC_RBRC // this is the "umlaut" char on Nordic keyboards, Apple layout #define NO_AE KC_SCLN #define NO_OSLH KC_QUOT #define NO_APOS KC_NUHS From 245c9508bd6169d2feb398e99234103cc669efa7 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Fri, 2 Dec 2016 13:32:50 -0500 Subject: [PATCH 55/62] adds warnings to 4 keymaps --- keyboards/planck/keymaps/bone2planck/Makefile | 4 +++- keyboards/planck/keymaps/brandon/Makefile | 4 +++- keyboards/planck/keymaps/impossible/Makefile | 4 +++- keyboards/planck/keymaps/jeebak/Makefile | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/keyboards/planck/keymaps/bone2planck/Makefile b/keyboards/planck/keymaps/bone2planck/Makefile index 581e08cd02..cf2c31f0fb 100644 --- a/keyboards/planck/keymaps/bone2planck/Makefile +++ b/keyboards/planck/keymaps/bone2planck/Makefile @@ -1,4 +1,6 @@ - +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options # change to "no" to disable the options, or define them in the Makefile in diff --git a/keyboards/planck/keymaps/brandon/Makefile b/keyboards/planck/keymaps/brandon/Makefile index 581e08cd02..cf2c31f0fb 100644 --- a/keyboards/planck/keymaps/brandon/Makefile +++ b/keyboards/planck/keymaps/brandon/Makefile @@ -1,4 +1,6 @@ - +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options # change to "no" to disable the options, or define them in the Makefile in diff --git a/keyboards/planck/keymaps/impossible/Makefile b/keyboards/planck/keymaps/impossible/Makefile index 581e08cd02..cf2c31f0fb 100644 --- a/keyboards/planck/keymaps/impossible/Makefile +++ b/keyboards/planck/keymaps/impossible/Makefile @@ -1,4 +1,6 @@ - +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options # change to "no" to disable the options, or define them in the Makefile in diff --git a/keyboards/planck/keymaps/jeebak/Makefile b/keyboards/planck/keymaps/jeebak/Makefile index 581e08cd02..cf2c31f0fb 100644 --- a/keyboards/planck/keymaps/jeebak/Makefile +++ b/keyboards/planck/keymaps/jeebak/Makefile @@ -1,4 +1,6 @@ - +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options # change to "no" to disable the options, or define them in the Makefile in From cee0cf8a6eca8d2316dd75f39351f13132ff0257 Mon Sep 17 00:00:00 2001 From: cbbrowne Date: Fri, 2 Dec 2016 14:12:55 -0500 Subject: [PATCH 56/62] Adds warnings to Planck keymaps that exceed 0x7000 bytes in size #929 --- keyboards/planck/keymaps/jhenahan/Makefile | 4 +++- keyboards/planck/keymaps/joe/Makefile | 5 ++++- keyboards/planck/keymaps/leo/Makefile | 5 ++++- keyboards/planck/keymaps/lucas/Makefile | 5 ++++- keyboards/planck/keymaps/mollat/Makefile | 5 ++++- keyboards/planck/keymaps/nico/Makefile | 5 ++++- keyboards/planck/keymaps/premek/Makefile | 3 +++ keyboards/planck/keymaps/priyadi/Makefile | 3 +++ keyboards/planck/keymaps/pvc/Makefile | 5 ++++- keyboards/planck/keymaps/sgoodwin/Makefile | 5 ++++- keyboards/planck/keymaps/tak3over/Makefile | 5 ++++- keyboards/planck/keymaps/thermal_printer/Makefile | 3 +++ keyboards/planck/keymaps/vifon/Makefile | 3 +++ 13 files changed, 47 insertions(+), 9 deletions(-) diff --git a/keyboards/planck/keymaps/jhenahan/Makefile b/keyboards/planck/keymaps/jhenahan/Makefile index de01ad2404..83da2a7f89 100644 --- a/keyboards/planck/keymaps/jhenahan/Makefile +++ b/keyboards/planck/keymaps/jhenahan/Makefile @@ -1,4 +1,6 @@ - +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options # change to "no" to disable the options, or define them in the Makefile in diff --git a/keyboards/planck/keymaps/joe/Makefile b/keyboards/planck/keymaps/joe/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/joe/Makefile +++ b/keyboards/planck/keymaps/joe/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/leo/Makefile b/keyboards/planck/keymaps/leo/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/leo/Makefile +++ b/keyboards/planck/keymaps/leo/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/lucas/Makefile b/keyboards/planck/keymaps/lucas/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/lucas/Makefile +++ b/keyboards/planck/keymaps/lucas/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/mollat/Makefile b/keyboards/planck/keymaps/mollat/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/mollat/Makefile +++ b/keyboards/planck/keymaps/mollat/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/nico/Makefile b/keyboards/planck/keymaps/nico/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/nico/Makefile +++ b/keyboards/planck/keymaps/nico/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/premek/Makefile b/keyboards/planck/keymaps/premek/Makefile index 0f4953888d..b2ca419445 100644 --- a/keyboards/planck/keymaps/premek/Makefile +++ b/keyboards/planck/keymaps/premek/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options diff --git a/keyboards/planck/keymaps/priyadi/Makefile b/keyboards/planck/keymaps/priyadi/Makefile index aa211d2f05..f113f496c2 100644 --- a/keyboards/planck/keymaps/priyadi/Makefile +++ b/keyboards/planck/keymaps/priyadi/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options diff --git a/keyboards/planck/keymaps/pvc/Makefile b/keyboards/planck/keymaps/pvc/Makefile index b2ff961fa5..c92ca1bffa 100644 --- a/keyboards/planck/keymaps/pvc/Makefile +++ b/keyboards/planck/keymaps/pvc/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options # change to "no" to disable the options, or define them in the Makefile in @@ -21,4 +24,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/sgoodwin/Makefile b/keyboards/planck/keymaps/sgoodwin/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/sgoodwin/Makefile +++ b/keyboards/planck/keymaps/sgoodwin/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/tak3over/Makefile b/keyboards/planck/keymaps/tak3over/Makefile index 581e08cd02..b2ca419445 100644 --- a/keyboards/planck/keymaps/tak3over/Makefile +++ b/keyboards/planck/keymaps/tak3over/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options @@ -22,4 +25,4 @@ SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend ifndef QUANTUM_DIR include ../../../../Makefile -endif \ No newline at end of file +endif diff --git a/keyboards/planck/keymaps/thermal_printer/Makefile b/keyboards/planck/keymaps/thermal_printer/Makefile index 3d1d11877f..9477d1179a 100644 --- a/keyboards/planck/keymaps/thermal_printer/Makefile +++ b/keyboards/planck/keymaps/thermal_printer/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options diff --git a/keyboards/planck/keymaps/vifon/Makefile b/keyboards/planck/keymaps/vifon/Makefile index 838cb4e885..53660a2e76 100644 --- a/keyboards/planck/keymaps/vifon/Makefile +++ b/keyboards/planck/keymaps/vifon/Makefile @@ -1,3 +1,6 @@ +# Please remove if no longer applicable +$(warning THIS FILE MAY BE TOO LARGE FOR YOUR KEYBOARD) +$(warning Please disable some options in the Makefile to resolve) # Build Options From 044fa3ff856393d75a80fe6625b4a5682b81b76d Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:51:30 -0800 Subject: [PATCH 57/62] Connect the adafruit ble code to the lufa main loop There are now 3 potential locations to send HID reports: 1. USB 2. The bluefruit easy key 3. Adafruit BLE Generally speaking, if USB is connected then we should prefer to send the reports there; it is generally the best channel for this. The bluefruit module has no feedback about bluetooth connectivity so the code must speculatively send reports over both USB and bluetooth. The BLE module has connectivity feedback. In general we want to prefer to send HID reports over USB while connected there, even if BLE is connected. Except that it is convenient to force them over BLE while testing the implementation. This policy has been extracted out into a where_to_send function which returns a bitmask of which of the channels should be used. --- tmk_core/protocol/lufa/lufa.c | 82 ++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 39d4824b6b..ee2552c190 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -52,6 +52,7 @@ #include "descriptor.h" #include "lufa.h" #include "quantum.h" +#include #ifdef NKRO_ENABLE #include "keycode_config.h" @@ -67,13 +68,16 @@ #ifdef BLUETOOTH_ENABLE #include "bluetooth.h" #endif +#ifdef ADAFRUIT_BLE_ENABLE + #include "adafruit_ble.h" +#endif #ifdef VIRTSER_ENABLE #include "virtser.h" #endif #if (defined(RGB_MIDI) | defined(RGBLIGHT_ANIMATIONS)) & defined(RGBLIGHT_ENABLE) - #include "rgblight.h" + #include "rgblight.h" #endif #ifdef MIDI_ENABLE @@ -297,7 +301,9 @@ void EVENT_USB_Device_WakeUp() #ifdef CONSOLE_ENABLE static bool console_flush = false; #define CONSOLE_FLUSH_SET(b) do { \ - uint8_t sreg = SREG; cli(); console_flush = b; SREG = sreg; \ + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {\ + console_flush = b; \ + } \ } while (0) // called every 1ms @@ -501,9 +507,35 @@ static uint8_t keyboard_leds(void) return keyboard_led_stats; } +#define SendToUSB 1 +#define SendToBT 2 +#define SendToBLE 4 + +static inline uint8_t where_to_send(void) { +#ifdef ADAFRUIT_BLE_ENABLE +#if 0 + if (adafruit_ble_is_connected()) { + // For testing, send to BLE as a priority + return SendToBLE; + } +#endif + + // This is the real policy + if (USB_DeviceState != DEVICE_STATE_Configured) { + if (adafruit_ble_is_connected()) { + return SendToBLE; + } + } +#endif + return ((USB_DeviceState == DEVICE_STATE_Configured) ? SendToUSB : 0) +#ifdef BLUETOOTH_ENABLE + || SendToBT +#endif + ; +} + static void send_keyboard(report_keyboard_t *report) { - #ifdef BLUETOOTH_ENABLE bluefruit_serial_send(0xFD); for (uint8_t i = 0; i < KEYBOARD_EPSIZE; i++) { @@ -512,9 +544,17 @@ static void send_keyboard(report_keyboard_t *report) #endif uint8_t timeout = 255; + uint8_t where = where_to_send(); - if (USB_DeviceState != DEVICE_STATE_Configured) - return; +#ifdef ADAFRUIT_BLE_ENABLE + if (where & SendToBLE) { + adafruit_ble_send_keys(report->mods, report->keys, sizeof(report->keys)); + } +#endif + + if (!(where & SendToUSB)) { + return; + } /* Select the Keyboard Report Endpoint */ #ifdef NKRO_ENABLE @@ -567,8 +607,17 @@ static void send_mouse(report_mouse_t *report) uint8_t timeout = 255; - if (USB_DeviceState != DEVICE_STATE_Configured) - return; + uint8_t where = where_to_send(); + +#ifdef ADAFRUIT_BLE_ENABLE + if (where & SendToBLE) { + // FIXME: mouse buttons + adafruit_ble_send_mouse_move(report->x, report->y, report->v, report->h); + } +#endif + if (!(where & SendToUSB)) { + return; + } /* Select the Mouse Report Endpoint */ Endpoint_SelectEndpoint(MOUSE_IN_EPNUM); @@ -626,9 +675,16 @@ static void send_consumer(uint16_t data) #endif uint8_t timeout = 255; + uint8_t where = where_to_send(); - if (USB_DeviceState != DEVICE_STATE_Configured) - return; +#ifdef ADAFRUIT_BLE_ENABLE + if (where & SendToBLE) { + adafruit_ble_send_consumer_key(data, 0); + } +#endif + if (!(where & SendToUSB)) { + return; + } report_extra_t r = { .report_id = REPORT_ID_CONSUMER, @@ -1038,7 +1094,7 @@ int main(void) print("Keyboard start.\n"); while (1) { - #ifndef BLUETOOTH_ENABLE + #if !defined(BLUETOOTH_ENABLE) && !defined(ADAFRUIT_BLE_ENABLE) while (USB_DeviceState == DEVICE_STATE_Suspended) { print("[s]"); suspend_power_down(); @@ -1054,11 +1110,15 @@ int main(void) midi_device_process(&midi_device); // MIDI_Task(); #endif - + #if defined(RGBLIGHT_ANIMATIONS) & defined(RGBLIGHT_ENABLE) rgblight_task(); #endif +#ifdef ADAFRUIT_BLE_ENABLE + adafruit_ble_task(); +#endif + #ifdef VIRTSER_ENABLE virtser_task(); CDC_Device_USBTask(&cdc_device); From d639e08a3131892c608760df4e3806d843a91176 Mon Sep 17 00:00:00 2001 From: ofples Date: Sat, 3 Dec 2016 13:05:02 +0200 Subject: [PATCH 58/62] Refactored and improved ps2 mouse feature --- tmk_core/protocol/ps2_mouse.c | 373 ++++++++++++++++++++-------------- tmk_core/protocol/ps2_mouse.h | 81 +++++++- 2 files changed, 288 insertions(+), 166 deletions(-) diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index 82f6966e8e..f247ba8dca 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c @@ -18,63 +18,99 @@ along with this program. If not, see . #include #include #include -#include "ps2.h" #include "ps2_mouse.h" -#include "report.h" #include "host.h" #include "timer.h" #include "print.h" +#include "report.h" #include "debug.h" +#include "ps2.h" -#ifndef PS2_INIT_DELAY -#define PS2_INIT_DELAY 1000 -#endif +/* ============================= MACROS ============================ */ + +#define PS2_MOUSE_SEND(command, message) \ +do { \ + uint8_t rcv = ps2_host_send(command); \ + if (debug_mouse) { \ + print((message)); \ + xprintf(" command: %X, result: %X, error: %X \n", command, rcv, ps2_error); \ + } \ +} while(0) + +#define PS2_MOUSE_SEND_SAFE(command, message) \ +do { \ + if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ + ps2_mouse_disable_data_reporting(); \ + } \ + PS2_MOUSE_SEND(command, message); \ + if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ + ps2_mouse_enable_data_reporting(); \ + } \ +} while(0) + +#define PS2_MOUSE_SET_SAFE(command, value, message) \ +do { \ + if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ + ps2_mouse_disable_data_reporting(); \ + } \ + PS2_MOUSE_SEND(command, message); \ + PS2_MOUSE_SEND(value, "Sending value"); \ + if (PS2_MOUSE_STREAM_MODE == ps2_mouse_mode) { \ + ps2_mouse_enable_data_reporting(); \ + } \ +} while(0) + +#define PS2_MOUSE_RECEIVE(message) \ +do { \ + uint8_t rcv = ps2_host_recv_response(); \ + if (debug_mouse) { \ + print((message)); \ + xprintf(" result: %X, error: %X \n", rcv, ps2_error); \ + } \ +} while(0) + +static enum ps2_mouse_mode_e { + PS2_MOUSE_STREAM_MODE, + PS2_MOUSE_REMOTE_MODE, +} ps2_mouse_mode = PS2_MOUSE_STREAM_MODE; static report_mouse_t mouse_report = {}; +static inline void ps2_mouse_print_report(report_mouse_t *mouse_report); +static inline void ps2_mouse_convert_report_to_hid(report_mouse_t *mouse_report); +static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report); +static inline void ps2_mouse_enable_scrolling(void); +static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report); -static void print_usb_data(void); - +/* ============================= IMPLEMENTATION ============================ */ /* supports only 3 button mouse at this time */ -uint8_t ps2_mouse_init(void) { - uint8_t rcv; - +void ps2_mouse_init(void) { ps2_host_init(); - _delay_ms(PS2_INIT_DELAY); // wait for powering up + _delay_ms(1000); // wait for powering up - // send Reset - rcv = ps2_host_send(0xFF); - print("ps2_mouse_init: send Reset: "); - phex(rcv); phex(ps2_error); print("\n"); + PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset"); - // read completion code of BAT - rcv = ps2_host_recv_response(); - print("ps2_mouse_init: read BAT: "); - phex(rcv); phex(ps2_error); print("\n"); + PS2_MOUSE_RECEIVE("ps2_mouse_init: read BAT"); + PS2_MOUSE_RECEIVE("ps2_mouse_init: read DevID"); - // read Device ID - rcv = ps2_host_recv_response(); - print("ps2_mouse_init: read DevID: "); - phex(rcv); phex(ps2_error); print("\n"); +#ifdef PS2_MOUSE_USE_REMOTE_MODE + ps2_mouse_set_remote_mode(); +#else + ps2_mouse_enable_data_reporting(); +#endif - // send Set Remote mode - rcv = ps2_host_send(0xF0); - print("ps2_mouse_init: send 0xF0: "); - phex(rcv); phex(ps2_error); print("\n"); +#ifdef PS2_MOUSE_ENABLE_SCROLLING + ps2_mouse_enable_scrolling(); +#endif - return 0; +#ifdef PS2_MOUSE_USE_2_1_SCALING + ps2_mouse_set_scaling_2_1(); +#endif } -#define X_IS_NEG (mouse_report.buttons & (1<buttons & (1<buttons & (1<buttons & (1<buttons & (1<x = X_IS_NEG ? + ((!X_IS_OVF && -127 <= mouse_report->x && mouse_report->x <= -1) ? mouse_report->x : -127) : + ((!X_IS_OVF && 0 <= mouse_report->x && mouse_report->x <= 127) ? mouse_report->x : 127); + mouse_report->y = Y_IS_NEG ? + ((!Y_IS_OVF && -127 <= mouse_report->y && mouse_report->y <= -1) ? mouse_report->y : -127) : + ((!Y_IS_OVF && 0 <= mouse_report->y && mouse_report->y <= 127) ? mouse_report->y : 127); + + // remove sign and overflow flags + mouse_report->buttons &= PS2_MOUSE_BTN_MASK; + + // invert coordinate of y to conform to USB HID mouse + mouse_report->y = -mouse_report->y; +} + +static inline void ps2_mouse_clear_report(report_mouse_t *mouse_report) { + mouse_report->x = 0; + mouse_report->y = 0; + mouse_report->v = 0; + mouse_report->h = 0; + mouse_report->buttons = 0; +} + +static inline void ps2_mouse_print_report(report_mouse_t *mouse_report) { if (!debug_mouse) return; - print("ps2_mouse usb: ["); - phex(mouse_report.buttons); print("|"); - print_hex8((uint8_t)mouse_report.x); print(" "); - print_hex8((uint8_t)mouse_report.y); print(" "); - print_hex8((uint8_t)mouse_report.v); print(" "); - print_hex8((uint8_t)mouse_report.h); print("]\n"); + print("ps2_mouse: ["); + phex(mouse_report->buttons); print("|"); + print_hex8((uint8_t)mouse_report->x); print(" "); + print_hex8((uint8_t)mouse_report->y); print(" "); + print_hex8((uint8_t)mouse_report->v); print(" "); + print_hex8((uint8_t)mouse_report->h); print("]\n"); } +static inline void ps2_mouse_enable_scrolling(void) { + PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Initiaing scroll wheel enable: Set sample rate"); + PS2_MOUSE_SEND(200, "200"); + PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate"); + PS2_MOUSE_SEND(100, "100"); + PS2_MOUSE_SEND(PS2_MOUSE_SET_SAMPLE_RATE, "Set sample rate"); + PS2_MOUSE_SEND(80, "80"); + PS2_MOUSE_SEND(PS2_MOUSE_GET_DEVICE_ID, "Finished enabling scroll wheel"); + _delay_ms(20); +} -/* PS/2 Mouse Synopsis - * http://www.computer-engineering.org/ps2mouse/ - * - * Command: - * 0xFF: Reset - * 0xF6: Set Defaults Sampling; rate=100, resolution=4cnt/mm, scaling=1:1, reporting=disabled - * 0xF5: Disable Data Reporting - * 0xF4: Enable Data Reporting - * 0xF3: Set Sample Rate - * 0xF2: Get Device ID - * 0xF0: Set Remote Mode - * 0xEB: Read Data - * 0xEA: Set Stream Mode - * 0xE9: Status Request - * 0xE8: Set Resolution - * 0xE7: Set Scaling 2:1 - * 0xE6: Set Scaling 1:1 - * - * Mode: - * Stream Mode: devices sends the data when it changs its state - * Remote Mode: host polls the data periodically - * - * This code uses Remote Mode and polls the data with Read Data(0xEB). - * - * Data format: - * byte|7 6 5 4 3 2 1 0 - * ----+-------------------------------------------------------------- - * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left - * 1| X movement - * 2| Y movement - */ +#define PRESS_SCROLL_BUTTONS mouse_report->buttons |= (PS2_MOUSE_SCROLL_BTN_MASK) +#define RELEASE_SCROLL_BUTTONS mouse_report->buttons &= ~(PS2_MOUSE_SCROLL_BTN_MASK) +static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) { + static enum { + SCROLL_NONE, + SCROLL_BTN, + SCROLL_SENT, + } scroll_state = SCROLL_NONE; + static uint16_t scroll_button_time = 0; + + if (PS2_MOUSE_SCROLL_BTN_MASK == (mouse_report->buttons & (PS2_MOUSE_SCROLL_BTN_MASK))) { + // All scroll buttons are pressed + + if (scroll_state == SCROLL_NONE) { + scroll_button_time = timer_read(); + scroll_state = SCROLL_BTN; + } + + // If the mouse has moved, update the report to scroll instead of move the mouse + if (mouse_report->x || mouse_report->y) { + scroll_state = SCROLL_SENT; + mouse_report->v = -mouse_report->y/(PS2_MOUSE_SCROLL_DIVISOR_V); + mouse_report->h = mouse_report->x/(PS2_MOUSE_SCROLL_DIVISOR_H); + mouse_report->x = 0; + mouse_report->y = 0; + } + } else if (0 == (PS2_MOUSE_SCROLL_BTN_MASK & mouse_report->buttons)) { + // None of the scroll buttons are pressed + +#if PS2_MOUSE_SCROLL_BTN_SEND + if (scroll_state == SCROLL_BTN + && timer_elapsed(scroll_button_time) < PS2_MOUSE_SCROLL_BTN_SEND) { + PRESS_SCROLL_BUTTONS; + host_mouse_send(mouse_report); + _delay_ms(100); + RELEASE_SCROLL_BUTTONS; + } +#endif + scroll_state = SCROLL_NONE; + } + + RELEASE_SCROLL_BUTTONS; +} \ No newline at end of file diff --git a/tmk_core/protocol/ps2_mouse.h b/tmk_core/protocol/ps2_mouse.h index 27d9790d43..3b498059dc 100644 --- a/tmk_core/protocol/ps2_mouse.h +++ b/tmk_core/protocol/ps2_mouse.h @@ -20,15 +20,13 @@ along with this program. If not, see . #include -#define PS2_MOUSE_READ_DATA 0xEB - /* * Data format: * byte|7 6 5 4 3 2 1 0 - * ----+-------------------------------------------------------------- - * 0|Yovflw Xovflw Ysign Xsign 1 Middle Right Left - * 1| X movement(0-255) - * 2| Y movement(0-255) + * ----+---------------------------------------------------------------- + * 0|[Yovflw][Xovflw][Ysign ][Xsign ][ 1 ][Middle][Right ][Left ] + * 1|[ X movement(0-255) ] + * 2|[ Y movement(0-255) ] */ #define PS2_MOUSE_BTN_MASK 0x07 #define PS2_MOUSE_BTN_LEFT 0 @@ -39,10 +37,6 @@ along with this program. If not, see . #define PS2_MOUSE_X_OVFLW 6 #define PS2_MOUSE_Y_OVFLW 7 - -/* - * Scroll by mouse move with pressing button - */ /* mouse button to start scrolling; set 0 to disable scroll */ #ifndef PS2_MOUSE_SCROLL_BTN_MASK #define PS2_MOUSE_SCROLL_BTN_MASK (1<. #ifndef PS2_MOUSE_SCROLL_DIVISOR_H #define PS2_MOUSE_SCROLL_DIVISOR_H 2 #endif +/* multiply reported mouse values by these */ +#ifndef PS2_MOUSE_X_MULTIPLIER +#define PS2_MOUSE_X_MULTIPLIER 1 +#endif +#ifndef PS2_MOUSE_Y_MULTIPLIER +#define PS2_MOUSE_Y_MULTIPLIER 1 +#endif +#ifndef PS2_MOUSE_V_MULTIPLIER +#define PS2_MOUSE_V_MULTIPLIER 1 +#endif +/* For some mice this will need to be 0x0F */ +#ifndef PS2_MOUSE_SCROLL_MASK +#define PS2_MOUSE_SCROLL_MASK 0xFF +#endif +enum ps2_mouse_command_e { + PS2_MOUSE_RESET = 0xFF, + PS2_MOUSE_RESEND = 0xFE, + PS2_MOSUE_SET_DEFAULTS = 0xF6, + PS2_MOUSE_DISABLE_DATA_REPORTING = 0xF5, + PS2_MOUSE_ENABLE_DATA_REPORTING = 0xF4, + PS2_MOUSE_SET_SAMPLE_RATE = 0xF3, + PS2_MOUSE_GET_DEVICE_ID = 0xF2, + PS2_MOUSE_SET_REMOTE_MODE = 0xF0, + PS2_MOUSE_SET_WRAP_MODE = 0xEC, + PS2_MOUSE_READ_DATA = 0xEB, + PS2_MOUSE_SET_STREAM_MODE = 0xEA, + PS2_MOUSE_STATUS_REQUEST = 0xE9, + PS2_MOUSE_SET_RESOLUTION = 0xE8, + PS2_MOUSE_SET_SCALING_2_1 = 0xE7, + PS2_MOUSE_SET_SCALING_1_1 = 0xE6, +}; + +typedef enum ps2_mouse_resolution_e { + PS2_MOUSE_1_COUNT_MM, + PS2_MOUSE_2_COUNT_MM, + PS2_MOUSE_4_COUNT_MM, + PS2_MOUSE_8_COUNT_MM, +} ps2_mouse_resolution_t; + +typedef enum ps2_mouse_sample_rate_e { + PS2_MOUSE_10_SAMPLES_SEC = 10, + PS2_MOUSE_20_SAMPLES_SEC = 20, + PS2_MOUSE_40_SAMPLES_SEC = 40, + PS2_MOUSE_60_SAMPLES_SEC = 60, + PS2_MOUSE_80_SAMPLES_SEC = 80, + PS2_MOUSE_100_SAMPLES_SEC = 100, + PS2_MOUSE_200_SAMPLES_SEC = 200, +} ps2_mouse_sample_rate_t; + +void ps2_mouse_init(void); -uint8_t ps2_mouse_init(void); void ps2_mouse_task(void); +void ps2_mouse_disable_data_reporting(void); + +void ps2_mouse_enable_data_reporting(void); + +void ps2_mouse_set_remote_mode(void); + +void ps2_mouse_set_stream_mode(void); + +void ps2_mouse_set_scaling_2_1(void); + +void ps2_mouse_set_scaling_1_1(void); + +void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution); + +void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate); + #endif From 9f41544e1de12b92bdc15538ec7a9e66a4af0c43 Mon Sep 17 00:00:00 2001 From: Ofer Plesser Date: Sat, 3 Dec 2016 13:09:42 +0200 Subject: [PATCH 59/62] Added back PS2_MOUSE_INIT_DELAY define --- tmk_core/protocol/ps2_mouse.c | 2 +- tmk_core/protocol/ps2_mouse.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index f247ba8dca..04c15dd4fd 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c @@ -283,4 +283,4 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report) { } RELEASE_SCROLL_BUTTONS; -} \ No newline at end of file +} diff --git a/tmk_core/protocol/ps2_mouse.h b/tmk_core/protocol/ps2_mouse.h index 3b498059dc..e11c705fc6 100644 --- a/tmk_core/protocol/ps2_mouse.h +++ b/tmk_core/protocol/ps2_mouse.h @@ -66,6 +66,9 @@ along with this program. If not, see . #ifndef PS2_MOUSE_SCROLL_MASK #define PS2_MOUSE_SCROLL_MASK 0xFF #endif +#ifndef PS2_MOUSE_INIT_DELAY +#define PS2_MOUSE_INIT_DELAY 1000 +#endif enum ps2_mouse_command_e { PS2_MOUSE_RESET = 0xFF, From 8e2732edf3c457d98dd4526d88dad26786cb3db9 Mon Sep 17 00:00:00 2001 From: Ofer Plesser Date: Sat, 3 Dec 2016 13:11:37 +0200 Subject: [PATCH 60/62] Updated ps2 mouse documentation in readme --- readme.md | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index be15108329..1f06fe79fa 100644 --- a/readme.md +++ b/readme.md @@ -1191,7 +1191,7 @@ Please note the USB port can only supply a limited amount of power to the keyboa Its possible to hook up a PS/2 mouse (for example touchpads or trackpoints) to your keyboard as a composite device. -Then, decide whether to use USART (best), interrupts (better) or busywait (not recommended), and enable the relevant option. +There are three available modes for hooking up PS/2 devices: USART (best), interrupts (better) or busywait (not recommended). ### Busywait version @@ -1316,6 +1316,116 @@ In your keyboard config.h: #endif ``` +### Additional Settings + +#### PS/2 mouse features + +These enable settings supported by the PS/2 mouse protocol: http://www.computer-engineering.org/ps2mouse/ + +``` +/* Use remote mode instead of the default stream mode (see link) */ +#define PS2_MOUSE_USE_REMOTE_MODE + +/* Enable the scrollwheel or scroll gesture on your mouse or touchpad */ +#define PS2_MOUSE_ENABLE_SCROLLING + +/* Some mice will need a scroll mask to be configured. The default is 0xFF. */ +#define PS2_MOUSE_SCROLL_MASK 0x0F + +/* Applies a transformation to the movement before sending to the host (see link) */ +#define PS2_MOUSE_USE_2_1_SCALING + +/* The time to wait after initializing the ps2 host */ +#define PS2_MOUSE_INIT_DELAY 1000 /* Default */ +``` + +You can also call the following functions from ps2_mouse.h + +``` +void ps2_mouse_disable_data_reporting(void); + +void ps2_mouse_enable_data_reporting(void); + +void ps2_mouse_set_remote_mode(void); + +void ps2_mouse_set_stream_mode(void); + +void ps2_mouse_set_scaling_2_1(void); + +void ps2_mouse_set_scaling_1_1(void); + +void ps2_mouse_set_resolution(ps2_mouse_resolution_t resolution); + +void ps2_mouse_set_sample_rate(ps2_mouse_sample_rate_t sample_rate); +``` + +#### Fine control + +Use the following defines to change the sensitivity and speed of the mouse. +Note: you can also use `ps2_mouse_set_resolution` for the same effect (not supported on most touchpads). + +``` +#define PS2_MOUSE_X_MULTIPLIER 3 +#define PS2_MOUSE_Y_MULTIPLIER 3 +#define PS2_MOUSE_V_MULTIPLIER 1 +``` + +#### Scroll button + +If you're using a trackpoint, you will likely want to be able to use it for scrolling. +Its possible to enable a "scroll button/s" that when pressed will cause the mouse to scroll instead of moving. +To enable the feature, you must set a scroll button mask as follows: + +``` +#define PS2_MOUSE_SCROLL_BTN_MASK (1< Date: Sat, 3 Dec 2016 13:41:56 +0200 Subject: [PATCH 61/62] Forgot to use define in delay instead of hardcoded number --- tmk_core/protocol/ps2_mouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index 04c15dd4fd..af971dd497 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c @@ -88,7 +88,7 @@ static inline void ps2_mouse_scroll_button_task(report_mouse_t *mouse_report); void ps2_mouse_init(void) { ps2_host_init(); - _delay_ms(1000); // wait for powering up + _delay_ms(PS2_MOUSE_INIT_DELAY); // wait for powering up PS2_MOUSE_SEND(PS2_MOUSE_RESET, "ps2_mouse_init: sending reset"); From f39e1b5dfe7552f01dbc6eab95c268f41a9d98e2 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sat, 3 Dec 2016 14:36:39 -0500 Subject: [PATCH 62/62] cleans-up formatting of readme --- readme.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1f06fe79fa..b618334dc3 100644 --- a/readme.md +++ b/readme.md @@ -1442,13 +1442,16 @@ what things are (and likely aren't) too risky. flash the keyboard, leaving it in DFU mode. - To this end, note that the maximum .hex file size on Planck is 7000h (28672 decimal) -```Linking: .build/planck_rev4_cbbrowne.elf [OK] + +``` +Linking: .build/planck_rev4_cbbrowne.elf [OK] Creating load file for Flash: .build/planck_rev4_cbbrowne.hex [OK] Size after: text data bss dec hex filename 0 22396 0 22396 577c planck_rev4_cbbrowne.hex ``` + - The above file is of size 22396/577ch, which is less than 28672/7000h - As long as you have a suitable alternative .hex file around, you