aboutsummaryrefslogtreecommitdiff
path: root/tmk_core/protocol/lufa
diff options
context:
space:
mode:
authorskullY <skullydazed@gmail.com>2019-08-30 11:19:03 -0700
committerskullydazed <skullydazed@users.noreply.github.com>2019-08-30 15:01:52 -0700
commitb624f32f944acdc59dcb130674c09090c5c404cb (patch)
treebc13adbba137d122d9a2c2fb2fafcbb08ac10e25 /tmk_core/protocol/lufa
parent61af76a10d00aba185b8338604171de490a13e3b (diff)
downloadqmk_firmware-b624f32f944acdc59dcb130674c09090c5c404cb.tar.gz
qmk_firmware-b624f32f944acdc59dcb130674c09090c5c404cb.zip
clang-format changes
Diffstat (limited to 'tmk_core/protocol/lufa')
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.cpp1117
-rw-r--r--tmk_core/protocol/lufa/adafruit_ble.h30
-rw-r--r--tmk_core/protocol/lufa/bluetooth.c20
-rw-r--r--tmk_core/protocol/lufa/bluetooth.h37
-rw-r--r--tmk_core/protocol/lufa/lufa.c692
-rw-r--r--tmk_core/protocol/lufa/lufa.h20
-rw-r--r--tmk_core/protocol/lufa/outputselect.c9
-rw-r--r--tmk_core/protocol/lufa/outputselect.h14
8 files changed, 892 insertions, 1047 deletions
diff --git a/tmk_core/protocol/lufa/adafruit_ble.cpp b/tmk_core/protocol/lufa/adafruit_ble.cpp
index 80839731f..71d0936f8 100644
--- a/tmk_core/protocol/lufa/adafruit_ble.cpp
+++ b/tmk_core/protocol/lufa/adafruit_ble.cpp
@@ -15,35 +15,34 @@
15// You may define them to something else in your config.h 15// You may define them to something else in your config.h
16// if yours is wired up differently. 16// if yours is wired up differently.
17#ifndef AdafruitBleResetPin 17#ifndef AdafruitBleResetPin
18#define AdafruitBleResetPin D4 18# define AdafruitBleResetPin D4
19#endif 19#endif
20 20
21#ifndef AdafruitBleCSPin 21#ifndef AdafruitBleCSPin
22#define AdafruitBleCSPin B4 22# define AdafruitBleCSPin B4
23#endif 23#endif
24 24
25#ifndef AdafruitBleIRQPin 25#ifndef AdafruitBleIRQPin
26#define AdafruitBleIRQPin E6 26# define AdafruitBleIRQPin E6
27#endif 27#endif
28 28
29
30#define SAMPLE_BATTERY 29#define SAMPLE_BATTERY
31#define ConnectionUpdateInterval 1000 /* milliseconds */ 30#define ConnectionUpdateInterval 1000 /* milliseconds */
32 31
33static struct { 32static struct {
34 bool is_connected; 33 bool is_connected;
35 bool initialized; 34 bool initialized;
36 bool configured; 35 bool configured;
37 36
38#define ProbedEvents 1 37#define ProbedEvents 1
39#define UsingEvents 2 38#define UsingEvents 2
40 bool event_flags; 39 bool event_flags;
41 40
42#ifdef SAMPLE_BATTERY 41#ifdef SAMPLE_BATTERY
43 uint16_t last_battery_update; 42 uint16_t last_battery_update;
44 uint32_t vbat; 43 uint32_t vbat;
45#endif 44#endif
46 uint16_t last_connection_update; 45 uint16_t last_connection_update;
47} state; 46} state;
48 47
49// Commands are encoded using SDEP and sent via SPI 48// Commands are encoded using SDEP and sent via SPI
@@ -51,14 +50,14 @@ static struct {
51 50
52#define SdepMaxPayload 16 51#define SdepMaxPayload 16
53struct sdep_msg { 52struct sdep_msg {
54 uint8_t type; 53 uint8_t type;
55 uint8_t cmd_low; 54 uint8_t cmd_low;
56 uint8_t cmd_high; 55 uint8_t cmd_high;
57 struct __attribute__((packed)) { 56 struct __attribute__((packed)) {
58 uint8_t len:7; 57 uint8_t len : 7;
59 uint8_t more:1; 58 uint8_t more : 1;
60 }; 59 };
61 uint8_t payload[SdepMaxPayload]; 60 uint8_t payload[SdepMaxPayload];
62} __attribute__((packed)); 61} __attribute__((packed));
63 62
64// The recv latency is relatively high, so when we're hammering keys quickly, 63// The recv latency is relatively high, so when we're hammering keys quickly,
@@ -68,28 +67,28 @@ struct sdep_msg {
68// information here. 67// information here.
69 68
70enum queue_type { 69enum queue_type {
71 QTKeyReport, // 1-byte modifier + 6-byte key report 70 QTKeyReport, // 1-byte modifier + 6-byte key report
72 QTConsumer, // 16-bit key code 71 QTConsumer, // 16-bit key code
73#ifdef MOUSE_ENABLE 72#ifdef MOUSE_ENABLE
74 QTMouseMove, // 4-byte mouse report 73 QTMouseMove, // 4-byte mouse report
75#endif 74#endif
76}; 75};
77 76
78struct queue_item { 77struct queue_item {
79 enum queue_type queue_type; 78 enum queue_type queue_type;
80 uint16_t added; 79 uint16_t added;
81 union __attribute__((packed)) { 80 union __attribute__((packed)) {
82 struct __attribute__((packed)) { 81 struct __attribute__((packed)) {
83 uint8_t modifier; 82 uint8_t modifier;
84 uint8_t keys[6]; 83 uint8_t keys[6];
85 } key; 84 } key;
86 85
87 uint16_t consumer; 86 uint16_t consumer;
88 struct __attribute__((packed)) { 87 struct __attribute__((packed)) {
89 int8_t x, y, scroll, pan; 88 int8_t x, y, scroll, pan;
90 uint8_t buttons; 89 uint8_t buttons;
91 } mousemove; 90 } mousemove;
92 }; 91 };
93}; 92};
94 93
95// Items that we wish to send 94// Items that we wish to send
@@ -102,108 +101,104 @@ static RingBuffer<uint16_t, 2> resp_buf;
102static bool process_queue_item(struct queue_item *item, uint16_t timeout); 101static bool process_queue_item(struct queue_item *item, uint16_t timeout);
103 102
104enum sdep_type { 103enum sdep_type {
105 SdepCommand = 0x10, 104 SdepCommand = 0x10,
106 SdepResponse = 0x20, 105 SdepResponse = 0x20,
107 SdepAlert = 0x40, 106 SdepAlert = 0x40,
108 SdepError = 0x80, 107 SdepError = 0x80,
109 SdepSlaveNotReady = 0xfe, // Try again later 108 SdepSlaveNotReady = 0xfe, // Try again later
110 SdepSlaveOverflow = 0xff, // You read more data than is available 109 SdepSlaveOverflow = 0xff, // You read more data than is available
111}; 110};
112 111
113enum ble_cmd { 112enum ble_cmd {
114 BleInitialize = 0xbeef, 113 BleInitialize = 0xbeef,
115 BleAtWrapper = 0x0a00, 114 BleAtWrapper = 0x0a00,
116 BleUartTx = 0x0a01, 115 BleUartTx = 0x0a01,
117 BleUartRx = 0x0a02, 116 BleUartRx = 0x0a02,
118}; 117};
119 118
120enum ble_system_event_bits { 119enum ble_system_event_bits {
121 BleSystemConnected = 0, 120 BleSystemConnected = 0,
122 BleSystemDisconnected = 1, 121 BleSystemDisconnected = 1,
123 BleSystemUartRx = 8, 122 BleSystemUartRx = 8,
124 BleSystemMidiRx = 10, 123 BleSystemMidiRx = 10,
125}; 124};
126 125
127// The SDEP.md file says 2MHz but the web page and the sample driver 126// The SDEP.md file says 2MHz but the web page and the sample driver
128// both use 4MHz 127// both use 4MHz
129#define SpiBusSpeed 4000000 128#define SpiBusSpeed 4000000
130 129
131#define SdepTimeout 150 /* milliseconds */ 130#define SdepTimeout 150 /* milliseconds */
132#define SdepShortTimeout 10 /* milliseconds */ 131#define SdepShortTimeout 10 /* milliseconds */
133#define SdepBackOff 25 /* microseconds */ 132#define SdepBackOff 25 /* microseconds */
134#define BatteryUpdateInterval 10000 /* milliseconds */ 133#define BatteryUpdateInterval 10000 /* milliseconds */
135 134
136static bool at_command(const char *cmd, char *resp, uint16_t resplen, 135static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout);
137 bool verbose, uint16_t timeout = SdepTimeout); 136static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false);
138static bool at_command_P(const char *cmd, char *resp, uint16_t resplen,
139 bool verbose = false);
140 137
141struct SPI_Settings { 138struct SPI_Settings {
142 uint8_t spcr, spsr; 139 uint8_t spcr, spsr;
143}; 140};
144 141
145static struct SPI_Settings spi; 142static struct SPI_Settings spi;
146 143
147// Initialize 4Mhz MSBFIRST MODE0 144// Initialize 4Mhz MSBFIRST MODE0
148void SPI_init(struct SPI_Settings *spi) { 145void SPI_init(struct SPI_Settings *spi) {
149 spi->spcr = _BV(SPE) | _BV(MSTR); 146 spi->spcr = _BV(SPE) | _BV(MSTR);
150 spi->spsr = _BV(SPI2X); 147 spi->spsr = _BV(SPI2X);
151 148
152 static_assert(SpiBusSpeed == F_CPU / 2, "hard coded at 4Mhz"); 149 static_assert(SpiBusSpeed == F_CPU / 2, "hard coded at 4Mhz");
153 150
154 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { 151 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
155 // Ensure that SS is OUTPUT High 152 // Ensure that SS is OUTPUT High
156 digitalWrite(B0, PinLevelHigh); 153 digitalWrite(B0, PinLevelHigh);
157 pinMode(B0, PinDirectionOutput); 154 pinMode(B0, PinDirectionOutput);
158 155
159 SPCR |= _BV(MSTR); 156 SPCR |= _BV(MSTR);
160 SPCR |= _BV(SPE); 157 SPCR |= _BV(SPE);
161 pinMode(B1 /* SCK */, PinDirectionOutput); 158 pinMode(B1 /* SCK */, PinDirectionOutput);
162 pinMode(B2 /* MOSI */, PinDirectionOutput); 159 pinMode(B2 /* MOSI */, PinDirectionOutput);
163 } 160 }
164} 161}
165 162
166static inline void SPI_begin(struct SPI_Settings*spi) { 163static inline void SPI_begin(struct SPI_Settings *spi) {
167 SPCR = spi->spcr; 164 SPCR = spi->spcr;
168 SPSR = spi->spsr; 165 SPSR = spi->spsr;
169} 166}
170 167
171static inline uint8_t SPI_TransferByte(uint8_t data) { 168static inline uint8_t SPI_TransferByte(uint8_t data) {
172 SPDR = data; 169 SPDR = data;
173 asm volatile("nop"); 170 asm volatile("nop");
174 while (!(SPSR & _BV(SPIF))) { 171 while (!(SPSR & _BV(SPIF))) {
175 ; // wait 172 ; // wait
176 } 173 }
177 return SPDR; 174 return SPDR;
178} 175}
179 176
180static inline void spi_send_bytes(const uint8_t *buf, uint8_t len) { 177static inline void spi_send_bytes(const uint8_t *buf, uint8_t len) {
181 if (len == 0) return; 178 if (len == 0) return;
182 const uint8_t *end = buf + len; 179 const uint8_t *end = buf + len;
183 while (buf < end) { 180 while (buf < end) {
184 SPDR = *buf; 181 SPDR = *buf;
185 while (!(SPSR & _BV(SPIF))) { 182 while (!(SPSR & _BV(SPIF))) {
186 ; // wait 183 ; // wait
184 }
185 ++buf;
187 } 186 }
188 ++buf;
189 }
190} 187}
191 188
192static inline uint16_t spi_read_byte(void) { 189static inline uint16_t spi_read_byte(void) { return SPI_TransferByte(0x00 /* dummy */); }
193 return SPI_TransferByte(0x00 /* dummy */);
194}
195 190
196static inline void spi_recv_bytes(uint8_t *buf, uint8_t len) { 191static inline void spi_recv_bytes(uint8_t *buf, uint8_t len) {
197 const uint8_t *end = buf + len; 192 const uint8_t *end = buf + len;
198 if (len == 0) return; 193 if (len == 0) return;
199 while (buf < end) { 194 while (buf < end) {
200 SPDR = 0; // write a dummy to initiate read 195 SPDR = 0; // write a dummy to initiate read
201 while (!(SPSR & _BV(SPIF))) { 196 while (!(SPSR & _BV(SPIF))) {
202 ; // wait 197 ; // wait
198 }
199 *buf = SPDR;
200 ++buf;
203 } 201 }
204 *buf = SPDR;
205 ++buf;
206 }
207} 202}
208 203
209#if 0 204#if 0
@@ -223,600 +218,572 @@ static void dump_pkt(const struct sdep_msg *msg) {
223 218
224// Send a single SDEP packet 219// Send a single SDEP packet
225static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) { 220static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
226 SPI_begin(&spi); 221 SPI_begin(&spi);
222
223 digitalWrite(AdafruitBleCSPin, PinLevelLow);
224 uint16_t timerStart = timer_read();
225 bool success = false;
226 bool ready = false;
227
228 do {
229 ready = SPI_TransferByte(msg->type) != SdepSlaveNotReady;
230 if (ready) {
231 break;
232 }
227 233
228 digitalWrite(AdafruitBleCSPin, PinLevelLow); 234 // Release it and let it initialize
229 uint16_t timerStart = timer_read(); 235 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
230 bool success = false; 236 _delay_us(SdepBackOff);
231 bool ready = false; 237 digitalWrite(AdafruitBleCSPin, PinLevelLow);
238 } while (timer_elapsed(timerStart) < timeout);
232 239
233 do {
234 ready = SPI_TransferByte(msg->type) != SdepSlaveNotReady;
235 if (ready) { 240 if (ready) {
236 break; 241 // Slave is ready; send the rest of the packet
242 spi_send_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
243 success = true;
237 } 244 }
238 245
239 // Release it and let it initialize
240 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 246 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
241 _delay_us(SdepBackOff);
242 digitalWrite(AdafruitBleCSPin, PinLevelLow);
243 } while (timer_elapsed(timerStart) < timeout);
244
245 if (ready) {
246 // Slave is ready; send the rest of the packet
247 spi_send_bytes(&msg->cmd_low,
248 sizeof(*msg) - (1 + sizeof(msg->payload)) + msg->len);
249 success = true;
250 }
251 247
252 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 248 return success;
253
254 return success;
255} 249}
256 250
257static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, 251static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, const uint8_t *payload, uint8_t len, bool moredata) {
258 const uint8_t *payload, uint8_t len, 252 msg->type = SdepCommand;
259 bool moredata) { 253 msg->cmd_low = command & 0xff;
260 msg->type = SdepCommand; 254 msg->cmd_high = command >> 8;
261 msg->cmd_low = command & 0xff; 255 msg->len = len;
262 msg->cmd_high = command >> 8; 256 msg->more = (moredata && len == SdepMaxPayload) ? 1 : 0;
263 msg->len = len;
264 msg->more = (moredata && len == SdepMaxPayload) ? 1 : 0;
265 257
266 static_assert(sizeof(*msg) == 20, "msg is correctly packed"); 258 static_assert(sizeof(*msg) == 20, "msg is correctly packed");
267 259
268 memcpy(msg->payload, payload, len); 260 memcpy(msg->payload, payload, len);
269} 261}
270 262
271// Read a single SDEP packet 263// Read a single SDEP packet
272static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) { 264static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
273 bool success = false; 265 bool success = false;
274 uint16_t timerStart = timer_read(); 266 uint16_t timerStart = timer_read();
275 bool ready = false; 267 bool ready = false;
268
269 do {
270 ready = digitalRead(AdafruitBleIRQPin);
271 if (ready) {
272 break;
273 }
274 _delay_us(1);
275 } while (timer_elapsed(timerStart) < timeout);
276 276
277 do {
278 ready = digitalRead(AdafruitBleIRQPin);
279 if (ready) { 277 if (ready) {
280 break; 278 SPI_begin(&spi);
281 }
282 _delay_us(1);
283 } while (timer_elapsed(timerStart) < timeout);
284 279
285 if (ready) { 280 digitalWrite(AdafruitBleCSPin, PinLevelLow);
286 SPI_begin(&spi);
287 281
288 digitalWrite(AdafruitBleCSPin, PinLevelLow); 282 do {
283 // Read the command type, waiting for the data to be ready
284 msg->type = spi_read_byte();
285 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
286 // Release it and let it initialize
287 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
288 _delay_us(SdepBackOff);
289 digitalWrite(AdafruitBleCSPin, PinLevelLow);
290 continue;
291 }
292
293 // Read the rest of the header
294 spi_recv_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
295
296 // and get the payload if there is any
297 if (msg->len <= SdepMaxPayload) {
298 spi_recv_bytes(msg->payload, msg->len);
299 }
300 success = true;
301 break;
302 } while (timer_elapsed(timerStart) < timeout);
289 303
290 do {
291 // Read the command type, waiting for the data to be ready
292 msg->type = spi_read_byte();
293 if (msg->type == SdepSlaveNotReady || msg->type == SdepSlaveOverflow) {
294 // Release it and let it initialize
295 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 304 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
296 _delay_us(SdepBackOff); 305 }
297 digitalWrite(AdafruitBleCSPin, PinLevelLow); 306 return success;
298 continue;
299 }
300
301 // Read the rest of the header
302 spi_recv_bytes(&msg->cmd_low, sizeof(*msg) - (1 + sizeof(msg->payload)));
303
304 // and get the payload if there is any
305 if (msg->len <= SdepMaxPayload) {
306 spi_recv_bytes(msg->payload, msg->len);
307 }
308 success = true;
309 break;
310 } while (timer_elapsed(timerStart) < timeout);
311
312 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
313 }
314 return success;
315} 307}
316 308
317static void resp_buf_read_one(bool greedy) { 309static void resp_buf_read_one(bool greedy) {
318 uint16_t last_send; 310 uint16_t last_send;
319 if (!resp_buf.peek(last_send)) { 311 if (!resp_buf.peek(last_send)) {
320 return; 312 return;
321 } 313 }
322 314
323 if (digitalRead(AdafruitBleIRQPin)) { 315 if (digitalRead(AdafruitBleIRQPin)) {
324 struct sdep_msg msg; 316 struct sdep_msg msg;
325 317
326again: 318 again:
327 if (sdep_recv_pkt(&msg, SdepTimeout)) { 319 if (sdep_recv_pkt(&msg, SdepTimeout)) {
328 if (!msg.more) { 320 if (!msg.more) {
329 // We got it; consume this entry 321 // We got it; consume this entry
330 resp_buf.get(last_send); 322 resp_buf.get(last_send);
331 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send)); 323 dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
332 } 324 }
333 325
334 if (greedy && resp_buf.peek(last_send) && digitalRead(AdafruitBleIRQPin)) { 326 if (greedy && resp_buf.peek(last_send) && digitalRead(AdafruitBleIRQPin)) {
335 goto again; 327 goto again;
336 } 328 }
337 } 329 }
338 330
339 } else if (timer_elapsed(last_send) > SdepTimeout * 2) { 331 } else if (timer_elapsed(last_send) > SdepTimeout * 2) {
340 dprintf("waiting_for_result: timeout, resp_buf size %d\n", 332 dprintf("waiting_for_result: timeout, resp_buf size %d\n", (int)resp_buf.size());
341 (int)resp_buf.size());
342 333
343 // Timed out: consume this entry 334 // Timed out: consume this entry
344 resp_buf.get(last_send); 335 resp_buf.get(last_send);
345 } 336 }
346} 337}
347 338
348static void send_buf_send_one(uint16_t timeout = SdepTimeout) { 339static void send_buf_send_one(uint16_t timeout = SdepTimeout) {
349 struct queue_item item; 340 struct queue_item item;
350 341
351 // Don't send anything more until we get an ACK 342 // Don't send anything more until we get an ACK
352 if (!resp_buf.empty()) { 343 if (!resp_buf.empty()) {
353 return; 344 return;
354 } 345 }
355 346
356 if (!send_buf.peek(item)) { 347 if (!send_buf.peek(item)) {
357 return; 348 return;
358 } 349 }
359 if (process_queue_item(&item, timeout)) { 350 if (process_queue_item(&item, timeout)) {
360 // commit that peek 351 // commit that peek
361 send_buf.get(item); 352 send_buf.get(item);
362 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size()); 353 dprintf("send_buf_send_one: have %d remaining\n", (int)send_buf.size());
363 } else { 354 } else {
364 dprint("failed to send, will retry\n"); 355 dprint("failed to send, will retry\n");
365 _delay_ms(SdepTimeout); 356 _delay_ms(SdepTimeout);
366 resp_buf_read_one(true); 357 resp_buf_read_one(true);
367 } 358 }
368} 359}
369 360
370static void resp_buf_wait(const char *cmd) { 361static void resp_buf_wait(const char *cmd) {
371 bool didPrint = false; 362 bool didPrint = false;
372 while (!resp_buf.empty()) { 363 while (!resp_buf.empty()) {
373 if (!didPrint) { 364 if (!didPrint) {
374 dprintf("wait on buf for %s\n", cmd); 365 dprintf("wait on buf for %s\n", cmd);
375 didPrint = true; 366 didPrint = true;
367 }
368 resp_buf_read_one(true);
376 } 369 }
377 resp_buf_read_one(true);
378 }
379} 370}
380 371
381static bool ble_init(void) { 372static bool ble_init(void) {
382 state.initialized = false; 373 state.initialized = false;
383 state.configured = false; 374 state.configured = false;
384 state.is_connected = false; 375 state.is_connected = false;
385 376
386 pinMode(AdafruitBleIRQPin, PinDirectionInput); 377 pinMode(AdafruitBleIRQPin, PinDirectionInput);
387 pinMode(AdafruitBleCSPin, PinDirectionOutput); 378 pinMode(AdafruitBleCSPin, PinDirectionOutput);
388 digitalWrite(AdafruitBleCSPin, PinLevelHigh); 379 digitalWrite(AdafruitBleCSPin, PinLevelHigh);
389 380
390 SPI_init(&spi); 381 SPI_init(&spi);
391 382
392 // Perform a hardware reset 383 // Perform a hardware reset
393 pinMode(AdafruitBleResetPin, PinDirectionOutput); 384 pinMode(AdafruitBleResetPin, PinDirectionOutput);
394 digitalWrite(AdafruitBleResetPin, PinLevelHigh); 385 digitalWrite(AdafruitBleResetPin, PinLevelHigh);
395 digitalWrite(AdafruitBleResetPin, PinLevelLow); 386 digitalWrite(AdafruitBleResetPin, PinLevelLow);
396 _delay_ms(10); 387 _delay_ms(10);
397 digitalWrite(AdafruitBleResetPin, PinLevelHigh); 388 digitalWrite(AdafruitBleResetPin, PinLevelHigh);
398 389
399 _delay_ms(1000); // Give it a second to initialize 390 _delay_ms(1000); // Give it a second to initialize
400 391
401 state.initialized = true; 392 state.initialized = true;
402 return state.initialized; 393 return state.initialized;
403} 394}
404 395
405static inline uint8_t min(uint8_t a, uint8_t b) { 396static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; }
406 return a < b ? a : b;
407}
408 397
409static bool read_response(char *resp, uint16_t resplen, bool verbose) { 398static bool read_response(char *resp, uint16_t resplen, bool verbose) {
410 char *dest = resp; 399 char *dest = resp;
411 char *end = dest + resplen; 400 char *end = dest + resplen;
412 401
413 while (true) { 402 while (true) {
414 struct sdep_msg msg; 403 struct sdep_msg msg;
415 404
416 if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) { 405 if (!sdep_recv_pkt(&msg, 2 * SdepTimeout)) {
417 dprint("sdep_recv_pkt failed\n"); 406 dprint("sdep_recv_pkt failed\n");
418 return false; 407 return false;
408 }
409
410 if (msg.type != SdepResponse) {
411 *resp = 0;
412 return false;
413 }
414
415 uint8_t len = min(msg.len, end - dest);
416 if (len > 0) {
417 memcpy(dest, msg.payload, len);
418 dest += len;
419 }
420
421 if (!msg.more) {
422 // No more data is expected!
423 break;
424 }
419 } 425 }
420 426
421 if (msg.type != SdepResponse) { 427 // Ensure the response is NUL terminated
422 *resp = 0; 428 *dest = 0;
423 return false;
424 }
425 429
426 uint8_t len = min(msg.len, end - dest); 430 // "Parse" the result text; we want to snip off the trailing OK or ERROR line
427 if (len > 0) { 431 // Rewind past the possible trailing CRLF so that we can strip it
428 memcpy(dest, msg.payload, len); 432 --dest;
429 dest += len; 433 while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) {
434 *dest = 0;
435 --dest;
430 } 436 }
431 437
432 if (!msg.more) { 438 // Look back for start of preceeding line
433 // No more data is expected! 439 char *last_line = strrchr(resp, '\n');
434 break; 440 if (last_line) {
441 ++last_line;
442 } else {
443 last_line = resp;
435 } 444 }
436 }
437
438 // Ensure the response is NUL terminated
439 *dest = 0;
440 445
441 // "Parse" the result text; we want to snip off the trailing OK or ERROR line 446 bool success = false;
442 // Rewind past the possible trailing CRLF so that we can strip it 447 static const char kOK[] PROGMEM = "OK";
443 --dest;
444 while (dest > resp && (dest[0] == '\n' || dest[0] == '\r')) {
445 *dest = 0;
446 --dest;
447 }
448 448
449 // Look back for start of preceeding line 449 success = !strcmp_P(last_line, kOK);
450 char *last_line = strrchr(resp, '\n');
451 if (last_line) {
452 ++last_line;
453 } else {
454 last_line = resp;
455 }
456 450
457 bool success = false; 451 if (verbose || !success) {
458 static const char kOK[] PROGMEM = "OK"; 452 dprintf("result: %s\n", resp);
453 }
454 return success;
455}
459 456
460 success = !strcmp_P(last_line, kOK ); 457static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout) {
458 const char * end = cmd + strlen(cmd);
459 struct sdep_msg msg;
461 460
462 if (verbose || !success) { 461 if (verbose) {
463 dprintf("result: %s\n", resp); 462 dprintf("ble send: %s\n", cmd);
464 } 463 }
465 return success;
466}
467 464
468static bool at_command(const char *cmd, char *resp, uint16_t resplen, 465 if (resp) {
469 bool verbose, uint16_t timeout) { 466 // They want to decode the response, so we need to flush and wait
470 const char *end = cmd + strlen(cmd); 467 // for all pending I/O to finish before we start this one, so
471 struct sdep_msg msg; 468 // that we don't confuse the results
472 469 resp_buf_wait(cmd);
473 if (verbose) { 470 *resp = 0;
474 dprintf("ble send: %s\n", cmd);
475 }
476
477 if (resp) {
478 // They want to decode the response, so we need to flush and wait
479 // for all pending I/O to finish before we start this one, so
480 // that we don't confuse the results
481 resp_buf_wait(cmd);
482 *resp = 0;
483 }
484
485 // Fragment the command into a series of SDEP packets
486 while (end - cmd > SdepMaxPayload) {
487 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true);
488 if (!sdep_send_pkt(&msg, timeout)) {
489 return false;
490 } 471 }
491 cmd += SdepMaxPayload;
492 }
493 472
494 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false); 473 // Fragment the command into a series of SDEP packets
495 if (!sdep_send_pkt(&msg, timeout)) { 474 while (end - cmd > SdepMaxPayload) {
496 return false; 475 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, SdepMaxPayload, true);
497 } 476 if (!sdep_send_pkt(&msg, timeout)) {
477 return false;
478 }
479 cmd += SdepMaxPayload;
480 }
498 481
499 if (resp == NULL) { 482 sdep_build_pkt(&msg, BleAtWrapper, (uint8_t *)cmd, end - cmd, false);
500 auto now = timer_read(); 483 if (!sdep_send_pkt(&msg, timeout)) {
501 while (!resp_buf.enqueue(now)) { 484 return false;
502 resp_buf_read_one(false);
503 } 485 }
504 auto later = timer_read(); 486
505 if (TIMER_DIFF_16(later, now) > 0) { 487 if (resp == NULL) {
506 dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now)); 488 auto now = timer_read();
489 while (!resp_buf.enqueue(now)) {
490 resp_buf_read_one(false);
491 }
492 auto later = timer_read();
493 if (TIMER_DIFF_16(later, now) > 0) {
494 dprintf("waited %dms for resp_buf\n", TIMER_DIFF_16(later, now));
495 }
496 return true;
507 } 497 }
508 return true;
509 }
510 498
511 return read_response(resp, resplen, verbose); 499 return read_response(resp, resplen, verbose);
512} 500}
513 501
514bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) { 502bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
515 auto cmdbuf = (char *)alloca(strlen_P(cmd) + 1); 503 auto cmdbuf = (char *)alloca(strlen_P(cmd) + 1);
516 strcpy_P(cmdbuf, cmd); 504 strcpy_P(cmdbuf, cmd);
517 return at_command(cmdbuf, resp, resplen, verbose); 505 return at_command(cmdbuf, resp, resplen, verbose);
518} 506}
519 507
520bool adafruit_ble_is_connected(void) { 508bool adafruit_ble_is_connected(void) { return state.is_connected; }
521 return state.is_connected;
522}
523 509
524bool adafruit_ble_enable_keyboard(void) { 510bool adafruit_ble_enable_keyboard(void) {
525 char resbuf[128]; 511 char resbuf[128];
526 512
527 if (!state.initialized && !ble_init()) { 513 if (!state.initialized && !ble_init()) {
528 return false; 514 return false;
529 } 515 }
530 516
531 state.configured = false; 517 state.configured = false;
532 518
533 // Disable command echo 519 // Disable command echo
534 static const char kEcho[] PROGMEM = "ATE=0"; 520 static const char kEcho[] PROGMEM = "ATE=0";
535 // Make the advertised name match the keyboard 521 // Make the advertised name match the keyboard
536 static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT); 522 static const char kGapDevName[] PROGMEM = "AT+GAPDEVNAME=" STR(PRODUCT);
537 // Turn on keyboard support 523 // Turn on keyboard support
538 static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1"; 524 static const char kHidEnOn[] PROGMEM = "AT+BLEHIDEN=1";
539 525
540 // Adjust intervals to improve latency. This causes the "central" 526 // Adjust intervals to improve latency. This causes the "central"
541 // system (computer/tablet) to poll us every 10-30 ms. We can't 527 // system (computer/tablet) to poll us every 10-30 ms. We can't
542 // set a smaller value than 10ms, and 30ms seems to be the natural 528 // set a smaller value than 10ms, and 30ms seems to be the natural
543 // processing time on my macbook. Keeping it constrained to that 529 // processing time on my macbook. Keeping it constrained to that
544 // feels reasonable to type to. 530 // feels reasonable to type to.
545 static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,"; 531 static const char kGapIntervals[] PROGMEM = "AT+GAPINTERVALS=10,30,,";
546 532
547 // Reset the device so that it picks up the above changes 533 // Reset the device so that it picks up the above changes
548 static const char kATZ[] PROGMEM = "ATZ"; 534 static const char kATZ[] PROGMEM = "ATZ";
549 535
550 // Turn down the power level a bit 536 // Turn down the power level a bit
551 static const char kPower[] PROGMEM = "AT+BLEPOWERLEVEL=-12"; 537 static const char kPower[] PROGMEM = "AT+BLEPOWERLEVEL=-12";
552 static PGM_P const configure_commands[] PROGMEM = { 538 static PGM_P const configure_commands[] PROGMEM = {
553 kEcho, 539 kEcho, kGapIntervals, kGapDevName, kHidEnOn, kPower, kATZ,
554 kGapIntervals, 540 };
555 kGapDevName, 541
556 kHidEnOn, 542 uint8_t i;
557 kPower, 543 for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); ++i) {
558 kATZ, 544 PGM_P cmd;
559 }; 545 memcpy_P(&cmd, configure_commands + i, sizeof(cmd));
560 546
561 uint8_t i; 547 if (!at_command_P(cmd, resbuf, sizeof(resbuf))) {
562 for (i = 0; i < sizeof(configure_commands) / sizeof(configure_commands[0]); 548 dprintf("failed BLE command: %S: %s\n", cmd, resbuf);
563 ++i) { 549 goto fail;
564 PGM_P cmd; 550 }
565 memcpy_P(&cmd, configure_commands + i, sizeof(cmd)); 551 }
566 552
567 if (!at_command_P(cmd, resbuf, sizeof(resbuf))) { 553 state.configured = true;
568 dprintf("failed BLE command: %S: %s\n", cmd, resbuf); 554
569 goto fail; 555 // Check connection status in a little while; allow the ATZ time
570 } 556 // to kick in.
571 } 557 state.last_connection_update = timer_read();
572
573 state.configured = true;
574
575 // Check connection status in a little while; allow the ATZ time
576 // to kick in.
577 state.last_connection_update = timer_read();
578fail: 558fail:
579 return state.configured; 559 return state.configured;
580} 560}
581 561
582static void set_connected(bool connected) { 562static void set_connected(bool connected) {
583 if (connected != state.is_connected) { 563 if (connected != state.is_connected) {
584 if (connected) { 564 if (connected) {
585 print("****** BLE CONNECT!!!!\n"); 565 print("****** BLE CONNECT!!!!\n");
586 } else { 566 } else {
587 print("****** BLE DISCONNECT!!!!\n"); 567 print("****** BLE DISCONNECT!!!!\n");
588 } 568 }
589 state.is_connected = connected; 569 state.is_connected = connected;
590 570
591 // TODO: if modifiers are down on the USB interface and 571 // TODO: if modifiers are down on the USB interface and
592 // we cut over to BLE or vice versa, they will remain stuck. 572 // we cut over to BLE or vice versa, they will remain stuck.
593 // This feels like a good point to do something like clearing 573 // This feels like a good point to do something like clearing
594 // the keyboard and/or generating a fake all keys up message. 574 // the keyboard and/or generating a fake all keys up message.
595 // However, I've noticed that it takes a couple of seconds 575 // However, I've noticed that it takes a couple of seconds
596 // for macOS to to start recognizing key presses after BLE 576 // for macOS to to start recognizing key presses after BLE
597 // is in the connected state, so I worry that doing that 577 // is in the connected state, so I worry that doing that
598 // here may not be good enough. 578 // here may not be good enough.
599 } 579 }
600} 580}
601 581
602void adafruit_ble_task(void) { 582void adafruit_ble_task(void) {
603 char resbuf[48]; 583 char resbuf[48];
604
605 if (!state.configured && !adafruit_ble_enable_keyboard()) {
606 return;
607 }
608 resp_buf_read_one(true);
609 send_buf_send_one(SdepShortTimeout);
610
611 if (resp_buf.empty() && (state.event_flags & UsingEvents) &&
612 digitalRead(AdafruitBleIRQPin)) {
613 // Must be an event update
614 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
615 uint32_t mask = strtoul(resbuf, NULL, 16);
616
617 if (mask & BleSystemConnected) {
618 set_connected(true);
619 } else if (mask & BleSystemDisconnected) {
620 set_connected(false);
621 }
622 }
623 }
624
625 if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) {
626 bool shouldPoll = true;
627 if (!(state.event_flags & ProbedEvents)) {
628 // Request notifications about connection status changes.
629 // This only works in SPIFRIEND firmware > 0.6.7, which is why
630 // we check for this conditionally here.
631 // Note that at the time of writing, HID reports only work correctly
632 // with Apple products on firmware version 0.6.7!
633 // https://forums.adafruit.com/viewtopic.php?f=8&t=104052
634 if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) {
635 at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf));
636 state.event_flags |= UsingEvents;
637 }
638 state.event_flags |= ProbedEvents;
639
640 // leave shouldPoll == true so that we check at least once
641 // before relying solely on events
642 } else {
643 shouldPoll = false;
644 }
645 584
646 static const char kGetConn[] PROGMEM = "AT+GAPGETCONN"; 585 if (!state.configured && !adafruit_ble_enable_keyboard()) {
647 state.last_connection_update = timer_read(); 586 return;
587 }
588 resp_buf_read_one(true);
589 send_buf_send_one(SdepShortTimeout);
590
591 if (resp_buf.empty() && (state.event_flags & UsingEvents) && digitalRead(AdafruitBleIRQPin)) {
592 // Must be an event update
593 if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
594 uint32_t mask = strtoul(resbuf, NULL, 16);
595
596 if (mask & BleSystemConnected) {
597 set_connected(true);
598 } else if (mask & BleSystemDisconnected) {
599 set_connected(false);
600 }
601 }
602 }
648 603
649 if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) { 604 if (timer_elapsed(state.last_connection_update) > ConnectionUpdateInterval) {
650 set_connected(atoi(resbuf)); 605 bool shouldPoll = true;
606 if (!(state.event_flags & ProbedEvents)) {
607 // Request notifications about connection status changes.
608 // This only works in SPIFRIEND firmware > 0.6.7, which is why
609 // we check for this conditionally here.
610 // Note that at the time of writing, HID reports only work correctly
611 // with Apple products on firmware version 0.6.7!
612 // https://forums.adafruit.com/viewtopic.php?f=8&t=104052
613 if (at_command_P(PSTR("AT+EVENTENABLE=0x1"), resbuf, sizeof(resbuf))) {
614 at_command_P(PSTR("AT+EVENTENABLE=0x2"), resbuf, sizeof(resbuf));
615 state.event_flags |= UsingEvents;
616 }
617 state.event_flags |= ProbedEvents;
618
619 // leave shouldPoll == true so that we check at least once
620 // before relying solely on events
621 } else {
622 shouldPoll = false;
623 }
624
625 static const char kGetConn[] PROGMEM = "AT+GAPGETCONN";
626 state.last_connection_update = timer_read();
627
628 if (at_command_P(kGetConn, resbuf, sizeof(resbuf))) {
629 set_connected(atoi(resbuf));
630 }
651 } 631 }
652 }
653 632
654#ifdef SAMPLE_BATTERY 633#ifdef SAMPLE_BATTERY
655 // I don't know if this really does anything useful yet; the reported 634 // I don't know if this really does anything useful yet; the reported
656 // voltage level always seems to be around 3200mV. We may want to just rip 635 // voltage level always seems to be around 3200mV. We may want to just rip
657 // this code out. 636 // this code out.
658 if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && 637 if (timer_elapsed(state.last_battery_update) > BatteryUpdateInterval && resp_buf.empty()) {
659 resp_buf.empty()) { 638 state.last_battery_update = timer_read();
660 state.last_battery_update = timer_read(); 639
661 640 if (at_command_P(PSTR("AT+HWVBAT"), resbuf, sizeof(resbuf))) {
662 if (at_command_P(PSTR("AT+HWVBAT"), resbuf, sizeof(resbuf))) { 641 state.vbat = atoi(resbuf);
663 state.vbat = atoi(resbuf); 642 }
664 } 643 }
665 }
666#endif 644#endif
667} 645}
668 646
669static bool process_queue_item(struct queue_item *item, uint16_t timeout) { 647static bool process_queue_item(struct queue_item *item, uint16_t timeout) {
670 char cmdbuf[48]; 648 char cmdbuf[48];
671 char fmtbuf[64]; 649 char fmtbuf[64];
672 650
673 // Arrange to re-check connection after keys have settled 651 // Arrange to re-check connection after keys have settled
674 state.last_connection_update = timer_read(); 652 state.last_connection_update = timer_read();
675 653
676#if 1 654#if 1
677 if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) { 655 if (TIMER_DIFF_16(state.last_connection_update, item->added) > 0) {
678 dprintf("send latency %dms\n", 656 dprintf("send latency %dms\n", TIMER_DIFF_16(state.last_connection_update, item->added));
679 TIMER_DIFF_16(state.last_connection_update, item->added)); 657 }
680 }
681#endif 658#endif
682 659
683 switch (item->queue_type) { 660 switch (item->queue_type) {
684 case QTKeyReport: 661 case QTKeyReport:
685 strcpy_P(fmtbuf, 662 strcpy_P(fmtbuf, PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x"));
686 PSTR("AT+BLEKEYBOARDCODE=%02x-00-%02x-%02x-%02x-%02x-%02x-%02x")); 663 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]);
687 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->key.modifier, 664 return at_command(cmdbuf, NULL, 0, true, timeout);
688 item->key.keys[0], item->key.keys[1], item->key.keys[2],
689 item->key.keys[3], item->key.keys[4], item->key.keys[5]);
690 return at_command(cmdbuf, NULL, 0, true, timeout);
691 665
692 case QTConsumer: 666 case QTConsumer:
693 strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x")); 667 strcpy_P(fmtbuf, PSTR("AT+BLEHIDCONTROLKEY=0x%04x"));
694 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer); 668 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->consumer);
695 return at_command(cmdbuf, NULL, 0, true, timeout); 669 return at_command(cmdbuf, NULL, 0, true, timeout);
696 670
697#ifdef MOUSE_ENABLE 671#ifdef MOUSE_ENABLE
698 case QTMouseMove: 672 case QTMouseMove:
699 strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d")); 673 strcpy_P(fmtbuf, PSTR("AT+BLEHIDMOUSEMOVE=%d,%d,%d,%d"));
700 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, 674 snprintf(cmdbuf, sizeof(cmdbuf), fmtbuf, item->mousemove.x, item->mousemove.y, item->mousemove.scroll, item->mousemove.pan);
701 item->mousemove.y, item->mousemove.scroll, item->mousemove.pan); 675 if (!at_command(cmdbuf, NULL, 0, true, timeout)) {
702 if (!at_command(cmdbuf, NULL, 0, true, timeout)) { 676 return false;
703 return false; 677 }
704 } 678 strcpy_P(cmdbuf, PSTR("AT+BLEHIDMOUSEBUTTON="));
705 strcpy_P(cmdbuf, PSTR("AT+BLEHIDMOUSEBUTTON=")); 679 if (item->mousemove.buttons & MOUSE_BTN1) {
706 if (item->mousemove.buttons & MOUSE_BTN1) { 680 strcat(cmdbuf, "L");
707 strcat(cmdbuf, "L"); 681 }
708 } 682 if (item->mousemove.buttons & MOUSE_BTN2) {
709 if (item->mousemove.buttons & MOUSE_BTN2) { 683 strcat(cmdbuf, "R");
710 strcat(cmdbuf, "R"); 684 }
711 } 685 if (item->mousemove.buttons & MOUSE_BTN3) {
712 if (item->mousemove.buttons & MOUSE_BTN3) { 686 strcat(cmdbuf, "M");
713 strcat(cmdbuf, "M"); 687 }
714 } 688 if (item->mousemove.buttons == 0) {
715 if (item->mousemove.buttons == 0) { 689 strcat(cmdbuf, "0");
716 strcat(cmdbuf, "0"); 690 }
717 } 691 return at_command(cmdbuf, NULL, 0, true, timeout);
718 return at_command(cmdbuf, NULL, 0, true, timeout);
719#endif 692#endif
720 default: 693 default:
721 return true; 694 return true;
722 }
723}
724
725bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys,
726 uint8_t nkeys) {
727 struct queue_item item;
728 bool didWait = false;
729
730 item.queue_type = QTKeyReport;
731 item.key.modifier = hid_modifier_mask;
732 item.added = timer_read();
733
734 while (nkeys >= 0) {
735 item.key.keys[0] = keys[0];
736 item.key.keys[1] = nkeys >= 1 ? keys[1] : 0;
737 item.key.keys[2] = nkeys >= 2 ? keys[2] : 0;
738 item.key.keys[3] = nkeys >= 3 ? keys[3] : 0;
739 item.key.keys[4] = nkeys >= 4 ? keys[4] : 0;
740 item.key.keys[5] = nkeys >= 5 ? keys[5] : 0;
741
742 if (!send_buf.enqueue(item)) {
743 if (!didWait) {
744 dprint("wait for buf space\n");
745 didWait = true;
746 }
747 send_buf_send_one();
748 continue;
749 } 695 }
696}
750 697
751 if (nkeys <= 6) { 698bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
752 return true; 699 struct queue_item item;
700 bool didWait = false;
701
702 item.queue_type = QTKeyReport;
703 item.key.modifier = hid_modifier_mask;
704 item.added = timer_read();
705
706 while (nkeys >= 0) {
707 item.key.keys[0] = keys[0];
708 item.key.keys[1] = nkeys >= 1 ? keys[1] : 0;
709 item.key.keys[2] = nkeys >= 2 ? keys[2] : 0;
710 item.key.keys[3] = nkeys >= 3 ? keys[3] : 0;
711 item.key.keys[4] = nkeys >= 4 ? keys[4] : 0;
712 item.key.keys[5] = nkeys >= 5 ? keys[5] : 0;
713
714 if (!send_buf.enqueue(item)) {
715 if (!didWait) {
716 dprint("wait for buf space\n");
717 didWait = true;
718 }
719 send_buf_send_one();
720 continue;
721 }
722
723 if (nkeys <= 6) {
724 return true;
725 }
726
727 nkeys -= 6;
728 keys += 6;
753 } 729 }
754 730
755 nkeys -= 6; 731 return true;
756 keys += 6;
757 }
758
759 return true;
760} 732}
761 733
762bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration) { 734bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration) {
763 struct queue_item item; 735 struct queue_item item;
764 736
765 item.queue_type = QTConsumer; 737 item.queue_type = QTConsumer;
766 item.consumer = keycode; 738 item.consumer = keycode;
767 739
768 while (!send_buf.enqueue(item)) { 740 while (!send_buf.enqueue(item)) {
769 send_buf_send_one(); 741 send_buf_send_one();
770 } 742 }
771 return true; 743 return true;
772} 744}
773 745
774#ifdef MOUSE_ENABLE 746#ifdef MOUSE_ENABLE
775bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, 747bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
776 int8_t pan, uint8_t buttons) { 748 struct queue_item item;
777 struct queue_item item; 749
778 750 item.queue_type = QTMouseMove;
779 item.queue_type = QTMouseMove; 751 item.mousemove.x = x;
780 item.mousemove.x = x; 752 item.mousemove.y = y;
781 item.mousemove.y = y; 753 item.mousemove.scroll = scroll;
782 item.mousemove.scroll = scroll; 754 item.mousemove.pan = pan;
783 item.mousemove.pan = pan; 755 item.mousemove.buttons = buttons;
784 item.mousemove.buttons = buttons; 756
785 757 while (!send_buf.enqueue(item)) {
786 while (!send_buf.enqueue(item)) { 758 send_buf_send_one();
787 send_buf_send_one(); 759 }
788 } 760 return true;
789 return true;
790} 761}
791#endif 762#endif
792 763
793uint32_t adafruit_ble_read_battery_voltage(void) { 764uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; }
794 return state.vbat;
795}
796 765
797bool adafruit_ble_set_mode_leds(bool on) { 766bool adafruit_ble_set_mode_leds(bool on) {
798 if (!state.configured) { 767 if (!state.configured) {
799 return false; 768 return false;
800 } 769 }
801 770
802 // The "mode" led is the red blinky one 771 // The "mode" led is the red blinky one
803 at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0); 772 at_command_P(on ? PSTR("AT+HWMODELED=1") : PSTR("AT+HWMODELED=0"), NULL, 0);
804 773
805 // Pin 19 is the blue "connected" LED; turn that off too. 774 // Pin 19 is the blue "connected" LED; turn that off too.
806 // When turning LEDs back on, don't turn that LED on if we're 775 // When turning LEDs back on, don't turn that LED on if we're
807 // not connected, as that would be confusing. 776 // not connected, as that would be confusing.
808 at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") 777 at_command_P(on && state.is_connected ? PSTR("AT+HWGPIO=19,1") : PSTR("AT+HWGPIO=19,0"), NULL, 0);
809 : PSTR("AT+HWGPIO=19,0"), 778 return true;
810 NULL, 0);
811 return true;
812} 779}
813 780
814// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel 781// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel
815bool adafruit_ble_set_power_level(int8_t level) { 782bool adafruit_ble_set_power_level(int8_t level) {
816 char cmd[46]; 783 char cmd[46];
817 if (!state.configured) { 784 if (!state.configured) {
818 return false; 785 return false;
819 } 786 }
820 snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level); 787 snprintf(cmd, sizeof(cmd), "AT+BLEPOWERLEVEL=%d", level);
821 return at_command(cmd, NULL, 0, false); 788 return at_command(cmd, NULL, 0, false);
822} 789}
diff --git a/tmk_core/protocol/lufa/adafruit_ble.h b/tmk_core/protocol/lufa/adafruit_ble.h
index 5d26a9d5a..cef46fe9f 100644
--- a/tmk_core/protocol/lufa/adafruit_ble.h
+++ b/tmk_core/protocol/lufa/adafruit_ble.h
@@ -4,16 +4,16 @@
4 */ 4 */
5#pragma once 5#pragma once
6#ifdef MODULE_ADAFRUIT_BLE 6#ifdef MODULE_ADAFRUIT_BLE
7#include <stdbool.h> 7# include <stdbool.h>
8#include <stdint.h> 8# include <stdint.h>
9#include <string.h> 9# include <string.h>
10 10
11#include "config_common.h" 11# include "config_common.h"
12#include "progmem.h" 12# include "progmem.h"
13 13
14#ifdef __cplusplus 14# ifdef __cplusplus
15extern "C" { 15extern "C" {
16#endif 16# endif
17 17
18/* Instruct the module to enable HID keyboard support and reset */ 18/* Instruct the module to enable HID keyboard support and reset */
19extern bool adafruit_ble_enable_keyboard(void); 19extern bool adafruit_ble_enable_keyboard(void);
@@ -34,20 +34,18 @@ extern void adafruit_ble_task(void);
34 * this set of keys. 34 * this set of keys.
35 * Also sends a key release indicator, so that the keys do not remain 35 * Also sends a key release indicator, so that the keys do not remain
36 * held down. */ 36 * held down. */
37extern bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, 37extern bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
38 uint8_t nkeys);
39 38
40/* Send a consumer keycode, holding it down for the specified duration 39/* Send a consumer keycode, holding it down for the specified duration
41 * (milliseconds) */ 40 * (milliseconds) */
42extern bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration); 41extern bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration);
43 42
44#ifdef MOUSE_ENABLE 43# ifdef MOUSE_ENABLE
45/* Send a mouse/wheel movement report. 44/* Send a mouse/wheel movement report.
46 * The parameters are signed and indicate positive of negative direction 45 * The parameters are signed and indicate positive of negative direction
47 * change. */ 46 * change. */
48extern bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, 47extern bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
49 int8_t pan, uint8_t buttons); 48# endif
50#endif
51 49
52/* Compute battery voltage by reading an analog pin. 50/* Compute battery voltage by reading an analog pin.
53 * Returns the integer number of millivolts */ 51 * Returns the integer number of millivolts */
@@ -56,8 +54,8 @@ extern uint32_t adafruit_ble_read_battery_voltage(void);
56extern bool adafruit_ble_set_mode_leds(bool on); 54extern bool adafruit_ble_set_mode_leds(bool on);
57extern bool adafruit_ble_set_power_level(int8_t level); 55extern bool adafruit_ble_set_power_level(int8_t level);
58 56
59#ifdef __cplusplus 57# ifdef __cplusplus
60} 58}
61#endif 59# endif
62 60
63#endif // MODULE_ADAFRUIT_BLE 61#endif // MODULE_ADAFRUIT_BLE
diff --git a/tmk_core/protocol/lufa/bluetooth.c b/tmk_core/protocol/lufa/bluetooth.c
index 549606162..5eb52860b 100644
--- a/tmk_core/protocol/lufa/bluetooth.c
+++ b/tmk_core/protocol/lufa/bluetooth.c
@@ -21,16 +21,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
21#include "debug.h" 21#include "debug.h"
22#include "bluetooth.h" 22#include "bluetooth.h"
23 23
24void bluefruit_keyboard_print_report(report_keyboard_t *report) 24void bluefruit_keyboard_print_report(report_keyboard_t *report) {
25{
26 if (!debug_keyboard) return; 25 if (!debug_keyboard) return;
27 dprintf("keys: "); for (int i = 0; i < KEYBOARD_REPORT_KEYS; i++) { debug_hex8(report->keys[i]); dprintf(" "); } 26 dprintf("keys: ");
28 dprintf(" mods: "); debug_hex8(report->mods); 27 for (int i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
29 dprintf(" reserved: "); debug_hex8(report->reserved); 28 debug_hex8(report->keys[i]);
29 dprintf(" ");
30 }
31 dprintf(" mods: ");
32 debug_hex8(report->mods);
33 dprintf(" reserved: ");
34 debug_hex8(report->reserved);
30 dprintf("\n"); 35 dprintf("\n");
31} 36}
32 37
33void bluefruit_serial_send(uint8_t data) 38void bluefruit_serial_send(uint8_t data) { serial_send(data); } \ No newline at end of file
34{
35 serial_send(data);
36} \ No newline at end of file
diff --git a/tmk_core/protocol/lufa/bluetooth.h b/tmk_core/protocol/lufa/bluetooth.h
index f4b2f6f8b..081271a4e 100644
--- a/tmk_core/protocol/lufa/bluetooth.h
+++ b/tmk_core/protocol/lufa/bluetooth.h
@@ -41,39 +41,8 @@ void bluefruit_serial_send(uint8_t data);
41| Stop | 00000000 00010000 | 00 10 | 41| Stop | 00000000 00010000 | 00 10 |
42+-------------------------------------+-------+ 42+-------------------------------------+-------+
43*/ 43*/
44#define CONSUMER2BLUEFRUIT(usage) \ 44#define CONSUMER2BLUEFRUIT(usage) (usage == AUDIO_MUTE ? 0x0000 : (usage == AUDIO_VOL_UP ? 0x1000 : (usage == AUDIO_VOL_DOWN ? 0x2000 : (usage == TRANSPORT_NEXT_TRACK ? 0x0002 : (usage == TRANSPORT_PREV_TRACK ? 0x0004 : (usage == TRANSPORT_STOP ? 0x0010 : (usage == TRANSPORT_STOP_EJECT ? 0x0000 : (usage == TRANSPORT_PLAY_PAUSE ? 0x4000 : (usage == AL_CC_CONFIG ? 0x0000 : (usage == AL_EMAIL ? 0x0000 : (usage == AL_CALCULATOR ? 0x0000 : (usage == AL_LOCAL_BROWSER ? 0x0000 : (usage == AC_SEARCH ? 0x0400 : (usage == AC_HOME ? 0x0100 : (usage == AC_BACK ? 0x0000 : (usage == AC_FORWARD ? 0x0000 : (usage == AC_STOP ? 0x0000 : (usage == AC_REFRESH ? 0x0000 : (usage == AC_BOOKMARKS ? 0x0000 : 0)))))))))))))))))))
45 (usage == AUDIO_MUTE ? 0x0000 : \
46 (usage == AUDIO_VOL_UP ? 0x1000 : \
47 (usage == AUDIO_VOL_DOWN ? 0x2000 : \
48 (usage == TRANSPORT_NEXT_TRACK ? 0x0002 : \
49 (usage == TRANSPORT_PREV_TRACK ? 0x0004 : \
50 (usage == TRANSPORT_STOP ? 0x0010 : \
51 (usage == TRANSPORT_STOP_EJECT ? 0x0000 : \
52 (usage == TRANSPORT_PLAY_PAUSE ? 0x4000 : \
53 (usage == AL_CC_CONFIG ? 0x0000 : \
54 (usage == AL_EMAIL ? 0x0000 : \
55 (usage == AL_CALCULATOR ? 0x0000 : \
56 (usage == AL_LOCAL_BROWSER ? 0x0000 : \
57 (usage == AC_SEARCH ? 0x0400 : \
58 (usage == AC_HOME ? 0x0100 : \
59 (usage == AC_BACK ? 0x0000 : \
60 (usage == AC_FORWARD ? 0x0000 : \
61 (usage == AC_STOP ? 0x0000 : \
62 (usage == AC_REFRESH ? 0x0000 : \
63 (usage == AC_BOOKMARKS ? 0x0000 : 0)))))))))))))))))))
64 45
65#define CONSUMER2RN42(usage) \ 46#define CONSUMER2RN42(usage) (usage == AUDIO_MUTE ? 0x0040 : (usage == AUDIO_VOL_UP ? 0x0010 : (usage == AUDIO_VOL_DOWN ? 0x0020 : (usage == TRANSPORT_NEXT_TRACK ? 0x0100 : (usage == TRANSPORT_PREV_TRACK ? 0x0200 : (usage == TRANSPORT_STOP ? 0x0400 : (usage == TRANSPORT_STOP_EJECT ? 0x0800 : (usage == TRANSPORT_PLAY_PAUSE ? 0x0080 : (usage == AL_EMAIL ? 0x0200 : (usage == AL_LOCAL_BROWSER ? 0x8000 : (usage == AC_SEARCH ? 0x0400 : (usage == AC_HOME ? 0x0100 : 0))))))))))))
66 (usage == AUDIO_MUTE ? 0x0040 : \
67 (usage == AUDIO_VOL_UP ? 0x0010 : \
68 (usage == AUDIO_VOL_DOWN ? 0x0020 : \
69 (usage == TRANSPORT_NEXT_TRACK ? 0x0100 : \
70 (usage == TRANSPORT_PREV_TRACK ? 0x0200 : \
71 (usage == TRANSPORT_STOP ? 0x0400 : \
72 (usage == TRANSPORT_STOP_EJECT ? 0x0800 : \
73 (usage == TRANSPORT_PLAY_PAUSE ? 0x0080 : \
74 (usage == AL_EMAIL ? 0x0200 : \
75 (usage == AL_LOCAL_BROWSER ? 0x8000 : \
76 (usage == AC_SEARCH ? 0x0400 : \
77 (usage == AC_HOME ? 0x0100 : 0))))))))))))
78 47
79 #endif 48#endif
diff --git a/tmk_core/protocol/lufa/lufa.c b/tmk_core/protocol/lufa/lufa.c
index f2ecf2465..12a6924fd 100644
--- a/tmk_core/protocol/lufa/lufa.c
+++ b/tmk_core/protocol/lufa/lufa.c
@@ -45,7 +45,7 @@
45#include "sendchar.h" 45#include "sendchar.h"
46#include "debug.h" 46#include "debug.h"
47#ifdef SLEEP_LED_ENABLE 47#ifdef SLEEP_LED_ENABLE
48#include "sleep_led.h" 48# include "sleep_led.h"
49#endif 49#endif
50#include "suspend.h" 50#include "suspend.h"
51 51
@@ -57,86 +57,80 @@
57#include "rgblight_reconfig.h" 57#include "rgblight_reconfig.h"
58 58
59#ifdef NKRO_ENABLE 59#ifdef NKRO_ENABLE
60 #include "keycode_config.h" 60# include "keycode_config.h"
61 61
62 extern keymap_config_t keymap_config; 62extern keymap_config_t keymap_config;
63#endif 63#endif
64 64
65
66#ifdef AUDIO_ENABLE 65#ifdef AUDIO_ENABLE
67 #include <audio.h> 66# include <audio.h>
68#endif 67#endif
69 68
70#ifdef BLUETOOTH_ENABLE 69#ifdef BLUETOOTH_ENABLE
71 #ifdef MODULE_ADAFRUIT_BLE 70# ifdef MODULE_ADAFRUIT_BLE
72 #include "adafruit_ble.h" 71# include "adafruit_ble.h"
73 #else 72# else
74 #include "bluetooth.h" 73# include "bluetooth.h"
75 #endif 74# endif
76#endif 75#endif
77 76
78#ifdef VIRTSER_ENABLE 77#ifdef VIRTSER_ENABLE
79 #include "virtser.h" 78# include "virtser.h"
80#endif 79#endif
81 80
82#if (defined(RGB_MIDI) | defined(RGBLIGHT_ANIMATIONS)) & defined(RGBLIGHT_ENABLE) 81#if (defined(RGB_MIDI) | defined(RGBLIGHT_ANIMATIONS)) & defined(RGBLIGHT_ENABLE)
83 #include "rgblight.h" 82# include "rgblight.h"
84#endif 83#endif
85 84
86#ifdef MIDI_ENABLE 85#ifdef MIDI_ENABLE
87 #include "qmk_midi.h" 86# include "qmk_midi.h"
88#endif 87#endif
89 88
90#ifdef RAW_ENABLE 89#ifdef RAW_ENABLE
91 #include "raw_hid.h" 90# include "raw_hid.h"
92#endif 91#endif
93 92
94uint8_t keyboard_idle = 0; 93uint8_t keyboard_idle = 0;
95/* 0: Boot Protocol, 1: Report Protocol(default) */ 94/* 0: Boot Protocol, 1: Report Protocol(default) */
96uint8_t keyboard_protocol = 1; 95uint8_t keyboard_protocol = 1;
97static uint8_t keyboard_led_stats = 0; 96static uint8_t keyboard_led_stats = 0;
98 97
99static report_keyboard_t keyboard_report_sent; 98static report_keyboard_t keyboard_report_sent;
100 99
101/* Host driver */ 100/* Host driver */
102static uint8_t keyboard_leds(void); 101static uint8_t keyboard_leds(void);
103static void send_keyboard(report_keyboard_t *report); 102static void send_keyboard(report_keyboard_t *report);
104static void send_mouse(report_mouse_t *report); 103static void send_mouse(report_mouse_t *report);
105static void send_system(uint16_t data); 104static void send_system(uint16_t data);
106static void send_consumer(uint16_t data); 105static void send_consumer(uint16_t data);
107host_driver_t lufa_driver = { 106host_driver_t lufa_driver = {
108 keyboard_leds, 107 keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer,
109 send_keyboard,
110 send_mouse,
111 send_system,
112 send_consumer,
113}; 108};
114 109
115#ifdef VIRTSER_ENABLE 110#ifdef VIRTSER_ENABLE
116USB_ClassInfo_CDC_Device_t cdc_device = 111USB_ClassInfo_CDC_Device_t cdc_device = {
117{ 112 .Config =
118 .Config = 113 {
119 { 114 .ControlInterfaceNumber = CCI_INTERFACE,
120 .ControlInterfaceNumber = CCI_INTERFACE, 115 .DataINEndpoint =
121 .DataINEndpoint = 116 {
122 { 117 .Address = CDC_IN_EPADDR,
123 .Address = CDC_IN_EPADDR, 118 .Size = CDC_EPSIZE,
124 .Size = CDC_EPSIZE, 119 .Banks = 1,
125 .Banks = 1, 120 },
126 }, 121 .DataOUTEndpoint =
127 .DataOUTEndpoint = 122 {
128 { 123 .Address = CDC_OUT_EPADDR,
129 .Address = CDC_OUT_EPADDR, 124 .Size = CDC_EPSIZE,
130 .Size = CDC_EPSIZE, 125 .Banks = 1,
131 .Banks = 1, 126 },
132 }, 127 .NotificationEndpoint =
133 .NotificationEndpoint = 128 {
134 { 129 .Address = CDC_NOTIFICATION_EPADDR,
135 .Address = CDC_NOTIFICATION_EPADDR, 130 .Size = CDC_NOTIFICATION_EPSIZE,
136 .Size = CDC_NOTIFICATION_EPSIZE, 131 .Banks = 1,
137 .Banks = 1, 132 },
138 }, 133 },
139 },
140}; 134};
141#endif 135#endif
142 136
@@ -146,84 +140,73 @@ USB_ClassInfo_CDC_Device_t cdc_device =
146 * 140 *
147 * FIXME: Needs doc 141 * FIXME: Needs doc
148 */ 142 */
149void raw_hid_send( uint8_t *data, uint8_t length ) 143void raw_hid_send(uint8_t *data, uint8_t length) {
150{ 144 // TODO: implement variable size packet
151 // TODO: implement variable size packet 145 if (length != RAW_EPSIZE) {
152 if ( length != RAW_EPSIZE ) 146 return;
153 { 147 }
154 return; 148
155 } 149 if (USB_DeviceState != DEVICE_STATE_Configured) {
156 150 return;
157 if (USB_DeviceState != DEVICE_STATE_Configured) 151 }
158 { 152
159 return; 153 // TODO: decide if we allow calls to raw_hid_send() in the middle
160 } 154 // of other endpoint usage.
161 155 uint8_t ep = Endpoint_GetCurrentEndpoint();
162 // TODO: decide if we allow calls to raw_hid_send() in the middle 156
163 // of other endpoint usage. 157 Endpoint_SelectEndpoint(RAW_IN_EPNUM);
164 uint8_t ep = Endpoint_GetCurrentEndpoint(); 158
165 159 // Check to see if the host is ready to accept another packet
166 Endpoint_SelectEndpoint(RAW_IN_EPNUM); 160 if (Endpoint_IsINReady()) {
167 161 // Write data
168 // Check to see if the host is ready to accept another packet 162 Endpoint_Write_Stream_LE(data, RAW_EPSIZE, NULL);
169 if (Endpoint_IsINReady()) 163 // Finalize the stream transfer to send the last packet
170 { 164 Endpoint_ClearIN();
171 // Write data 165 }
172 Endpoint_Write_Stream_LE(data, RAW_EPSIZE, NULL); 166
173 // Finalize the stream transfer to send the last packet 167 Endpoint_SelectEndpoint(ep);
174 Endpoint_ClearIN();
175 }
176
177 Endpoint_SelectEndpoint(ep);
178} 168}
179 169
180/** \brief Raw HID Receive 170/** \brief Raw HID Receive
181 * 171 *
182 * FIXME: Needs doc 172 * FIXME: Needs doc
183 */ 173 */
184__attribute__ ((weak)) 174__attribute__((weak)) void raw_hid_receive(uint8_t *data, uint8_t length) {
185void raw_hid_receive( uint8_t *data, uint8_t length ) 175 // Users should #include "raw_hid.h" in their own code
186{ 176 // and implement this function there. Leave this as weak linkage
187 // Users should #include "raw_hid.h" in their own code 177 // so users can opt to not handle data coming in.
188 // and implement this function there. Leave this as weak linkage
189 // so users can opt to not handle data coming in.
190} 178}
191 179
192/** \brief Raw HID Task 180/** \brief Raw HID Task
193 * 181 *
194 * FIXME: Needs doc 182 * FIXME: Needs doc
195 */ 183 */
196static void raw_hid_task(void) 184static void raw_hid_task(void) {
197{ 185 // Create a temporary buffer to hold the read in data from the host
198 // Create a temporary buffer to hold the read in data from the host 186 uint8_t data[RAW_EPSIZE];
199 uint8_t data[RAW_EPSIZE]; 187 bool data_read = false;
200 bool data_read = false; 188
201 189 // Device must be connected and configured for the task to run
202 // Device must be connected and configured for the task to run 190 if (USB_DeviceState != DEVICE_STATE_Configured) return;
203 if (USB_DeviceState != DEVICE_STATE_Configured) 191
204 return; 192 Endpoint_SelectEndpoint(RAW_OUT_EPNUM);
205 193
206 Endpoint_SelectEndpoint(RAW_OUT_EPNUM); 194 // Check to see if a packet has been sent from the host
207 195 if (Endpoint_IsOUTReceived()) {
208 // Check to see if a packet has been sent from the host 196 // Check to see if the packet contains data
209 if (Endpoint_IsOUTReceived()) 197 if (Endpoint_IsReadWriteAllowed()) {
210 { 198 /* Read data */
211 // Check to see if the packet contains data 199 Endpoint_Read_Stream_LE(data, sizeof(data), NULL);
212 if (Endpoint_IsReadWriteAllowed()) 200 data_read = true;
213 { 201 }
214 /* Read data */ 202
215 Endpoint_Read_Stream_LE(data, sizeof(data), NULL); 203 // Finalize the stream transfer to receive the last packet
216 data_read = true; 204 Endpoint_ClearOUT();
217 } 205
218 206 if (data_read) {
219 // Finalize the stream transfer to receive the last packet 207 raw_hid_receive(data, sizeof(data));
220 Endpoint_ClearOUT(); 208 }
221 209 }
222 if ( data_read )
223 {
224 raw_hid_receive( data, sizeof(data) );
225 }
226 }
227} 210}
228#endif 211#endif
229 212
@@ -235,15 +218,13 @@ static void raw_hid_task(void)
235 * 218 *
236 * FIXME: Needs doc 219 * FIXME: Needs doc
237 */ 220 */
238static void Console_Task(void) 221static void Console_Task(void) {
239{
240 /* Device must be connected and configured for the task to run */ 222 /* Device must be connected and configured for the task to run */
241 if (USB_DeviceState != DEVICE_STATE_Configured) 223 if (USB_DeviceState != DEVICE_STATE_Configured) return;
242 return;
243 224
244 uint8_t ep = Endpoint_GetCurrentEndpoint(); 225 uint8_t ep = Endpoint_GetCurrentEndpoint();
245 226
246#if 0 227# if 0
247 // TODO: impl receivechar()/recvchar() 228 // TODO: impl receivechar()/recvchar()
248 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM); 229 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
249 230
@@ -266,7 +247,7 @@ static void Console_Task(void)
266 /* Finalize the stream transfer to send the last packet */ 247 /* Finalize the stream transfer to send the last packet */
267 Endpoint_ClearOUT(); 248 Endpoint_ClearOUT();
268 } 249 }
269#endif 250# endif
270 251
271 /* IN packet */ 252 /* IN packet */
272 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM); 253 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
@@ -276,8 +257,7 @@ static void Console_Task(void)
276 } 257 }
277 258
278 // fill empty bank 259 // fill empty bank
279 while (Endpoint_IsReadWriteAllowed()) 260 while (Endpoint_IsReadWriteAllowed()) Endpoint_Write_8(0);
280 Endpoint_Write_8(0);
281 261
282 // flash senchar packet 262 // flash senchar packet
283 if (Endpoint_IsINReady()) { 263 if (Endpoint_IsINReady()) {
@@ -288,7 +268,6 @@ static void Console_Task(void)
288} 268}
289#endif 269#endif
290 270
291
292/******************************************************************************* 271/*******************************************************************************
293 * USB Events 272 * USB Events
294 ******************************************************************************/ 273 ******************************************************************************/
@@ -298,13 +277,12 @@ static void Console_Task(void)
298 * 1) EVENT_USB_Device_Suspend 277 * 1) EVENT_USB_Device_Suspend
299 * 2) EVENT_USB_Device_Reset 278 * 2) EVENT_USB_Device_Reset
300 * 3) EVENT_USB_Device_Wake 279 * 3) EVENT_USB_Device_Wake
301*/ 280 */
302/** \brief Event USB Device Connect 281/** \brief Event USB Device Connect
303 * 282 *
304 * FIXME: Needs doc 283 * FIXME: Needs doc
305 */ 284 */
306void EVENT_USB_Device_Connect(void) 285void EVENT_USB_Device_Connect(void) {
307{
308 print("[C]"); 286 print("[C]");
309 /* For battery powered device */ 287 /* For battery powered device */
310 if (!USB_IsInitialized) { 288 if (!USB_IsInitialized) {
@@ -318,35 +296,30 @@ void EVENT_USB_Device_Connect(void)
318 * 296 *
319 * FIXME: Needs doc 297 * FIXME: Needs doc
320 */ 298 */
321void EVENT_USB_Device_Disconnect(void) 299void EVENT_USB_Device_Disconnect(void) {
322{
323 print("[D]"); 300 print("[D]");
324 /* For battery powered device */ 301 /* For battery powered device */
325 USB_IsInitialized = false; 302 USB_IsInitialized = false;
326/* TODO: This doesn't work. After several plug in/outs can not be enumerated. 303 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
327 if (USB_IsInitialized) { 304 if (USB_IsInitialized) {
328 USB_Disable(); // Disable all interrupts 305 USB_Disable(); // Disable all interrupts
329 USB_Controller_Enable(); 306 USB_Controller_Enable();
330 USB_INT_Enable(USB_INT_VBUSTI); 307 USB_INT_Enable(USB_INT_VBUSTI);
331 } 308 }
332*/ 309 */
333} 310}
334 311
335/** \brief Event USB Device Connect 312/** \brief Event USB Device Connect
336 * 313 *
337 * FIXME: Needs doc 314 * FIXME: Needs doc
338 */ 315 */
339void EVENT_USB_Device_Reset(void) 316void EVENT_USB_Device_Reset(void) { print("[R]"); }
340{
341 print("[R]");
342}
343 317
344/** \brief Event USB Device Connect 318/** \brief Event USB Device Connect
345 * 319 *
346 * FIXME: Needs doc 320 * FIXME: Needs doc
347 */ 321 */
348void EVENT_USB_Device_Suspend() 322void EVENT_USB_Device_Suspend() {
349{
350 print("[S]"); 323 print("[S]");
351#ifdef SLEEP_LED_ENABLE 324#ifdef SLEEP_LED_ENABLE
352 sleep_led_enable(); 325 sleep_led_enable();
@@ -357,8 +330,7 @@ void EVENT_USB_Device_Suspend()
357 * 330 *
358 * FIXME: Needs doc 331 * FIXME: Needs doc
359 */ 332 */
360void EVENT_USB_Device_WakeUp() 333void EVENT_USB_Device_WakeUp() {
361{
362 print("[W]"); 334 print("[W]");
363 suspend_wakeup_init(); 335 suspend_wakeup_init();
364 336
@@ -369,23 +341,19 @@ void EVENT_USB_Device_WakeUp()
369#endif 341#endif
370} 342}
371 343
372
373
374#ifdef CONSOLE_ENABLE 344#ifdef CONSOLE_ENABLE
375static bool console_flush = false; 345static bool console_flush = false;
376#define CONSOLE_FLUSH_SET(b) do { \ 346# define CONSOLE_FLUSH_SET(b) \
377 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {\ 347 do { \
378 console_flush = b; \ 348 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { console_flush = b; } \
379 } \ 349 } while (0)
380} while (0)
381 350
382/** \brief Event USB Device Start Of Frame 351/** \brief Event USB Device Start Of Frame
383 * 352 *
384 * FIXME: Needs doc 353 * FIXME: Needs doc
385 * called every 1ms 354 * called every 1ms
386 */ 355 */
387void EVENT_USB_Device_StartOfFrame(void) 356void EVENT_USB_Device_StartOfFrame(void) {
388{
389 static uint8_t count; 357 static uint8_t count;
390 if (++count % 50) return; 358 if (++count % 50) return;
391 count = 0; 359 count = 0;
@@ -404,44 +372,37 @@ void EVENT_USB_Device_StartOfFrame(void)
404 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4, 372 * ATMega32u2 supports dual bank(ping-pong mode) only on endpoint 3 and 4,
405 * it is safe to use single bank for all endpoints. 373 * it is safe to use single bank for all endpoints.
406 */ 374 */
407void EVENT_USB_Device_ConfigurationChanged(void) 375void EVENT_USB_Device_ConfigurationChanged(void) {
408{
409 bool ConfigSuccess = true; 376 bool ConfigSuccess = true;
410 377
411 /* Setup Keyboard HID Report Endpoints */ 378 /* Setup Keyboard HID Report Endpoints */
412#ifndef KEYBOARD_SHARED_EP 379#ifndef KEYBOARD_SHARED_EP
413 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, 380 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
414 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
415#endif 381#endif
416 382
417#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP) 383#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
418 /* Setup Mouse HID Report Endpoint */ 384 /* Setup Mouse HID Report Endpoint */
419 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, 385 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
420 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
421#endif 386#endif
422 387
423#ifdef SHARED_EP_ENABLE 388#ifdef SHARED_EP_ENABLE
424 /* Setup Shared HID Report Endpoint */ 389 /* Setup Shared HID Report Endpoint */
425 ConfigSuccess &= ENDPOINT_CONFIG(SHARED_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, 390 ConfigSuccess &= ENDPOINT_CONFIG(SHARED_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, SHARED_EPSIZE, ENDPOINT_BANK_SINGLE);
426 SHARED_EPSIZE, ENDPOINT_BANK_SINGLE);
427#endif 391#endif
428 392
429#ifdef RAW_ENABLE 393#ifdef RAW_ENABLE
430 /* Setup Raw HID Report Endpoints */ 394 /* Setup Raw HID Report Endpoints */
431 ConfigSuccess &= ENDPOINT_CONFIG(RAW_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, 395 ConfigSuccess &= ENDPOINT_CONFIG(RAW_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, RAW_EPSIZE, ENDPOINT_BANK_SINGLE);
432 RAW_EPSIZE, ENDPOINT_BANK_SINGLE); 396 ConfigSuccess &= ENDPOINT_CONFIG(RAW_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, RAW_EPSIZE, ENDPOINT_BANK_SINGLE);
433 ConfigSuccess &= ENDPOINT_CONFIG(RAW_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
434 RAW_EPSIZE, ENDPOINT_BANK_SINGLE);
435#endif 397#endif
436 398
437#ifdef CONSOLE_ENABLE 399#ifdef CONSOLE_ENABLE
438 /* Setup Console HID Report Endpoints */ 400 /* Setup Console HID Report Endpoints */
439 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, 401 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN, CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
440 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE); 402# if 0
441#if 0
442 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT, 403 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
443 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE); 404 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
444#endif 405# endif
445#endif 406#endif
446 407
447#ifdef MIDI_ENABLE 408#ifdef MIDI_ENABLE
@@ -473,26 +434,23 @@ Other Device Required Optional Optional Optional Optional Opti
473 * 434 *
474 * This is fired before passing along unhandled control requests to the library for processing internally. 435 * This is fired before passing along unhandled control requests to the library for processing internally.
475 */ 436 */
476void EVENT_USB_Device_ControlRequest(void) 437void EVENT_USB_Device_ControlRequest(void) {
477{ 438 uint8_t *ReportData = NULL;
478 uint8_t* ReportData = NULL;
479 uint8_t ReportSize = 0; 439 uint8_t ReportSize = 0;
480 440
481 /* Handle HID Class specific requests */ 441 /* Handle HID Class specific requests */
482 switch (USB_ControlRequest.bRequest) 442 switch (USB_ControlRequest.bRequest) {
483 {
484 case HID_REQ_GetReport: 443 case HID_REQ_GetReport:
485 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) 444 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) {
486 {
487 Endpoint_ClearSETUP(); 445 Endpoint_ClearSETUP();
488 446
489 // Interface 447 // Interface
490 switch (USB_ControlRequest.wIndex) { 448 switch (USB_ControlRequest.wIndex) {
491 case KEYBOARD_INTERFACE: 449 case KEYBOARD_INTERFACE:
492 // TODO: test/check 450 // TODO: test/check
493 ReportData = (uint8_t*)&keyboard_report_sent; 451 ReportData = (uint8_t *)&keyboard_report_sent;
494 ReportSize = sizeof(keyboard_report_sent); 452 ReportSize = sizeof(keyboard_report_sent);
495 break; 453 break;
496 } 454 }
497 455
498 /* Write the report data to the control endpoint */ 456 /* Write the report data to the control endpoint */
@@ -502,47 +460,43 @@ void EVENT_USB_Device_ControlRequest(void)
502 460
503 break; 461 break;
504 case HID_REQ_SetReport: 462 case HID_REQ_SetReport:
505 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) 463 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) {
506 {
507
508 // Interface 464 // Interface
509 switch (USB_ControlRequest.wIndex) { 465 switch (USB_ControlRequest.wIndex) {
510 case KEYBOARD_INTERFACE: 466 case KEYBOARD_INTERFACE:
511#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP) 467#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
512 case SHARED_INTERFACE: 468 case SHARED_INTERFACE:
513#endif 469#endif
514 Endpoint_ClearSETUP(); 470 Endpoint_ClearSETUP();
515 471
516 while (!(Endpoint_IsOUTReceived())) { 472 while (!(Endpoint_IsOUTReceived())) {
517 if (USB_DeviceState == DEVICE_STATE_Unattached) 473 if (USB_DeviceState == DEVICE_STATE_Unattached) return;
518 return; 474 }
519 }
520 475
521 if (Endpoint_BytesInEndpoint() == 2) { 476 if (Endpoint_BytesInEndpoint() == 2) {
522 uint8_t report_id = Endpoint_Read_8(); 477 uint8_t report_id = Endpoint_Read_8();
523 478
524 if (report_id == REPORT_ID_KEYBOARD || report_id == REPORT_ID_NKRO) { 479 if (report_id == REPORT_ID_KEYBOARD || report_id == REPORT_ID_NKRO) {
525 keyboard_led_stats = Endpoint_Read_8(); 480 keyboard_led_stats = Endpoint_Read_8();
526 } 481 }
527 } else { 482 } else {
528 keyboard_led_stats = Endpoint_Read_8(); 483 keyboard_led_stats = Endpoint_Read_8();
529 } 484 }
530 485
531 Endpoint_ClearOUT(); 486 Endpoint_ClearOUT();
532 Endpoint_ClearStatusStage(); 487 Endpoint_ClearStatusStage();
533 break; 488 break;
534 } 489 }
535
536 } 490 }
537 491
538 break; 492 break;
539 493
540 case HID_REQ_GetProtocol: 494 case HID_REQ_GetProtocol:
541 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) 495 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) {
542 {
543 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) { 496 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
544 Endpoint_ClearSETUP(); 497 Endpoint_ClearSETUP();
545 while (!(Endpoint_IsINReady())); 498 while (!(Endpoint_IsINReady()))
499 ;
546 Endpoint_Write_8(keyboard_protocol); 500 Endpoint_Write_8(keyboard_protocol);
547 Endpoint_ClearIN(); 501 Endpoint_ClearIN();
548 Endpoint_ClearStatusStage(); 502 Endpoint_ClearStatusStage();
@@ -551,8 +505,7 @@ void EVENT_USB_Device_ControlRequest(void)
551 505
552 break; 506 break;
553 case HID_REQ_SetProtocol: 507 case HID_REQ_SetProtocol:
554 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) 508 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) {
555 {
556 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) { 509 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
557 Endpoint_ClearSETUP(); 510 Endpoint_ClearSETUP();
558 Endpoint_ClearStatusStage(); 511 Endpoint_ClearStatusStage();
@@ -564,8 +517,7 @@ void EVENT_USB_Device_ControlRequest(void)
564 517
565 break; 518 break;
566 case HID_REQ_SetIdle: 519 case HID_REQ_SetIdle:
567 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) 520 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)) {
568 {
569 Endpoint_ClearSETUP(); 521 Endpoint_ClearSETUP();
570 Endpoint_ClearStatusStage(); 522 Endpoint_ClearStatusStage();
571 523
@@ -574,10 +526,10 @@ void EVENT_USB_Device_ControlRequest(void)
574 526
575 break; 527 break;
576 case HID_REQ_GetIdle: 528 case HID_REQ_GetIdle:
577 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) 529 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE)) {
578 {
579 Endpoint_ClearSETUP(); 530 Endpoint_ClearSETUP();
580 while (!(Endpoint_IsINReady())); 531 while (!(Endpoint_IsINReady()))
532 ;
581 Endpoint_Write_8(keyboard_idle); 533 Endpoint_Write_8(keyboard_idle);
582 Endpoint_ClearIN(); 534 Endpoint_ClearIN();
583 Endpoint_ClearStatusStage(); 535 Endpoint_ClearStatusStage();
@@ -598,54 +550,50 @@ void EVENT_USB_Device_ControlRequest(void)
598 * 550 *
599 * FIXME: Needs doc 551 * FIXME: Needs doc
600 */ 552 */
601static uint8_t keyboard_leds(void) 553static uint8_t keyboard_leds(void) { return keyboard_led_stats; }
602{
603 return keyboard_led_stats;
604}
605 554
606/** \brief Send Keyboard 555/** \brief Send Keyboard
607 * 556 *
608 * FIXME: Needs doc 557 * FIXME: Needs doc
609 */ 558 */
610static void send_keyboard(report_keyboard_t *report) 559static void send_keyboard(report_keyboard_t *report) {
611{
612 uint8_t timeout = 255; 560 uint8_t timeout = 255;
613 uint8_t where = where_to_send(); 561 uint8_t where = where_to_send();
614 562
615#ifdef BLUETOOTH_ENABLE 563#ifdef BLUETOOTH_ENABLE
616 if (where == OUTPUT_BLUETOOTH || where == OUTPUT_USB_AND_BT) { 564 if (where == OUTPUT_BLUETOOTH || where == OUTPUT_USB_AND_BT) {
617 #ifdef MODULE_ADAFRUIT_BLE 565# ifdef MODULE_ADAFRUIT_BLE
618 adafruit_ble_send_keys(report->mods, report->keys, sizeof(report->keys)); 566 adafruit_ble_send_keys(report->mods, report->keys, sizeof(report->keys));
619 #elif MODULE_RN42 567# elif MODULE_RN42
620 bluefruit_serial_send(0xFD); 568 bluefruit_serial_send(0xFD);
621 bluefruit_serial_send(0x09); 569 bluefruit_serial_send(0x09);
622 bluefruit_serial_send(0x01); 570 bluefruit_serial_send(0x01);
623 bluefruit_serial_send(report->mods); 571 bluefruit_serial_send(report->mods);
624 bluefruit_serial_send(report->reserved); 572 bluefruit_serial_send(report->reserved);
625 for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { 573 for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
626 bluefruit_serial_send(report->keys[i]); 574 bluefruit_serial_send(report->keys[i]);
627 } 575 }
628 #else 576# else
629 bluefruit_serial_send(0xFD); 577 bluefruit_serial_send(0xFD);
630 bluefruit_serial_send(report->mods); 578 bluefruit_serial_send(report->mods);
631 bluefruit_serial_send(report->reserved); 579 bluefruit_serial_send(report->reserved);
632 for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { 580 for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
633 bluefruit_serial_send(report->keys[i]); 581 bluefruit_serial_send(report->keys[i]);
634 } 582 }
635 #endif 583# endif
636 } 584 }
637#endif 585#endif
638 586
639 if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) { 587 if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) {
640 return; 588 return;
641 } 589 }
642 590
643 /* Select the Keyboard Report Endpoint */ 591 /* Select the Keyboard Report Endpoint */
644 uint8_t ep = KEYBOARD_IN_EPNUM; 592 uint8_t ep = KEYBOARD_IN_EPNUM;
645 uint8_t size = KEYBOARD_REPORT_SIZE; 593 uint8_t size = KEYBOARD_REPORT_SIZE;
646#ifdef NKRO_ENABLE 594#ifdef NKRO_ENABLE
647 if (keyboard_protocol && keymap_config.nkro) { 595 if (keyboard_protocol && keymap_config.nkro) {
648 ep = SHARED_IN_EPNUM; 596 ep = SHARED_IN_EPNUM;
649 size = sizeof(struct nkro_report); 597 size = sizeof(struct nkro_report);
650 } 598 }
651#endif 599#endif
@@ -666,38 +614,37 @@ static void send_keyboard(report_keyboard_t *report)
666 614
667 keyboard_report_sent = *report; 615 keyboard_report_sent = *report;
668} 616}
669 617
670/** \brief Send Mouse 618/** \brief Send Mouse
671 * 619 *
672 * FIXME: Needs doc 620 * FIXME: Needs doc
673 */ 621 */
674static void send_mouse(report_mouse_t *report) 622static void send_mouse(report_mouse_t *report) {
675{
676#ifdef MOUSE_ENABLE 623#ifdef MOUSE_ENABLE
677 uint8_t timeout = 255; 624 uint8_t timeout = 255;
678 uint8_t where = where_to_send(); 625 uint8_t where = where_to_send();
679 626
680#ifdef BLUETOOTH_ENABLE 627# ifdef BLUETOOTH_ENABLE
681 if (where == OUTPUT_BLUETOOTH || where == OUTPUT_USB_AND_BT) { 628 if (where == OUTPUT_BLUETOOTH || where == OUTPUT_USB_AND_BT) {
682 #ifdef MODULE_ADAFRUIT_BLE 629# ifdef MODULE_ADAFRUIT_BLE
683 // FIXME: mouse buttons 630 // FIXME: mouse buttons
684 adafruit_ble_send_mouse_move(report->x, report->y, report->v, report->h, report->buttons); 631 adafruit_ble_send_mouse_move(report->x, report->y, report->v, report->h, report->buttons);
685 #else 632# else
686 bluefruit_serial_send(0xFD); 633 bluefruit_serial_send(0xFD);
687 bluefruit_serial_send(0x00); 634 bluefruit_serial_send(0x00);
688 bluefruit_serial_send(0x03); 635 bluefruit_serial_send(0x03);
689 bluefruit_serial_send(report->buttons); 636 bluefruit_serial_send(report->buttons);
690 bluefruit_serial_send(report->x); 637 bluefruit_serial_send(report->x);
691 bluefruit_serial_send(report->y); 638 bluefruit_serial_send(report->y);
692 bluefruit_serial_send(report->v); // should try sending the wheel v here 639 bluefruit_serial_send(report->v); // should try sending the wheel v here
693 bluefruit_serial_send(report->h); // should try sending the wheel h here 640 bluefruit_serial_send(report->h); // should try sending the wheel h here
694 bluefruit_serial_send(0x00); 641 bluefruit_serial_send(0x00);
695 #endif 642# endif
696 } 643 }
697#endif 644# endif
698 645
699 if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) { 646 if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) {
700 return; 647 return;
701 } 648 }
702 649
703 /* Select the Mouse Report Endpoint */ 650 /* Select the Mouse Report Endpoint */
@@ -719,18 +666,13 @@ static void send_mouse(report_mouse_t *report)
719 * 666 *
720 * FIXME: Needs doc 667 * FIXME: Needs doc
721 */ 668 */
722static void send_system(uint16_t data) 669static void send_system(uint16_t data) {
723{
724#ifdef EXTRAKEY_ENABLE 670#ifdef EXTRAKEY_ENABLE
725 uint8_t timeout = 255; 671 uint8_t timeout = 255;
726 672
727 if (USB_DeviceState != DEVICE_STATE_Configured) 673 if (USB_DeviceState != DEVICE_STATE_Configured) return;
728 return;
729 674
730 report_extra_t r = { 675 report_extra_t r = {.report_id = REPORT_ID_SYSTEM, .usage = data - SYSTEM_POWER_DOWN + 1};
731 .report_id = REPORT_ID_SYSTEM,
732 .usage = data - SYSTEM_POWER_DOWN + 1
733 };
734 Endpoint_SelectEndpoint(SHARED_IN_EPNUM); 676 Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
735 677
736 /* Check if write ready for a polling interval around 10ms */ 678 /* Check if write ready for a polling interval around 10ms */
@@ -746,52 +688,48 @@ static void send_system(uint16_t data)
746 * 688 *
747 * FIXME: Needs doc 689 * FIXME: Needs doc
748 */ 690 */
749static void send_consumer(uint16_t data) 691static void send_consumer(uint16_t data) {
750{
751#ifdef EXTRAKEY_ENABLE 692#ifdef EXTRAKEY_ENABLE
752 uint8_t timeout = 255; 693 uint8_t timeout = 255;
753 uint8_t where = where_to_send(); 694 uint8_t where = where_to_send();
754 695
755#ifdef BLUETOOTH_ENABLE 696# ifdef BLUETOOTH_ENABLE
756 if (where == OUTPUT_BLUETOOTH || where == OUTPUT_USB_AND_BT) { 697 if (where == OUTPUT_BLUETOOTH || where == OUTPUT_USB_AND_BT) {
757 #ifdef MODULE_ADAFRUIT_BLE 698# ifdef MODULE_ADAFRUIT_BLE
758 adafruit_ble_send_consumer_key(data, 0); 699 adafruit_ble_send_consumer_key(data, 0);
759 #elif MODULE_RN42 700# elif MODULE_RN42
760 static uint16_t last_data = 0; 701 static uint16_t last_data = 0;
761 if (data == last_data) return; 702 if (data == last_data) return;
762 last_data = data; 703 last_data = data;
763 uint16_t bitmap = CONSUMER2RN42(data); 704 uint16_t bitmap = CONSUMER2RN42(data);
764 bluefruit_serial_send(0xFD); 705 bluefruit_serial_send(0xFD);
765 bluefruit_serial_send(0x03); 706 bluefruit_serial_send(0x03);
766 bluefruit_serial_send(0x03); 707 bluefruit_serial_send(0x03);
767 bluefruit_serial_send(bitmap&0xFF); 708 bluefruit_serial_send(bitmap & 0xFF);
768 bluefruit_serial_send((bitmap>>8)&0xFF); 709 bluefruit_serial_send((bitmap >> 8) & 0xFF);
769 #else 710# else
770 static uint16_t last_data = 0; 711 static uint16_t last_data = 0;
771 if (data == last_data) return; 712 if (data == last_data) return;
772 last_data = data; 713 last_data = data;
773 uint16_t bitmap = CONSUMER2BLUEFRUIT(data); 714 uint16_t bitmap = CONSUMER2BLUEFRUIT(data);
774 bluefruit_serial_send(0xFD); 715 bluefruit_serial_send(0xFD);
775 bluefruit_serial_send(0x00); 716 bluefruit_serial_send(0x00);
776 bluefruit_serial_send(0x02); 717 bluefruit_serial_send(0x02);
777 bluefruit_serial_send((bitmap>>8)&0xFF); 718 bluefruit_serial_send((bitmap >> 8) & 0xFF);
778 bluefruit_serial_send(bitmap&0xFF); 719 bluefruit_serial_send(bitmap & 0xFF);
779 bluefruit_serial_send(0x00); 720 bluefruit_serial_send(0x00);
780 bluefruit_serial_send(0x00); 721 bluefruit_serial_send(0x00);
781 bluefruit_serial_send(0x00); 722 bluefruit_serial_send(0x00);
782 bluefruit_serial_send(0x00); 723 bluefruit_serial_send(0x00);
783 #endif 724# endif
784 } 725 }
785#endif 726# endif
786 727
787 if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) { 728 if (where != OUTPUT_USB && where != OUTPUT_USB_AND_BT) {
788 return; 729 return;
789 } 730 }
790 731
791 report_extra_t r = { 732 report_extra_t r = {.report_id = REPORT_ID_CONSUMER, .usage = data};
792 .report_id = REPORT_ID_CONSUMER,
793 .usage = data
794 };
795 Endpoint_SelectEndpoint(SHARED_IN_EPNUM); 733 Endpoint_SelectEndpoint(SHARED_IN_EPNUM);
796 734
797 /* Check if write ready for a polling interval around 10ms */ 735 /* Check if write ready for a polling interval around 10ms */
@@ -803,18 +741,16 @@ static void send_consumer(uint16_t data)
803#endif 741#endif
804} 742}
805 743
806
807/******************************************************************************* 744/*******************************************************************************
808 * sendchar 745 * sendchar
809 ******************************************************************************/ 746 ******************************************************************************/
810#ifdef CONSOLE_ENABLE 747#ifdef CONSOLE_ENABLE
811#define SEND_TIMEOUT 5 748# define SEND_TIMEOUT 5
812/** \brief Send Char 749/** \brief Send Char
813 * 750 *
814 * FIXME: Needs doc 751 * FIXME: Needs doc
815 */ 752 */
816int8_t sendchar(uint8_t c) 753int8_t sendchar(uint8_t c) {
817{
818 // Not wait once timeouted. 754 // Not wait once timeouted.
819 // Because sendchar() is called so many times, waiting each call causes big lag. 755 // Because sendchar() is called so many times, waiting each call causes big lag.
820 static bool timeouted = false; 756 static bool timeouted = false;
@@ -823,8 +759,7 @@ int8_t sendchar(uint8_t c)
823 // or char will be lost. These two function is mutually exclusive. 759 // or char will be lost. These two function is mutually exclusive.
824 CONSOLE_FLUSH_SET(false); 760 CONSOLE_FLUSH_SET(false);
825 761
826 if (USB_DeviceState != DEVICE_STATE_Configured) 762 if (USB_DeviceState != DEVICE_STATE_Configured) return -1;
827 return -1;
828 763
829 uint8_t ep = Endpoint_GetCurrentEndpoint(); 764 uint8_t ep = Endpoint_GetCurrentEndpoint();
830 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM); 765 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
@@ -857,7 +792,8 @@ int8_t sendchar(uint8_t c)
857 792
858 // send when bank is full 793 // send when bank is full
859 if (!Endpoint_IsReadWriteAllowed()) { 794 if (!Endpoint_IsReadWriteAllowed()) {
860 while (!(Endpoint_IsINReady())); 795 while (!(Endpoint_IsINReady()))
796 ;
861 Endpoint_ClearIN(); 797 Endpoint_ClearIN();
862 } else { 798 } else {
863 CONSOLE_FLUSH_SET(true); 799 CONSOLE_FLUSH_SET(true);
@@ -870,10 +806,7 @@ ERROR_EXIT:
870 return -1; 806 return -1;
871} 807}
872#else 808#else
873int8_t sendchar(uint8_t c) 809int8_t sendchar(uint8_t c) { return 0; }
874{
875 return 0;
876}
877#endif 810#endif
878 811
879/******************************************************************************* 812/*******************************************************************************
@@ -881,33 +814,28 @@ int8_t sendchar(uint8_t c)
881 ******************************************************************************/ 814 ******************************************************************************/
882 815
883#ifdef MIDI_ENABLE 816#ifdef MIDI_ENABLE
884USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = 817USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = {
885{ 818 .Config =
886 .Config = 819 {
887 { 820 .StreamingInterfaceNumber = AS_INTERFACE,
888 .StreamingInterfaceNumber = AS_INTERFACE, 821 .DataINEndpoint =
889 .DataINEndpoint = 822 {
890 { 823 .Address = MIDI_STREAM_IN_EPADDR,
891 .Address = MIDI_STREAM_IN_EPADDR, 824 .Size = MIDI_STREAM_EPSIZE,
892 .Size = MIDI_STREAM_EPSIZE, 825 .Banks = 1,
893 .Banks = 1, 826 },
894 }, 827 .DataOUTEndpoint =
895 .DataOUTEndpoint = 828 {
896 { 829 .Address = MIDI_STREAM_OUT_EPADDR,
897 .Address = MIDI_STREAM_OUT_EPADDR, 830 .Size = MIDI_STREAM_EPSIZE,
898 .Size = MIDI_STREAM_EPSIZE, 831 .Banks = 1,
899 .Banks = 1, 832 },
900 }, 833 },
901 },
902}; 834};
903 835
904void send_midi_packet(MIDI_EventPacket_t* event) { 836void send_midi_packet(MIDI_EventPacket_t *event) { MIDI_Device_SendEventPacket(&USB_MIDI_Interface, event); }
905 MIDI_Device_SendEventPacket(&USB_MIDI_Interface, event);
906}
907 837
908bool recv_midi_packet(MIDI_EventPacket_t* const event) { 838bool recv_midi_packet(MIDI_EventPacket_t *const event) { return MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, event); }
909 return MIDI_Device_ReceiveEventPacket(&USB_MIDI_Interface, event);
910}
911 839
912#endif 840#endif
913 841
@@ -920,66 +848,60 @@ bool recv_midi_packet(MIDI_EventPacket_t* const event) {
920 * 848 *
921 * FIXME: Needs doc 849 * FIXME: Needs doc
922 */ 850 */
923void virtser_init(void) 851void virtser_init(void) {
924{ 852 cdc_device.State.ControlLineStates.DeviceToHost = CDC_CONTROL_LINE_IN_DSR;
925 cdc_device.State.ControlLineStates.DeviceToHost = CDC_CONTROL_LINE_IN_DSR ; 853 CDC_Device_SendControlLineStateChange(&cdc_device);
926 CDC_Device_SendControlLineStateChange(&cdc_device);
927} 854}
928 855
929/** \brief Virtual Serial Receive 856/** \brief Virtual Serial Receive
930 * 857 *
931 * FIXME: Needs doc 858 * FIXME: Needs doc
932 */ 859 */
933void virtser_recv(uint8_t c) __attribute__ ((weak)); 860void virtser_recv(uint8_t c) __attribute__((weak));
934void virtser_recv(uint8_t c) 861void virtser_recv(uint8_t c) {
935{ 862 // Ignore by default
936 // Ignore by default
937} 863}
938 864
939/** \brief Virtual Serial Task 865/** \brief Virtual Serial Task
940 * 866 *
941 * FIXME: Needs doc 867 * FIXME: Needs doc
942 */ 868 */
943void virtser_task(void) 869void virtser_task(void) {
944{ 870 uint16_t count = CDC_Device_BytesReceived(&cdc_device);
945 uint16_t count = CDC_Device_BytesReceived(&cdc_device); 871 uint8_t ch;
946 uint8_t ch; 872 if (count) {
947 if (count) 873 ch = CDC_Device_ReceiveByte(&cdc_device);
948 { 874 virtser_recv(ch);
949 ch = CDC_Device_ReceiveByte(&cdc_device); 875 }
950 virtser_recv(ch);
951 }
952} 876}
953/** \brief Virtual Serial Send 877/** \brief Virtual Serial Send
954 * 878 *
955 * FIXME: Needs doc 879 * FIXME: Needs doc
956 */ 880 */
957void virtser_send(const uint8_t byte) 881void virtser_send(const uint8_t byte) {
958{ 882 uint8_t timeout = 255;
959 uint8_t timeout = 255; 883 uint8_t ep = Endpoint_GetCurrentEndpoint();
960 uint8_t ep = Endpoint_GetCurrentEndpoint();
961 884
962 if (cdc_device.State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR) 885 if (cdc_device.State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR) {
963 { 886 /* IN packet */
964 /* IN packet */ 887 Endpoint_SelectEndpoint(cdc_device.Config.DataINEndpoint.Address);
965 Endpoint_SelectEndpoint(cdc_device.Config.DataINEndpoint.Address);
966 888
967 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) { 889 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
968 Endpoint_SelectEndpoint(ep); 890 Endpoint_SelectEndpoint(ep);
969 return; 891 return;
970 } 892 }
971 893
972 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40); 894 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
973 895
974 Endpoint_Write_8(byte); 896 Endpoint_Write_8(byte);
975 CDC_Device_Flush(&cdc_device); 897 CDC_Device_Flush(&cdc_device);
976 898
977 if (Endpoint_IsINReady()) { 899 if (Endpoint_IsINReady()) {
978 Endpoint_ClearIN(); 900 Endpoint_ClearIN();
979 } 901 }
980 902
981 Endpoint_SelectEndpoint(ep); 903 Endpoint_SelectEndpoint(ep);
982 } 904 }
983} 905}
984#endif 906#endif
985 907
@@ -990,8 +912,7 @@ void virtser_send(const uint8_t byte)
990 * 912 *
991 * FIXME: Needs doc 913 * FIXME: Needs doc
992 */ 914 */
993static void setup_mcu(void) 915static void setup_mcu(void) {
994{
995 /* Disable watchdog if enabled by bootloader/fuses */ 916 /* Disable watchdog if enabled by bootloader/fuses */
996 MCUSR &= ~(1 << WDRF); 917 MCUSR &= ~(1 << WDRF);
997 wdt_disable(); 918 wdt_disable();
@@ -1007,8 +928,7 @@ static void setup_mcu(void)
1007 * 928 *
1008 * FIXME: Needs doc 929 * FIXME: Needs doc
1009 */ 930 */
1010static void setup_usb(void) 931static void setup_usb(void) {
1011{
1012 // Leonardo needs. Without this USB device is not recognized. 932 // Leonardo needs. Without this USB device is not recognized.
1013 USB_Disable(); 933 USB_Disable();
1014 934
@@ -1023,9 +943,8 @@ static void setup_usb(void)
1023 * 943 *
1024 * FIXME: Needs doc 944 * FIXME: Needs doc
1025 */ 945 */
1026int main(void) __attribute__ ((weak)); 946int main(void) __attribute__((weak));
1027int main(void) 947int main(void) {
1028{
1029#ifdef MIDI_ENABLE 948#ifdef MIDI_ENABLE
1030 setup_midi(); 949 setup_midi();
1031#endif 950#endif
@@ -1043,11 +962,11 @@ int main(void)
1043 962
1044#ifdef WAIT_FOR_USB 963#ifdef WAIT_FOR_USB
1045 while (USB_DeviceState != DEVICE_STATE_Configured) { 964 while (USB_DeviceState != DEVICE_STATE_Configured) {
1046 #if defined(INTERRUPT_CONTROL_ENDPOINT) 965# if defined(INTERRUPT_CONTROL_ENDPOINT)
1047 ; 966 ;
1048 #else 967# else
1049 USB_USBTask(); 968 USB_USBTask();
1050 #endif 969# endif
1051 } 970 }
1052 print("USB configured.\n"); 971 print("USB configured.\n");
1053#else 972#else
@@ -1066,15 +985,15 @@ int main(void)
1066 985
1067 print("Keyboard start.\n"); 986 print("Keyboard start.\n");
1068 while (1) { 987 while (1) {
1069 #if !defined(NO_USB_STARTUP_CHECK) 988#if !defined(NO_USB_STARTUP_CHECK)
1070 while (USB_DeviceState == DEVICE_STATE_Suspended) { 989 while (USB_DeviceState == DEVICE_STATE_Suspended) {
1071 print("[s]"); 990 print("[s]");
1072 suspend_power_down(); 991 suspend_power_down();
1073 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) { 992 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
1074 USB_Device_SendRemoteWakeup(); 993 USB_Device_SendRemoteWakeup();
1075 } 994 }
1076 } 995 }
1077 #endif 996#endif
1078 997
1079 keyboard_task(); 998 keyboard_task();
1080 999
@@ -1102,14 +1021,7 @@ int main(void)
1102#if !defined(INTERRUPT_CONTROL_ENDPOINT) 1021#if !defined(INTERRUPT_CONTROL_ENDPOINT)
1103 USB_USBTask(); 1022 USB_USBTask();
1104#endif 1023#endif
1105
1106 } 1024 }
1107} 1025}
1108 1026
1109uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, 1027uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, const uint16_t wIndex, const void **const DescriptorAddress) { return get_usb_descriptor(wValue, wIndex, DescriptorAddress); }
1110 const uint16_t wIndex,
1111 const void** const DescriptorAddress)
1112{
1113 return get_usb_descriptor(wValue, wIndex, DescriptorAddress);
1114}
1115
diff --git a/tmk_core/protocol/lufa/lufa.h b/tmk_core/protocol/lufa/lufa.h
index 7364cdf7c..652e4e79b 100644
--- a/tmk_core/protocol/lufa/lufa.h
+++ b/tmk_core/protocol/lufa/lufa.h
@@ -62,27 +62,27 @@ extern host_driver_t lufa_driver;
62typedef struct { 62typedef struct {
63 uint8_t report_id; 63 uint8_t report_id;
64 uint16_t usage; 64 uint16_t usage;
65} __attribute__ ((packed)) report_extra_t; 65} __attribute__((packed)) report_extra_t;
66 66
67#ifdef API_ENABLE 67#ifdef API_ENABLE
68 #include "api.h" 68# include "api.h"
69#endif 69#endif
70 70
71#ifdef API_SYSEX_ENABLE 71#ifdef API_SYSEX_ENABLE
72 #include "api_sysex.h" 72# include "api_sysex.h"
73 // Allocate space for encoding overhead. 73// Allocate space for encoding overhead.
74 //The header and terminator are not stored to save a few bytes of precious ram 74// The header and terminator are not stored to save a few bytes of precious ram
75 #define MIDI_SYSEX_BUFFER (API_SYSEX_MAX_SIZE + API_SYSEX_MAX_SIZE / 7 + (API_SYSEX_MAX_SIZE % 7 ? 1 : 0)) 75# define MIDI_SYSEX_BUFFER (API_SYSEX_MAX_SIZE + API_SYSEX_MAX_SIZE / 7 + (API_SYSEX_MAX_SIZE % 7 ? 1 : 0))
76#endif 76#endif
77 77
78// #if LUFA_VERSION_INTEGER < 0x120730 78// #if LUFA_VERSION_INTEGER < 0x120730
79// /* old API 120219 */ 79// /* old API 120219 */
80// #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank) 80// #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
81// #else 81// #else
82 /* new API >= 120730 */ 82/* new API >= 120730 */
83 #define ENDPOINT_BANK_SINGLE 1 83#define ENDPOINT_BANK_SINGLE 1
84 #define ENDPOINT_BANK_DOUBLE 2 84#define ENDPOINT_BANK_DOUBLE 2
85 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank) 85#define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum), eptype, epsize, epbank)
86// #endif 86// #endif
87 87
88#endif 88#endif
diff --git a/tmk_core/protocol/lufa/outputselect.c b/tmk_core/protocol/lufa/outputselect.c
index 42de80612..b115ea969 100644
--- a/tmk_core/protocol/lufa/outputselect.c
+++ b/tmk_core/protocol/lufa/outputselect.c
@@ -15,7 +15,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
15#include "lufa.h" 15#include "lufa.h"
16#include "outputselect.h" 16#include "outputselect.h"
17#ifdef MODULE_ADAFRUIT_BLE 17#ifdef MODULE_ADAFRUIT_BLE
18 #include "adafruit_ble.h" 18# include "adafruit_ble.h"
19#endif 19#endif
20 20
21uint8_t desired_output = OUTPUT_DEFAULT; 21uint8_t desired_output = OUTPUT_DEFAULT;
@@ -33,9 +33,7 @@ void set_output(uint8_t output) {
33 * 33 *
34 * FIXME: Needs doc 34 * FIXME: Needs doc
35 */ 35 */
36__attribute__((weak)) 36__attribute__((weak)) void set_output_user(uint8_t output) {}
37void set_output_user(uint8_t output) {
38}
39 37
40/** \brief Auto Detect Output 38/** \brief Auto Detect Output
41 * 39 *
@@ -53,7 +51,7 @@ uint8_t auto_detect_output(void) {
53#endif 51#endif
54 52
55#ifdef BLUETOOTH_ENABLE 53#ifdef BLUETOOTH_ENABLE
56 return OUTPUT_BLUETOOTH; // should check if BT is connected here 54 return OUTPUT_BLUETOOTH; // should check if BT is connected here
57#endif 55#endif
58 56
59 return OUTPUT_NONE; 57 return OUTPUT_NONE;
@@ -69,4 +67,3 @@ uint8_t where_to_send(void) {
69 } 67 }
70 return desired_output; 68 return desired_output;
71} 69}
72
diff --git a/tmk_core/protocol/lufa/outputselect.h b/tmk_core/protocol/lufa/outputselect.h
index 28cc3298e..24fe4daa2 100644
--- a/tmk_core/protocol/lufa/outputselect.h
+++ b/tmk_core/protocol/lufa/outputselect.h
@@ -27,14 +27,14 @@ enum outputs {
27 * backward compatibility for BLUETOOTH_ENABLE, send to BT and USB by default 27 * backward compatibility for BLUETOOTH_ENABLE, send to BT and USB by default
28 */ 28 */
29#ifndef OUTPUT_DEFAULT 29#ifndef OUTPUT_DEFAULT
30 #ifdef BLUETOOTH_ENABLE 30# ifdef BLUETOOTH_ENABLE
31 #define OUTPUT_DEFAULT OUTPUT_USB_AND_BT 31# define OUTPUT_DEFAULT OUTPUT_USB_AND_BT
32 #else 32# else
33 #define OUTPUT_DEFAULT OUTPUT_AUTO 33# define OUTPUT_DEFAULT OUTPUT_AUTO
34 #endif 34# endif
35#endif 35#endif
36 36
37void set_output(uint8_t output); 37void set_output(uint8_t output);
38void set_output_user(uint8_t output); 38void set_output_user(uint8_t output);
39uint8_t auto_detect_output(void); 39uint8_t auto_detect_output(void);
40uint8_t where_to_send(void); \ No newline at end of file 40uint8_t where_to_send(void); \ No newline at end of file