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
10 Copyright (C) Dean Camera, 2012.
12 dean [at] fourwalledcubicle [dot] com
17 Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
18 Copyright 2010 Denver Gingerich (denver [at] ossguy [dot] com)
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.
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
39 #include <avr/sleep.h>
43 #include "host_driver.h"
50 #ifdef SLEEP_LED_ENABLE
51 #include "sleep_led.h"
54 #include "descriptor.h"
57 static uint8_t idle_duration = 0;
58 static uint8_t protocol_report = 1;
59 static uint8_t keyboard_led_stats = 0;
61 static report_keyboard_t keyboard_report_sent;
65 static uint8_t keyboard_leds(void);
66 static void send_keyboard(report_keyboard_t *report);
67 static void send_mouse(report_mouse_t *report);
68 static void send_system(uint16_t data);
69 static void send_consumer(uint16_t data);
70 host_driver_t lufa_driver = {
79 /*******************************************************************************
81 ******************************************************************************/
83 static void Console_Task(void)
85 /* Device must be connected and configured for the task to run */
86 if (USB_DeviceState != DEVICE_STATE_Configured)
89 uint8_t ep = Endpoint_GetCurrentEndpoint();
92 // TODO: impl receivechar()/recvchar()
93 Endpoint_SelectEndpoint(CONSOLE_OUT_EPNUM);
95 /* Check to see if a packet has been sent from the host */
96 if (Endpoint_IsOUTReceived())
98 /* Check to see if the packet contains data */
99 if (Endpoint_IsReadWriteAllowed())
101 /* Create a temporary buffer to hold the read in report from the host */
102 uint8_t ConsoleData[CONSOLE_EPSIZE];
104 /* Read Console Report Data */
105 Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
107 /* Process Console Report Data */
108 //ProcessConsoleHIDReport(ConsoleData);
111 /* Finalize the stream transfer to send the last packet */
117 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
118 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
119 Endpoint_SelectEndpoint(ep);
124 while (Endpoint_IsReadWriteAllowed())
127 // flash senchar packet
128 if (Endpoint_IsINReady()) {
132 Endpoint_SelectEndpoint(ep);
135 static void Console_Task(void)
141 /*******************************************************************************
143 ******************************************************************************/
145 * Event Order of Plug in:
146 * 0) EVENT_USB_Device_Connect
147 * 1) EVENT_USB_Device_Suspend
148 * 2) EVENT_USB_Device_Reset
149 * 3) EVENT_USB_Device_Wake
151 void EVENT_USB_Device_Connect(void)
153 led_set(0x1f); // all on
156 void EVENT_USB_Device_Disconnect(void)
160 void EVENT_USB_Device_Reset(void)
164 void EVENT_USB_Device_Suspend()
166 #ifdef SLEEP_LED_ENABLE
171 void EVENT_USB_Device_WakeUp()
177 #ifdef SLEEP_LED_ENABLE
180 led_set(host_keyboard_leds());
183 void EVENT_USB_Device_StartOfFrame(void)
188 /** Event handler for the USB_ConfigurationChanged event.
189 * This is fired when the host sets the current configuration of the USB device after enumeration.
191 #if LUFA_VERSION_INTEGER < 0x120730
193 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint(epnum, eptype, epdir, epsize, epbank)
195 /* new API >= 120730 */
196 #define ENDPOINT_BANK_SINGLE 1
197 #define ENDPOINT_BANK_DOUBLE 2
198 #define ENDPOINT_CONFIG(epnum, eptype, epdir, epsize, epbank) Endpoint_ConfigureEndpoint((epdir) | (epnum) , eptype, epsize, epbank)
200 void EVENT_USB_Device_ConfigurationChanged(void)
202 bool ConfigSuccess = true;
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);
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);
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);
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 ConfigSuccess &= ENDPOINT_CONFIG(CONSOLE_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
225 CONSOLE_EPSIZE, ENDPOINT_BANK_SINGLE);
230 Appendix G: HID Request Support Requirements
232 The following table enumerates the requests that need to be supported by various types of HID class devices.
234 Device type GetReport SetReport GetIdle SetIdle GetProtocol SetProtocol
235 ------------------------------------------------------------------------------------------
236 Boot Mouse Required Optional Optional Optional Required Required
237 Non-Boot Mouse Required Optional Optional Optional Optional Optional
238 Boot Keyboard Required Optional Required Required Required Required
239 Non-Boot Keybrd Required Optional Required Required Optional Optional
240 Other Device Required Optional Optional Optional Optional Optional
242 /** Event handler for the USB_ControlRequest event.
243 * This is fired before passing along unhandled control requests to the library for processing internally.
245 void EVENT_USB_Device_ControlRequest(void)
247 uint8_t* ReportData = NULL;
248 uint8_t ReportSize = 0;
250 /* Handle HID Class specific requests */
251 switch (USB_ControlRequest.bRequest)
253 case HID_REQ_GetReport:
254 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
256 Endpoint_ClearSETUP();
259 switch (USB_ControlRequest.wIndex) {
260 case KEYBOARD_INTERFACE:
262 ReportData = (uint8_t*)&keyboard_report_sent;
263 ReportSize = sizeof(keyboard_report_sent);
267 /* Write the report data to the control endpoint */
268 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
273 case HID_REQ_SetReport:
274 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
278 switch (USB_ControlRequest.wIndex) {
279 case KEYBOARD_INTERFACE:
280 Endpoint_ClearSETUP();
282 while (!(Endpoint_IsOUTReceived())) {
283 if (USB_DeviceState == DEVICE_STATE_Unattached)
286 keyboard_led_stats = Endpoint_Read_8();
289 Endpoint_ClearStatusStage();
297 case HID_REQ_GetProtocol:
298 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
300 Endpoint_ClearSETUP();
301 while (!(Endpoint_IsINReady()));
302 Endpoint_Write_8(protocol_report);
304 Endpoint_ClearStatusStage();
308 case HID_REQ_SetProtocol:
309 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
311 Endpoint_ClearSETUP();
312 Endpoint_ClearStatusStage();
314 protocol_report = ((USB_ControlRequest.wValue & 0xFF) != 0x00);
318 case HID_REQ_SetIdle:
319 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
321 Endpoint_ClearSETUP();
322 Endpoint_ClearStatusStage();
324 idle_duration = ((USB_ControlRequest.wValue & 0xFF00) >> 8);
328 case HID_REQ_GetIdle:
329 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
331 Endpoint_ClearSETUP();
332 while (!(Endpoint_IsINReady()));
333 Endpoint_Write_8(idle_duration);
335 Endpoint_ClearStatusStage();
342 /*******************************************************************************
344 ******************************************************************************/
345 static uint8_t keyboard_leds(void)
347 return keyboard_led_stats;
350 static void send_keyboard(report_keyboard_t *report)
354 // TODO: handle NKRO report
355 /* Select the Keyboard Report Endpoint */
356 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
358 /* Check if Keyboard Endpoint Ready for Read/Write */
359 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
361 /* Write Keyboard Report Data */
362 Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
364 /* Finalize the stream transfer to send the last packet */
367 keyboard_report_sent = *report;
370 static void send_mouse(report_mouse_t *report)
375 /* Select the Mouse Report Endpoint */
376 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
378 /* Check if Mouse Endpoint Ready for Read/Write */
379 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
381 /* Write Mouse Report Data */
382 Endpoint_Write_Stream_LE(report, sizeof(report_mouse_t), NULL);
384 /* Finalize the stream transfer to send the last packet */
389 static void send_system(uint16_t data)
394 .report_id = REPORT_ID_SYSTEM,
397 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
398 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
399 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
403 static void send_consumer(uint16_t data)
408 .report_id = REPORT_ID_CONSUMER,
411 Endpoint_SelectEndpoint(EXTRAKEY_IN_EPNUM);
412 while (--timeout && !Endpoint_IsReadWriteAllowed()) ;
413 Endpoint_Write_Stream_LE(&r, sizeof(report_extra_t), NULL);
418 /*******************************************************************************
420 ******************************************************************************/
421 #ifdef CONSOLE_ENABLE
422 #define SEND_TIMEOUT 5
423 int8_t sendchar(uint8_t c)
425 // Not wait once timeouted.
426 // Because sendchar() is called so many times, waiting each call causes big lag.
427 static bool timeouted = false;
429 if (USB_DeviceState != DEVICE_STATE_Configured)
432 uint8_t ep = Endpoint_GetCurrentEndpoint();
433 Endpoint_SelectEndpoint(CONSOLE_IN_EPNUM);
434 if (!Endpoint_IsEnabled() || !Endpoint_IsConfigured()) {
435 Endpoint_SelectEndpoint(ep);
439 if (timeouted && !Endpoint_IsReadWriteAllowed()) {
440 Endpoint_SelectEndpoint(ep);
446 uint8_t timeout = SEND_TIMEOUT;
447 uint16_t prevFN = USB_Device_GetFrameNumber();
448 while (!Endpoint_IsReadWriteAllowed()) {
449 switch (USB_DeviceState) {
450 case DEVICE_STATE_Unattached:
451 case DEVICE_STATE_Suspended:
454 if (Endpoint_IsStalled()) {
455 Endpoint_SelectEndpoint(ep);
458 if (prevFN != USB_Device_GetFrameNumber()) {
461 Endpoint_SelectEndpoint(ep);
464 prevFN = USB_Device_GetFrameNumber();
470 // send when bank is full
471 if (!Endpoint_IsReadWriteAllowed())
474 Endpoint_SelectEndpoint(ep);
478 int8_t sendchar(uint8_t c)
485 /*******************************************************************************
487 ******************************************************************************/
488 static void SetupHardware(void)
490 /* Disable watchdog if enabled by bootloader/fuses */
491 MCUSR &= ~(1 << WDRF);
494 /* Disable clock division */
495 clock_prescale_set(clock_div_1);
497 // Leonardo needs. Without this USB device is not recognized.
503 USB_Device_EnableSOFEvents();
507 static bool wakeup_condition(void)
510 for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
511 if (matrix_get_row(r)) return true;
516 #define wdt_intr_enable(value) \
517 __asm__ __volatile__ ( \
518 "in __tmp_reg__,__SREG__" "\n\t" \
522 "out __SREG__,__tmp_reg__" "\n\t" \
525 : "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
526 "r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
527 "r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | \
528 _BV(WDIE) | (value & 0x07)) ) \
532 int main(void) __attribute__ ((weak));
537 host_set_driver(&lufa_driver);
538 #ifdef SLEEP_LED_ENABLE
545 while (USB_DeviceState == DEVICE_STATE_Suspended) {
546 #ifndef NO_SUSPEND_POWER_DOWN
547 // Enable watchdog to wake from MCU sleep
551 // Watchdog Interrupt and System Reset Mode
552 //wdt_enable(WDTO_1S);
553 //WDTCSR |= _BV(WDIE);
555 // Watchdog Interrupt Mode
556 wdt_intr_enable(WDTO_120MS);
558 // TODO: more power saving
559 // See PicoPower application note
560 // - I/O port input with pullup
563 // - Power Reduction Register PRR
564 // sleep in power down mode
565 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
571 // Disable watchdog after sleep
575 // Send request of USB Wakeup from Suspend to host
576 if (USB_Device_RemoteWakeupEnabled) {
577 if (wakeup_condition()) {
578 USB_Device_SendRemoteWakeup();
585 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
591 #ifndef NO_SUSPEND_POWER_DOWN
592 /* watchdog timeout */
595 /* wakeup from MCU sleep mode */
598 static uint8_t led_state = 0;
599 static uint8_t led_count = 0;
601 if ((led_count & 0x07) == 0) {
602 led_set((led_state ^= (1<<USB_LED_CAPS_LOCK)));