aboutsummaryrefslogtreecommitdiff
path: root/tmk_core
diff options
context:
space:
mode:
Diffstat (limited to 'tmk_core')
-rw-r--r--tmk_core/common.mk19
-rw-r--r--tmk_core/common/arm_atsam/eeprom.c94
-rw-r--r--tmk_core/common/avr/suspend.c98
-rw-r--r--tmk_core/common/chibios/_wait.h2
-rw-r--r--tmk_core/common/chibios/chibios_config.h41
-rw-r--r--tmk_core/common/chibios/eeprom_stm32.c57
-rw-r--r--tmk_core/common/chibios/eeprom_stm32_defs.h19
-rw-r--r--tmk_core/common/chibios/flash_stm32.c41
-rw-r--r--tmk_core/common/chibios/suspend.c89
-rw-r--r--tmk_core/common/host.c15
-rw-r--r--tmk_core/common/host.h2
-rw-r--r--tmk_core/common/host_driver.h1
-rw-r--r--tmk_core/common/report.h6
-rw-r--r--tmk_core/common/suspend.h2
-rw-r--r--tmk_core/common/test/rules.mk1
-rw-r--r--tmk_core/protocol/chibios/chibios.c3
-rw-r--r--tmk_core/protocol/chibios/usb_main.c15
-rw-r--r--tmk_core/protocol/ibm4704.c185
-rw-r--r--tmk_core/protocol/ibm4704.h103
-rw-r--r--tmk_core/protocol/lufa.mk27
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.cpp701
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.h59
-rw-r--r--tmk_core/protocol/lufa/lufa.c48
-rw-r--r--tmk_core/protocol/lufa/outputselect.c79
-rw-r--r--tmk_core/protocol/lufa/outputselect.h34
-rw-r--r--tmk_core/protocol/lufa/ringbuffer.hpp66
-rw-r--r--tmk_core/protocol/news.c161
-rw-r--r--tmk_core/protocol/news.h48
-rw-r--r--tmk_core/protocol/next_kbd.c219
-rw-r--r--tmk_core/protocol/next_kbd.h60
-rw-r--r--tmk_core/protocol/usb_descriptor.c19
-rw-r--r--tmk_core/protocol/usb_hid/parser.h5
-rw-r--r--tmk_core/protocol/usb_hid/usb_hid.h6
-rw-r--r--tmk_core/protocol/vusb/vusb.c36
34 files changed, 323 insertions, 2038 deletions
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index e44ff2f0a..f0faa2dc3 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -55,8 +55,6 @@ ifeq ($(strip $(NKRO_ENABLE)), yes)
55 $(info NKRO is not currently supported on V-USB, and has been disabled.) 55 $(info NKRO is not currently supported on V-USB, and has been disabled.)
56 else ifeq ($(strip $(BLUETOOTH_ENABLE)), yes) 56 else ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
57 $(info NKRO is not currently supported with Bluetooth, and has been disabled.) 57 $(info NKRO is not currently supported with Bluetooth, and has been disabled.)
58 else ifneq ($(BLUETOOTH),)
59 $(info NKRO is not currently supported with Bluetooth, and has been disabled.)
60 else 58 else
61 TMK_COMMON_DEFS += -DNKRO_ENABLE 59 TMK_COMMON_DEFS += -DNKRO_ENABLE
62 SHARED_EP_ENABLE = yes 60 SHARED_EP_ENABLE = yes
@@ -77,23 +75,6 @@ ifeq ($(strip $(NO_SUSPEND_POWER_DOWN)), yes)
77 TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN 75 TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN
78endif 76endif
79 77
80ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
81 TMK_COMMON_DEFS += -DBLUETOOTH_ENABLE
82 TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK
83endif
84
85ifeq ($(strip $(BLUETOOTH)), AdafruitBLE)
86 TMK_COMMON_DEFS += -DBLUETOOTH_ENABLE
87 TMK_COMMON_DEFS += -DMODULE_ADAFRUIT_BLE
88 TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK
89endif
90
91ifeq ($(strip $(BLUETOOTH)), RN42)
92 TMK_COMMON_DEFS += -DBLUETOOTH_ENABLE
93 TMK_COMMON_DEFS += -DMODULE_RN42
94 TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK
95endif
96
97ifeq ($(strip $(SWAP_HANDS_ENABLE)), yes) 78ifeq ($(strip $(SWAP_HANDS_ENABLE)), yes)
98 TMK_COMMON_DEFS += -DSWAP_HANDS_ENABLE 79 TMK_COMMON_DEFS += -DSWAP_HANDS_ENABLE
99endif 80endif
diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c
index ccd5d15a5..ff1a69262 100644
--- a/tmk_core/common/arm_atsam/eeprom.c
+++ b/tmk_core/common/arm_atsam/eeprom.c
@@ -13,24 +13,110 @@
13 * You should have received a copy of the GNU General Public License 13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16
17#include "eeprom.h" 16#include "eeprom.h"
17#include "debug.h"
18#include "samd51j18a.h"
19#include "core_cm4.h"
20#include "component/nvmctrl.h"
18 21
19#ifndef EEPROM_SIZE 22#ifndef EEPROM_SIZE
20# include "eeconfig.h" 23# include "eeconfig.h"
21# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO 24# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
22#endif 25#endif
23 26
24__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE]; 27#ifndef MAX
28# define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
29#endif
30
31#ifndef BUSY_RETRIES
32# define BUSY_RETRIES 10000
33#endif
34
35// #define DEBUG_EEPROM_OUTPUT
36
37/*
38 * Debug print utils
39 */
40#if defined(DEBUG_EEPROM_OUTPUT)
41# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__);
42#else /* NO_DEBUG */
43# define eeprom_printf(fmt, ...)
44#endif /* NO_DEBUG */
45
46__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE] = {0};
47volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR;
48
49static inline bool eeprom_is_busy(void) {
50 int timeout = BUSY_RETRIES;
51 while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0)
52 ;
53
54 return NVMCTRL->SEESTAT.bit.BUSY;
55}
56
57static uint32_t get_virtual_eeprom_size(void) {
58 // clang-format off
59 static const uint32_t VIRTUAL_EEPROM_MAP[11][8] = {
60 /* 4 8 16 32 64 128 256 512 */
61 /* 0*/ { 0, 0, 0, 0, 0, 0, 0, 0 },
62 /* 1*/ { 512, 1024, 2048, 4096, 4096, 4096, 4096, 4096 },
63 /* 2*/ { 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192 },
64 /* 3*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 },
65 /* 4*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 },
66 /* 5*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
67 /* 6*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
68 /* 7*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
69 /* 8*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 },
70 /* 9*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 },
71 /*10*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 },
72 };
73 // clang-format on
74
75 static uint32_t virtual_eeprom_size = UINT32_MAX;
76 if (virtual_eeprom_size == UINT32_MAX) {
77 virtual_eeprom_size = VIRTUAL_EEPROM_MAP[NVMCTRL->SEESTAT.bit.PSZ][NVMCTRL->SEESTAT.bit.SBLK];
78 }
79 // eeprom_printf("get_virtual_eeprom_size:: %d:%d:%d\n", NVMCTRL->SEESTAT.bit.PSZ, NVMCTRL->SEESTAT.bit.SBLK, virtual_eeprom_size);
80 return virtual_eeprom_size;
81}
25 82
26uint8_t eeprom_read_byte(const uint8_t *addr) { 83uint8_t eeprom_read_byte(const uint8_t *addr) {
27 uintptr_t offset = (uintptr_t)addr; 84 uintptr_t offset = (uintptr_t)addr;
28 return buffer[offset]; 85 if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) {
86 eeprom_printf("eeprom_read_byte:: out of bounds\n");
87 return 0x0;
88 }
89
90 if (get_virtual_eeprom_size() == 0) {
91 return buffer[offset];
92 }
93
94 if (eeprom_is_busy()) {
95 eeprom_printf("eeprom_write_byte:: timeout\n");
96 return 0x0;
97 }
98
99 return SmartEEPROM8[offset];
29} 100}
30 101
31void eeprom_write_byte(uint8_t *addr, uint8_t value) { 102void eeprom_write_byte(uint8_t *addr, uint8_t value) {
32 uintptr_t offset = (uintptr_t)addr; 103 uintptr_t offset = (uintptr_t)addr;
33 buffer[offset] = value; 104 if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) {
105 eeprom_printf("eeprom_write_byte:: out of bounds\n");
106 return;
107 }
108
109 if (get_virtual_eeprom_size() == 0) {
110 buffer[offset] = value;
111 return;
112 }
113
114 if (eeprom_is_busy()) {
115 eeprom_printf("eeprom_write_byte:: timeout\n");
116 return;
117 }
118
119 SmartEEPROM8[offset] = value;
34} 120}
35 121
36uint16_t eeprom_read_word(const uint16_t *addr) { 122uint16_t eeprom_read_word(const uint16_t *addr) {
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c
index 690d7f38c..b614746e6 100644
--- a/tmk_core/common/avr/suspend.c
+++ b/tmk_core/common/avr/suspend.c
@@ -16,25 +16,6 @@
16# include "vusb.h" 16# include "vusb.h"
17#endif 17#endif
18 18
19#ifdef BACKLIGHT_ENABLE
20# include "backlight.h"
21#endif
22
23#ifdef AUDIO_ENABLE
24# include "audio.h"
25#endif /* AUDIO_ENABLE */
26
27#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
28# include "rgblight.h"
29#endif
30
31#ifdef LED_MATRIX_ENABLE
32# include "led_matrix.h"
33#endif
34#ifdef RGB_MATRIX_ENABLE
35# include "rgb_matrix.h"
36#endif
37
38/** \brief Suspend idle 19/** \brief Suspend idle
39 * 20 *
40 * FIXME: needs doc 21 * FIXME: needs doc
@@ -50,17 +31,6 @@ void suspend_idle(uint8_t time) {
50 31
51// TODO: This needs some cleanup 32// TODO: This needs some cleanup
52 33
53/** \brief Run keyboard level Power down
54 *
55 * FIXME: needs doc
56 */
57__attribute__((weak)) void suspend_power_down_user(void) {}
58/** \brief Run keyboard level Power down
59 *
60 * FIXME: needs doc
61 */
62__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); }
63
64#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) 34#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
65 35
66// clang-format off 36// clang-format off
@@ -135,41 +105,9 @@ void suspend_power_down(void) {
135 if (!vusb_suspended) return; 105 if (!vusb_suspended) return;
136#endif 106#endif
137 107
138 suspend_power_down_kb(); 108 suspend_power_down_quantum();
139 109
140#ifndef NO_SUSPEND_POWER_DOWN 110#ifndef NO_SUSPEND_POWER_DOWN
141 // Turn off backlight
142# ifdef BACKLIGHT_ENABLE
143 backlight_set(0);
144# endif
145
146 // Turn off LED indicators
147 uint8_t leds_off = 0;
148# if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE)
149 if (is_backlight_enabled()) {
150 // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off
151 leds_off |= (1 << USB_LED_CAPS_LOCK);
152 }
153# endif
154 led_set(leds_off);
155
156 // Turn off audio
157# ifdef AUDIO_ENABLE
158 stop_all_notes();
159# endif
160
161 // Turn off underglow
162# if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
163 rgblight_suspend();
164# endif
165
166# if defined(LED_MATRIX_ENABLE)
167 led_matrix_set_suspend_state(true);
168# endif
169# if defined(RGB_MATRIX_ENABLE)
170 rgb_matrix_set_suspend_state(true);
171# endif
172
173 // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt) 111 // Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt)
174# if defined(WDT_vect) 112# if defined(WDT_vect)
175 power_down(WDTO_15MS); 113 power_down(WDTO_15MS);
@@ -189,18 +127,6 @@ bool suspend_wakeup_condition(void) {
189 return false; 127 return false;
190} 128}
191 129
192/** \brief run user level code immediately after wakeup
193 *
194 * FIXME: needs doc
195 */
196__attribute__((weak)) void suspend_wakeup_init_user(void) {}
197
198/** \brief run keyboard level code immediately after wakeup
199 *
200 * FIXME: needs doc
201 */
202__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); }
203
204/** \brief run immediately after wakeup 130/** \brief run immediately after wakeup
205 * 131 *
206 * FIXME: needs doc 132 * FIXME: needs doc
@@ -209,27 +135,7 @@ void suspend_wakeup_init(void) {
209 // clear keyboard state 135 // clear keyboard state
210 clear_keyboard(); 136 clear_keyboard();
211 137
212 // Turn on backlight 138 suspend_wakeup_init_quantum();
213#ifdef BACKLIGHT_ENABLE
214 backlight_init();
215#endif
216
217 // Restore LED indicators
218 led_set(host_keyboard_leds());
219
220 // Wake up underglow
221#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
222 rgblight_wakeup();
223#endif
224
225#if defined(LED_MATRIX_ENABLE)
226 led_matrix_set_suspend_state(false);
227#endif
228#if defined(RGB_MATRIX_ENABLE)
229 rgb_matrix_set_suspend_state(false);
230#endif
231
232 suspend_wakeup_init_kb();
233} 139}
234 140
235#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect) 141#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
diff --git a/tmk_core/common/chibios/_wait.h b/tmk_core/common/chibios/_wait.h
index b740afbd2..2f36c64a2 100644
--- a/tmk_core/common/chibios/_wait.h
+++ b/tmk_core/common/chibios/_wait.h
@@ -43,8 +43,6 @@ void wait_us(uint16_t duration);
43 43
44#include "_wait.c" 44#include "_wait.c"
45 45
46#define CPU_CLOCK STM32_SYSCLK
47
48/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus 46/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
49 * to which the GPIO is connected. 47 * to which the GPIO is connected.
50 * The connected buses differ depending on the various series of MCUs. 48 * The connected buses differ depending on the various series of MCUs.
diff --git a/tmk_core/common/chibios/chibios_config.h b/tmk_core/common/chibios/chibios_config.h
index 23c65f942..c35f58955 100644
--- a/tmk_core/common/chibios/chibios_config.h
+++ b/tmk_core/common/chibios/chibios_config.h
@@ -19,22 +19,33 @@
19# define SPLIT_USB_DETECT // Force this on when dedicated pin is not used 19# define SPLIT_USB_DETECT // Force this on when dedicated pin is not used
20#endif 20#endif
21 21
22#if defined(STM32F1XX) 22// STM32 compatibility
23# define USE_GPIOV1 23#if defined(MCU_STM32)
24#endif 24# define CPU_CLOCK STM32_SYSCLK
25 25
26#if defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32L1XX) 26# if defined(STM32F1XX)
27# define USE_I2CV1 27# define USE_GPIOV1
28#endif 28# define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_STM32_ALTERNATE_OPENDRAIN
29# define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_STM32_ALTERNATE_PUSHPULL
30# else
31# define PAL_OUTPUT_TYPE_OPENDRAIN PAL_STM32_OTYPE_OPENDRAIN
32# define PAL_OUTPUT_TYPE_PUSHPULL PAL_STM32_OTYPE_PUSHPULL
33# define PAL_OUTPUT_SPEED_HIGHEST PAL_STM32_OSPEED_HIGHEST
34# define PAL_PUPDR_FLOATING PAL_STM32_PUPDR_FLOATING
35# endif
29 36
30// teensy 37# if defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32L1XX)
31#if defined(K20x) || defined(KL2x) 38# define USE_I2CV1
32# define USE_I2CV1 39# endif
33# define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed
34# define USE_GPIOV1
35# define STM32_SYSCLK KINETIS_SYSCLK_FREQUENCY
36#endif 40#endif
37 41
38#if defined(MK66F18) 42// teensy compatibility
39# define STM32_SYSCLK KINETIS_SYSCLK_FREQUENCY 43#if defined(MCU_KINETIS)
40#endif 44# define CPU_CLOCK KINETIS_SYSCLK_FREQUENCY
45
46# if defined(K20x) || defined(KL2x)
47# define USE_I2CV1
48# define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed
49# define USE_GPIOV1
50# endif
51#endif \ No newline at end of file
diff --git a/tmk_core/common/chibios/eeprom_stm32.c b/tmk_core/common/chibios/eeprom_stm32.c
index 1fdf8c1e2..acc6a4851 100644
--- a/tmk_core/common/chibios/eeprom_stm32.c
+++ b/tmk_core/common/chibios/eeprom_stm32.c
@@ -620,48 +620,11 @@ uint16_t EEPROM_ReadDataWord(uint16_t Address) {
620} 620}
621 621
622/***************************************************************************** 622/*****************************************************************************
623 * Wrap library in AVR style functions. 623 * Bind to eeprom_driver.c
624 *******************************************************************************/ 624 *******************************************************************************/
625uint8_t eeprom_read_byte(const uint8_t *Address) { return EEPROM_ReadDataByte((const uintptr_t)Address); } 625void eeprom_driver_init(void) { EEPROM_Init(); }
626 626
627void eeprom_write_byte(uint8_t *Address, uint8_t Value) { EEPROM_WriteDataByte((uintptr_t)Address, Value); } 627void eeprom_driver_erase(void) { EEPROM_Erase(); }
628
629void eeprom_update_byte(uint8_t *Address, uint8_t Value) { EEPROM_WriteDataByte((uintptr_t)Address, Value); }
630
631uint16_t eeprom_read_word(const uint16_t *Address) { return EEPROM_ReadDataWord((const uintptr_t)Address); }
632
633void eeprom_write_word(uint16_t *Address, uint16_t Value) { EEPROM_WriteDataWord((uintptr_t)Address, Value); }
634
635void eeprom_update_word(uint16_t *Address, uint16_t Value) { EEPROM_WriteDataWord((uintptr_t)Address, Value); }
636
637uint32_t eeprom_read_dword(const uint32_t *Address) {
638 const uint16_t p = (const uintptr_t)Address;
639 /* Check word alignment */
640 if (p % 2) {
641 /* Not aligned */
642 return (uint32_t)EEPROM_ReadDataByte(p) | (uint32_t)(EEPROM_ReadDataWord(p + 1) << 8) | (uint32_t)(EEPROM_ReadDataByte(p + 3) << 24);
643 } else {
644 /* Aligned */
645 return EEPROM_ReadDataWord(p) | (EEPROM_ReadDataWord(p + 2) << 16);
646 }
647}
648
649void eeprom_write_dword(uint32_t *Address, uint32_t Value) {
650 uint16_t p = (const uintptr_t)Address;
651 /* Check word alignment */
652 if (p % 2) {
653 /* Not aligned */
654 EEPROM_WriteDataByte(p, (uint8_t)Value);
655 EEPROM_WriteDataWord(p + 1, (uint16_t)(Value >> 8));
656 EEPROM_WriteDataByte(p + 3, (uint8_t)(Value >> 24));
657 } else {
658 /* Aligned */
659 EEPROM_WriteDataWord(p, (uint16_t)Value);
660 EEPROM_WriteDataWord(p + 2, (uint16_t)(Value >> 16));
661 }
662}
663
664void eeprom_update_dword(uint32_t *Address, uint32_t Value) { eeprom_write_dword(Address, Value); }
665 628
666void eeprom_read_block(void *buf, const void *addr, size_t len) { 629void eeprom_read_block(void *buf, const void *addr, size_t len) {
667 const uint8_t *src = (const uint8_t *)addr; 630 const uint8_t *src = (const uint8_t *)addr;
@@ -670,14 +633,14 @@ void eeprom_read_block(void *buf, const void *addr, size_t len) {
670 /* Check word alignment */ 633 /* Check word alignment */
671 if (len && (uintptr_t)src % 2) { 634 if (len && (uintptr_t)src % 2) {
672 /* Read the unaligned first byte */ 635 /* Read the unaligned first byte */
673 *dest++ = eeprom_read_byte(src++); 636 *dest++ = EEPROM_ReadDataByte((const uintptr_t)src++);
674 --len; 637 --len;
675 } 638 }
676 639
677 uint16_t value; 640 uint16_t value;
678 bool aligned = ((uintptr_t)dest % 2 == 0); 641 bool aligned = ((uintptr_t)dest % 2 == 0);
679 while (len > 1) { 642 while (len > 1) {
680 value = eeprom_read_word((uint16_t *)src); 643 value = EEPROM_ReadDataWord((const uintptr_t)((uint16_t *)src));
681 if (aligned) { 644 if (aligned) {
682 *(uint16_t *)dest = value; 645 *(uint16_t *)dest = value;
683 dest += 2; 646 dest += 2;
@@ -689,7 +652,7 @@ void eeprom_read_block(void *buf, const void *addr, size_t len) {
689 len -= 2; 652 len -= 2;
690 } 653 }
691 if (len) { 654 if (len) {
692 *dest = eeprom_read_byte(src); 655 *dest = EEPROM_ReadDataByte((const uintptr_t)src);
693 } 656 }
694} 657}
695 658
@@ -700,7 +663,7 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
700 /* Check word alignment */ 663 /* Check word alignment */
701 if (len && (uintptr_t)dest % 2) { 664 if (len && (uintptr_t)dest % 2) {
702 /* Write the unaligned first byte */ 665 /* Write the unaligned first byte */
703 eeprom_write_byte(dest++, *src++); 666 EEPROM_WriteDataByte((uintptr_t)dest++, *src++);
704 --len; 667 --len;
705 } 668 }
706 669
@@ -712,15 +675,13 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
712 } else { 675 } else {
713 value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8); 676 value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8);
714 } 677 }
715 eeprom_write_word((uint16_t *)dest, value); 678 EEPROM_WriteDataWord((uintptr_t)((uint16_t *)dest), value);
716 dest += 2; 679 dest += 2;
717 src += 2; 680 src += 2;
718 len -= 2; 681 len -= 2;
719 } 682 }
720 683
721 if (len) { 684 if (len) {
722 eeprom_write_byte(dest, *src); 685 EEPROM_WriteDataByte((uintptr_t)dest, *src);
723 } 686 }
724} 687}
725
726void eeprom_update_block(const void *buf, void *addr, size_t len) { eeprom_write_block(buf, addr, len); }
diff --git a/tmk_core/common/chibios/eeprom_stm32_defs.h b/tmk_core/common/chibios/eeprom_stm32_defs.h
index 22b4ab858..cc64cda74 100644
--- a/tmk_core/common/chibios/eeprom_stm32_defs.h
+++ b/tmk_core/common/chibios/eeprom_stm32_defs.h
@@ -32,6 +32,13 @@
32# ifndef FEE_PAGE_COUNT 32# ifndef FEE_PAGE_COUNT
33# define FEE_PAGE_COUNT 4 // How many pages are used 33# define FEE_PAGE_COUNT 4 // How many pages are used
34# endif 34# endif
35# elif defined(STM32F401xC) || defined(STM32F405xG) || defined(STM32F411xE)
36# ifndef FEE_PAGE_SIZE
37# define FEE_PAGE_SIZE 0x4000 // Page size = 16KByte
38# endif
39# ifndef FEE_PAGE_COUNT
40# define FEE_PAGE_COUNT 1 // How many pages are used
41# endif
35# endif 42# endif
36#endif 43#endif
37 44
@@ -40,17 +47,21 @@
40# define FEE_MCU_FLASH_SIZE 32 // Size in Kb 47# define FEE_MCU_FLASH_SIZE 32 // Size in Kb
41# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB) 48# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB)
42# define FEE_MCU_FLASH_SIZE 128 // Size in Kb 49# define FEE_MCU_FLASH_SIZE 128 // Size in Kb
43# elif defined(STM32F303xC) 50# elif defined(STM32F303xC) || defined(STM32F401xC)
44# define FEE_MCU_FLASH_SIZE 256 // Size in Kb 51# define FEE_MCU_FLASH_SIZE 256 // Size in Kb
45# elif defined(STM32F103xE) 52# elif defined(STM32F103xE) || defined(STM32F411xE)
46# define FEE_MCU_FLASH_SIZE 512 // Size in Kb 53# define FEE_MCU_FLASH_SIZE 512 // Size in Kb
54# elif defined(STM32F405xG)
55# define FEE_MCU_FLASH_SIZE 1024 // Size in Kb
47# endif 56# endif
48#endif 57#endif
49 58
50/* Start of the emulated eeprom */ 59/* Start of the emulated eeprom */
51#if !defined(FEE_PAGE_BASE_ADDRESS) 60#if !defined(FEE_PAGE_BASE_ADDRESS)
52# if 0 61# if defined(STM32F401xC) || defined(STM32F405xG) || defined(STM32F411xE)
53/* TODO: Add support for F4 */ 62# ifndef FEE_PAGE_BASE_ADDRESS
63# define FEE_PAGE_BASE_ADDRESS 0x08004000 // bodge to force 2nd 16k page
64# endif
54# else 65# else
55# ifndef FEE_FLASH_BASE 66# ifndef FEE_FLASH_BASE
56# define FEE_FLASH_BASE 0x8000000 67# define FEE_FLASH_BASE 0x8000000
diff --git a/tmk_core/common/chibios/flash_stm32.c b/tmk_core/common/chibios/flash_stm32.c
index 6b80ff71c..8f10903d3 100644
--- a/tmk_core/common/chibios/flash_stm32.c
+++ b/tmk_core/common/chibios/flash_stm32.c
@@ -23,6 +23,29 @@
23# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR 23# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR
24#endif 24#endif
25 25
26#if defined(EEPROM_EMU_STM32F401xC)
27# define FLASH_SR_PGERR (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR)
28
29# define FLASH_KEY1 0x45670123U
30# define FLASH_KEY2 0xCDEF89ABU
31
32static uint8_t ADDR2PAGE(uint32_t Page_Address) {
33 switch (Page_Address) {
34 case 0x08000000 ... 0x08003FFF:
35 return 0;
36 case 0x08004000 ... 0x08007FFF:
37 return 1;
38 case 0x08008000 ... 0x0800BFFF:
39 return 2;
40 case 0x0800C000 ... 0x0800FFFF:
41 return 3;
42 }
43
44 // TODO: bad times...
45 return 7;
46}
47#endif
48
26/* Delay definition */ 49/* Delay definition */
27#define EraseTimeout ((uint32_t)0x00000FFF) 50#define EraseTimeout ((uint32_t)0x00000FFF)
28#define ProgramTimeout ((uint32_t)0x0000001F) 51#define ProgramTimeout ((uint32_t)0x0000001F)
@@ -53,7 +76,9 @@ FLASH_Status FLASH_GetStatus(void) {
53 76
54 if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP; 77 if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP;
55 78
79#if defined(FLASH_OBR_OPTERR)
56 if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT; 80 if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT;
81#endif
57 82
58 return FLASH_COMPLETE; 83 return FLASH_COMPLETE;
59} 84}
@@ -95,15 +120,24 @@ FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
95 120
96 if (status == FLASH_COMPLETE) { 121 if (status == FLASH_COMPLETE) {
97 /* if the previous operation is completed, proceed to erase the page */ 122 /* if the previous operation is completed, proceed to erase the page */
123#if defined(FLASH_CR_SNB)
124 FLASH->CR &= ~FLASH_CR_SNB;
125 FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos);
126#else
98 FLASH->CR |= FLASH_CR_PER; 127 FLASH->CR |= FLASH_CR_PER;
99 FLASH->AR = Page_Address; 128 FLASH->AR = Page_Address;
129#endif
100 FLASH->CR |= FLASH_CR_STRT; 130 FLASH->CR |= FLASH_CR_STRT;
101 131
102 /* Wait for last operation to be completed */ 132 /* Wait for last operation to be completed */
103 status = FLASH_WaitForLastOperation(EraseTimeout); 133 status = FLASH_WaitForLastOperation(EraseTimeout);
104 if (status != FLASH_TIMEOUT) { 134 if (status != FLASH_TIMEOUT) {
105 /* if the erase operation is completed, disable the PER Bit */ 135 /* if the erase operation is completed, disable the configured Bits */
136#if defined(FLASH_CR_SNB)
137 FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB);
138#else
106 FLASH->CR &= ~FLASH_CR_PER; 139 FLASH->CR &= ~FLASH_CR_PER;
140#endif
107 } 141 }
108 FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR); 142 FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
109 } 143 }
@@ -126,6 +160,11 @@ FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
126 status = FLASH_WaitForLastOperation(ProgramTimeout); 160 status = FLASH_WaitForLastOperation(ProgramTimeout);
127 if (status == FLASH_COMPLETE) { 161 if (status == FLASH_COMPLETE) {
128 /* if the previous operation is completed, proceed to program the new data */ 162 /* if the previous operation is completed, proceed to program the new data */
163
164#if defined(FLASH_CR_PSIZE)
165 FLASH->CR &= ~FLASH_CR_PSIZE;
166 FLASH->CR |= FLASH_CR_PSIZE_0;
167#endif
129 FLASH->CR |= FLASH_CR_PG; 168 FLASH->CR |= FLASH_CR_PG;
130 *(__IO uint16_t*)Address = Data; 169 *(__IO uint16_t*)Address = Data;
131 /* Wait for last operation to be completed */ 170 /* Wait for last operation to be completed */
diff --git a/tmk_core/common/chibios/suspend.c b/tmk_core/common/chibios/suspend.c
index 38517e06f..9310a9992 100644
--- a/tmk_core/common/chibios/suspend.c
+++ b/tmk_core/common/chibios/suspend.c
@@ -7,30 +7,12 @@
7#include "action.h" 7#include "action.h"
8#include "action_util.h" 8#include "action_util.h"
9#include "mousekey.h" 9#include "mousekey.h"
10#include "programmable_button.h"
10#include "host.h" 11#include "host.h"
11#include "suspend.h" 12#include "suspend.h"
12#include "led.h" 13#include "led.h"
13#include "wait.h" 14#include "wait.h"
14 15
15#ifdef AUDIO_ENABLE
16# include "audio.h"
17#endif /* AUDIO_ENABLE */
18
19#ifdef BACKLIGHT_ENABLE
20# include "backlight.h"
21#endif
22
23#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
24# include "rgblight.h"
25#endif
26
27#ifdef LED_MATRIX_ENABLE
28# include "led_matrix.h"
29#endif
30#ifdef RGB_MATRIX_ENABLE
31# include "rgb_matrix.h"
32#endif
33
34/** \brief suspend idle 16/** \brief suspend idle
35 * 17 *
36 * FIXME: needs doc 18 * FIXME: needs doc
@@ -40,61 +22,12 @@ void suspend_idle(uint8_t time) {
40 wait_ms(time); 22 wait_ms(time);
41} 23}
42 24
43/** \brief Run keyboard level Power down
44 *
45 * FIXME: needs doc
46 */
47__attribute__((weak)) void suspend_power_down_user(void) {}
48/** \brief Run keyboard level Power down
49 *
50 * FIXME: needs doc
51 */
52__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); }
53
54/** \brief suspend power down 25/** \brief suspend power down
55 * 26 *
56 * FIXME: needs doc 27 * FIXME: needs doc
57 */ 28 */
58void suspend_power_down(void) { 29void suspend_power_down(void) {
59#ifdef BACKLIGHT_ENABLE 30 suspend_power_down_quantum();
60 backlight_set(0);
61#endif
62
63#ifdef LED_MATRIX_ENABLE
64 led_matrix_task();
65#endif
66#ifdef RGB_MATRIX_ENABLE
67 rgb_matrix_task();
68#endif
69
70 // Turn off LED indicators
71 uint8_t leds_off = 0;
72#if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE)
73 if (is_backlight_enabled()) {
74 // Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off
75 leds_off |= (1 << USB_LED_CAPS_LOCK);
76 }
77#endif
78 led_set(leds_off);
79
80 // TODO: figure out what to power down and how
81 // shouldn't power down TPM/FTM if we want a breathing LED
82 // also shouldn't power down USB
83#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
84 rgblight_suspend();
85#endif
86
87#if defined(LED_MATRIX_ENABLE)
88 led_matrix_set_suspend_state(true);
89#endif
90#if defined(RGB_MATRIX_ENABLE)
91 rgb_matrix_set_suspend_state(true);
92#endif
93#ifdef AUDIO_ENABLE
94 stop_all_notes();
95#endif /* AUDIO_ENABLE */
96
97 suspend_power_down_kb();
98 // on AVR, this enables the watchdog for 15ms (max), and goes to 31 // on AVR, this enables the watchdog for 15ms (max), and goes to
99 // SLEEP_MODE_PWR_DOWN 32 // SLEEP_MODE_PWR_DOWN
100 33
@@ -147,23 +80,13 @@ void suspend_wakeup_init(void) {
147#ifdef MOUSEKEY_ENABLE 80#ifdef MOUSEKEY_ENABLE
148 mousekey_clear(); 81 mousekey_clear();
149#endif /* MOUSEKEY_ENABLE */ 82#endif /* MOUSEKEY_ENABLE */
83#ifdef PROGRAMMABLE_BUTTON_ENABLE
84 programmable_button_clear();
85#endif /* PROGRAMMABLE_BUTTON_ENABLE */
150#ifdef EXTRAKEY_ENABLE 86#ifdef EXTRAKEY_ENABLE
151 host_system_send(0); 87 host_system_send(0);
152 host_consumer_send(0); 88 host_consumer_send(0);
153#endif /* EXTRAKEY_ENABLE */ 89#endif /* EXTRAKEY_ENABLE */
154#ifdef BACKLIGHT_ENABLE
155 backlight_init();
156#endif /* BACKLIGHT_ENABLE */
157 led_set(host_keyboard_leds());
158#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
159 rgblight_wakeup();
160#endif
161 90
162#if defined(LED_MATRIX_ENABLE) 91 suspend_wakeup_init_quantum();
163 led_matrix_set_suspend_state(false);
164#endif
165#if defined(RGB_MATRIX_ENABLE)
166 rgb_matrix_set_suspend_state(false);
167#endif
168 suspend_wakeup_init_kb();
169} 92}
diff --git a/tmk_core/common/host.c b/tmk_core/common/host.c
index f0c396b18..56d4bb084 100644
--- a/tmk_core/common/host.c
+++ b/tmk_core/common/host.c
@@ -30,8 +30,9 @@ extern keymap_config_t keymap_config;
30#endif 30#endif
31 31
32static host_driver_t *driver; 32static host_driver_t *driver;
33static uint16_t last_system_report = 0; 33static uint16_t last_system_report = 0;
34static uint16_t last_consumer_report = 0; 34static uint16_t last_consumer_report = 0;
35static uint32_t last_programmable_button_report = 0;
35 36
36void host_set_driver(host_driver_t *d) { driver = d; } 37void host_set_driver(host_driver_t *d) { driver = d; }
37 38
@@ -122,6 +123,16 @@ void host_digitizer_send(digitizer_t *digitizer) {
122 123
123__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {} 124__attribute__((weak)) void send_digitizer(report_digitizer_t *report) {}
124 125
126void host_programmable_button_send(uint32_t report) {
127 if (report == last_programmable_button_report) return;
128 last_programmable_button_report = report;
129
130 if (!driver) return;
131 (*driver->send_programmable_button)(report);
132}
133
125uint16_t host_last_system_report(void) { return last_system_report; } 134uint16_t host_last_system_report(void) { return last_system_report; }
126 135
127uint16_t host_last_consumer_report(void) { return last_consumer_report; } 136uint16_t host_last_consumer_report(void) { return last_consumer_report; }
137
138uint32_t host_last_programmable_button_report(void) { return last_programmable_button_report; }
diff --git a/tmk_core/common/host.h b/tmk_core/common/host.h
index 2cffef6e1..6b15f0d0c 100644
--- a/tmk_core/common/host.h
+++ b/tmk_core/common/host.h
@@ -47,9 +47,11 @@ void host_keyboard_send(report_keyboard_t *report);
47void host_mouse_send(report_mouse_t *report); 47void host_mouse_send(report_mouse_t *report);
48void host_system_send(uint16_t data); 48void host_system_send(uint16_t data);
49void host_consumer_send(uint16_t data); 49void host_consumer_send(uint16_t data);
50void host_programmable_button_send(uint32_t data);
50 51
51uint16_t host_last_system_report(void); 52uint16_t host_last_system_report(void);
52uint16_t host_last_consumer_report(void); 53uint16_t host_last_consumer_report(void);
54uint32_t host_last_programmable_button_report(void);
53 55
54#ifdef __cplusplus 56#ifdef __cplusplus
55} 57}
diff --git a/tmk_core/common/host_driver.h b/tmk_core/common/host_driver.h
index 2aebca043..affd0dcb3 100644
--- a/tmk_core/common/host_driver.h
+++ b/tmk_core/common/host_driver.h
@@ -29,6 +29,7 @@ typedef struct {
29 void (*send_mouse)(report_mouse_t *); 29 void (*send_mouse)(report_mouse_t *);
30 void (*send_system)(uint16_t); 30 void (*send_system)(uint16_t);
31 void (*send_consumer)(uint16_t); 31 void (*send_consumer)(uint16_t);
32 void (*send_programmable_button)(uint32_t);
32} host_driver_t; 33} host_driver_t;
33 34
34void send_digitizer(report_digitizer_t *report); \ No newline at end of file 35void send_digitizer(report_digitizer_t *report); \ No newline at end of file
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index f2223e806..1adc892f3 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -29,6 +29,7 @@ enum hid_report_ids {
29 REPORT_ID_MOUSE, 29 REPORT_ID_MOUSE,
30 REPORT_ID_SYSTEM, 30 REPORT_ID_SYSTEM,
31 REPORT_ID_CONSUMER, 31 REPORT_ID_CONSUMER,
32 REPORT_ID_PROGRAMMABLE_BUTTON,
32 REPORT_ID_NKRO, 33 REPORT_ID_NKRO,
33 REPORT_ID_JOYSTICK, 34 REPORT_ID_JOYSTICK,
34 REPORT_ID_DIGITIZER 35 REPORT_ID_DIGITIZER
@@ -196,6 +197,11 @@ typedef struct {
196} __attribute__((packed)) report_extra_t; 197} __attribute__((packed)) report_extra_t;
197 198
198typedef struct { 199typedef struct {
200 uint8_t report_id;
201 uint32_t usage;
202} __attribute__((packed)) report_programmable_button_t;
203
204typedef struct {
199#ifdef MOUSE_SHARED_EP 205#ifdef MOUSE_SHARED_EP
200 uint8_t report_id; 206 uint8_t report_id;
201#endif 207#endif
diff --git a/tmk_core/common/suspend.h b/tmk_core/common/suspend.h
index 95845e4b6..081735f90 100644
--- a/tmk_core/common/suspend.h
+++ b/tmk_core/common/suspend.h
@@ -10,8 +10,10 @@ void suspend_wakeup_init(void);
10 10
11void suspend_wakeup_init_user(void); 11void suspend_wakeup_init_user(void);
12void suspend_wakeup_init_kb(void); 12void suspend_wakeup_init_kb(void);
13void suspend_wakeup_init_quantum(void);
13void suspend_power_down_user(void); 14void suspend_power_down_user(void);
14void suspend_power_down_kb(void); 15void suspend_power_down_kb(void);
16void suspend_power_down_quantum(void);
15 17
16#ifndef USB_SUSPEND_WAKEUP_DELAY 18#ifndef USB_SUSPEND_WAKEUP_DELAY
17# define USB_SUSPEND_WAKEUP_DELAY 0 19# define USB_SUSPEND_WAKEUP_DELAY 0
diff --git a/tmk_core/common/test/rules.mk b/tmk_core/common/test/rules.mk
index 48632a095..73d2302da 100644
--- a/tmk_core/common/test/rules.mk
+++ b/tmk_core/common/test/rules.mk
@@ -16,6 +16,7 @@ eeprom_stm32_tiny_INC := $(eeprom_stm32_INC)
16eeprom_stm32_large_INC := $(eeprom_stm32_INC) 16eeprom_stm32_large_INC := $(eeprom_stm32_INC)
17 17
18eeprom_stm32_SRC := \ 18eeprom_stm32_SRC := \
19 $(TOP_DIR)/drivers/eeprom/eeprom_driver.c \
19 $(TMK_PATH)/common/test/eeprom_stm32_tests.cpp \ 20 $(TMK_PATH)/common/test/eeprom_stm32_tests.cpp \
20 $(TMK_PATH)/common/test/flash_stm32_mock.c \ 21 $(TMK_PATH)/common/test/flash_stm32_mock.c \
21 $(TMK_PATH)/common/chibios/eeprom_stm32.c 22 $(TMK_PATH)/common/chibios/eeprom_stm32.c
diff --git a/tmk_core/protocol/chibios/chibios.c b/tmk_core/protocol/chibios/chibios.c
index 78a2e3fcb..e5d3a4c54 100644
--- a/tmk_core/protocol/chibios/chibios.c
+++ b/tmk_core/protocol/chibios/chibios.c
@@ -27,6 +27,7 @@
27#include "keyboard.h" 27#include "keyboard.h"
28#include "action.h" 28#include "action.h"
29#include "action_util.h" 29#include "action_util.h"
30#include "usb_device_state.h"
30#include "mousekey.h" 31#include "mousekey.h"
31#include "led.h" 32#include "led.h"
32#include "sendchar.h" 33#include "sendchar.h"
@@ -139,6 +140,8 @@ void boardInit(void) {
139} 140}
140 141
141void protocol_setup(void) { 142void protocol_setup(void) {
143 usb_device_state_init();
144
142 // TESTING 145 // TESTING
143 // chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); 146 // chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
144 147
diff --git a/tmk_core/protocol/chibios/usb_main.c b/tmk_core/protocol/chibios/usb_main.c
index cc282e6a9..9b139b399 100644
--- a/tmk_core/protocol/chibios/usb_main.c
+++ b/tmk_core/protocol/chibios/usb_main.c
@@ -39,6 +39,7 @@
39# include "led.h" 39# include "led.h"
40#endif 40#endif
41#include "wait.h" 41#include "wait.h"
42#include "usb_device_state.h"
42#include "usb_descriptor.h" 43#include "usb_descriptor.h"
43#include "usb_driver.h" 44#include "usb_driver.h"
44 45
@@ -412,6 +413,7 @@ static inline bool usb_event_queue_dequeue(usbevent_t *event) {
412} 413}
413 414
414static inline void usb_event_suspend_handler(void) { 415static inline void usb_event_suspend_handler(void) {
416 usb_device_state_set_suspend(USB_DRIVER.configuration != 0, USB_DRIVER.configuration);
415#ifdef SLEEP_LED_ENABLE 417#ifdef SLEEP_LED_ENABLE
416 sleep_led_enable(); 418 sleep_led_enable();
417#endif /* SLEEP_LED_ENABLE */ 419#endif /* SLEEP_LED_ENABLE */
@@ -419,6 +421,7 @@ static inline void usb_event_suspend_handler(void) {
419 421
420static inline void usb_event_wakeup_handler(void) { 422static inline void usb_event_wakeup_handler(void) {
421 suspend_wakeup_init(); 423 suspend_wakeup_init();
424 usb_device_state_set_resume(USB_DRIVER.configuration != 0, USB_DRIVER.configuration);
422#ifdef SLEEP_LED_ENABLE 425#ifdef SLEEP_LED_ENABLE
423 sleep_led_disable(); 426 sleep_led_disable();
424 // NOTE: converters may not accept this 427 // NOTE: converters may not accept this
@@ -440,6 +443,15 @@ void usb_event_queue_task(void) {
440 last_suspend_state = false; 443 last_suspend_state = false;
441 usb_event_wakeup_handler(); 444 usb_event_wakeup_handler();
442 break; 445 break;
446 case USB_EVENT_CONFIGURED:
447 usb_device_state_set_configuration(USB_DRIVER.configuration != 0, USB_DRIVER.configuration);
448 break;
449 case USB_EVENT_UNCONFIGURED:
450 usb_device_state_set_configuration(false, 0);
451 break;
452 case USB_EVENT_RESET:
453 usb_device_state_set_reset();
454 break;
443 default: 455 default:
444 // Nothing to do, we don't handle it. 456 // Nothing to do, we don't handle it.
445 break; 457 break;
@@ -482,13 +494,14 @@ static void usb_event_cb(USBDriver *usbp, usbevent_t event) {
482 if (last_suspend_state) { 494 if (last_suspend_state) {
483 usb_event_queue_enqueue(USB_EVENT_WAKEUP); 495 usb_event_queue_enqueue(USB_EVENT_WAKEUP);
484 } 496 }
497 usb_event_queue_enqueue(USB_EVENT_CONFIGURED);
485 return; 498 return;
486 case USB_EVENT_SUSPEND: 499 case USB_EVENT_SUSPEND:
487 usb_event_queue_enqueue(USB_EVENT_SUSPEND);
488 /* Falls into.*/ 500 /* Falls into.*/
489 case USB_EVENT_UNCONFIGURED: 501 case USB_EVENT_UNCONFIGURED:
490 /* Falls into.*/ 502 /* Falls into.*/
491 case USB_EVENT_RESET: 503 case USB_EVENT_RESET:
504 usb_event_queue_enqueue(event);
492 for (int i = 0; i < NUM_USB_DRIVERS; i++) { 505 for (int i = 0; i < NUM_USB_DRIVERS; i++) {
493 chSysLockFromISR(); 506 chSysLockFromISR();
494 /* Disconnection event on suspend.*/ 507 /* Disconnection event on suspend.*/
diff --git a/tmk_core/protocol/ibm4704.c b/tmk_core/protocol/ibm4704.c
deleted file mode 100644
index a19443976..000000000
--- a/tmk_core/protocol/ibm4704.c
+++ /dev/null
@@ -1,185 +0,0 @@
1/*
2Copyright 2010,2011,2012,2013 Jun WAKO <wakojun@gmail.com>
3*/
4#include <stdbool.h>
5#include <util/delay.h>
6#include "debug.h"
7#include "ring_buffer.h"
8#include "ibm4704.h"
9
10#define WAIT(stat, us, err) \
11 do { \
12 if (!wait_##stat(us)) { \
13 ibm4704_error = err; \
14 goto ERROR; \
15 } \
16 } while (0)
17
18uint8_t ibm4704_error = 0;
19
20void ibm4704_init(void) {
21 inhibit(); // keep keyboard from sending
22 IBM4704_INT_INIT();
23 IBM4704_INT_ON();
24 idle(); // allow keyboard sending
25}
26
27/*
28Host to Keyboard
29----------------
30Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
31
32 ____ __ __ __ __ __ __ __ __ __ ________
33Clock \______/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
34 ^ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ___
35Data ____|__/ X____X____X____X____X____X____X____X____X____X \___
36 | Start 0 1 2 3 4 5 6 7 P Stop
37 Request by host
38
39Start bit: can be long as 300-350us.
40Request: Host pulls Clock line down to request to send a command.
41Timing: After Request keyboard pull up Data and down Clock line to low for start bit.
42 After request host release Clock line once Data line becomes hi.
43 Host writes a bit while Clock is hi and Keyboard reads while low.
44Stop bit: Host releases or pulls up Data line to hi after 9th clock and waits for keyboard pull down the line to lo.
45*/
46uint8_t ibm4704_send(uint8_t data) {
47 bool parity = true; // odd parity
48 ibm4704_error = 0;
49
50 IBM4704_INT_OFF();
51
52 /* Request to send */
53 idle();
54 clock_lo();
55
56 /* wait for Start bit(Clock:lo/Data:hi) */
57 WAIT(data_hi, 300, 0x30);
58
59 /* Data bit */
60 for (uint8_t i = 0; i < 8; i++) {
61 WAIT(clock_hi, 100, 0x40 + i);
62 if (data & (1 << i)) {
63 parity = !parity;
64 data_hi();
65 } else {
66 data_lo();
67 }
68 WAIT(clock_lo, 100, 0x48 + i);
69 }
70
71 /* Parity bit */
72 WAIT(clock_hi, 100, 0x34);
73 if (parity) {
74 data_hi();
75 } else {
76 data_lo();
77 }
78 WAIT(clock_lo, 100, 0x35);
79
80 /* Stop bit */
81 WAIT(clock_hi, 100, 0x34);
82 data_hi();
83
84 /* End */
85 WAIT(data_lo, 100, 0x36);
86
87 idle();
88 IBM4704_INT_ON();
89 return 0;
90ERROR:
91 idle();
92 if (ibm4704_error > 0x30) {
93 xprintf("S:%02X ", ibm4704_error);
94 }
95 IBM4704_INT_ON();
96 return -1;
97}
98
99/* wait forever to receive data */
100uint8_t ibm4704_recv_response(void) {
101 while (!rbuf_has_data()) {
102 _delay_ms(1);
103 }
104 return rbuf_dequeue();
105}
106
107uint8_t ibm4704_recv(void) {
108 if (rbuf_has_data()) {
109 return rbuf_dequeue();
110 } else {
111 return -1;
112 }
113}
114
115/*
116Keyboard to Host
117----------------
118Data bits are LSB first and Parity is odd. Clock has around 60us high and 30us low part.
119
120 ____ __ __ __ __ __ __ __ __ __ _______
121Clock \_____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/
122 ____ ____ ____ ____ ____ ____ ____ ____ ____ ____
123Data ____/ X____X____X____X____X____X____X____X____X____X________
124 Start 0 1 2 3 4 5 6 7 P Stop
125
126Start bit: can be long as 300-350us.
127Inhibit: Pull Data line down to inhibit keyboard to send.
128Timing: Host reads bit while Clock is hi.(rising edge)
129Stop bit: Keyboard pulls down Data line to lo after 9th clock.
130*/
131ISR(IBM4704_INT_VECT) {
132 static enum { BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, PARITY, STOP } state = BIT0;
133 // LSB first
134 static uint8_t data = 0;
135 // Odd parity
136 static uint8_t parity = false;
137
138 ibm4704_error = 0;
139
140 switch (state) {
141 case BIT0:
142 case BIT1:
143 case BIT2:
144 case BIT3:
145 case BIT4:
146 case BIT5:
147 case BIT6:
148 case BIT7:
149 data >>= 1;
150 if (data_in()) {
151 data |= 0x80;
152 parity = !parity;
153 }
154 break;
155 case PARITY:
156 if (data_in()) {
157 parity = !parity;
158 }
159 if (!parity) goto ERROR;
160 break;
161 case STOP:
162 // Data:Low
163 WAIT(data_lo, 100, state);
164 if (!rbuf_enqueue(data)) {
165 print("rbuf: full\n");
166 }
167 ibm4704_error = IBM4704_ERR_NONE;
168 goto DONE;
169 break;
170 default:
171 goto ERROR;
172 }
173 state++;
174 goto RETURN;
175ERROR:
176 ibm4704_error = state;
177 while (ibm4704_send(0xFE)) _delay_ms(1); // resend
178 xprintf("R:%02X%02X\n", state, data);
179DONE:
180 state = BIT0;
181 data = 0;
182 parity = false;
183RETURN:
184 return;
185}
diff --git a/tmk_core/protocol/ibm4704.h b/tmk_core/protocol/ibm4704.h
deleted file mode 100644
index 4f88d148b..000000000
--- a/tmk_core/protocol/ibm4704.h
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2Copyright 2014 Jun WAKO <wakojun@gmail.com>
3*/
4
5#pragma once
6
7#define IBM4704_ERR_NONE 0
8#define IBM4704_ERR_PARITY 0x70
9
10void ibm4704_init(void);
11uint8_t ibm4704_send(uint8_t data);
12uint8_t ibm4704_recv_response(void);
13uint8_t ibm4704_recv(void);
14
15/* Check pin configuration */
16#if !(defined(IBM4704_CLOCK_PORT) && defined(IBM4704_CLOCK_PIN) && defined(IBM4704_CLOCK_DDR) && defined(IBM4704_CLOCK_BIT))
17# error "ibm4704 clock pin configuration is required in config.h"
18#endif
19
20#if !(defined(IBM4704_DATA_PORT) && defined(IBM4704_DATA_PIN) && defined(IBM4704_DATA_DDR) && defined(IBM4704_DATA_BIT))
21# error "ibm4704 data pin configuration is required in config.h"
22#endif
23
24/*--------------------------------------------------------------------
25 * static functions
26 *------------------------------------------------------------------*/
27static inline void clock_lo(void) {
28 IBM4704_CLOCK_PORT &= ~(1 << IBM4704_CLOCK_BIT);
29 IBM4704_CLOCK_DDR |= (1 << IBM4704_CLOCK_BIT);
30}
31static inline void clock_hi(void) {
32 /* input with pull up */
33 IBM4704_CLOCK_DDR &= ~(1 << IBM4704_CLOCK_BIT);
34 IBM4704_CLOCK_PORT |= (1 << IBM4704_CLOCK_BIT);
35}
36static inline bool clock_in(void) {
37 IBM4704_CLOCK_DDR &= ~(1 << IBM4704_CLOCK_BIT);
38 IBM4704_CLOCK_PORT |= (1 << IBM4704_CLOCK_BIT);
39 _delay_us(1);
40 return IBM4704_CLOCK_PIN & (1 << IBM4704_CLOCK_BIT);
41}
42static inline void data_lo(void) {
43 IBM4704_DATA_PORT &= ~(1 << IBM4704_DATA_BIT);
44 IBM4704_DATA_DDR |= (1 << IBM4704_DATA_BIT);
45}
46static inline void data_hi(void) {
47 /* input with pull up */
48 IBM4704_DATA_DDR &= ~(1 << IBM4704_DATA_BIT);
49 IBM4704_DATA_PORT |= (1 << IBM4704_DATA_BIT);
50}
51static inline bool data_in(void) {
52 IBM4704_DATA_DDR &= ~(1 << IBM4704_DATA_BIT);
53 IBM4704_DATA_PORT |= (1 << IBM4704_DATA_BIT);
54 _delay_us(1);
55 return IBM4704_DATA_PIN & (1 << IBM4704_DATA_BIT);
56}
57
58static inline uint16_t wait_clock_lo(uint16_t us) {
59 while (clock_in() && us) {
60 asm("");
61 _delay_us(1);
62 us--;
63 }
64 return us;
65}
66static inline uint16_t wait_clock_hi(uint16_t us) {
67 while (!clock_in() && us) {
68 asm("");
69 _delay_us(1);
70 us--;
71 }
72 return us;
73}
74static inline uint16_t wait_data_lo(uint16_t us) {
75 while (data_in() && us) {
76 asm("");
77 _delay_us(1);
78 us--;
79 }
80 return us;
81}
82static inline uint16_t wait_data_hi(uint16_t us) {
83 while (!data_in() && us) {
84 asm("");
85 _delay_us(1);
86 us--;
87 }
88 return us;
89}
90
91/* idle state that device can send */
92static inline void idle(void) {
93 clock_hi();
94 data_hi();
95}
96
97/* inhibit device to send
98 * keyboard checks Data line on start bit(Data:hi) and it stops sending if Data line is low.
99 */
100static inline void inhibit(void) {
101 clock_hi();
102 data_lo();
103}
diff --git a/tmk_core/protocol/lufa.mk b/tmk_core/protocol/lufa.mk
index c8935dacb..00fec478a 100644
--- a/tmk_core/protocol/lufa.mk
+++ b/tmk_core/protocol/lufa.mk
@@ -3,7 +3,6 @@ LUFA_DIR = protocol/lufa
3# Path to the LUFA library 3# Path to the LUFA library
4LUFA_PATH = $(LIB_PATH)/lufa 4LUFA_PATH = $(LIB_PATH)/lufa
5 5
6
7# Create the LUFA source path variables by including the LUFA makefile 6# Create the LUFA source path variables by including the LUFA makefile
8ifneq (, $(wildcard $(LUFA_PATH)/LUFA/Build/lufa_sources.mk)) 7ifneq (, $(wildcard $(LUFA_PATH)/LUFA/Build/lufa_sources.mk))
9 # New build system from 20120730 8 # New build system from 20120730
@@ -22,23 +21,6 @@ ifeq ($(strip $(MIDI_ENABLE)), yes)
22 include $(TMK_PATH)/protocol/midi.mk 21 include $(TMK_PATH)/protocol/midi.mk
23endif 22endif
24 23
25ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
26 LUFA_SRC += outputselect.c \
27 $(TMK_DIR)/protocol/serial_uart.c
28endif
29
30ifeq ($(strip $(BLUETOOTH)), AdafruitBLE)
31 LUFA_SRC += spi_master.c \
32 analog.c \
33 outputselect.c \
34 $(LUFA_DIR)/adafruit_ble.cpp
35endif
36
37ifeq ($(strip $(BLUETOOTH)), RN42)
38 LUFA_SRC += outputselect.c \
39 $(TMK_DIR)/protocol/serial_uart.c
40endif
41
42ifeq ($(strip $(VIRTSER_ENABLE)), yes) 24ifeq ($(strip $(VIRTSER_ENABLE)), yes)
43 LUFA_SRC += $(LUFA_ROOT_PATH)/Drivers/USB/Class/Device/CDCClassDevice.c 25 LUFA_SRC += $(LUFA_ROOT_PATH)/Drivers/USB/Class/Device/CDCClassDevice.c
44endif 26endif
@@ -50,19 +32,10 @@ SRC += $(LUFA_DIR)/usb_util.c
50VPATH += $(TMK_PATH)/$(LUFA_DIR) 32VPATH += $(TMK_PATH)/$(LUFA_DIR)
51VPATH += $(LUFA_PATH) 33VPATH += $(LUFA_PATH)
52 34
53# Option modules
54#ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
55#endif
56
57#ifdef EXTRAKEY_ENABLE
58#endif
59
60# LUFA library compile-time options and predefined tokens 35# LUFA library compile-time options and predefined tokens
61LUFA_OPTS = -DUSB_DEVICE_ONLY 36LUFA_OPTS = -DUSB_DEVICE_ONLY
62LUFA_OPTS += -DUSE_FLASH_DESCRIPTORS 37LUFA_OPTS += -DUSE_FLASH_DESCRIPTORS
63LUFA_OPTS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" 38LUFA_OPTS += -DUSE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"
64#LUFA_OPTS += -DINTERRUPT_CONTROL_ENDPOINT
65LUFA_OPTS += -DFIXED_CONTROL_ENDPOINT_SIZE=8
66LUFA_OPTS += -DFIXED_CONTROL_ENDPOINT_SIZE=8 39LUFA_OPTS += -DFIXED_CONTROL_ENDPOINT_SIZE=8
67LUFA_OPTS += -DFIXED_NUM_CONFIGURATIONS=1 40LUFA_OPTS += -DFIXED_NUM_CONFIGURATIONS=1
68 41
diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp
deleted file mode 100644
index 3f2cc3573..000000000
--- a/tmk_core/protocol/lufa/adafruit_ble.cpp
+++ /dev/null
@@ -1,701 +0,0 @@
1#include "adafruit_ble.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <alloca.h>
6#include "debug.h"
7#include "timer.h"
8#include "action_util.h"
9#include "ringbuffer.hpp"
10#include <string.h>
11#include "spi_master.h"
12#include "wait.h"
13#include "analog.h"
14#include "progmem.h"
15
16// These are the pin assignments for the 32u4 boards.
17// You may define them to something else in your config.h
18// if yours is wired up differently.
19#ifndef AdafruitBleResetPin
20# define AdafruitBleResetPin D4
21#endif
22
23#ifndef AdafruitBleCSPin
24# define AdafruitBleCSPin B4
25#endif
26
27#ifndef AdafruitBleIRQPin
28# define AdafruitBleIRQPin E6
29#endif
30
31#ifndef AdafruitBleSpiClockSpeed
32# define AdafruitBleSpiClockSpeed 4000000UL // SCK frequency
33#endif
34
35#define SCK_DIVISOR (F_CPU / AdafruitBleSpiClockSpeed)
36
37#define SAMPLE_BATTERY
38#define ConnectionUpdateInterval 1000 /* milliseconds */
39
40#ifndef BATTERY_LEVEL_PIN
41# define BATTERY_LEVEL_PIN B5
42#endif
43
44static struct {
45 bool is_connected;
46 bool initialized;
47 bool configured;
48
49#define ProbedEvents 1
50#define UsingEvents 2
51 bool event_flags;
52
53#ifdef SAMPLE_BATTERY
54 uint16_t last_battery_update;
55 uint32_t vbat;
56#endif
57 uint16_t last_connection_update;
58} state;
59
60// Commands are encoded using SDEP and sent via SPI
61// https://github.com/adafruit/Adafruit_BluefruitLE_nRF51/blob/master/SDEP.md
62
63#define SdepMaxPayload 16
64struct sdep_msg {
65 uint8_t type;
66 uint8_t cmd_low;
67 uint8_t cmd_high;
68 struct __attribute__((packed)) {
69 uint8_t len : 7;
70 uint8_t more : 1;
71 };
72 uint8_t payload[SdepMaxPayload];
73} __attribute__((packed));
74
75// The recv latency is relatively high, so when we're hammering keys quickly,
76// we want to avoid waiting for the responses in the matrix loop. We maintain
77// a short queue for that. Since there is quite a lot of space overhead for
78// the AT command representation wrapped up in SDEP, we queue the minimal
79// information here.
80
81enum queue_type {
82 QTKeyReport, // 1-byte modifier + 6-byte key report
83 QTConsumer, // 16-bit key code
84#ifdef MOUSE_ENABLE
85 QTMouseMove, // 4-byte mouse report
86#endif
87};
88
89struct queue_item {
90 enum queue_type queue_type;
91 uint16_t added;
92 union __attribute__((packed)) {
93 struct __attribute__((packed)) {
94 uint8_t modifier;
95 uint8_t keys[6];
96 } key;
97
98 uint16_t consumer;
99 struct __attribute__((packed)) {
100 int8_t x, y, scroll, pan;
101 uint8_t buttons;
102 } mousemove;
103 };
104};
105
106// Items that we wish to send
107static RingBuffer<queue_item, 40> send_buf;
108// Pending response; while pending, we can't send any more requests.
109// This records the time at which we sent the command for which we
110// are expecting a response.
111static RingBuffer<uint16_t, 2> resp_buf;
112
113static bool process_queue_item(struct queue_item *item, uint16_t timeout);
114
115enum sdep_type {
116 SdepCommand = 0x10,
117 SdepResponse = 0x20,
118 SdepAlert = 0x40,
119 SdepError = 0x80,
120 SdepSlaveNotReady = 0xFE, // Try again later
121 SdepSlaveOverflow = 0xFF, // You read more data than is available
122};
123
124enum ble_cmd {
125 BleInitialize = 0xBEEF,
126 BleAtWrapper = 0x0A00,
127 BleUartTx = 0x0A01,
128 BleUartRx = 0x0A02,
129};
130
131enum ble_system_event_bits {
132 BleSystemConnected = 0,
133 BleSystemDisconnected = 1,
134 BleSystemUartRx = 8,
135 BleSystemMidiRx = 10,
136};
137
138#define SdepTimeout 150 /* milliseconds */
139#define SdepShortTimeout 10 /* milliseconds */
140#define SdepBackOff 25 /* microseconds */
141#define BatteryUpdateInterval 10000 /* milliseconds */
142
143static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout);
144static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false);
145
146// Send a single SDEP packet
147static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
148 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
149 uint16_t timerStart = timer_read();
150 bool success = false;
151 bool ready = false;
152
153 do {
154 ready = spi_write(msg->type) != SdepSlaveNotReady;
155 if (ready) {
156 break;
157 }
158
159 // Release it and let it initialize
160 spi_stop();
161 wait_us(SdepBackOff);
162 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
163 } while (timer_elapsed(timerStart) < timeout);
164
165 if (ready) {
166 // Slave is ready; send the rest of the packet
167 spi_transmit(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
168 success = true;
169 }
170
171 spi_stop();
172
173 return success;
174}
175
176static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, const uint8_t *payload, uint8_t len, bool moredata) {
177 msg->type = SdepCommand;
178 msg->cmd_low = command & 0xFF;
179 msg->cmd_high = command >> 8;
180 msg->len = len;
181 msg->more = (moredata && len == SdepMaxPayload) ? 1 : 0;
182
183 static_assert(sizeof(*msg) == 20, "msg is correctly packed");
184
185 memcpy(msg->payload, payload, len);
186}
187
188// Read a single SDEP packet
189static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
190 bool success = false;
191 uint16_t timerStart = timer_read();
192 bool ready = false;
193
194 do {
195 ready = readPin(AdafruitBleIRQPin);
196 if (ready) {
197 break;
198 }
199 wait_us(1);
200 } while (timer_elapsed(timerStart) < timeout);
201
202 if (ready) {
203 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
204
205 do {
206 // Read the command type, waiting for the data to be ready
207 msg->type = spi_read();
208 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
209 // Release it and let it initialize
210 spi_stop();
211 wait_us(SdepBackOff);
212 spi_start(AdafruitBleCSPin, false, 0, SCK_DIVISOR);
213 continue;
214 }
215
216 // Read the rest of the header
217 spi_receive(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
218
219 // and get the payload if there is any
220 if (msg->len <= SdepMaxPayload) {
221 spi_receive(msg->payload, msg->len);
222 }
223 success = true;
224 break;
225 } while (timer_elapsed(timerStart) < timeout);
226
227 spi_stop();
228 }
229 return success;
230}
231
232static void resp_buf_read_one(bool greedy) {
233 uint16_t last_send;
234 if (!resp_buf.peek(last_send)) {
235 return;
236 }
237
238 if (readPin(AdafruitBleIRQPin)) {
239 struct sdep_msg msg;
240
241 again:
242 if (sdep_recv_pkt(&msg, SdepTimeout)) {
243 if (!msg.more) {
244 // We got it; consume this entry
245 resp_buf.get(last_send);
246 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
247 }
248
249 if (greedy && resp_buf.peek(last_send) && readPin(AdafruitBleIRQPin)) {
250 goto again;
251 }
252 }
253
254 } else if (timer_elapsed(last_send) > SdepTimeout * 2) {
255 dprintf("waiting_for_result: timeout, resp_buf size %d\n", (int)resp_buf.size());
256
257 // Timed out: consume this entry
258 resp_buf.get(last_send);
259 }
260}
261
262static void send_buf_send_one(uint16_t timeout = SdepTimeout) {
263 struct queue_item item;
264
265 // Don't send anything more until we get an ACK
266 if (!resp_buf.empty()) {
267 return;
268 }
269
270 if (!send_buf.peek(item)) {
271 return;
272 }
273 if (process_queue_item(&item, timeout)) {
274 // commit that peek
275 send_buf.get(item);
276 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size());
277 } else {
278 dprint("failed to send, will retry\n");
279 wait_ms(SdepTimeout);
280 resp_buf_read_one(true);
281 }
282}
283
284static void resp_buf_wait(const char *cmd) {
285 bool didPrint = false;
286 while (!resp_buf.empty()) {
287 if (!didPrint) {
288 dprintf("wait on buf for %s\n", cmd);
289 didPrint = true;
290 }
291 resp_buf_read_one(true);
292 }
293}
294
295static bool ble_init(void) {
296 state.initialized = false;
297 state.configured = false;
298 state.is_connected = false;
299
300 setPinInput(AdafruitBleIRQPin);
301
302 spi_init();
303
304 // Perform a hardware reset
305 setPinOutput(AdafruitBleResetPin);
306 writePinHigh(AdafruitBleResetPin);
307 writePinLow(AdafruitBleResetPin);
308 wait_ms(10);
309 writePinHigh(AdafruitBleResetPin);
310
311 wait_ms(1000); // Give it a second to initialize
312
313 state.initialized = true;
314 return state.initialized;
315}
316
317static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }
318
319static bool read_response(char *resp, uint16_t resplen, bool verbose) {
320 char *dest = resp;
321 char *end = dest + resplen;
322
323 while (true) {
324 struct sdep_msg msg;
325
326 if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) {
327 dprint("sdep_recv_pkt failed\n");
328 return false;
329 }
330
331 if (msg.type != SdepResponse) {
332 *resp = 0;
333 return false;
334 }
335
336 uint8_t len = min(msg.len, end - dest);
337 if (len > 0) {
338 memcpy(dest, msg.payload, len);
339 dest += len;
340 }
341
342 if (!msg.more) {
343 // No more data is expected!
344 break;
345 }
346 }
347
348 // Ensure the response is NUL terminated
349 *dest = 0;
350
351 // "Parse" the result text; we want to snip off the trailing OK or ERROR line
352 // Rewind past the possible trailing CRLF so that we can strip it
353 --dest;
354 while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) {
355 *dest = 0;
356 --dest;
357 }
358
359 // Look back for start of preceeding line
360 char *last_line = strrchr(resp, '\n');
361 if (last_line) {
362 ++last_line;
363 } else {
364 last_line = resp;
365 }
366
367 bool success = false;
368 static const char kOK[] PROGMEM = "OK";
369
370 success = !strcmp_P(last_line, kOK);
371
372 if (verbose || !success) {
373 dprintf("result: %s\n", resp);
374 }
375 return success;
376}
377
378static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout) {
379 const char * end = cmd + strlen(cmd);
380 struct sdep_msg msg;
381
382 if (verbose) {
383 dprintf("ble send: %s\n", cmd);
384 }
385
386 if (resp) {
387 // They want to decode the response, so we need to flush and wait
388 // for all pending I/O to finish before we start this one, so
389 // that we don't confuse the results
390 resp_buf_wait(cmd);
391 *resp = 0;
392 }
393
394 // Fragment the command into a series of SDEP packets
395 while (end - cmd > SdepMaxPayload) {
396 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true);
397 if (!sdep_send_pkt(&msg, timeout)) {
398 return false;
399 }
400 cmd += SdepMaxPayload;
401 }
402
403 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false);
404 if (!sdep_send_pkt(&msg, timeout)) {
405 return false;
406 }
407
408 if (resp == NULL) {
409 uint16_t now = timer_read();
410 while (!resp_buf.enqueue(now)) {
411 resp_buf_read_one(false);
412 }
413 uint16_t later = timer_read();
414 if (TIMER_DIFF_16(later, now) > 0) {
415 dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now));
416 }
417 return true;
418 }
419
420 return read_response(resp, resplen, verbose);
421}
422
423bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
424 char *cmdbuf = (char *)alloca(strlen_P(cmd) + 1);
425 strcpy_P(cmdbuf, cmd);
426 return at_command(cmdbuf, resp, resplen, verbose);
427}
428
429bool adafruit_ble_is_connected(void) { return state.is_connected; }
430
431bool adafruit_ble_enable_keyboard(void) {
432 char resbuf[128];
433
434 if (!state.initialized && !ble_init()) {
435 return false;
436 }
437
438 state.configured = false;
439
440 // Disable command echo
441 static const char kEcho[] PROGMEM = "ATE=0";
442 // Make the advertised name match the keyboard
443 static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT);
444 // Turn on keyboard support
445 static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1";
446
447 // Adjust intervals to improve latency. This causes the "central"
448 // system (computer/tablet) to poll us every 10-30 ms. We can't
449 // set a smaller value than 10ms, and 30ms seems to be the natural
450 // processing time on my macbook. Keeping it constrained to that
451 // feels reasonable to type to.
452 static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,";
453
454 // Reset the device so that it picks up the above changes
455 static const char kATZ[] PROGMEM = "ATZ";
456
457 // Turn down the power level a bit
458 static const char kPower[] PROGMEM = "AT+BLEPOWERLEVEL=-12";
459 static PGM_P const configure_commands[] PROGMEM = {
460 kEcho, kGapIntervals, kGapDevName, kHidEnOn, kPower, kATZ,
461 };
462
463 uint8_t i;
464 for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); ++i) {
465 PGM_P cmd;
466 memcpy_P(&cmd, configure_commands + i, sizeof(cmd));
467
468 if (!at_command_P(cmd, resbuf, sizeof(resbuf))) {
469 dprintf("failed BLE command: %S: %s\n", cmd, resbuf);
470 goto fail;
471 }
472 }
473
474 state.configured = true;
475
476 // Check connection status in a little while; allow the ATZ time
477 // to kick in.
478 state.last_connection_update = timer_read();
479fail:
480 return state.configured;
481}
482
483static void set_connected(bool connected) {
484 if (connected != state.is_connected) {
485 if (connected) {
486 dprint("BLE connected\n");
487 } else {
488 dprint("BLE disconnected\n");
489 }
490 state.is_connected = connected;
491
492 // TODO: if modifiers are down on the USB interface and
493 // we cut over to BLE or vice versa, they will remain stuck.
494 // This feels like a good point to do something like clearing
495 // the keyboard and/or generating a fake all keys up message.
496 // However, I've noticed that it takes a couple of seconds
497 // for macOS to to start recognizing key presses after BLE
498 // is in the connected state, so I worry that doing that
499 // here may not be good enough.
500 }
501}
502
503void adafruit_ble_task(void) {
504 char resbuf[48];
505
506 if (!state.configured && !adafruit_ble_enable_keyboard()) {
507 return;
508 }
509 resp_buf_read_one(true);
510 send_buf_send_one(SdepShortTimeout);
511
512 if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(AdafruitBleIRQPin)) {
513 // Must be an event update
514 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
515 uint32_t mask = strtoul(resbuf, NULL, 16);
516
517 if (mask & BleSystemConnected) {
518 set_connected(true);
519 } else if (mask & BleSystemDisconnected) {
520 set_connected(false);
521 }
522 }
523 }
524
525 if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) {
526 bool shouldPoll = true;
527 if (!(state.event_flags & ProbedEvents)) {
528 // Request notifications about connection status changes.
529 // This only works in SPIFRIEND firmware > 0.6.7, which is why
530 // we check for this conditionally here.
531 // Note that at the time of writing, HID reports only work correctly
532 // with Apple products on firmware version 0.6.7!
533 // https://forums.adafruit.com/viewtopic.php?f=8&t=104052
534 if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) {
535 at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf));
536 state.event_flags |= UsingEvents;
537 }
538 state.event_flags |= ProbedEvents;
539
540 // leave shouldPoll == true so that we check at least once
541 // before relying solely on events
542 } else {
543 shouldPoll = false;
544 }
545
546 static const char kGetConn[] PROGMEM = "AT+GAPGETCONN";
547 state.last_connection_update = timer_read();
548
549 if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) {
550 set_connected(atoi(resbuf));
551 }
552 }
553
554#ifdef SAMPLE_BATTERY
555 if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && resp_buf.empty()) {
556 state.last_battery_update = timer_read();
557
558 state.vbat = analogReadPin(BATTERY_LEVEL_PIN);
559 }
560#endif
561}
562
563static bool process_queue_item(struct queue_item *item, uint16_t timeout) {
564 char cmdbuf[48];
565 char fmtbuf[64];
566
567 // Arrange to re-check connection after keys have settled
568 state.last_connection_update = timer_read();
569
570#if 1
571 if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) {
572 dprintf("send latency %dms\n", TIMER_DIFF_16(state.last_connection_update, item->added));
573 }
574#endif
575
576 switch (item->queue_type) {
577 case QTKeyReport:
578 strcpy_P(fmtbuf, PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x"));
579 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]);
580 return at_command(cmdbuf, NULL, 0, true, timeout);
581
582 case QTConsumer:
583 strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x"));
584 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer);
585 return at_command(cmdbuf, NULL, 0, true, timeout);
586
587#ifdef MOUSE_ENABLE
588 case QTMouseMove:
589 strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d"));
590 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, item->mousemove.y, item->mousemove.scroll, item->mousemove.pan);
591 if (!at_command(cmdbuf, NULL, 0, true, timeout)) {
592 return false;
593 }
594 strcpy_P(cmdbuf, PSTR("AT+BLEHIDMOUSEBUTTON="));
595 if (item->mousemove.buttons & MOUSE_BTN1) {
596 strcat(cmdbuf, "L");
597 }
598 if (item->mousemove.buttons & MOUSE_BTN2) {
599 strcat(cmdbuf, "R");
600 }
601 if (item->mousemove.buttons & MOUSE_BTN3) {
602 strcat(cmdbuf, "M");
603 }
604 if (item->mousemove.buttons == 0) {
605 strcat(cmdbuf, "0");
606 }
607 return at_command(cmdbuf, NULL, 0, true, timeout);
608#endif
609 default:
610 return true;
611 }
612}
613
614void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
615 struct queue_item item;
616 bool didWait = false;
617
618 item.queue_type = QTKeyReport;
619 item.key.modifier = hid_modifier_mask;
620 item.added = timer_read();
621
622 while (nkeys >= 0) {
623 item.key.keys[0] = keys[0];
624 item.key.keys[1] = nkeys >= 1 ? keys[1] : 0;
625 item.key.keys[2] = nkeys >= 2 ? keys[2] : 0;
626 item.key.keys[3] = nkeys >= 3 ? keys[3] : 0;
627 item.key.keys[4] = nkeys >= 4 ? keys[4] : 0;
628 item.key.keys[5] = nkeys >= 5 ? keys[5] : 0;
629
630 if (!send_buf.enqueue(item)) {
631 if (!didWait) {
632 dprint("wait for buf space\n");
633 didWait = true;
634 }
635 send_buf_send_one();
636 continue;
637 }
638
639 if (nkeys <= 6) {
640 return;
641 }
642
643 nkeys -= 6;
644 keys += 6;
645 }
646}
647
648void adafruit_ble_send_consumer_key(uint16_t usage) {
649 struct queue_item item;
650
651 item.queue_type = QTConsumer;
652 item.consumer = usage;
653
654 while (!send_buf.enqueue(item)) {
655 send_buf_send_one();
656 }
657}
658
659#ifdef MOUSE_ENABLE
660void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
661 struct queue_item item;
662
663 item.queue_type = QTMouseMove;
664 item.mousemove.x = x;
665 item.mousemove.y = y;
666 item.mousemove.scroll = scroll;
667 item.mousemove.pan = pan;
668 item.mousemove.buttons = buttons;
669
670 while (!send_buf.enqueue(item)) {
671 send_buf_send_one();
672 }
673}
674#endif
675
676uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; }
677
678bool adafruit_ble_set_mode_leds(bool on) {
679 if (!state.configured) {
680 return false;
681 }
682
683 // The "mode" led is the red blinky one
684 at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0);
685
686 // Pin 19 is the blue "connected" LED; turn that off too.
687 // When turning LEDs back on, don't turn that LED on if we're
688 // not connected, as that would be confusing.
689 at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") : PSTR("AT+HWGPIO=19,0"), NULL, 0);
690 return true;
691}
692
693// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel
694bool adafruit_ble_set_power_level(int8_t level) {
695 char cmd[46];
696 if (!state.configured) {
697 return false;
698 }
699 snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level);
700 return at_command(cmd, NULL, 0, false);
701}
diff --git a/tmk_core/protocol/lufa/adafruit_ble.h b/tmk_core/protocol/lufa/adafruit_ble.h
deleted file mode 100644
index b43e0771d..000000000
--- a/tmk_core/protocol/lufa/adafruit_ble.h
+++ /dev/null
@@ -1,59 +0,0 @@
1/* Bluetooth Low Energy Protocol for QMK.
2 * Author: Wez Furlong, 2016
3 * Supports the Adafruit BLE board built around the nRF51822 chip.
4 */
5
6#pragma once
7
8#include <stdbool.h>
9#include <stdint.h>
10#include <string.h>
11
12#include "config_common.h"
13
14#ifdef __cplusplus
15extern "C" {
16#endif
17
18/* Instruct the module to enable HID keyboard support and reset */
19extern bool adafruit_ble_enable_keyboard(void);
20
21/* Query to see if the BLE module is connected */
22extern bool adafruit_ble_query_is_connected(void);
23
24/* Returns true if we believe that the BLE module is connected.
25 * This uses our cached understanding that is maintained by
26 * calling ble_task() periodically. */
27extern bool adafruit_ble_is_connected(void);
28
29/* Call this periodically to process BLE-originated things */
30extern void adafruit_ble_task(void);
31
32/* Generates keypress events for a set of keys.
33 * The hid modifier mask specifies the state of the modifier keys for
34 * this set of keys.
35 * Also sends a key release indicator, so that the keys do not remain
36 * held down. */
37extern void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
38
39/* Send a consumer usage.
40 * (milliseconds) */
41extern void adafruit_ble_send_consumer_key(uint16_t usage);
42
43#ifdef MOUSE_ENABLE
44/* Send a mouse/wheel movement report.
45 * The parameters are signed and indicate positive or negative direction
46 * change. */
47extern void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
48#endif
49
50/* Compute battery voltage by reading an analog pin.
51 * Returns the integer number of millivolts */
52extern uint32_t adafruit_ble_read_battery_voltage(void);
53
54extern bool adafruit_ble_set_mode_leds(bool on);
55extern bool adafruit_ble_set_power_level(int8_t level);
56
57#ifdef __cplusplus
58}
59#endif
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index 5b56e8a03..753762358 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -52,6 +52,7 @@
52#include "usb_descriptor.h" 52#include "usb_descriptor.h"
53#include "lufa.h" 53#include "lufa.h"
54#include "quantum.h" 54#include "quantum.h"
55#include "usb_device_state.h"
55#include <util/atomic.h> 56#include <util/atomic.h>
56 57
57#ifdef NKRO_ENABLE 58#ifdef NKRO_ENABLE
@@ -142,7 +143,8 @@ static void send_keyboard(report_keyboard_t *report);
142static void send_mouse(report_mouse_t *report); 143static void send_mouse(report_mouse_t *report);
143static void send_system(uint16_t data); 144static void send_system(uint16_t data);
144static void send_consumer(uint16_t data); 145static void send_consumer(uint16_t data);
145host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; 146static void send_programmable_button(uint32_t data);
147host_driver_t lufa_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};
146 148
147#ifdef VIRTSER_ENABLE 149#ifdef VIRTSER_ENABLE
148// clang-format off 150// clang-format off
@@ -413,7 +415,10 @@ void EVENT_USB_Device_Disconnect(void) {
413 * 415 *
414 * FIXME: Needs doc 416 * FIXME: Needs doc
415 */ 417 */
416void EVENT_USB_Device_Reset(void) { print("[R]"); } 418void EVENT_USB_Device_Reset(void) {
419 print("[R]");
420 usb_device_state_set_reset();
421}
417 422
418/** \brief Event USB Device Connect 423/** \brief Event USB Device Connect
419 * 424 *
@@ -421,6 +426,8 @@ void EVENT_USB_Device_Reset(void) { print("[R]"); }
421 */ 426 */
422void EVENT_USB_Device_Suspend() { 427void EVENT_USB_Device_Suspend() {
423 print("[S]"); 428 print("[S]");
429 usb_device_state_set_suspend(USB_Device_ConfigurationNumber != 0, USB_Device_ConfigurationNumber);
430
424#ifdef SLEEP_LED_ENABLE 431#ifdef SLEEP_LED_ENABLE
425 sleep_led_enable(); 432 sleep_led_enable();
426#endif 433#endif
@@ -436,6 +443,8 @@ void EVENT_USB_Device_WakeUp() {
436 suspend_wakeup_init(); 443 suspend_wakeup_init();
437#endif 444#endif
438 445
446 usb_device_state_set_resume(USB_DeviceState == DEVICE_STATE_Configured, USB_Device_ConfigurationNumber);
447
439#ifdef SLEEP_LED_ENABLE 448#ifdef SLEEP_LED_ENABLE
440 sleep_led_disable(); 449 sleep_led_disable();
441 // NOTE: converters may not accept this 450 // NOTE: converters may not accept this
@@ -528,6 +537,8 @@ void EVENT_USB_Device_ConfigurationChanged(void) {
528 /* Setup digitizer endpoint */ 537 /* Setup digitizer endpoint */
529 ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1); 538 ConfigSuccess &= Endpoint_ConfigureEndpoint((DIGITIZER_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, DIGITIZER_EPSIZE, 1);
530#endif 539#endif
540
541 usb_device_state_set_configuration(USB_DeviceState == DEVICE_STATE_Configured, USB_Device_ConfigurationNumber);
531} 542}
532 543
533/* FIXME: Expose this table in the docs somehow 544/* FIXME: Expose this table in the docs somehow
@@ -760,29 +771,35 @@ static void send_mouse(report_mouse_t *report) {
760#endif 771#endif
761} 772}
762 773
763/** \brief Send Extra 774#if defined(EXTRAKEY_ENABLE) || defined(PROGRAMMABLE_BUTTON_ENABLE)
764 * 775static void send_report(void *report, size_t size) {
765 * FIXME: Needs doc
766 */
767#ifdef EXTRAKEY_ENABLE
768static void send_extra(uint8_t report_id, uint16_t data) {
769 uint8_t timeout = 255; 776 uint8_t timeout = 255;
770 777
771 if (USB_DeviceState != DEVICE_STATE_Configured) return; 778 if (USB_DeviceState != DEVICE_STATE_Configured) return;
772 779
773 static report_extra_t r;
774 r = (report_extra_t){.report_id = report_id, .usage = data};
775 Endpoint_SelectEndpoint(SHARED_IN_EPNUM); 780 Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
776 781
777 /* Check if write ready for a polling interval around 10ms */ 782 /* Check if write ready for a polling interval around 10ms */
778 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); 783 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
779 if (!Endpoint_IsReadWriteAllowed()) return; 784 if (!Endpoint_IsReadWriteAllowed()) return;
780 785
781 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL); 786 Endpoint_Write_Stream_LE(report, size, NULL);
782 Endpoint_ClearIN(); 787 Endpoint_ClearIN();
783} 788}
784#endif 789#endif
785 790
791/** \brief Send Extra
792 *
793 * FIXME: Needs doc
794 */
795#ifdef EXTRAKEY_ENABLE
796static void send_extra(uint8_t report_id, uint16_t data) {
797 static report_extra_t r;
798 r = (report_extra_t){.report_id = report_id, .usage = data};
799 send_report(&r, sizeof(r));
800}
801#endif
802
786/** \brief Send System 803/** \brief Send System
787 * 804 *
788 * FIXME: Needs doc 805 * FIXME: Needs doc
@@ -822,6 +839,14 @@ static void send_consumer(uint16_t data) {
822#endif 839#endif
823} 840}
824 841
842static void send_programmable_button(uint32_t data) {
843#ifdef PROGRAMMABLE_BUTTON_ENABLE
844 static report_programmable_button_t r;
845 r = (report_programmable_button_t){.report_id = REPORT_ID_PROGRAMMABLE_BUTTON, .usage = data};
846 send_report(&r, sizeof(r));
847#endif
848}
849
825/******************************************************************************* 850/*******************************************************************************
826 * sendchar 851 * sendchar
827 ******************************************************************************/ 852 ******************************************************************************/
@@ -1044,6 +1069,7 @@ void protocol_setup(void) {
1044#endif 1069#endif
1045 1070
1046 setup_mcu(); 1071 setup_mcu();
1072 usb_device_state_init();
1047 keyboard_setup(); 1073 keyboard_setup();
1048} 1074}
1049 1075
diff --git a/tmk_core/protocol/lufa/outputselect.c b/tmk_core/protocol/lufa/outputselect.c
deleted file mode 100644
index f758c6528..000000000
--- a/tmk_core/protocol/lufa/outputselect.c
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, either version 2 of the License, or
6(at your option) any later version.
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15#include "outputselect.h"
16
17#if defined(PROTOCOL_LUFA)
18# include "lufa.h"
19#endif
20
21#ifdef MODULE_ADAFRUIT_BLE
22# include "adafruit_ble.h"
23#endif
24
25uint8_t desired_output = OUTPUT_DEFAULT;
26
27/** \brief Set Output
28 *
29 * FIXME: Needs doc
30 */
31void set_output(uint8_t output) {
32 set_output_user(output);
33 desired_output = output;
34}
35
36/** \brief Set Output User
37 *
38 * FIXME: Needs doc
39 */
40__attribute__((weak)) void set_output_user(uint8_t output) {}
41
42static bool is_usb_configured(void) {
43#if defined(PROTOCOL_LUFA)
44 return USB_DeviceState == DEVICE_STATE_Configured;
45#endif
46}
47
48/** \brief Auto Detect Output
49 *
50 * FIXME: Needs doc
51 */
52uint8_t auto_detect_output(void) {
53 if (is_usb_configured()) {
54 return OUTPUT_USB;
55 }
56
57#ifdef MODULE_ADAFRUIT_BLE
58 if (adafruit_ble_is_connected()) {
59 return OUTPUT_BLUETOOTH;
60 }
61#endif
62
63#ifdef BLUETOOTH_ENABLE
64 return OUTPUT_BLUETOOTH; // should check if BT is connected here
65#endif
66
67 return OUTPUT_NONE;
68}
69
70/** \brief Where To Send
71 *
72 * FIXME: Needs doc
73 */
74uint8_t where_to_send(void) {
75 if (desired_output == OUTPUT_AUTO) {
76 return auto_detect_output();
77 }
78 return desired_output;
79}
diff --git a/tmk_core/protocol/lufa/outputselect.h b/tmk_core/protocol/lufa/outputselect.h
deleted file mode 100644
index c4548e112..000000000
--- a/tmk_core/protocol/lufa/outputselect.h
+++ /dev/null
@@ -1,34 +0,0 @@
1/*
2Copyright 2017 Priyadi Iman Nurcahyo
3This program is free software: you can redistribute it and/or modify
4it under the terms of the GNU General Public License as published by
5the Free Software Foundation, either version 2 of the License, or
6(at your option) any later version.
7This program is distributed in the hope that it will be useful,
8but WITHOUT ANY WARRANTY; without even the implied warranty of
9MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10GNU General Public License for more details.
11You should have received a copy of the GNU General Public License
12along with this program. If not, see <http://www.gnu.org/licenses/>.
13*/
14
15#pragma once
16
17#include <stdint.h>
18
19enum outputs {
20 OUTPUT_AUTO,
21
22 OUTPUT_NONE,
23 OUTPUT_USB,
24 OUTPUT_BLUETOOTH
25};
26
27#ifndef OUTPUT_DEFAULT
28# define OUTPUT_DEFAULT OUTPUT_AUTO
29#endif
30
31void set_output(uint8_t output);
32void set_output_user(uint8_t output);
33uint8_t auto_detect_output(void);
34uint8_t where_to_send(void);
diff --git a/tmk_core/protocol/lufa/ringbuffer.hpp b/tmk_core/protocol/lufa/ringbuffer.hpp
deleted file mode 100644
index 70a3c4881..000000000
--- a/tmk_core/protocol/lufa/ringbuffer.hpp
+++ /dev/null
@@ -1,66 +0,0 @@
1#pragma once
2// A simple ringbuffer holding Size elements of type T
3template <typename T, uint8_t Size>
4class RingBuffer {
5 protected:
6 T buf_[Size];
7 uint8_t head_{0}, tail_{0};
8 public:
9 inline uint8_t nextPosition(uint8_t position) {
10 return (position + 1) % Size;
11 }
12
13 inline uint8_t prevPosition(uint8_t position) {
14 if (position == 0) {
15 return Size - 1;
16 }
17 return position - 1;
18 }
19
20 inline bool enqueue(const T &item) {
21 static_assert(Size > 1, "RingBuffer size must be > 1");
22 uint8_t next = nextPosition(head_);
23 if (next == tail_) {
24 // Full
25 return false;
26 }
27
28 buf_[head_] = item;
29 head_ = next;
30 return true;
31 }
32
33 inline bool get(T &dest, bool commit = true) {
34 auto tail = tail_;
35 if (tail == head_) {
36 // No more data
37 return false;
38 }
39
40 dest = buf_[tail];
41 tail = nextPosition(tail);
42
43 if (commit) {
44 tail_ = tail;
45 }
46 return true;
47 }
48
49 inline bool empty() const { return head_ == tail_; }
50
51 inline uint8_t size() const {
52 int diff = head_ - tail_;
53 if (diff >= 0) {
54 return diff;
55 }
56 return Size + diff;
57 }
58
59 inline T& front() {
60 return buf_[tail_];
61 }
62
63 inline bool peek(T &item) {
64 return get(item, false);
65 }
66};
diff --git a/tmk_core/protocol/news.c b/tmk_core/protocol/news.c
deleted file mode 100644
index 4463e8dd4..000000000
--- a/tmk_core/protocol/news.c
+++ /dev/null
@@ -1,161 +0,0 @@
1/*
2Copyright 2012 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38#include <stdbool.h>
39#include <avr/io.h>
40#include <avr/interrupt.h>
41#include "news.h"
42
43void news_init(void) { NEWS_KBD_RX_INIT(); }
44
45// RX ring buffer
46#define RBUF_SIZE 8
47static uint8_t rbuf[RBUF_SIZE];
48static uint8_t rbuf_head = 0;
49static uint8_t rbuf_tail = 0;
50
51uint8_t news_recv(void) {
52 uint8_t data = 0;
53 if (rbuf_head == rbuf_tail) {
54 return 0;
55 }
56
57 data = rbuf[rbuf_tail];
58 rbuf_tail = (rbuf_tail + 1) % RBUF_SIZE;
59 return data;
60}
61
62// USART RX complete interrupt
63ISR(NEWS_KBD_RX_VECT) {
64 uint8_t next = (rbuf_head + 1) % RBUF_SIZE;
65 if (next != rbuf_tail) {
66 rbuf[rbuf_head] = NEWS_KBD_RX_DATA;
67 rbuf_head = next;
68 }
69}
70
71/*
72SONY NEWS Keyboard Protocol
73===========================
74
75Resources
76---------
77 Mouse protocol of NWA-5461(Japanese)
78 http://groups.google.com/group/fj.sys.news/browse_thread/thread/a01b3e3ac6ae5b2d
79
80 SONY NEWS Info(Japanese)
81 http://katsu.watanabe.name/doc/sonynews/
82
83
84Pinouts
85-------
86 EIA 232 male connector from NWP-5461
87 -------------
88 \ 1 2 3 4 5 /
89 \ 6 7 8 9 /
90 ---------
91 1 VCC
92 2 BZ(Speaker)
93 3 Keyboard Data(from keyboard MCU TxD)
94 4 NC
95 5 GND
96 6 Unknown Input(to keyboard MCU RxD via schmitt trigger)
97 7 Mouse Data(from Mouse Ext connector)
98 8 Unknown Input(to Keyboard MCU Input via diode and buffer)
99 9 FG
100 NOTE: Two LED on keyboard are controlled by pin 6,8?
101
102 EIA 232 male connector from NWP-411A
103 -------------
104 \ 1 2 3 4 5 /
105 \ 6 7 8 9 /
106 ---------
107 1 VCC
108 2 BZ(Speaker)
109 3 Keyboard Data(from keyboard MCU TxD)
110 4 NC
111 5 GND
112 6 NC
113 7 Mouse Data(from Mouse Ext connector)
114 8 NC
115 9 FG
116 NOTE: These are just from my guess and not confirmed.
117
118
119Signaling
120---------
121 ~~~~~~~~~~ ____XOO0X111X222X333X444X555X666X777~~~~ ~~~~~~~
122 Idle Start LSB MSB Stop Idle
123
124 Idle: High
125 Start bit: Low
126 Stop bit: High
127 Bit order: LSB first
128
129 Baud rate: 9600
130 Interface: TTL level(5V) UART
131
132 NOTE: This is observed on NWP-5461 with its DIP switch all OFF.
133
134
135Format
136------
137 MSB LSB
138 7 6 5 4 3 2 1 0 bit
139 | | | | | | | |
140 | +-+-+-+-+-+-+-- scan code(00-7F)
141 +---------------- break flag: sets when released
142
143
144Scan Codes
145----------
146 SONY NEWS NWP-5461
147 ,---. ,------------------------, ,------------------------. ,---------.
148 | 7A| | 01 | 02 | 03 | 04 | 05 | | 06 | 07 | 08 | 09 | 0A | | 68 | 69 | ,-----------.
149 `---' `------------------------' `------------------------' `---------' | 64| 65| 52|
150 ,-------------------------------------------------------------. ,---. ,---------------|
151 | 0B| 0C| 0D| 0E| 0F| 10| 11| 12| 13| 14| 15| 16| 17| 18| 19 | | 6A| | 4B| 4C| 4D| 4E|
152 |-------------------------------------------------------------| |---| |---------------|
153 | 1A | 1B| 1C| 1D| 1E| 1F| 20| 21| 22| 23| 24| 25| 26| 27| | | 6B| | 4F| 50| 51| 56|
154 |---------------------------------------------------------' | |---| |---------------|
155 | 28 | 29| 2A| 2B| 2C| 2D| 2E| 2F| 30| 31| 32| 33| 34| 35 | | 6C| | 53| 54| 55| |
156 |-------------------------------------------------------------| |---| |-----------| 5A|
157 | 36 | 37| 38| 39| 3A| 3B| 3C| 3D| 3E| 3F| 40| 41| 42 | | 6D| | 57| 59| 58| |
158 |-------------------------------------------------------------| |---| |---------------|
159 | 43 | 44 | 45 | 46 | 47 | 48| 49| 4A | | 6E| | 66| 5B| 5C| 5D|
160 `-------------------------------------------------------------' `---' `---------------'
161*/
diff --git a/tmk_core/protocol/news.h b/tmk_core/protocol/news.h
deleted file mode 100644
index 327a13856..000000000
--- a/tmk_core/protocol/news.h
+++ /dev/null
@@ -1,48 +0,0 @@
1/*
2Copyright 2012 Jun WAKO <wakojun@gmail.com>
3
4This software is licensed with a Modified BSD License.
5All of this is supposed to be Free Software, Open Source, DFSG-free,
6GPL-compatible, and OK to use in both free and proprietary applications.
7Additions and corrections to this file are welcome.
8
9
10Redistribution and use in source and binary forms, with or without
11modification, are permitted provided that the following conditions are met:
12
13* Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16* Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21* Neither the name of the copyright holders nor the names of
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35POSSIBILITY OF SUCH DAMAGE.
36*/
37
38#pragma once
39
40/*
41 * Primitive PS/2 Library for AVR
42 */
43
44/* host role */
45void news_init(void);
46uint8_t news_recv(void);
47
48/* device role */
diff --git a/tmk_core/protocol/next_kbd.c b/tmk_core/protocol/next_kbd.c
deleted file mode 100644
index 6f118e617..000000000
--- a/tmk_core/protocol/next_kbd.c
+++ /dev/null
@@ -1,219 +0,0 @@
1/*
2
3NeXT non-ADB Keyboard Protocol
4
5Copyright 2013, Benjamin Gould (bgould@github.com)
6
7Based on:
8TMK firmware code Copyright 2011,2012 Jun WAKO <wakojun@gmail.com>
9Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license
10
11Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB
12Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html
13Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/
14
15This software is licensed with a Modified BSD License.
16All of this is supposed to be Free Software, Open Source, DFSG-free,
17GPL-compatible, and OK to use in both free and proprietary applications.
18Additions and corrections to this file are welcome.
19
20Redistribution and use in source and binary forms, with or without
21modification, are permitted provided that the following conditions are met:
22
23* Redistributions of source code must retain the above copyright
24 notice, this list of conditions and the following disclaimer.
25
26* Redistributions in binary form must reproduce the above copyright
27 notice, this list of conditions and the following disclaimer in
28 the documentation and/or other materials provided with the
29 distribution.
30
31* Neither the name of the copyright holders nor the names of
32 contributors may be used to endorse or promote products derived
33 from this software without specific prior written permission.
34
35THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
39LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
42INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
44ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45POSSIBILITY OF SUCH DAMAGE.
46
47*/
48
49#include <stdint.h>
50#include <stdbool.h>
51#include <util/atomic.h>
52#include <util/delay.h>
53#include "next_kbd.h"
54#include "debug.h"
55
56static inline void out_lo(void);
57static inline void out_hi(void);
58static inline void query(void);
59static inline void reset(void);
60static inline uint32_t response(void);
61
62/* The keyboard sends signal with 50us pulse width on OUT line
63 * while it seems to miss the 50us pulse on In line.
64 * next_kbd_set_leds() often fails to sync LED status with 50us
65 * but it works well with 51us(+1us) on TMK converter(ATMeaga32u2) at least.
66 * TODO: test on Teensy and Pro Micro configuration
67 */
68#define out_hi_delay(intervals) \
69 do { \
70 out_hi(); \
71 _delay_us((NEXT_KBD_TIMING + 1) * intervals); \
72 } while (0);
73#define out_lo_delay(intervals) \
74 do { \
75 out_lo(); \
76 _delay_us((NEXT_KBD_TIMING + 1) * intervals); \
77 } while (0);
78#define query_delay(intervals) \
79 do { \
80 query(); \
81 _delay_us((NEXT_KBD_TIMING + 1) * intervals); \
82 } while (0);
83#define reset_delay(intervals) \
84 do { \
85 reset(); \
86 _delay_us((NEXT_KBD_TIMING + 1) * intervals); \
87 } while (0);
88
89void next_kbd_init(void) {
90 out_hi();
91 NEXT_KBD_IN_DDR &= ~(1 << NEXT_KBD_IN_BIT); // KBD_IN to input
92 NEXT_KBD_IN_PORT |= (1 << NEXT_KBD_IN_BIT); // KBD_IN pull up
93
94 query_delay(5);
95 reset_delay(8);
96
97 query_delay(5);
98 reset_delay(8);
99}
100
101void next_kbd_set_leds(bool left, bool right) {
102 cli();
103 out_lo_delay(9);
104
105 out_hi_delay(3);
106 out_lo_delay(1);
107
108 if (left) {
109 out_hi_delay(1);
110 } else {
111 out_lo_delay(1);
112 }
113
114 if (right) {
115 out_hi_delay(1);
116 } else {
117 out_lo_delay(1);
118 }
119
120 out_lo_delay(7);
121 out_hi();
122 sei();
123}
124
125#define NEXT_KBD_READ (NEXT_KBD_IN_PIN & (1 << NEXT_KBD_IN_BIT))
126uint32_t next_kbd_recv(void) {
127 // First check to make sure that the keyboard is actually connected;
128 // if not, just return
129 // TODO: reflect the status of the keyboard in a return code
130 if (!NEXT_KBD_READ) {
131 sei();
132 return 0;
133 }
134
135 query();
136 uint32_t resp = response();
137
138 return resp;
139}
140
141static inline uint32_t response(void) {
142 cli();
143
144 // try a 5ms read; this should be called after the query method has
145 // been run so if a key is pressed we should get a response within
146 // 5ms; if not then send a reset and exit
147 uint8_t i = 0;
148 uint32_t data = 0;
149 uint16_t reset_timeout = 50000;
150 while (NEXT_KBD_READ && reset_timeout) {
151 asm("");
152 _delay_us(1);
153 reset_timeout--;
154 }
155 if (!reset_timeout) {
156 reset();
157 sei();
158 return 0;
159 }
160 _delay_us(NEXT_KBD_TIMING / 2);
161 for (; i < 22; i++) {
162 if (NEXT_KBD_READ) {
163 data |= ((uint32_t)1 << i);
164 /* Note:
165 * My testing with the ATmega32u4 showed that there might
166 * something wrong with the timing here; by the end of the
167 * second data byte some of the modifiers can get bumped out
168 * to the next bit over if we just cycle through the data
169 * based on the expected interval. There is a bit (i = 10)
170 * in the middle of the data that is always on followed by
171 * one that is always off - so we'll use that to reset our
172 * timing in case we've gotten ahead of the keyboard;
173 */
174 if (i == 10) {
175 i++;
176 while (NEXT_KBD_READ)
177 ;
178 _delay_us(NEXT_KBD_TIMING / 2);
179 }
180 } else {
181 /* redundant - but I don't want to remove if it might screw
182 * up the timing
183 */
184 data |= ((uint32_t)0 << i);
185 }
186 _delay_us(NEXT_KBD_TIMING);
187 }
188
189 sei();
190
191 return data;
192}
193
194static inline void out_lo(void) {
195 NEXT_KBD_OUT_PORT &= ~(1 << NEXT_KBD_OUT_BIT);
196 NEXT_KBD_OUT_DDR |= (1 << NEXT_KBD_OUT_BIT);
197}
198
199static inline void out_hi(void) {
200 /* input with pull up */
201 NEXT_KBD_OUT_DDR &= ~(1 << NEXT_KBD_OUT_BIT);
202 NEXT_KBD_OUT_PORT |= (1 << NEXT_KBD_OUT_BIT);
203}
204
205static inline void query(void) {
206 out_lo_delay(5);
207 out_hi_delay(1);
208 out_lo_delay(3);
209 out_hi();
210}
211
212static inline void reset(void) {
213 out_lo_delay(1);
214 out_hi_delay(4);
215 out_lo_delay(1);
216 out_hi_delay(6);
217 out_lo_delay(10);
218 out_hi();
219}
diff --git a/tmk_core/protocol/next_kbd.h b/tmk_core/protocol/next_kbd.h
deleted file mode 100644
index 1249ebf39..000000000
--- a/tmk_core/protocol/next_kbd.h
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2NeXT non-ADB Keyboard Protocol
3
4Copyright 2013, Benjamin Gould (bgould@github.com)
5
6Based on:
7TMK firmware code Copyright 2011,2012 Jun WAKO <wakojun@gmail.com>
8Arduino code by "Ladyada" Limor Fried (http://ladyada.net/, http://adafruit.com/), released under BSD license
9
10Timing reference thanks to http://m0115.web.fc2.com/ (dead link), http://cfile7.uf.tistory.com/image/14448E464F410BF22380BB
11Pinouts thanks to http://www.68k.org/~degs/nextkeyboard.html
12Keycodes from http://ftp.netbsd.org/pub/NetBSD/NetBSD-release-6/src/sys/arch/next68k/dev/
13
14This software is licensed with a Modified BSD License.
15All of this is supposed to be Free Software, Open Source, DFSG-free,
16GPL-compatible, and OK to use in both free and proprietary applications.
17Additions and corrections to this file are welcome.
18
19Redistribution and use in source and binary forms, with or without
20modification, are permitted provided that the following conditions are met:
21
22* Redistributions of source code must retain the above copyright
23 notice, this list of conditions and the following disclaimer.
24
25* Redistributions in binary form must reproduce the above copyright
26 notice, this list of conditions and the following disclaimer in
27 the documentation and/or other materials provided with the
28 distribution.
29
30* Neither the name of the copyright holders nor the names of
31 contributors may be used to endorse or promote products derived
32 from this software without specific prior written permission.
33
34THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
38LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44POSSIBILITY OF SUCH DAMAGE.
45
46*/
47
48#pragma once
49
50#include <stdbool.h>
51
52#define NEXT_KBD_KMBUS_IDLE 0x300600
53#define NEXT_KBD_TIMING 50
54
55extern uint8_t next_kbd_error;
56
57/* host role */
58void next_kbd_init(void);
59void next_kbd_set_leds(bool left, bool right);
60uint32_t next_kbd_recv(void);
diff --git a/tmk_core/protocol/usb_descriptor.c b/tmk_core/protocol/usb_descriptor.c
index 099964ae5..a43755f89 100644
--- a/tmk_core/protocol/usb_descriptor.c
+++ b/tmk_core/protocol/usb_descriptor.c
@@ -237,6 +237,25 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM SharedReport[] = {
237 HID_RI_END_COLLECTION(0), 237 HID_RI_END_COLLECTION(0),
238#endif 238#endif
239 239
240#ifdef PROGRAMMABLE_BUTTON_ENABLE
241 HID_RI_USAGE_PAGE(8, 0x0C), // Consumer
242 HID_RI_USAGE(8, 0x01), // Consumer Control
243 HID_RI_COLLECTION(8, 0x01), // Application
244 HID_RI_REPORT_ID(8, REPORT_ID_PROGRAMMABLE_BUTTON),
245 HID_RI_USAGE(8, 0x03), // Programmable Buttons
246 HID_RI_COLLECTION(8, 0x04), // Named Array
247 HID_RI_USAGE_PAGE(8, 0x09), // Button
248 HID_RI_USAGE_MINIMUM(8, 0x01), // Button 1
249 HID_RI_USAGE_MAXIMUM(8, 0x20), // Button 32
250 HID_RI_LOGICAL_MINIMUM(8, 0x00),
251 HID_RI_LOGICAL_MAXIMUM(8, 0x01),
252 HID_RI_REPORT_COUNT(8, 32),
253 HID_RI_REPORT_SIZE(8, 1),
254 HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
255 HID_RI_END_COLLECTION(0),
256 HID_RI_END_COLLECTION(0),
257#endif
258
240#ifdef NKRO_ENABLE 259#ifdef NKRO_ENABLE
241 HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop 260 HID_RI_USAGE_PAGE(8, 0x01), // Generic Desktop
242 HID_RI_USAGE(8, 0x06), // Keyboard 261 HID_RI_USAGE(8, 0x06), // Keyboard
diff --git a/tmk_core/protocol/usb_hid/parser.h b/tmk_core/protocol/usb_hid/parser.h
index 036281fa6..ba35b7af5 100644
--- a/tmk_core/protocol/usb_hid/parser.h
+++ b/tmk_core/protocol/usb_hid/parser.h
@@ -1,5 +1,4 @@
1#ifndef PARSER_H 1#pragma once
2#define PARSER_H
3 2
4#include "hid.h" 3#include "hid.h"
5#include "report.h" 4#include "report.h"
@@ -11,5 +10,3 @@ public:
11 uint16_t time_stamp; 10 uint16_t time_stamp;
12 virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); 11 virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
13}; 12};
14
15#endif
diff --git a/tmk_core/protocol/usb_hid/usb_hid.h b/tmk_core/protocol/usb_hid/usb_hid.h
index 083b68d1f..5cb5f5d03 100644
--- a/tmk_core/protocol/usb_hid/usb_hid.h
+++ b/tmk_core/protocol/usb_hid/usb_hid.h
@@ -1,10 +1,6 @@
1#ifndef USB_HID_H 1#pragma once
2#define USB_HID_H
3 2
4#include "report.h" 3#include "report.h"
5 4
6
7extern report_keyboard_t usb_hid_keyboard_report; 5extern report_keyboard_t usb_hid_keyboard_report;
8extern uint16_t usb_hid_time_stamp; 6extern uint16_t usb_hid_time_stamp;
9
10#endif
diff --git a/tmk_core/protocol/vusb/vusb.c b/tmk_core/protocol/vusb/vusb.c
index 485b20c90..e4db5d065 100644
--- a/tmk_core/protocol/vusb/vusb.c
+++ b/tmk_core/protocol/vusb/vusb.c
@@ -226,8 +226,9 @@ static void send_keyboard(report_keyboard_t *report);
226static void send_mouse(report_mouse_t *report); 226static void send_mouse(report_mouse_t *report);
227static void send_system(uint16_t data); 227static void send_system(uint16_t data);
228static void send_consumer(uint16_t data); 228static void send_consumer(uint16_t data);
229static void send_programmable_button(uint32_t data);
229 230
230static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer}; 231static host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer, send_programmable_button};
231 232
232host_driver_t *vusb_driver(void) { return &driver; } 233host_driver_t *vusb_driver(void) { return &driver; }
233 234
@@ -296,6 +297,19 @@ void send_digitizer(report_digitizer_t *report) {
296#ifdef DIGITIZER_ENABLE 297#ifdef DIGITIZER_ENABLE
297 if (usbInterruptIsReadyShared()) { 298 if (usbInterruptIsReadyShared()) {
298 usbSetInterruptShared((void *)report, sizeof(report_digitizer_t)); 299 usbSetInterruptShared((void *)report, sizeof(report_digitizer_t));
300#endif
301}
302
303static void send_programmable_button(uint32_t data) {
304#ifdef PROGRAMMABLE_BUTTON_ENABLE
305 static report_programmable_button_t report = {
306 .report_id = REPORT_ID_PROGRAMMABLE_BUTTON,
307 };
308
309 report.usage = data;
310
311 if (usbInterruptIsReadyShared()) {
312 usbSetInterruptShared((void *)&report, sizeof(report));
299 } 313 }
300#endif 314#endif
301} 315}
@@ -558,6 +572,26 @@ const PROGMEM uchar shared_hid_report[] = {
558 0xC0 // End Collection 572 0xC0 // End Collection
559#endif 573#endif
560 574
575#ifdef PROGRAMMABLE_BUTTON_ENABLE
576 // Programmable buttons report descriptor
577 0x05, 0x0C, // Usage Page (Consumer)
578 0x09, 0x01, // Usage (Consumer Control)
579 0xA1, 0x01, // Collection (Application)
580 0x85, REPORT_ID_PROGRAMMABLE_BUTTON, // Report ID
581 0x09, 0x03, // Usage (Programmable Buttons)
582 0xA1, 0x04, // Collection (Named Array)
583 0x05, 0x09, // Usage Page (Button)
584 0x19, 0x01, // Usage Minimum (Button 1)
585 0x29, 0x20, // Usage Maximum (Button 32)
586 0x15, 0x00, // Logical Minimum (0)
587 0x25, 0x01, // Logical Maximum (1)
588 0x95, 0x20, // Report Count (32)
589 0x75, 0x01, // Report Size (1)
590 0x81, 0x02, // Input (Data, Variable, Absolute)
591 0xC0, // End Collection
592 0xC0 // End Collection
593#endif
594
561#ifdef SHARED_EP_ENABLE 595#ifdef SHARED_EP_ENABLE
562}; 596};
563#endif 597#endif