Update other_projects.md - added TMK/Ergodox
[tmk_keyboard.git] / protocol / lufa / lufa.c
1 /*
2 * Copyright 2012 Jun Wako <wakojun@gmail.com>
3 * This file is based on:
4 * LUFA-120219/Demos/Device/Lowlevel/KeyboardMouse
5 * LUFA-120219/Demos/Device/Lowlevel/GenericHID
6 */
7
8 /*
9 LUFA Library
10 Copyright (C) Dean Camera, 2012.
11
12 dean [at] fourwalledcubicle [dot] com
13 www.lufa-lib.org
14 */
15
16 /*
17 Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
18 Copyright 2010 Denver Gingerich (denver [at] ossguy [dot] com)
19
20 Permission to use, copy, modify, distribute, and sell this
21 software and its documentation for any purpose is hereby granted
22 without fee, provided that the above copyright notice appear in
23 all copies and that both that the copyright notice and this
24 permission notice and warranty disclaimer appear in supporting
25 documentation, and that the name of the author not be used in
26 advertising or publicity pertaining to distribution of the
27 software without specific, written prior permission.
28
29 The author disclaim all warranties with regard to this
30 software, including all implied warranties of merchantability
31 and fitness. In no event shall the author be liable for any
32 special, indirect or consequential damages or any damages
33 whatsoever resulting from loss of use, data or profits, whether
34 in an action of contract, negligence or other tortious action,
35 arising out of or in connection with the use or performance of
36 this software.
37 */
38
39 #include "report.h"
40 #include "host.h"
41 #include "host_driver.h"
42 #include "keyboard.h"
43 #include "action.h"
44 #include "led.h"
45 #include "sendchar.h"
46 #include "debug.h"
47 #ifdef SLEEP_LED_ENABLE
48 #include "sleep_led.h"
49 #endif
50 #include "suspend.h"
51
52 #include "descriptor.h"
53 #include "lufa.h"
54
55 uint8_t keyboard_idle = 0;
56 uint8_t keyboard_protocol = 1;
57 static uint8_t keyboard_led_stats = 0;
58
59 static report_keyboard_t keyboard_report_sent;
60
61
62 /* Host driver */
63 static uint8_t keyboard_leds(void);
64 static void send_keyboard(report_keyboard_t *report);
65 static void send_mouse(report_mouse_t *report);
66 static void send_system(uint16_t data);
67 static void send_consumer(uint16_t data);
68 host_driver_t lufa_driver = {
69 keyboard_leds,
70 send_keyboard,
71 send_mouse,
72 send_system,
73 send_consumer
74 };
75
76
77 /*******************************************************************************
78 * Console
79 ******************************************************************************/
80 #ifdef CONSOLE_ENABLE
81 static void Console_Task(void)
82 {
83 /* Device must be connected and configured for the task to run */
84 if (USB_DeviceState != DEVICE_STATE_Configured)
85 return;
86
87 uint8_t ep = Endpoint_GetCurrentEndpoint();
88
89 #if 0
90 // TODO: impl receivechar()/recvchar()
91 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
92
93 /* Check to see if a packet has been sent from the host */
94 if (Endpoint_IsOUTReceived())
95 {
96 /* Check to see if the packet contains data */
97 if (Endpoint_IsReadWriteAllowed())
98 {
99 /* Create a temporary buffer to hold the read in report from the host */
100 uint8_t ConsoleData[CONSOLE_EPSIZE];
101
102 /* Read Console Report Data */
103 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
104
105 /* Process Console Report Data */
106 //ProcessConsoleHIDReport(ConsoleData);
107 }
108
109 /* Finalize the stream transfer to send the last packet */
110 Endpoint_ClearOUT();
111 }
112 #endif
113
114 /* IN packet */
115 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
116 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
117 Endpoint_SelectEndpoint(ep);
118 return;
119 }
120
121 // fill empty bank
122 while (Endpoint_IsReadWriteAllowed())
123 Endpoint_Write_8(0);
124
125 // flash senchar packet
126 if (Endpoint_IsINReady()) {
127 Endpoint_ClearIN();
128 }
129
130 Endpoint_SelectEndpoint(ep);
131 }
132 #else
133 static void Console_Task(void)
134 {
135 }
136 #endif
137
138
139 /*******************************************************************************
140 * USB Events
141 ******************************************************************************/
142 /*
143 * Event Order of Plug in:
144 * 0) EVENT_USB_Device_Connect
145 * 1) EVENT_USB_Device_Suspend
146 * 2) EVENT_USB_Device_Reset
147 * 3) EVENT_USB_Device_Wake
148 */
149 void EVENT_USB_Device_Connect(void)
150 {
151 /* For battery powered device */
152 if (!USB_IsInitialized) {
153 USB_Init();
154 USB_Device_EnableSOFEvents();
155 }
156 }
157
158 void EVENT_USB_Device_Disconnect(void)
159 {
160 /* For battery powered device */
161 /* TODO: This doesn't work. After several plug in/outs can not be enumerated.
162 if (USB_IsInitialized) {
163 USB_Disable(); // Disable all interrupts
164 USB_Controller_Enable();
165 USB_INT_Enable(USB_INT_VBUSTI);
166 }
167 */
168 }
169
170 void EVENT_USB_Device_Reset(void)
171 {
172 }
173
174 void EVENT_USB_Device_Suspend()
175 {
176 #ifdef SLEEP_LED_ENABLE
177 sleep_led_enable();
178 #endif
179 }
180
181 void EVENT_USB_Device_WakeUp()
182 {
183 suspend_wakeup_init();
184
185 #ifdef SLEEP_LED_ENABLE
186 sleep_led_disable();
187 // NOTE: converters may not accept this
188 led_set(host_keyboard_leds());
189 #endif
190 }
191
192 void EVENT_USB_Device_StartOfFrame(void)
193 {
194 Console_Task();
195 }
196
197 /** Event handler for the USB_ConfigurationChanged event.
198 * This is fired when the host sets the current configuration of the USB device after enumeration.
199 */
200 void EVENT_USB_Device_ConfigurationChanged(void)
201 {
202 bool ConfigSuccess = true;
203
204 /* Setup Keyboard HID Report Endpoints */
205 ConfigSuccess &= ENDPOINT_CONFIG(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
206 KEYBOARD_EPSIZE, ENDPOINT_BANK_SINGLE);
207
208 #ifdef MOUSE_ENABLE
209 /* Setup Mouse HID Report Endpoint */
210 ConfigSuccess &= ENDPOINT_CONFIG(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
211 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
212 #endif
213
214 #ifdef EXTRAKEY_ENABLE
215 /* Setup Extra HID Report Endpoint */
216 ConfigSuccess &= ENDPOINT_CONFIG(EXTRAKEY_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
217 EXTRAKEY_EPSIZE, ENDPOINT_BANK_SINGLE);
218 #endif
219
220 #ifdef CONSOLE_ENABLE
221 /* Setup Console HID Report Endpoints */
222 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
223 CONSOLE_EPSIZE, ENDPOINT_BANK_DOUBLE);
224 #if 0
225 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
226 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
227 #endif
228 #endif
229
230 #ifdef NKRO_ENABLE
231 /* Setup NKRO HID Report Endpoints */
232 ConfigSuccess &= ENDPOINT_CONFIG(NKRO_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
233 NKRO_EPSIZE, ENDPOINT_BANK_SINGLE);
234 #endif
235 }
236
237 /*
238 Appendix G: HID Request Support Requirements
239
240 The following table enumerates the requests that need to be supported by various types of HID class devices.
241
242 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
243 ------------------------------------------------------------------------------------------
244 Boot Mouse Required Optional Optional Optional Required Required
245 Non-Boot Mouse Required Optional Optional Optional Optional Optional
246 Boot Keyboard Required Optional Required Required Required Required
247 Non-Boot Keybrd Required Optional Required Required Optional Optional
248 Other Device Required Optional Optional Optional Optional Optional
249 */
250 /** Event handler for the USB_ControlRequest event.
251 * This is fired before passing along unhandled control requests to the library for processing internally.
252 */
253 void EVENT_USB_Device_ControlRequest(void)
254 {
255 uint8_t* ReportData = NULL;
256 uint8_t ReportSize = 0;
257
258 /* Handle HID Class specific requests */
259 switch (USB_ControlRequest.bRequest)
260 {
261 case HID_REQ_GetReport:
262 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
263 {
264 Endpoint_ClearSETUP();
265
266 // Interface
267 switch (USB_ControlRequest.wIndex) {
268 case KEYBOARD_INTERFACE:
269 // TODO: test/check
270 ReportData = (uint8_t*)&keyboard_report_sent;
271 ReportSize = sizeof(keyboard_report_sent);
272 break;
273 }
274
275 /* Write the report data to the control endpoint */
276 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
277 Endpoint_ClearOUT();
278 }
279
280 break;
281 case HID_REQ_SetReport:
282 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
283 {
284
285 // Interface
286 switch (USB_ControlRequest.wIndex) {
287 case KEYBOARD_INTERFACE:
288 #ifdef NKRO_ENABLE
289 case NKRO_INTERFACE:
290 #endif
291 Endpoint_ClearSETUP();
292
293 while (!(Endpoint_IsOUTReceived())) {
294 if (USB_DeviceState == DEVICE_STATE_Unattached)
295 return;
296 }
297 keyboard_led_stats = Endpoint_Read_8();
298
299 Endpoint_ClearOUT();
300 Endpoint_ClearStatusStage();
301 break;
302 }
303
304 }
305
306 break;
307
308 case HID_REQ_GetProtocol:
309 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
310 {
311 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
312 Endpoint_ClearSETUP();
313 while (!(Endpoint_IsINReady()));
314 Endpoint_Write_8(keyboard_protocol);
315 Endpoint_ClearIN();
316 Endpoint_ClearStatusStage();
317 }
318 }
319
320 break;
321 case HID_REQ_SetProtocol:
322 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
323 {
324 if (USB_ControlRequest.wIndex == KEYBOARD_INTERFACE) {
325 Endpoint_ClearSETUP();
326 Endpoint_ClearStatusStage();
327
328 keyboard_protocol = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
329 #ifdef NKRO_ENABLE
330 keyboard_nkro = !!keyboard_protocol;
331 #endif
332 clear_keyboard();
333 }
334 }
335
336 break;
337 case HID_REQ_SetIdle:
338 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
339 {
340 Endpoint_ClearSETUP();
341 Endpoint_ClearStatusStage();
342
343 keyboard_idle = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
344 }
345
346 break;
347 case HID_REQ_GetIdle:
348 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
349 {
350 Endpoint_ClearSETUP();
351 while (!(Endpoint_IsINReady()));
352 Endpoint_Write_8(keyboard_idle);
353 Endpoint_ClearIN();
354 Endpoint_ClearStatusStage();
355 }
356
357 break;
358 }
359 }
360
361 /*******************************************************************************
362 * Host driver
363 ******************************************************************************/
364 static uint8_t keyboard_leds(void)
365 {
366 return keyboard_led_stats;
367 }
368
369 static void send_keyboard(report_keyboard_t *report)
370 {
371 uint8_t timeout = 255;
372
373 if (USB_DeviceState != DEVICE_STATE_Configured)
374 return;
375
376 /* Select the Keyboard Report Endpoint */
377 #ifdef NKRO_ENABLE
378 if (keyboard_nkro) {
379 /* Report protocol - NKRO */
380 Endpoint_SelectEndpoint(NKRO_IN_EPNUM);
381
382 /* Check if write ready for a polling interval around 1ms */
383 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(4);
384 if (!Endpoint_IsReadWriteAllowed()) return;
385
386 /* Write Keyboard Report Data */
387 Endpoint_Write_Stream_LE(report, NKRO_EPSIZE, NULL);
388 }
389 else
390 #endif
391 {
392 /* Boot protocol */
393 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
394
395 /* Check if write ready for a polling interval around 10ms */
396 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
397 if (!Endpoint_IsReadWriteAllowed()) return;
398
399 /* Write Keyboard Report Data */
400 Endpoint_Write_Stream_LE(report, KEYBOARD_EPSIZE, NULL);
401 }
402
403 /* Finalize the stream transfer to send the last packet */
404 Endpoint_ClearIN();
405
406 keyboard_report_sent = *report;
407 }
408
409 static void send_mouse(report_mouse_t *report)
410 {
411 #ifdef MOUSE_ENABLE
412 uint8_t timeout = 255;
413
414 if (USB_DeviceState != DEVICE_STATE_Configured)
415 return;
416
417 /* Select the Mouse Report Endpoint */
418 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
419
420 /* Check if write ready for a polling interval around 10ms */
421 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
422 if (!Endpoint_IsReadWriteAllowed()) return;
423
424 /* Write Mouse Report Data */
425 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
426
427 /* Finalize the stream transfer to send the last packet */
428 Endpoint_ClearIN();
429 #endif
430 }
431
432 static void send_system(uint16_t data)
433 {
434 uint8_t timeout = 255;
435
436 if (USB_DeviceState != DEVICE_STATE_Configured)
437 return;
438
439 report_extra_t r = {
440 .report_id = REPORT_ID_SYSTEM,
441 .usage = data
442 };
443 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
444
445 /* Check if write ready for a polling interval around 10ms */
446 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
447 if (!Endpoint_IsReadWriteAllowed()) return;
448
449 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
450 Endpoint_ClearIN();
451 }
452
453 static void send_consumer(uint16_t data)
454 {
455 uint8_t timeout = 255;
456
457 if (USB_DeviceState != DEVICE_STATE_Configured)
458 return;
459
460 report_extra_t r = {
461 .report_id = REPORT_ID_CONSUMER,
462 .usage = data
463 };
464 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
465
466 /* Check if write ready for a polling interval around 10ms */
467 while (timeout-- && !Endpoint_IsReadWriteAllowed()) _delay_us(40);
468 if (!Endpoint_IsReadWriteAllowed()) return;
469
470 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
471 Endpoint_ClearIN();
472 }
473
474
475 /*******************************************************************************
476 * sendchar
477 ******************************************************************************/
478 #ifdef CONSOLE_ENABLE
479 #define SEND_TIMEOUT 5
480 int8_t sendchar(uint8_t c)
481 {
482 // Not wait once timeouted.
483 // Because sendchar() is called so many times, waiting each call causes big lag.
484 static bool timeouted = false;
485
486 if (USB_DeviceState != DEVICE_STATE_Configured)
487 return -1;
488
489 uint8_t ep = Endpoint_GetCurrentEndpoint();
490 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
491 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
492 Endpoint_SelectEndpoint(ep);
493 return -1;
494 }
495
496 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
497 Endpoint_SelectEndpoint(ep);
498 return - 1;
499 }
500
501 timeouted = false;
502
503 uint8_t timeout = SEND_TIMEOUT;
504 uint16_t prevFN = USB_Device_GetFrameNumber();
505 while (!Endpoint_IsReadWriteAllowed()) {
506 switch (USB_DeviceState) {
507 case DEVICE_STATE_Unattached:
508 case DEVICE_STATE_Suspended:
509 return -1;
510 }
511 if (Endpoint_IsStalled()) {
512 Endpoint_SelectEndpoint(ep);
513 return -1;
514 }
515 if (prevFN != USB_Device_GetFrameNumber()) {
516 if (!(timeout--)) {
517 timeouted = true;
518 Endpoint_SelectEndpoint(ep);
519 return -1;
520 }
521 prevFN = USB_Device_GetFrameNumber();
522 }
523 }
524
525 Endpoint_Write_8(c);
526
527 // send when bank is full
528 if (!Endpoint_IsReadWriteAllowed())
529 Endpoint_ClearIN();
530
531 Endpoint_SelectEndpoint(ep);
532 return 0;
533 }
534 #else
535 int8_t sendchar(uint8_t c)
536 {
537 return 0;
538 }
539 #endif
540
541
542 /*******************************************************************************
543 * main
544 ******************************************************************************/
545 static void SetupHardware(void)
546 {
547 /* Disable watchdog if enabled by bootloader/fuses */
548 MCUSR &= ~(1 << WDRF);
549 wdt_disable();
550
551 /* Disable clock division */
552 clock_prescale_set(clock_div_1);
553
554 // Leonardo needs. Without this USB device is not recognized.
555 USB_Disable();
556
557 USB_Init();
558
559 // for Console_Task
560 USB_Device_EnableSOFEvents();
561 print_set_sendchar(sendchar);
562 }
563
564 int main(void) __attribute__ ((weak));
565 int main(void)
566 {
567 SetupHardware();
568 sei();
569
570 /* wait for USB startup & debug output */
571 while (USB_DeviceState != DEVICE_STATE_Configured) {
572 #if defined(INTERRUPT_CONTROL_ENDPOINT)
573 ;
574 #else
575 USB_USBTask();
576 #endif
577 }
578 print("USB configured.\n");
579
580 /* init modules */
581 keyboard_init();
582 host_set_driver(&lufa_driver);
583 #ifdef SLEEP_LED_ENABLE
584 sleep_led_init();
585 #endif
586
587 print("Keyboard start.\n");
588 while (1) {
589 while (USB_DeviceState == DEVICE_STATE_Suspended) {
590 suspend_power_down(WDTO_120MS);
591 if (USB_Device_RemoteWakeupEnabled && suspend_wakeup_condition()) {
592 USB_Device_SendRemoteWakeup();
593 }
594 }
595
596 keyboard_task();
597
598 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
599 USB_USBTask();
600 #endif
601 }
602 }
Imprint / Impressum