diff options
author | skullY <skullydazed@gmail.com> | 2019-08-30 11:19:03 -0700 |
---|---|---|
committer | skullydazed <skullydazed@users.noreply.github.com> | 2019-08-30 15:01:52 -0700 |
commit | b624f32f944acdc59dcb130674c09090c5c404cb (patch) | |
tree | bc13adbba137d122d9a2c2fb2fafcbb08ac10e25 /tmk_core/protocol/lufa | |
parent | 61af76a10d00aba185b8338604171de490a13e3b (diff) | |
download | qmk_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.cpp | 1117 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/adafruit_ble.h | 30 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/bluetooth.c | 20 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/bluetooth.h | 37 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/lufa.c | 692 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/lufa.h | 20 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/outputselect.c | 9 | ||||
-rw-r--r-- | tmk_core/protocol/lufa/outputselect.h | 14 |
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 | ||
33 | static struct { | 32 | static 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 |
53 | struct sdep_msg { | 52 | struct 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 | ||
70 | enum queue_type { | 69 | enum 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 | ||
78 | struct queue_item { | 77 | struct 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; | |||
102 | static bool process_queue_item(struct queue_item *item, uint16_t timeout); | 101 | static bool process_queue_item(struct queue_item *item, uint16_t timeout); |
103 | 102 | ||
104 | enum sdep_type { | 103 | enum 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 | ||
113 | enum ble_cmd { | 112 | enum 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 | ||
120 | enum ble_system_event_bits { | 119 | enum 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 | ||
136 | static bool at_command(const char *cmd, char *resp, uint16_t resplen, | 135 | static bool at_command(const char *cmd, char *resp, uint16_t resplen, bool verbose, uint16_t timeout = SdepTimeout); |
137 | bool verbose, uint16_t timeout = SdepTimeout); | 136 | static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose = false); |
138 | static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, | ||
139 | bool verbose = false); | ||
140 | 137 | ||
141 | struct SPI_Settings { | 138 | struct SPI_Settings { |
142 | uint8_t spcr, spsr; | 139 | uint8_t spcr, spsr; |
143 | }; | 140 | }; |
144 | 141 | ||
145 | static struct SPI_Settings spi; | 142 | static struct SPI_Settings spi; |
146 | 143 | ||
147 | // Initialize 4Mhz MSBFIRST MODE0 | 144 | // Initialize 4Mhz MSBFIRST MODE0 |
148 | void SPI_init(struct SPI_Settings *spi) { | 145 | void 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 | ||
166 | static inline void SPI_begin(struct SPI_Settings*spi) { | 163 | static 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 | ||
171 | static inline uint8_t SPI_TransferByte(uint8_t data) { | 168 | static 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 | ||
180 | static inline void spi_send_bytes(const uint8_t *buf, uint8_t len) { | 177 | static 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 | ||
192 | static inline uint16_t spi_read_byte(void) { | 189 | static inline uint16_t spi_read_byte(void) { return SPI_TransferByte(0x00 /* dummy */); } |
193 | return SPI_TransferByte(0x00 /* dummy */); | ||
194 | } | ||
195 | 190 | ||
196 | static inline void spi_recv_bytes(uint8_t *buf, uint8_t len) { | 191 | static 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 |
225 | static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) { | 220 | static 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 | ||
257 | static inline void sdep_build_pkt(struct sdep_msg *msg, uint16_t command, | 251 | static 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 |
272 | static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) { | 264 | static 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 | ||
317 | static void resp_buf_read_one(bool greedy) { | 309 | static 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 | ||
326 | again: | 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 | ||
348 | static void send_buf_send_one(uint16_t timeout = SdepTimeout) { | 339 | static 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 | ||
370 | static void resp_buf_wait(const char *cmd) { | 361 | static 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 | ||
381 | static bool ble_init(void) { | 372 | static 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 | ||
405 | static inline uint8_t min(uint8_t a, uint8_t b) { | 396 | static inline uint8_t min(uint8_t a, uint8_t b) { return a < b ? a : b; } |
406 | return a < b ? a : b; | ||
407 | } | ||
408 | 397 | ||
409 | static bool read_response(char *resp, uint16_t resplen, bool verbose) { | 398 | static 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 ); | 457 | static 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 | ||
468 | static 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 | ||
514 | bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) { | 502 | bool 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 | ||
520 | bool adafruit_ble_is_connected(void) { | 508 | bool adafruit_ble_is_connected(void) { return state.is_connected; } |
521 | return state.is_connected; | ||
522 | } | ||
523 | 509 | ||
524 | bool adafruit_ble_enable_keyboard(void) { | 510 | bool 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(); | ||
578 | fail: | 558 | fail: |
579 | return state.configured; | 559 | return state.configured; |
580 | } | 560 | } |
581 | 561 | ||
582 | static void set_connected(bool connected) { | 562 | static 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 | ||
602 | void adafruit_ble_task(void) { | 582 | void 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 | ||
669 | static bool process_queue_item(struct queue_item *item, uint16_t timeout) { | 647 | static 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 | |||
725 | bool 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) { | 698 | bool 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 | ||
762 | bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration) { | 734 | bool 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 |
775 | bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, | 747 | bool 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 | ||
793 | uint32_t adafruit_ble_read_battery_voltage(void) { | 764 | uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; } |
794 | return state.vbat; | ||
795 | } | ||
796 | 765 | ||
797 | bool adafruit_ble_set_mode_leds(bool on) { | 766 | bool 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 |
815 | bool adafruit_ble_set_power_level(int8_t level) { | 782 | bool 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 |
15 | extern "C" { | 15 | extern "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 */ |
19 | extern bool adafruit_ble_enable_keyboard(void); | 19 | extern 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. */ |
37 | extern bool adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, | 37 | extern 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) */ |
42 | extern bool adafruit_ble_send_consumer_key(uint16_t keycode, int hold_duration); | 41 | extern 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. */ |
48 | extern bool adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, | 47 | extern 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); | |||
56 | extern bool adafruit_ble_set_mode_leds(bool on); | 54 | extern bool adafruit_ble_set_mode_leds(bool on); |
57 | extern bool adafruit_ble_set_power_level(int8_t level); | 55 | extern 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 | ||
24 | void bluefruit_keyboard_print_report(report_keyboard_t *report) | 24 | void 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 | ||
33 | void bluefruit_serial_send(uint8_t data) | 38 | void 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; | 62 | extern 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 | ||
94 | uint8_t keyboard_idle = 0; | 93 | uint8_t keyboard_idle = 0; |
95 | /* 0: Boot Protocol, 1: Report Protocol(default) */ | 94 | /* 0: Boot Protocol, 1: Report Protocol(default) */ |
96 | uint8_t keyboard_protocol = 1; | 95 | uint8_t keyboard_protocol = 1; |
97 | static uint8_t keyboard_led_stats = 0; | 96 | static uint8_t keyboard_led_stats = 0; |
98 | 97 | ||
99 | static report_keyboard_t keyboard_report_sent; | 98 | static report_keyboard_t keyboard_report_sent; |
100 | 99 | ||
101 | /* Host driver */ | 100 | /* Host driver */ |
102 | static uint8_t keyboard_leds(void); | 101 | static uint8_t keyboard_leds(void); |
103 | static void send_keyboard(report_keyboard_t *report); | 102 | static void send_keyboard(report_keyboard_t *report); |
104 | static void send_mouse(report_mouse_t *report); | 103 | static void send_mouse(report_mouse_t *report); |
105 | static void send_system(uint16_t data); | 104 | static void send_system(uint16_t data); |
106 | static void send_consumer(uint16_t data); | 105 | static void send_consumer(uint16_t data); |
107 | host_driver_t lufa_driver = { | 106 | host_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 |
116 | USB_ClassInfo_CDC_Device_t cdc_device = | 111 | USB_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 | */ |
149 | void raw_hid_send( uint8_t *data, uint8_t length ) | 143 | void 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) { |
185 | void 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 | */ |
196 | static void raw_hid_task(void) | 184 | static 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 | */ |
238 | static void Console_Task(void) | 221 | static 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 | */ |
306 | void EVENT_USB_Device_Connect(void) | 285 | void 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 | */ |
321 | void EVENT_USB_Device_Disconnect(void) | 299 | void 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 | */ |
339 | void EVENT_USB_Device_Reset(void) | 316 | void 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 | */ |
348 | void EVENT_USB_Device_Suspend() | 322 | void 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 | */ |
360 | void EVENT_USB_Device_WakeUp() | 333 | void 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 |
375 | static bool console_flush = false; | 345 | static 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 | */ |
387 | void EVENT_USB_Device_StartOfFrame(void) | 356 | void 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 | */ |
407 | void EVENT_USB_Device_ConfigurationChanged(void) | 375 | void 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 | */ |
476 | void EVENT_USB_Device_ControlRequest(void) | 437 | void 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 | */ |
601 | static uint8_t keyboard_leds(void) | 553 | static 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 | */ |
610 | static void send_keyboard(report_keyboard_t *report) | 559 | static 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 | */ |
674 | static void send_mouse(report_mouse_t *report) | 622 | static 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 | */ |
722 | static void send_system(uint16_t data) | 669 | static 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 | */ |
749 | static void send_consumer(uint16_t data) | 691 | static 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 | */ |
816 | int8_t sendchar(uint8_t c) | 753 | int8_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 |
873 | int8_t sendchar(uint8_t c) | 809 | int8_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 |
884 | USB_ClassInfo_MIDI_Device_t USB_MIDI_Interface = | 817 | USB_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 | ||
904 | void send_midi_packet(MIDI_EventPacket_t* event) { | 836 | void 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 | ||
908 | bool recv_midi_packet(MIDI_EventPacket_t* const event) { | 838 | bool 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 | */ |
923 | void virtser_init(void) | 851 | void 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 | */ |
933 | void virtser_recv(uint8_t c) __attribute__ ((weak)); | 860 | void virtser_recv(uint8_t c) __attribute__((weak)); |
934 | void virtser_recv(uint8_t c) | 861 | void 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 | */ |
943 | void virtser_task(void) | 869 | void 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 | */ |
957 | void virtser_send(const uint8_t byte) | 881 | void 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 | */ |
993 | static void setup_mcu(void) | 915 | static 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 | */ |
1010 | static void setup_usb(void) | 931 | static 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 | */ |
1026 | int main(void) __attribute__ ((weak)); | 946 | int main(void) __attribute__((weak)); |
1027 | int main(void) | 947 | int 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 | ||
1109 | uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, | 1027 | uint16_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; | |||
62 | typedef struct { | 62 | typedef 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 | ||
21 | uint8_t desired_output = OUTPUT_DEFAULT; | 21 | uint8_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) {} |
37 | void 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 | ||
37 | void set_output(uint8_t output); | 37 | void set_output(uint8_t output); |
38 | void set_output_user(uint8_t output); | 38 | void set_output_user(uint8_t output); |
39 | uint8_t auto_detect_output(void); | 39 | uint8_t auto_detect_output(void); |
40 | uint8_t where_to_send(void); \ No newline at end of file | 40 | uint8_t where_to_send(void); \ No newline at end of file |