From e9f748751808de2f1e85cf7fb670d78773bd5e76 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sun, 13 Nov 2016 23:02:38 -0500 Subject: mostly working --- tmk_core/protocol/lufa/lufa.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'tmk_core') 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 -- cgit v1.2.3 From 530dd3377e4d409a7ca2fee7e47b60b735ebc0fa Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Tue, 15 Nov 2016 13:18:10 -0500 Subject: animations, midi, etc --- tmk_core/protocol/lufa/lufa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tmk_core') diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index fe466f6047..b628cde370 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -1043,12 +1043,13 @@ int main(void) } #endif + keyboard_task(); + #ifdef MIDI_ENABLE midi_device_process(&midi_device); // MIDI_Task(); #endif - keyboard_task(); - + #ifdef RGBLIGHT_ENABLE rgblight_task(); #endif -- cgit v1.2.3 From 3774a7fcdab5544fc787f4c200be05fcd417e31f Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Thu, 17 Nov 2016 17:42:14 -0500 Subject: rgb light through midi --- tmk_core/protocol/lufa/lufa.c | 96 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) (limited to 'tmk_core') 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 -- cgit v1.2.3 From 161bd5596b5d8199f2e56246a27ccbdb8c80bb36 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Fri, 18 Nov 2016 22:22:24 -0500 Subject: midi back and forth --- tmk_core/protocol/lufa/lufa.c | 62 +++++++++++++++++++++++++++++++------------ tmk_core/protocol/lufa/lufa.h | 1 + 2 files changed, 46 insertions(+), 17 deletions(-) (limited to 'tmk_core') 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 -- cgit v1.2.3 From b57cf3c0c851f2fb0e32c955b16fc6f0ad236e54 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 12:54:06 -0500 Subject: more structure to the package --- tmk_core/protocol/lufa/lufa.c | 107 ++++++++++++++++++++++++++++++++++-------- tmk_core/protocol/lufa/lufa.h | 15 ++++-- 2 files changed, 100 insertions(+), 22 deletions(-) (limited to 'tmk_core') 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 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); + 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: ; // 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 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 -- cgit v1.2.3 From c1037b1dc060d14a09a59f697fefe2b5b91bf373 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 18:05:06 -0500 Subject: working with helper, qmk_helper_windows@05b0105 --- tmk_core/protocol/lufa/lufa.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tmk_core') 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 -- cgit v1.2.3 From 664c0a036b3d7c3ed39f4a7a78d97f4a9cc7d20c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 19:50:55 -0500 Subject: cleaning up new code --- tmk_core/protocol/lufa/lufa.c | 90 +++++++++++++------------------------------ 1 file changed, 27 insertions(+), 63 deletions(-) (limited to 'tmk_core') 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) { -- cgit v1.2.3 From 6390033e8688550826a4bd3004a2e76568600657 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Mon, 21 Nov 2016 20:14:16 -0500 Subject: cleaning up midid --- tmk_core/common/host_driver.h | 9 ++++++++- tmk_core/protocol/lufa/lufa.c | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'tmk_core') 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 -- cgit v1.2.3 From d37becc0a9203c4c7d52aca6190b4b3d9fb69a59 Mon Sep 17 00:00:00 2001 From: PureSpider Date: Tue, 22 Nov 2016 22:12:57 +0100 Subject: Set backlight status to on if it's at maximum brightness already and the brightness increase keybind is used Before it was turned on but the status wasn't set to on, so you had to push the backlight toggle bind twice to turn it off again --- tmk_core/common/backlight.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tmk_core') diff --git a/tmk_core/common/backlight.c b/tmk_core/common/backlight.c index c9e8fd3fd2..0e0ad2d154 100644 --- a/tmk_core/common/backlight.c +++ b/tmk_core/common/backlight.c @@ -36,9 +36,9 @@ void backlight_increase(void) if(backlight_config.level < BACKLIGHT_LEVELS) { backlight_config.level++; - backlight_config.enable = 1; - eeconfig_update_backlight(backlight_config.raw); } + backlight_config.enable = 1; + eeconfig_update_backlight(backlight_config.raw); dprintf("backlight increase: %u\n", backlight_config.level); backlight_set(backlight_config.level); } -- cgit v1.2.3 From 5893f0fa1fcecfface25ce570f37e51031a14489 Mon Sep 17 00:00:00 2001 From: Wilba6582 Date: Wed, 23 Nov 2016 16:22:57 +1100 Subject: Fixed NO_SUSPEND_POWER_DOWN handling --- tmk_core/common/avr/suspend.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tmk_core') diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c index 8a7272bbc5..939bda15eb 100644 --- a/tmk_core/common/avr/suspend.c +++ b/tmk_core/common/avr/suspend.c @@ -47,6 +47,7 @@ void suspend_idle(uint8_t time) sleep_disable(); } +#ifndef NO_SUSPEND_POWER_DOWN /* Power down MCU with watchdog timer * wdto: watchdog timer timeout defined in * WDTO_15MS @@ -61,6 +62,7 @@ void suspend_idle(uint8_t time) * WDTO_8S */ static uint8_t wdt_timeout = 0; + static void power_down(uint8_t wdto) { #ifdef PROTOCOL_LUFA @@ -98,10 +100,13 @@ static void power_down(uint8_t wdto) // Disable watchdog after sleep wdt_disable(); } +#endif void suspend_power_down(void) { +#ifndef NO_SUSPEND_POWER_DOWN power_down(WDTO_15MS); +#endif } __attribute__ ((weak)) void matrix_power_up(void) {} @@ -109,7 +114,9 @@ __attribute__ ((weak)) void matrix_power_down(void) {} bool suspend_wakeup_condition(void) { #ifdef BACKLIGHT_ENABLE +#ifndef NO_SUSPEND_POWER_DOWN backlight_set(0); +#endif #endif matrix_power_up(); matrix_scan(); @@ -126,7 +133,6 @@ void suspend_wakeup_init(void) // clear keyboard state clear_keyboard(); #ifdef BACKLIGHT_ENABLE - backlight_set(0); backlight_init(); #endif led_set(host_keyboard_leds()); -- cgit v1.2.3 From 3d7aaa31e41a9c96e785b0c089d74dfda525dfbe Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 00:30:06 -0500 Subject: converted to 8bit messages --- tmk_core/protocol/lufa/lufa.c | 119 ++++++++++++++++++++++++------------------ tmk_core/protocol/midi.mk | 1 + 2 files changed, 69 insertions(+), 51 deletions(-) (limited to 'tmk_core') 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 -- cgit v1.2.3 From cf3926a8e13edb76193b8af25b497f9ef61161fd Mon Sep 17 00:00:00 2001 From: Wilba6582 Date: Wed, 23 Nov 2016 19:45:50 +1100 Subject: Fixed NO_SUSPEND_POWER_DOWN handling --- tmk_core/common/avr/suspend.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'tmk_core') diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c index 939bda15eb..0c81e83612 100644 --- a/tmk_core/common/avr/suspend.c +++ b/tmk_core/common/avr/suspend.c @@ -113,11 +113,6 @@ __attribute__ ((weak)) void matrix_power_up(void) {} __attribute__ ((weak)) void matrix_power_down(void) {} bool suspend_wakeup_condition(void) { -#ifdef BACKLIGHT_ENABLE -#ifndef NO_SUSPEND_POWER_DOWN - backlight_set(0); -#endif -#endif matrix_power_up(); matrix_scan(); matrix_power_down(); @@ -135,7 +130,7 @@ void suspend_wakeup_init(void) #ifdef BACKLIGHT_ENABLE backlight_init(); #endif -led_set(host_keyboard_leds()); + led_set(host_keyboard_leds()); } #ifndef NO_SUSPEND_POWER_DOWN -- cgit v1.2.3 From 2e23689b8e3222982082c1f5a4f8ce7686f9658b Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 18:52:02 -0500 Subject: converted to new format --- tmk_core/protocol/lufa/lufa.c | 291 ++++++++++++++++++++++++++---------------- tmk_core/protocol/lufa/lufa.h | 16 ++- 2 files changed, 192 insertions(+), 115 deletions(-) (limited to 'tmk_core') 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,39 +1145,96 @@ 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; +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 decode_uint8_chunk(uint8_t * data) { - uint32_t part4 = *data++; - uint32_t part5 = *data++; - return (part4 << 7) | part5; +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 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; +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++) { + // 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(" "); + // } } -void encode_uint8_chunk(uint8_t data, uint8_t * pointer) { - *pointer++ = (data >> 7) & 0x7F; - *pointer++ = (data) & 0x7F; +#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); } -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; +__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) { @@ -1186,114 +1243,128 @@ void sysex_buffer_callback(MidiDevice * device, uint8_t length, uint8_t * data) // send_byte(data[i]); // SEND_STRING(" "); // } + if (!sysex_process_quantum(length, data)) + return; - 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])); + 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 0x08: ; // set keymap options - eeconfig_update_keymap(data[0]); + } + 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; + } } - break; - case 0x13: ; // Get info from keyboard - switch (*data++) { - case 0x00: ; // Handshake - send_bytes_sysex(0x00, NULL, 0); + case MT_GET_DATA: + switch (data[1]) { + case DT_HANDSHAKE: { + MT_GET_DATA_ACK(DT_HANDSHAKE, NULL, 0); break; - case 0x01: ; // Get debug state + } + case DT_DEBUG: { uint8_t debug_bytes[1] = { eeprom_read_byte(EECONFIG_DEBUG) }; - send_bytes_sysex(0x01, debug_bytes, 1); + MT_GET_DATA_ACK(DT_DEBUG, debug_bytes, 1); break; - case 0x02: ; // Get default layer + } + case DT_DEFAULT_LAYER: { uint8_t default_bytes[1] = { eeprom_read_byte(EECONFIG_DEFAULT_LAYER) }; - send_bytes_sysex(0x02, default_bytes, 1); + MT_GET_DATA_ACK(DT_DEFAULT_LAYER, 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 + } + case DT_CURRENT_LAYER: { uint8_t layer_state_bytes[4]; - dword_to_bytes(layer_state_bytes, layer_state); - send_bytes_sysex(0x04, layer_state_bytes, 4); + dword_to_bytes(layer_state, layer_state_bytes); + MT_GET_DATA_ACK(DT_CURRENT_LAYER, 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); + } + 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; - } - 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]); + } + 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 0x01: ; // Update RGB + } + 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 0x02: ; // Update mode - rgblight_mode(data[0]); + } + 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; - #endif + 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[5]; - encode_uint32_chunk(unicode, chunk); - send_bytes_sysex(0x05, chunk, 5); + uint8_t chunk[4]; + dword_to_bytes(unicode, chunk); + MT_SEND_DATA(DT_UNICODE, chunk, 5); } -void send_bytes_sysex(uint8_t 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 * 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(" "); - // } -} #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 -- cgit v1.2.3 From cefa8468fb5f28bd67a0c02d371a4aef0964e20c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 20:16:38 -0500 Subject: travis pls --- tmk_core/protocol/lufa/lufa.c | 49 ++----------------------------------------- tmk_core/protocol/lufa/lufa.h | 42 ++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 48 deletions(-) (limited to 'tmk_core') 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 -- cgit v1.2.3 From f25596b8dc2f15f620c07164d871023d9284618c Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Wed, 23 Nov 2016 21:28:12 -0500 Subject: rgblight fixes --- tmk_core/protocol/lufa/lufa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tmk_core') 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 -- cgit v1.2.3 From 9a071f051ca9dffdf64b68ea59b2424e37bc51e7 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Sat, 26 Nov 2016 13:24:53 +0700 Subject: Make PS2 init delay configurable. Some devices are not fully powered up after 1s. --- tmk_core/protocol/ps2_mouse.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tmk_core') diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index c3e8b3c1c3..82f6966e8e 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c @@ -26,6 +26,9 @@ along with this program. If not, see . #include "print.h" #include "debug.h" +#ifndef PS2_INIT_DELAY +#define PS2_INIT_DELAY 1000 +#endif static report_mouse_t mouse_report = {}; @@ -39,7 +42,7 @@ uint8_t ps2_mouse_init(void) { ps2_host_init(); - _delay_ms(1000); // wait for powering up + _delay_ms(PS2_INIT_DELAY); // wait for powering up // send Reset rcv = ps2_host_send(0xFF); -- cgit v1.2.3 From 7edac212c8ed8442bf4207e70dc8194631b2bf27 Mon Sep 17 00:00:00 2001 From: Jack Humbert Date: Sat, 26 Nov 2016 15:37:46 -0500 Subject: separated into api files/folder --- tmk_core/protocol/lufa/lufa.c | 203 +----------------------------------------- tmk_core/protocol/lufa/lufa.h | 61 ++----------- 2 files changed, 10 insertions(+), 254 deletions(-) (limited to 'tmk_core') 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++; } - // } - -} - -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; + #endif } -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 -- cgit v1.2.3 From be4e75423a232d9d328bb23835e0fa5152292c95 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:41:22 -0800 Subject: 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(-) (limited to 'tmk_core') 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 */ -- cgit v1.2.3 From 712476cd288505cabb2ad6163d1c1ba13a7a1cca Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:48:04 -0800 Subject: 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 (limited to 'tmk_core') 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); + } +}; -- cgit v1.2.3 From fe001d46fd06924bb81fe8d506f5be8894db3df0 Mon Sep 17 00:00:00 2001 From: Wilba6582 Date: Mon, 28 Nov 2016 18:31:16 +1100 Subject: Initial version of Raw HID interface --- tmk_core/common.mk | 4 ++ tmk_core/common/raw_hid.h | 8 ++++ tmk_core/protocol/lufa/descriptor.c | 87 +++++++++++++++++++++++++++++++++- tmk_core/protocol/lufa/descriptor.h | 35 +++++++++++--- tmk_core/protocol/lufa/lufa.c | 94 +++++++++++++++++++++++++++++++++++++ 5 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 tmk_core/common/raw_hid.h (limited to 'tmk_core') diff --git a/tmk_core/common.mk b/tmk_core/common.mk index f826a7b540..d65f02f12b 100644 --- a/tmk_core/common.mk +++ b/tmk_core/common.mk @@ -50,6 +50,10 @@ ifeq ($(strip $(EXTRAKEY_ENABLE)), yes) TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE endif +ifeq ($(strip $(RAW_ENABLE)), yes) + TMK_COMMON_DEFS += -DRAW_ENABLE +endif + ifeq ($(strip $(CONSOLE_ENABLE)), yes) TMK_COMMON_DEFS += -DCONSOLE_ENABLE else diff --git a/tmk_core/common/raw_hid.h b/tmk_core/common/raw_hid.h new file mode 100644 index 0000000000..86da02fd15 --- /dev/null +++ b/tmk_core/common/raw_hid.h @@ -0,0 +1,8 @@ +#ifndef _RAW_HID_H_ +#define _RAW_HID_H_ + +void raw_hid_receive( uint8_t *data, uint8_t length ); + +void raw_hid_send( uint8_t *data, uint8_t length ); + +#endif diff --git a/tmk_core/protocol/lufa/descriptor.c b/tmk_core/protocol/lufa/descriptor.c index 6f2407f580..bf47787d29 100644 --- a/tmk_core/protocol/lufa/descriptor.c +++ b/tmk_core/protocol/lufa/descriptor.c @@ -164,6 +164,28 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM ExtrakeyReport[] = }; #endif +#ifdef RAW_ENABLE +const USB_Descriptor_HIDReport_Datatype_t PROGMEM RawReport[] = +{ + HID_RI_USAGE_PAGE(16, 0xFF60), /* Vendor Page 0xFF60 */ + HID_RI_USAGE(8, 0x61), /* Vendor Usage 0x61 */ + HID_RI_COLLECTION(8, 0x01), /* Application */ + HID_RI_USAGE(8, 0x62), /* Vendor Usage 0x62 */ + HID_RI_LOGICAL_MINIMUM(8, 0x00), + HID_RI_LOGICAL_MAXIMUM(16, 0x00FF), + HID_RI_REPORT_COUNT(8, RAW_EPSIZE), + HID_RI_REPORT_SIZE(8, 0x08), + HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE), + HID_RI_USAGE(8, 0x63), /* Vendor Usage 0x63 */ + HID_RI_LOGICAL_MINIMUM(8, 0x00), + HID_RI_LOGICAL_MAXIMUM(16, 0x00FF), + HID_RI_REPORT_COUNT(8, RAW_EPSIZE), + HID_RI_REPORT_SIZE(8, 0x08), + HID_RI_OUTPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE | HID_IOF_NON_VOLATILE), + HID_RI_END_COLLECTION(0), +}; +#endif + #ifdef CONSOLE_ENABLE const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = { @@ -399,6 +421,58 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = }, #endif + /* + * Raw + */ + #ifdef RAW_ENABLE + .Raw_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = RAW_INTERFACE, + .AlternateSetting = 0x00, + + .TotalEndpoints = 2, + + .Class = HID_CSCP_HIDClass, + .SubClass = HID_CSCP_NonBootSubclass, + .Protocol = HID_CSCP_NonBootProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .Raw_HID = + { + .Header = {.Size = sizeof(USB_HID_Descriptor_HID_t), .Type = HID_DTYPE_HID}, + + .HIDSpec = VERSION_BCD(1,1,1), + .CountryCode = 0x00, + .TotalReportDescriptors = 1, + .HIDReportType = HID_DTYPE_Report, + .HIDReportLength = sizeof(RawReport) + }, + + .Raw_INEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DIR_IN | RAW_IN_EPNUM), + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = RAW_EPSIZE, + .PollingIntervalMS = 0x01 + }, + + .Raw_OUTEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = (ENDPOINT_DIR_OUT | RAW_OUT_EPNUM), + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = RAW_EPSIZE, + .PollingIntervalMS = 0x01 + }, + #endif + /* * Console */ @@ -754,7 +828,6 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = .PollingIntervalMS = 0x05 }, #endif - }; @@ -846,6 +919,12 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Size = sizeof(USB_HID_Descriptor_HID_t); break; #endif +#ifdef RAW_ENABLE + case RAW_INTERFACE: + Address = &ConfigurationDescriptor.Raw_HID; + Size = sizeof(USB_HID_Descriptor_HID_t); + break; +#endif #ifdef CONSOLE_ENABLE case CONSOLE_INTERFACE: Address = &ConfigurationDescriptor.Console_HID; @@ -878,6 +957,12 @@ uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, Size = sizeof(ExtrakeyReport); break; #endif +#ifdef RAW_ENABLE + case RAW_INTERFACE: + Address = &RawReport; + Size = sizeof(RawReport); + break; +#endif #ifdef CONSOLE_ENABLE case CONSOLE_INTERFACE: Address = &ConsoleReport; diff --git a/tmk_core/protocol/lufa/descriptor.h b/tmk_core/protocol/lufa/descriptor.h index c6c94e3618..24ce420e6a 100644 --- a/tmk_core/protocol/lufa/descriptor.h +++ b/tmk_core/protocol/lufa/descriptor.h @@ -71,6 +71,14 @@ typedef struct USB_Descriptor_Endpoint_t Extrakey_INEndpoint; #endif +#ifdef RAW_ENABLE + // Raw HID Interface + USB_Descriptor_Interface_t Raw_Interface; + USB_HID_Descriptor_HID_t Raw_HID; + USB_Descriptor_Endpoint_t Raw_INEndpoint; + USB_Descriptor_Endpoint_t Raw_OUTEndpoint; +#endif + #ifdef CONSOLE_ENABLE // Console HID Interface USB_Descriptor_Interface_t Console_Interface; @@ -137,10 +145,16 @@ typedef struct # define EXTRAKEY_INTERFACE MOUSE_INTERFACE #endif +#ifdef RAW_ENABLE +# define RAW_INTERFACE (EXTRAKEY_INTERFACE + 1) +#else +# define RAW_INTERFACE EXTRAKEY_INTERFACE +#endif + #ifdef CONSOLE_ENABLE -# define CONSOLE_INTERFACE (EXTRAKEY_INTERFACE + 1) +# define CONSOLE_INTERFACE (RAW_INTERFACE + 1) #else -# define CONSOLE_INTERFACE EXTRAKEY_INTERFACE +# define CONSOLE_INTERFACE RAW_INTERFACE #endif #ifdef NKRO_ENABLE @@ -182,12 +196,19 @@ typedef struct # define EXTRAKEY_IN_EPNUM MOUSE_IN_EPNUM #endif +#ifdef RAW_ENABLE +# define RAW_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1) +# define RAW_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 2) +#else +# define RAW_OUT_EPNUM EXTRAKEY_IN_EPNUM +#endif + #ifdef CONSOLE_ENABLE -# define CONSOLE_IN_EPNUM (EXTRAKEY_IN_EPNUM + 1) -# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 1) -//# define CONSOLE_OUT_EPNUM (EXTRAKEY_IN_EPNUM + 2) +# define CONSOLE_IN_EPNUM (RAW_OUT_EPNUM + 1) +//# define CONSOLE_OUT_EPNUM (RAW_OUT_EPNUM + 2) +# define CONSOLE_OUT_EPNUM (RAW_OUT_EPNUM + 1) #else -# define CONSOLE_OUT_EPNUM EXTRAKEY_IN_EPNUM +# define CONSOLE_OUT_EPNUM RAW_OUT_EPNUM #endif #ifdef NKRO_ENABLE @@ -217,7 +238,6 @@ typedef struct # define CDC_OUT_EPNUM MIDI_STREAM_OUT_EPNUM #endif - #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 @@ -225,6 +245,7 @@ typedef struct #define KEYBOARD_EPSIZE 8 #define MOUSE_EPSIZE 8 #define EXTRAKEY_EPSIZE 8 +#define RAW_EPSIZE 32 #define CONSOLE_EPSIZE 32 #define NKRO_EPSIZE 32 #define MIDI_STREAM_EPSIZE 64 diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c index 39d4824b6b..aeb5f07815 100644 --- a/tmk_core/protocol/lufa/lufa.c +++ b/tmk_core/protocol/lufa/lufa.c @@ -80,6 +80,10 @@ #include "sysex_tools.h" #endif +#ifdef RAW_ENABLE + #include "raw_hid.h" +#endif + uint8_t keyboard_idle = 0; /* 0: Boot Protocol, 1: Report Protocol(default) */ uint8_t keyboard_protocol = 1; @@ -175,6 +179,80 @@ USB_ClassInfo_CDC_Device_t cdc_device = }; #endif +#ifdef RAW_ENABLE + +void raw_hid_send( uint8_t *data, uint8_t length ) +{ + // TODO: implement variable size packet + if ( length != RAW_EPSIZE ) + { + return; + } + + if (USB_DeviceState != DEVICE_STATE_Configured) + { + return; + } + + // TODO: decide if we allow calls to raw_hid_send() in the middle + // of other endpoint usage. + uint8_t ep = Endpoint_GetCurrentEndpoint(); + + Endpoint_SelectEndpoint(RAW_IN_EPNUM); + + // Check to see if the host is ready to accept another packet + if (Endpoint_IsINReady()) + { + // Write data + Endpoint_Write_Stream_LE(data, RAW_EPSIZE, NULL); + // Finalize the stream transfer to send the last packet + Endpoint_ClearIN(); + } + + Endpoint_SelectEndpoint(ep); +} + +__attribute__ ((weak)) +void raw_hid_receive( uint8_t *data, uint8_t length ) +{ + // Users should #include "raw_hid.h" in their own code + // and implement this function there. Leave this as weak linkage + // so users can opt to not handle data coming in. +} + +static void raw_hid_task(void) +{ + // Create a temporary buffer to hold the read in data from the host + uint8_t data[RAW_EPSIZE]; + bool data_read = false; + + // Device must be connected and configured for the task to run + if (USB_DeviceState != DEVICE_STATE_Configured) + return; + + Endpoint_SelectEndpoint(RAW_OUT_EPNUM); + + // Check to see if a packet has been sent from the host + if (Endpoint_IsOUTReceived()) + { + // Check to see if the packet contains data + if (Endpoint_IsReadWriteAllowed()) + { + /* Read data */ + Endpoint_Read_Stream_LE(data, sizeof(data), NULL); + data_read = true; + } + + // Finalize the stream transfer to receive the last packet + Endpoint_ClearOUT(); + + if ( data_read ) + { + raw_hid_receive( data, sizeof(data) ); + } + } +} +#endif /******************************************************************************* * Console @@ -294,6 +372,8 @@ void EVENT_USB_Device_WakeUp() #endif } + + #ifdef CONSOLE_ENABLE static bool console_flush = false; #define CONSOLE_FLUSH_SET(b) do { \ @@ -311,6 +391,7 @@ void EVENT_USB_Device_StartOfFrame(void) Console_Task(); console_flush = false; } + #endif /** Event handler for the USB_ConfigurationChanged event. @@ -339,6 +420,14 @@ void EVENT_USB_Device_ConfigurationChanged(void) EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE); #endif +#ifdef RAW_ENABLE + /* Setup Raw HID Report Endpoints */ + ConfigSuccess &= ENDPOINT_CONFIG(RAW_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, + RAW_EPSIZE, ENDPOINT_BANK_SINGLE); + ConfigSuccess &= ENDPOINT_CONFIG(RAW_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, + RAW_EPSIZE, ENDPOINT_BANK_SINGLE); +#endif + #ifdef CONSOLE_ENABLE /* Setup Console HID Report Endpoints */ ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, @@ -1064,9 +1153,14 @@ int main(void) CDC_Device_USBTask(&cdc_device); #endif +#ifdef RAW_ENABLE + raw_hid_task(); +#endif + #if !defined(INTERRUPT_CONTROL_ENDPOINT) USB_USBTask(); #endif + } } -- cgit v1.2.3 From 044fa3ff856393d75a80fe6625b4a5682b81b76d Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sun, 27 Nov 2016 22:51:30 -0800 Subject: 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(-) (limited to 'tmk_core') 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); -- cgit v1.2.3 From d639e08a3131892c608760df4e3806d843a91176 Mon Sep 17 00:00:00 2001 From: ofples Date: Sat, 3 Dec 2016 13:05:02 +0200 Subject: Refactored and improved ps2 mouse feature --- tmk_core/protocol/ps2_mouse.c | 369 ++++++++++++++++++++++++------------------ tmk_core/protocol/ps2_mouse.h | 81 ++++++++-- 2 files changed, 286 insertions(+), 164 deletions(-) (limited to 'tmk_core') 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 void print_usb_data(void) -{ +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); } +#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; + } -/* 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 - */ + 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 -- cgit v1.2.3 From 9f41544e1de12b92bdc15538ec7a9e66a4af0c43 Mon Sep 17 00:00:00 2001 From: Ofer Plesser Date: Sat, 3 Dec 2016 13:09:42 +0200 Subject: 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(-) (limited to 'tmk_core') 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, -- cgit v1.2.3 From f0768f8be96fb7a9af354d5f1584b0f67cc5b960 Mon Sep 17 00:00:00 2001 From: Ofer Plesser Date: Sat, 3 Dec 2016 13:41:56 +0200 Subject: Forgot to use define in delay instead of hardcoded number --- tmk_core/protocol/ps2_mouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tmk_core') 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"); -- cgit v1.2.3 From d059624bfb32e268ff0972609d7eadbb212fa2d2 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Mon, 5 Dec 2016 01:07:12 +0700 Subject: Implemented weak ps2_mouse_init_user() There are a lot of PS/2 commands, some are vendor/device specific, so we provide a weak ps2_mouse_init_user() to be implemented in each keyboard that need it. --- tmk_core/protocol/ps2_mouse.c | 54 ++++++------------------------------------- tmk_core/protocol/ps2_mouse.h | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 47 deletions(-) (limited to 'tmk_core') diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index af971dd497..e3c6974440 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c @@ -28,53 +28,7 @@ along with this program. If not, see . /* ============================= 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 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); @@ -108,6 +62,12 @@ void ps2_mouse_init(void) { #ifdef PS2_MOUSE_USE_2_1_SCALING ps2_mouse_set_scaling_2_1(); #endif + + ps2_mouse_init_user(); +} + +__attribute__((weak)) +void ps2_mouse_init_user(void) { } void ps2_mouse_task(void) { diff --git a/tmk_core/protocol/ps2_mouse.h b/tmk_core/protocol/ps2_mouse.h index e11c705fc6..3c93a46342 100644 --- a/tmk_core/protocol/ps2_mouse.h +++ b/tmk_core/protocol/ps2_mouse.h @@ -19,6 +19,53 @@ along with this program. If not, see . #define PS2_MOUSE_H #include +#include "debug.h" + +#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; /* * Data format: @@ -107,6 +154,8 @@ typedef enum ps2_mouse_sample_rate_e { void ps2_mouse_init(void); +void ps2_mouse_init_user(void); + void ps2_mouse_task(void); void ps2_mouse_disable_data_reporting(void); -- cgit v1.2.3 From 07d29b7d29ce13a22f50270ab54d39f80103cc44 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Mon, 5 Dec 2016 01:22:40 +0700 Subject: syntax error fix --- tmk_core/protocol/ps2_mouse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tmk_core') diff --git a/tmk_core/protocol/ps2_mouse.c b/tmk_core/protocol/ps2_mouse.c index e3c6974440..d9ccbecb43 100644 --- a/tmk_core/protocol/ps2_mouse.c +++ b/tmk_core/protocol/ps2_mouse.c @@ -28,7 +28,7 @@ along with this program. If not, see . /* ============================= MACROS ============================ */ -static report_mouse_t mouse_report = {};./ +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); -- cgit v1.2.3