summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build_keyboard.mk4
-rw-r--r--keyboards/ergodox/ez/keymaps/steno/Makefile3
-rw-r--r--keyboards/ergodox/ez/keymaps/steno/keymap.c324
-rw-r--r--keyboards/ergodox/ez/keymaps/steno/readme.md92
-rw-r--r--tmk_core/common/virtser.h10
-rw-r--r--tmk_core/protocol/lufa.mk4
-rw-r--r--tmk_core/protocol/lufa/descriptor.c112
-rw-r--r--tmk_core/protocol/lufa/descriptor.h43
-rw-r--r--tmk_core/protocol/lufa/lufa.c107
9 files changed, 695 insertions, 4 deletions
diff --git a/build_keyboard.mk b/build_keyboard.mk
index a2a2871e6..f843572f6 100644
--- a/build_keyboard.mk
+++ b/build_keyboard.mk
@@ -138,6 +138,10 @@ ifeq ($(strip $(MIDI_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/process_keycode/process_midi.c
endif
+ifeq ($(strip $(VIRTSER_ENABLE)), yes)
+ OPT_DEFS += -DVIRTSER_ENABLE
+endif
+
ifeq ($(strip $(AUDIO_ENABLE)), yes)
OPT_DEFS += -DAUDIO_ENABLE
SRC += $(QUANTUM_DIR)/process_keycode/process_music.c
diff --git a/keyboards/ergodox/ez/keymaps/steno/Makefile b/keyboards/ergodox/ez/keymaps/steno/Makefile
new file mode 100644
index 000000000..b6fb9b1a8
--- /dev/null
+++ b/keyboards/ergodox/ez/keymaps/steno/Makefile
@@ -0,0 +1,3 @@
+VIRTSER_ENABLE = yes
+# Not enough interupts, so something has to go
+MOUSEKEY_ENABLE = no
diff --git a/keyboards/ergodox/ez/keymaps/steno/keymap.c b/keyboards/ergodox/ez/keymaps/steno/keymap.c
new file mode 100644
index 000000000..3e9830905
--- /dev/null
+++ b/keyboards/ergodox/ez/keymaps/steno/keymap.c
@@ -0,0 +1,324 @@
+#include "ergodox.h"
+#include "debug.h"
+#include "action_layer.h"
+#include "sendchar.h"
+#include "virtser.h"
+
+#define BASE 0 // default layer
+#define SYMB 1 // symbols
+#define MDIA 2 // media keys
+#define TXBOLT 3 // TxBolt Steno Virtual Serial
+#define TXBOLT2 4 // TxBolt Steno Virtual Serial Alternative Layout
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+/* Keymap 0: Basic layer
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | = | 1 | 2 | 3 | 4 | 5 | LEFT | | RIGHT| 6 | 7 | 8 | 9 | 0 | - |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | Del | Q | W | E | R | T | L1 | | TX | Y | U | I | O | P | \ |
+ * |--------+------+------+------+------+------| | | BOLT |------+------+------+------+------+--------|
+ * | BkSp | A | S | D | F | G |------| |------| H | J | K | L |; / L2|' / Cmd |
+ * |--------+------+------+------+------+------| Hyper| | Meh |------+------+------+------+------+--------|
+ * | LShift |Z/Ctrl| X | C | V | B | | | | N | M | , | . |//Ctrl| RShift |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * |Grv/L1| '" |AltShf| Left | Right| | Up | Down | [ | ] | ~L1 |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | App | LGui | | Alt |Ctrl/Esc|
+ * ,------|------|------| |------+--------+------.
+ * | | | Home | | PgUp | | |
+ * | Space|Backsp|------| |------| Tab |Enter |
+ * | |ace | End | | PgDn | | |
+ * `--------------------' `----------------------'
+ */
+// If it accepts an argument (i.e, is a function), it doesn't need KC_.
+// Otherwise, it needs KC_*
+[BASE] = KEYMAP( // layer 0 : default
+ // left hand
+ KC_EQL, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LEFT,
+ KC_DELT, KC_Q, KC_W, KC_E, KC_R, KC_T, TG(SYMB),
+ KC_BSPC, KC_A, KC_S, KC_D, KC_F, KC_G,
+ KC_LSFT, CTL_T(KC_Z), KC_X, KC_C, KC_V, KC_B, ALL_T(KC_NO),
+ LT(SYMB,KC_GRV),KC_QUOT, LALT(KC_LSFT), KC_LEFT,KC_RGHT,
+ ALT_T(KC_APP), KC_LGUI,
+ KC_HOME,
+ KC_SPC,KC_BSPC,KC_END,
+ // right hand
+ KC_RGHT, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
+ TG(TXBOLT), KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS,
+ KC_H, KC_J, KC_K, KC_L, LT(MDIA, KC_SCLN),GUI_T(KC_QUOT),
+ MEH_T(KC_NO),KC_N, KC_M, KC_COMM,KC_DOT, CTL_T(KC_SLSH), KC_RSFT,
+ KC_UP, KC_DOWN,KC_LBRC,KC_RBRC, KC_FN1,
+ KC_LALT, CTL_T(KC_ESC),
+ KC_PGUP,
+ KC_PGDN,KC_TAB, KC_ENT
+ ),
+/* Keymap 1: Symbol Layer
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * |Version | F1 | F2 | F3 | F4 | F5 | | | | F6 | F7 | F8 | F9 | F10 | F11 |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | ! | @ | { | } | | | | | | Up | 7 | 8 | 9 | * | F12 |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | # | $ | ( | ) | ` |------| |------| Down | 4 | 5 | 6 | + | |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | % | ^ | [ | ] | ~ | | | | & | 1 | 2 | 3 | \ | |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | | | | | . | 0 | = | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | | |
+ * | | |------| |------| | |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+// SYMBOLS
+[SYMB] = KEYMAP(
+ // left hand
+ M(0), KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRNS,
+ KC_TRNS,KC_EXLM,KC_AT, KC_LCBR,KC_RCBR,KC_PIPE,KC_TRNS,
+ KC_TRNS,KC_HASH,KC_DLR, KC_LPRN,KC_RPRN,KC_GRV,
+ KC_TRNS,KC_PERC,KC_CIRC,KC_LBRC,KC_RBRC,KC_TILD,KC_TRNS,
+ KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,KC_TRNS,
+ KC_TRNS,KC_TRNS,
+ KC_TRNS,
+ KC_TRNS,KC_TRNS,KC_TRNS,
+ // right hand
+ KC_TRNS, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11,
+ KC_TRNS, KC_UP, KC_7, KC_8, KC_9, KC_ASTR, KC_F12,
+ KC_DOWN, KC_4, KC_5, KC_6, KC_PLUS, KC_TRNS,
+ KC_TRNS, KC_AMPR, KC_1, KC_2, KC_3, KC_BSLS, KC_TRNS,
+ KC_TRNS,KC_DOT, KC_0, KC_EQL, KC_TRNS,
+ KC_TRNS, KC_TRNS,
+ KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS
+),
+/* Keymap 2: Media and mouse keys
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | RESET | | | | | | | | | | | | | | |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | | | MsUp | | | | | | | | | | | |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | |MsLeft|MsDown|MsRght| |------| |------| | | | | | Play |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | | | | | | | | | | | Prev | Next | | |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | Lclk | Rclk | |VolUp |VolDn | Mute | | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | |Brwser|
+ * | | |------| |------| |Back |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+// MEDIA AND MOUSE
+[MDIA] = KEYMAP(
+ RESET, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_U, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN1, KC_BTN2,
+ KC_TRNS, KC_TRNS,
+ KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS,
+ // right hand
+ 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, KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MPLY,
+ KC_TRNS, KC_TRNS, KC_TRNS, KC_MPRV, KC_MNXT, KC_TRNS, KC_TRNS,
+ KC_VOLU, KC_VOLD, KC_MUTE, KC_TRNS, KC_TRNS,
+ KC_TRNS, KC_TRNS,
+ KC_TRNS,
+ KC_TRNS, KC_TRNS, KC_WBAK
+),
+// TxBolt Codes
+#define Sl 0b00000001
+#define Tl 0b00000010
+#define Kl 0b00000100
+#define Pl 0b00001000
+#define Wl 0b00010000
+#define Hl 0b00100000
+#define Rl 0b01000001
+#define Al 0b01000010
+#define Ol 0b01000100
+#define X 0b01001000
+#define Er 0b01010000
+#define Ur 0b01100000
+#define Fr 0b10000001
+#define Rr 0b10000010
+#define Pr 0b10000100
+#define Br 0b10001000
+#define Lr 0b10010000
+#define Gr 0b10100000
+#define Tr 0b11000001
+#define Sr 0b11000010
+#define Dr 0b11000100
+#define Zr 0b11001000
+#define NM 0b11010000
+#define GRPMASK 0b11000000
+#define GRP0 0b00000000
+#define GRP1 0b01000000
+#define GRP2 0b10000000
+#define GRP3 0b11000000
+/* Keymap 3: TxBolt (Serial)
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | BKSPC | | | | | | | | | | | | | | |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | # | # | # | # | # | | | | # | # | # | # | # | # |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | S | T | P | H | * |------| |------| * | F | P | L | T | D |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | S | K | W | R | * | | | | * | R | B | G | S | Z |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | | | | | | | | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | | |
+ * | A | O |------| |------| E | U |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+// TxBolt over Serial
+[TXBOLT] = KEYMAP(
+ KC_BSPC, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_NO, M(NM), M(NM), M(NM), M(NM), M(NM), KC_NO,
+ KC_NO, M(Sl), M(Tl), M(Pl), M(Hl), M(X),
+ KC_NO, M(Sl), M(Kl), M(Wl), M(Rl), M(X), KC_NO,
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_NO, KC_NO,
+ KC_NO,
+ M(Al), M(Ol), KC_NO,
+ // right hand
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_TRNS, M(NM), M(NM), M(NM), M(NM), M(NM), M(NM),
+ M(X), M(Fr), M(Pr), M(Lr), M(Tr), M(Dr),
+ KC_NO, M(X), M(Rr), M(Br), M(Gr), M(Sr), M(Zr),
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_NO, KC_NO,
+ KC_NO,
+ KC_NO, M(Er), M(Ur)
+),
+/* Keymap 4: TxBolt (Serial) Alternative
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | | # | # | # | # | # | | | | # | # | # | # | # | # |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | S | T | P | H | * | | | | * | F | P | L | T | D |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | S | K | W | R | * |------| |------| * | R | B | G | S | Z |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | | | | | | | | | | | | | | |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | A | O | | E | U | | | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | | |
+ * | | |------| |------| | |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+// TxBolt over Serial
+[TXBOLT2] = KEYMAP(
+ KC_NO, M(NM), M(NM), M(NM), M(NM), M(NM), KC_NO,
+ KC_NO, M(Sl), M(Tl), M(Pl), M(Hl), M(X), KC_NO,
+ KC_NO, M(Sl), M(Kl), M(Wl), M(Rl), M(X),
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_NO, KC_NO, KC_NO, M(Al), M(Ol),
+ KC_NO, KC_NO,
+ KC_NO,
+ KC_NO, KC_NO, KC_NO,
+ // right hand
+ KC_NO, M(NM), M(NM), M(NM), M(NM), M(NM), M(NM),
+ KC_TRNS, M(X), M(Fr), M(Pr), M(Lr), M(Tr), M(Dr),
+ M(X), M(Rr), M(Br), M(Gr), M(Sr), M(Zr),
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ M(Er), M(Ur), KC_NO, KC_NO, KC_NO,
+ KC_NO, KC_NO,
+ KC_NO,
+ KC_NO, KC_NO, KC_NO
+),
+};
+
+const uint16_t PROGMEM fn_actions[] = {
+ [1] = ACTION_LAYER_TAP_TOGGLE(SYMB) // FN1 - Momentary Layer 1 (Symbols)
+};
+
+uint8_t chord[4] = {0,0,0,0};
+uint8_t pressed_count = 0;
+
+void send_chord(void)
+{
+ for(uint8_t i = 0; i < 4; i++)
+ {
+ if(chord[i])
+ virtser_send(chord[i]);
+ }
+ virtser_send(0);
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record)
+{
+ // We need to track keypresses in all modes, in case the user
+ // changes mode whilst pressing other keys.
+ if (record->event.pressed)
+ pressed_count++;
+ else
+ pressed_count--;
+ return true;
+}
+
+const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
+{
+ // MACRODOWN only works in this function
+
+ if (record->event.pressed) {
+ uint8_t grp = (id & GRPMASK) >> 6;
+ chord[grp] |= id;
+ }
+ else {
+ if (pressed_count == 0) {
+ send_chord();
+ chord[0] = chord[1] = chord[2] = chord[3] = 0;
+ }
+ }
+ 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) {
+
+ 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) {
+ // TODO: Make this relevant to the ErgoDox EZ.
+ case 1:
+ ergodox_right_led_1_on();
+ break;
+ case 2:
+ ergodox_right_led_2_on();
+ break;
+ default:
+ // none
+ break;
+ }
+
+};
diff --git a/keyboards/ergodox/ez/keymaps/steno/readme.md b/keyboards/ergodox/ez/keymaps/steno/readme.md
new file mode 100644
index 000000000..d67cde2a3
--- /dev/null
+++ b/keyboards/ergodox/ez/keymaps/steno/readme.md
@@ -0,0 +1,92 @@
+# ErgoDox EZ Steno Configuration
+
+This layout has a layer that uses the TxBolt Stenograph protocol over a Virtual Serial port. It requires something like Plover in order to function.
+
+In Plover, you can select TX Bolt as the Stenotype Machine, and find the COM port that was assigned. In this way, your regular keyboard will still function normally, and you can switch back and forth between the Steno and Keyboard layers.
+
+<pre><code>
+/* Keymap 0: Basic layer
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | = | 1 | 2 | 3 | 4 | 5 | LEFT | | RIGHT| 6 | 7 | 8 | 9 | 0 | - |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | Del | Q | W | E | R | T | L1 | | TX | Y | U | I | O | P | \ |
+ * |--------+------+------+------+------+------| | | BOLT |------+------+------+------+------+--------|
+ * | BkSp | A | S | D | F | G |------| |------| H | J | K | L |; / L2|' / Cmd |
+ * |--------+------+------+------+------+------| Hyper| | Meh |------+------+------+------+------+--------|
+ * | LShift |Z/Ctrl| X | C | V | B | | | | N | M | , | . |//Ctrl| RShift |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * |Grv/L1| '" |AltShf| Left | Right| | Up | Down | [ | ] | ~L1 |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | App | LGui | | Alt |Ctrl/Esc|
+ * ,------|------|------| |------+--------+------.
+ * | | | Home | | PgUp | | |
+ * | Space|Backsp|------| |------| Tab |Enter |
+ * | |ace | End | | PgDn | | |
+ * `--------------------' `----------------------'
+ */
+/* Keymap 1: Symbol Layer
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * |Version | F1 | F2 | F3 | F4 | F5 | | | | F6 | F7 | F8 | F9 | F10 | F11 |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | ! | @ | { | } | | | | | | Up | 7 | 8 | 9 | * | F12 |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | # | $ | ( | ) | ` |------| |------| Down | 4 | 5 | 6 | + | |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | % | ^ | [ | ] | ~ | | | | & | 1 | 2 | 3 | \ | |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | | | | | . | 0 | = | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | | |
+ * | | |------| |------| | |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+/* Keymap 2: Media keys
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | RESET | | | | | | | | | | | | | | |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | | | | | | | | | | | | | | |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | | | | | |------| |------| | | | | | Play |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | | | | | | | | | | | Prev | Next | | |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | | | |VolUp |VolDn | Mute | | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | |Brwser|
+ * | | |------| |------| |Back |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+/* Keymap 3: TxBolt (Serial)
+ *
+ * ,--------------------------------------------------. ,--------------------------------------------------.
+ * | BKSPC | | | | | | | | | | | | | | |
+ * |--------+------+------+------+------+-------------| |------+------+------+------+------+------+--------|
+ * | | # | # | # | # | # | | | | # | # | # | # | # | # |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | S | T | P | H | * |------| |------| * | F | P | L | T | D |
+ * |--------+------+------+------+------+------| | | |------+------+------+------+------+--------|
+ * | | S | K | W | R | * | | | | * | R | B | G | S | Z |
+ * `--------+------+------+------+------+-------------' `-------------+------+------+------+------+--------'
+ * | | | | | | | | | | | |
+ * `----------------------------------' `----------------------------------'
+ * ,-------------. ,-------------.
+ * | | | | | |
+ * ,------|------|------| |------+------+------.
+ * | | | | | | | |
+ * | A | O |------| |------| E | U |
+ * | | | | | | | |
+ * `--------------------' `--------------------'
+ */
+</code></pre>
diff --git a/tmk_core/common/virtser.h b/tmk_core/common/virtser.h
new file mode 100644
index 000000000..74891b6ae
--- /dev/null
+++ b/tmk_core/common/virtser.h
@@ -0,0 +1,10 @@
+#ifndef _VIRTSER_H_
+#define _VIRTSER_H_
+
+/* Define this function in your code to process incoming bytes */
+void virtser_recv(const uint8_t ch);
+
+/* Call this to send a character over the Virtual Serial Device */
+void virtser_send(const uint8_t byte);
+
+#endif
diff --git a/tmk_core/protocol/lufa.mk b/tmk_core/protocol/lufa.mk
index 0eeace44e..5b1e3d19d 100644
--- a/tmk_core/protocol/lufa.mk
+++ b/tmk_core/protocol/lufa.mk
@@ -26,6 +26,10 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
$(TMK_DIR)/protocol/serial_uart.c
endif
+ifeq ($(strip $(VIRTSER_ENABLE)), yes)
+ LUFA_SRC += $(LUFA_ROOT_PATH)/Drivers/USB/Class/Device/CDCClassDevice.c
+endif
+
SRC += $(LUFA_SRC)
# Search Path
diff --git a/tmk_core/protocol/lufa/descriptor.c b/tmk_core/protocol/lufa/descriptor.c
index 539a58d66..6f2407f58 100644
--- a/tmk_core/protocol/lufa/descriptor.c
+++ b/tmk_core/protocol/lufa/descriptor.c
@@ -231,9 +231,15 @@ const USB_Descriptor_Device_t PROGMEM DeviceDescriptor =
.Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device},
.USBSpecification = VERSION_BCD(1,1,0),
+#if VIRTSER_ENABLE
+ .Class = USB_CSCP_IADDeviceClass,
+ .SubClass = USB_CSCP_IADDeviceSubclass,
+ .Protocol = USB_CSCP_IADDeviceProtocol,
+#else
.Class = USB_CSCP_NoDeviceClass,
.SubClass = USB_CSCP_NoDeviceSubclass,
.Protocol = USB_CSCP_NoDeviceProtocol,
+#endif
.Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE,
@@ -643,8 +649,112 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor =
.TotalEmbeddedJacks = 0x01,
.AssociatedJackID = {0x03}
- }
+ },
#endif
+
+#ifdef VIRTSER_ENABLE
+ .CDC_Interface_Association =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Interface_Association_t), .Type = DTYPE_InterfaceAssociation},
+
+ .FirstInterfaceIndex = CCI_INTERFACE,
+ .TotalInterfaces = 2,
+
+ .Class = CDC_CSCP_CDCClass,
+ .SubClass = CDC_CSCP_ACMSubclass,
+ .Protocol = CDC_CSCP_ATCommandProtocol,
+
+ .IADStrIndex = NO_DESCRIPTOR,
+ },
+
+ .CDC_CCI_Interface =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
+
+ .InterfaceNumber = CCI_INTERFACE,
+ .AlternateSetting = 0,
+
+ .TotalEndpoints = 1,
+
+ .Class = CDC_CSCP_CDCClass,
+ .SubClass = CDC_CSCP_ACMSubclass,
+ .Protocol = CDC_CSCP_ATCommandProtocol,
+
+ .InterfaceStrIndex = NO_DESCRIPTOR
+ },
+
+ .CDC_Functional_Header =
+ {
+ .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = DTYPE_CSInterface},
+ .Subtype = 0x00,
+
+ .CDCSpecification = VERSION_BCD(1,1,0),
+ },
+
+ .CDC_Functional_ACM =
+ {
+ .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = DTYPE_CSInterface},
+ .Subtype = 0x02,
+
+ .Capabilities = 0x02,
+ },
+
+ .CDC_Functional_Union =
+ {
+ .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = DTYPE_CSInterface},
+ .Subtype = 0x06,
+
+ .MasterInterfaceNumber = CCI_INTERFACE,
+ .SlaveInterfaceNumber = CDI_INTERFACE,
+ },
+
+ .CDC_NotificationEndpoint =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+ .EndpointAddress = CDC_NOTIFICATION_EPADDR,
+ .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = CDC_NOTIFICATION_EPSIZE,
+ .PollingIntervalMS = 0xFF
+ },
+
+ .CDC_DCI_Interface =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface},
+
+ .InterfaceNumber = CDI_INTERFACE,
+ .AlternateSetting = 0,
+
+ .TotalEndpoints = 2,
+
+ .Class = CDC_CSCP_CDCDataClass,
+ .SubClass = CDC_CSCP_NoDataSubclass,
+ .Protocol = CDC_CSCP_NoDataProtocol,
+
+ .InterfaceStrIndex = NO_DESCRIPTOR
+ },
+
+ .CDC_DataOutEndpoint =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+ .EndpointAddress = CDC_OUT_EPADDR,
+ .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = CDC_EPSIZE,
+ .PollingIntervalMS = 0x05
+ },
+
+ .CDC_DataInEndpoint =
+ {
+ .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint},
+
+ .EndpointAddress = CDC_IN_EPADDR,
+ .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
+ .EndpointSize = CDC_EPSIZE,
+ .PollingIntervalMS = 0x05
+ },
+#endif
+
};
diff --git a/tmk_core/protocol/lufa/descriptor.h b/tmk_core/protocol/lufa/descriptor.h
index 4fd81a0e8..316650a7b 100644
--- a/tmk_core/protocol/lufa/descriptor.h
+++ b/tmk_core/protocol/lufa/descriptor.h
@@ -104,6 +104,21 @@ typedef struct
USB_MIDI_Descriptor_Jack_Endpoint_t MIDI_Out_Jack_Endpoint_SPC;
#endif
+#ifdef VIRTSER_ENABLE
+ USB_Descriptor_Interface_Association_t CDC_Interface_Association;
+
+ // CDC Control Interface
+ USB_Descriptor_Interface_t CDC_CCI_Interface;
+ USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header;
+ USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM;
+ USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union;
+ USB_Descriptor_Endpoint_t CDC_NotificationEndpoint;
+
+ // CDC Data Interface
+ USB_Descriptor_Interface_t CDC_DCI_Interface;
+ USB_Descriptor_Endpoint_t CDC_DataOutEndpoint;
+ USB_Descriptor_Endpoint_t CDC_DataInEndpoint;
+#endif
} USB_Descriptor_Configuration_t;
@@ -141,8 +156,15 @@ typedef struct
# define AS_INTERFACE NKRO_INTERFACE
#endif
+#ifdef VIRTSER_ENABLE
+# define CCI_INTERFACE (AS_INTERFACE + 1)
+# define CDI_INTERFACE (AS_INTERFACE + 2)
+#else
+# define CDI_INTERFACE AS_INTERFACE
+#endif
+
/* nubmer of interfaces */
-#define TOTAL_INTERFACES AS_INTERFACE + 1
+#define TOTAL_INTERFACES (CDI_INTERFACE + 1)
// Endopoint number and size
@@ -180,11 +202,24 @@ typedef struct
# define MIDI_STREAM_OUT_EPNUM (NKRO_IN_EPNUM + 2)
# define MIDI_STREAM_IN_EPADDR (ENDPOINT_DIR_IN | MIDI_STREAM_IN_EPNUM)
# define MIDI_STREAM_OUT_EPADDR (ENDPOINT_DIR_OUT | MIDI_STREAM_OUT_EPNUM)
+#else
+# define MIDI_STREAM_OUT_EPNUM NKRO_IN_EPNUM
+#endif
+
+#ifdef VIRTSER_ENABLE
+# define CDC_NOTIFICATION_EPNUM (MIDI_STREAM_OUT_EPNUM + 1)
+# define CDC_IN_EPNUM (MIDI_STREAM_OUT_EPNUM + 2)
+# define CDC_OUT_EPNUM (MIDI_STREAM_OUT_EPNUM + 3)
+# define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | CDC_NOTIFICATION_EPNUM)
+# define CDC_IN_EPADDR (ENDPOINT_DIR_IN | CDC_IN_EPNUM)
+# define CDC_OUT_EPADDR (ENDPOINT_DIR_OUT | CDC_OUT_EPNUM)
+#else
+# define CDC_OUT_EPNUM MIDI_STREAM_OUT_EPNUM
#endif
-#if defined(__AVR_ATmega32U2__) && MIDI_STREAM_OUT_EPADDR > 4
-# error "Endpoints are not available enough to support all functions. Remove some in Makefile.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI)"
+#if defined(__AVR_ATmega32U2__) && CDC_OUT_EPNUM > 4
+# error "Endpoints are not available enough to support all functions. Remove some in Makefile.(MOUSEKEY, EXTRAKEY, CONSOLE, NKRO, MIDI, SERIAL)"
#endif
#define KEYBOARD_EPSIZE 8
@@ -193,6 +228,8 @@ typedef struct
#define CONSOLE_EPSIZE 32
#define NKRO_EPSIZE 16
#define MIDI_STREAM_EPSIZE 64
+#define CDC_NOTIFICATION_EPSIZE 8
+#define CDC_EPSIZE 16
uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue,
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 9ca55dbc9..9b201374a 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -60,6 +60,10 @@
#include "bluetooth.h"
#endif
+#ifdef VIRTSER_ENABLE
+ #include "virtser.h"
+#endif
+
uint8_t keyboard_idle = 0;
/* 0: Boot Protocol, 1: Report Protocol(default) */
uint8_t keyboard_protocol = 1;
@@ -127,6 +131,34 @@ USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface =
#define SYS_COMMON_3 0x30
#endif
+#ifdef VIRTSER_ENABLE
+USB_ClassInfo_CDC_Device_t cdc_device =
+{
+ .Config =
+ {
+ .ControlInterfaceNumber = CCI_INTERFACE,
+ .DataINEndpoint =
+ {
+ .Address = CDC_IN_EPADDR,
+ .Size = CDC_EPSIZE,
+ .Banks = 1,
+ },
+ .DataOUTEndpoint =
+ {
+ .Address = CDC_OUT_EPADDR,
+ .Size = CDC_EPSIZE,
+ .Banks = 1,
+ },
+ .NotificationEndpoint =
+ {
+ .Address = CDC_NOTIFICATION_EPADDR,
+ .Size = CDC_NOTIFICATION_EPSIZE,
+ .Banks = 1,
+ },
+ },
+};
+#endif
+
/*******************************************************************************
* Console
@@ -311,6 +343,12 @@ void EVENT_USB_Device_ConfigurationChanged(void)
ConfigSuccess &= Endpoint_ConfigureEndpoint(MIDI_STREAM_IN_EPADDR, EP_TYPE_BULK, MIDI_STREAM_EPSIZE, ENDPOINT_BANK_SINGLE);
ConfigSuccess &= Endpoint_ConfigureEndpoint(MIDI_STREAM_OUT_EPADDR, EP_TYPE_BULK, MIDI_STREAM_EPSIZE, ENDPOINT_BANK_SINGLE);
#endif
+
+#ifdef VIRTSER_ENABLE
+ ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC_NOTIFICATION_EPADDR, EP_TYPE_INTERRUPT, CDC_NOTIFICATION_EPSIZE, ENDPOINT_BANK_SINGLE);
+ ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC_OUT_EPADDR, EP_TYPE_BULK, CDC_EPSIZE, ENDPOINT_BANK_SINGLE);
+ ConfigSuccess &= Endpoint_ConfigureEndpoint(CDC_IN_EPADDR, EP_TYPE_BULK, CDC_EPSIZE, ENDPOINT_BANK_SINGLE);
+#endif
}
/*
@@ -432,10 +470,15 @@ void EVENT_USB_Device_ControlRequest(void)
break;
}
+
+#ifdef VIRTSER_ENABLE
+ CDC_Device_ProcessControlRequest(&cdc_device);
+#endif
}
/*******************************************************************************
* Host driver
+p
******************************************************************************/
static uint8_t keyboard_leds(void)
{
@@ -827,6 +870,61 @@ void MIDI_Task(void)
#endif
+/*******************************************************************************
+ * VIRTUAL SERIAL
+ ******************************************************************************/
+
+#ifdef VIRTSER_ENABLE
+void virtser_init(void)
+{
+ cdc_device.State.ControlLineStates.DeviceToHost = CDC_CONTROL_LINE_IN_DSR ;
+ CDC_Device_SendControlLineStateChange(&cdc_device);
+}
+
+void virtser_recv(uint8_t c) __attribute__ ((weak));
+void virtser_recv(uint8_t c)
+{
+ // Ignore by default
+}
+
+void virtser_task(void)
+{
+ uint16_t count = CDC_Device_BytesReceived(&cdc_device);
+ uint8_t ch;
+ if (count)
+ {
+ ch = CDC_Device_ReceiveByte(&cdc_device);
+ virtser_recv(ch);
+ }
+}
+void virtser_send(const uint8_t byte)
+{
+ uint8_t timeout = 255;
+ uint8_t ep = Endpoint_GetCurrentEndpoint();
+
+ if (cdc_device.State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR)
+ {
+ /* IN packet */
+ Endpoint_SelectEndpoint(cdc_device.Config.DataINEndpoint.Address);
+
+ if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
+ Endpoint_SelectEndpoint(ep);
+ return;
+ }
+
+ while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
+
+ Endpoint_Write_8(byte);
+ CDC_Device_Flush(&cdc_device);
+
+ if (Endpoint_IsINReady()) {
+ Endpoint_ClearIN();
+ }
+
+ Endpoint_SelectEndpoint(ep);
+ }
+}
+#endif
/*******************************************************************************
* main
@@ -918,6 +1016,10 @@ int main(void)
sleep_led_init();
#endif
+#ifdef VIRTSER_ENABLE
+ virtser_init();
+#endif
+
print("Keyboard start.\n");
while (1) {
#ifndef BLUETOOTH_ENABLE
@@ -936,6 +1038,11 @@ int main(void)
#endif
keyboard_task();
+#ifdef VIRTSER_ENABLE
+ virtser_task();
+ CDC_Device_USBTask(&cdc_device);
+#endif
+
#if !defined(INTERRUPT_CONTROL_ENDPOINT)
USB_USBTask();
#endif