]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/lufa/lufa.c
Add LUFA mouse feature and fix mouse report.
[tmk_firmware.git] / keyboard / 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 "sendchar.h"
44 #include "debug.h"
45
46 #include "descriptor.h"
47 #include "lufa.h"
48
49 static uint8_t keyboard_led_stats = 0;
50
51 // TODO: impl Control Request GET_REPORT
52 static report_keyboard_t keyboard_report_sent;
53 static report_mouse_t mouse_report_sent;
54
55 /* Host driver */
56 static uint8_t keyboard_leds(void);
57 static void send_keyboard(report_keyboard_t *report);
58 static void send_mouse(report_mouse_t *report);
59 static void send_system(uint16_t data);
60 static void send_consumer(uint16_t data);
61 static host_driver_t lufa_driver = {
62     keyboard_leds,
63     send_keyboard,
64     send_mouse,
65     send_system,
66     send_consumer
67 };
68
69
70 static void SetupHardware(void);
71 static void Console_HID_Task(void);
72
73 int main(void)
74 {
75     SetupHardware();
76     sei();
77
78     print_enable = true;
79     debug_enable = true;
80     debug_matrix = true;
81     debug_keyboard = true;
82     debug_mouse = true;
83
84 /* TODO: can't print here
85     _delay_ms(5000);
86     USB_USBTask();
87     print("abcdefg\n");
88     USB_USBTask();
89 */
90
91     keyboard_init();
92     host_set_driver(&lufa_driver);
93     while (1) {
94         keyboard_proc();
95
96         Console_HID_Task();
97         USB_USBTask();
98     }
99 }
100
101 void SetupHardware(void)
102 {
103     /* Disable watchdog if enabled by bootloader/fuses */
104     MCUSR &= ~(1 << WDRF);
105     wdt_disable();
106
107     /* Disable clock division */
108     clock_prescale_set(clock_div_1);
109
110     USB_Init();
111 }
112
113 static void Console_HID_Task(void)
114 {
115         /* Device must be connected and configured for the task to run */
116         if (USB_DeviceState != DEVICE_STATE_Configured)
117           return;
118
119         // TODO: impl receivechar()/recvchar()
120         Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM);
121
122         /* Check to see if a packet has been sent from the host */
123         if (Endpoint_IsOUTReceived())
124         {
125                 /* Check to see if the packet contains data */
126                 if (Endpoint_IsReadWriteAllowed())
127                 {
128                         /* Create a temporary buffer to hold the read in report from the host */
129                         uint8_t ConsoleData[GENERIC_REPORT_SIZE];
130
131                         /* Read Console Report Data */
132                         Endpoint_Read_Stream_LE(&ConsoleData, sizeof(ConsoleData), NULL);
133
134                         /* Process Console Report Data */
135                         //ProcessConsoleHIDReport(ConsoleData);
136                 }
137
138                 /* Finalize the stream transfer to send the last packet */
139                 Endpoint_ClearOUT();
140         }
141
142         /* IN packet */
143         Endpoint_SelectEndpoint(GENERIC_IN_EPNUM);
144         // send IN packet
145         if (Endpoint_IsINReady())
146             Endpoint_ClearIN();
147 }
148
149
150 /*******************************************************************************
151  * USB Events
152  ******************************************************************************/
153 /** Event handler for the USB_Connect event. */
154 void EVENT_USB_Device_Connect(void)
155 {
156 }
157
158 /** Event handler for the USB_Disconnect event. */
159 void EVENT_USB_Device_Disconnect(void)
160 {
161 }
162
163 /** Event handler for the USB_ConfigurationChanged event.
164  * This is fired when the host sets the current configuration of the USB device after enumeration.
165  */
166 void EVENT_USB_Device_ConfigurationChanged(void)
167 {
168     bool ConfigSuccess = true;
169
170     /* Setup Keyboard HID Report Endpoints */
171     ConfigSuccess &= Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
172                                                 HID_EPSIZE, ENDPOINT_BANK_SINGLE);
173
174     /* Setup Mouse HID Report Endpoint */
175     ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
176                                                 HID_EPSIZE, ENDPOINT_BANK_SINGLE);
177
178     /* Setup Console HID Report Endpoints */
179     ConfigSuccess &= Endpoint_ConfigureEndpoint(GENERIC_IN_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
180                                                 GENERIC_EPSIZE, ENDPOINT_BANK_SINGLE);
181     ConfigSuccess &= Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_OUT,
182                                                 GENERIC_EPSIZE, ENDPOINT_BANK_SINGLE);
183 }
184
185 /*
186 Appendix G: HID Request Support Requirements
187
188 The following table enumerates the requests that need to be supported by various types of HID class devices.
189
190 Device type     GetReport   SetReport   GetIdle     SetIdle     GetProtocol SetProtocol
191 ------------------------------------------------------------------------------------------
192 Boot Mouse      Required    Optional    Optional    Optional    Required    Required
193 Non-Boot Mouse  Required    Optional    Optional    Optional    Optional    Optional
194 Boot Keyboard   Required    Optional    Required    Required    Required    Required
195 Non-Boot Keybrd Required    Optional    Required    Required    Optional    Optional
196 Other Device    Required    Optional    Optional    Optional    Optional    Optional
197 */
198 /** Event handler for the USB_ControlRequest event.
199  *  This is fired before passing along unhandled control requests to the library for processing internally.
200  */
201 void EVENT_USB_Device_ControlRequest(void)
202 {
203     uint8_t* ReportData = NULL;
204     uint8_t  ReportSize = 0;
205
206     /* Handle HID Class specific requests */
207     switch (USB_ControlRequest.bRequest)
208     {
209         case HID_REQ_GetReport:
210             if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
211             {
212                 Endpoint_ClearSETUP();
213
214                 // Interface
215                 switch (USB_ControlRequest.wIndex) {
216                 case KEYBOARD_INTERFACE:
217                     // TODO: test/check
218                     ReportData = (uint8_t*)&keyboard_report_sent;
219                     ReportSize = sizeof(keyboard_report_sent);
220                     break;
221                 case MOUSE_INTERFACE:
222                     // TODO: test/check
223                     ReportData = (uint8_t*)&mouse_report_sent;
224                     ReportSize = sizeof(mouse_report_sent);
225                     break;
226                 case GENERIC_INTERFACE:
227                     break;
228                 }
229
230                 /* Write the report data to the control endpoint */
231                 Endpoint_Write_Control_Stream_LE(ReportData, ReportSize);
232                 Endpoint_ClearOUT();
233             }
234
235             break;
236         case HID_REQ_SetReport:
237             if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
238             {
239                 Endpoint_ClearSETUP();
240
241                 /* Wait until the LED report has been sent by the host */
242                 while (!(Endpoint_IsOUTReceived()))
243                 {
244                     if (USB_DeviceState == DEVICE_STATE_Unattached)
245                       return;
246                 }
247
248                 // Interface
249                 switch (USB_ControlRequest.wIndex) {
250                 case KEYBOARD_INTERFACE:
251                     // TODO: test/check
252                     /* Read in the LED report from the host */
253                     keyboard_led_stats = Endpoint_Read_8();
254                     break;
255                 case MOUSE_INTERFACE:
256                     break;
257                 case GENERIC_INTERFACE:
258                     break;
259                 }
260
261                 Endpoint_ClearOUT();
262                 Endpoint_ClearStatusStage();
263             }
264
265             break;
266     }
267 }
268
269 /*******************************************************************************
270  * Host driver 
271  ******************************************************************************/
272 static uint8_t keyboard_leds(void)
273 {
274     return keyboard_led_stats;
275 }
276
277 static void send_keyboard(report_keyboard_t *report)
278 {
279     // TODO: handle NKRO report
280     /* Select the Keyboard Report Endpoint */
281     Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
282
283     /* Check if Keyboard Endpoint Ready for Read/Write */
284     if (Endpoint_IsReadWriteAllowed())
285     {
286         /* Write Keyboard Report Data */
287         Endpoint_Write_Stream_LE(report, sizeof(report_keyboard_t), NULL);
288
289         /* Finalize the stream transfer to send the last packet */
290         Endpoint_ClearIN();
291     }
292     keyboard_report_sent = *report;
293 }
294
295 static void send_mouse(report_mouse_t *report)
296 {
297     /* Select the Mouse Report Endpoint */
298     Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
299
300     /* Check if Mouse Endpoint Ready for Read/Write */
301     if (Endpoint_IsReadWriteAllowed())
302     {
303         /* Write Mouse Report Data */
304         /* Mouse report data structure
305          * LUFA: { buttons, x, y }
306          * tmk:  { buttons, x, y, v, h }
307          */
308         //Endpoint_Write_Stream_LE((uint8_t *)report+1, 3, NULL);
309         Endpoint_Write_Stream_LE(report, 3, NULL);
310
311         /* Finalize the stream transfer to send the last packet */
312         Endpoint_ClearIN();
313     }
314     mouse_report_sent = *report;
315 }
316
317 static void send_system(uint16_t data)
318 {
319 }
320
321 static void send_consumer(uint16_t data)
322 {
323 }
324
325
326 /*******************************************************************************
327  * sendchar
328  ******************************************************************************/
329 int8_t sendchar(uint8_t c)
330 {
331     if (USB_DeviceState != DEVICE_STATE_Configured)
332       return -1;
333
334     Endpoint_SelectEndpoint(GENERIC_IN_EPNUM);
335
336     uint8_t timeout = 10;
337     uint16_t prevFN = USB_Device_GetFrameNumber();
338     while (!Endpoint_IsINReady()) {
339         switch (USB_DeviceState) {
340         case DEVICE_STATE_Unattached:
341         case DEVICE_STATE_Suspended:
342             return -1;
343         }
344         if (Endpoint_IsStalled())
345             return -1;
346         if (prevFN != USB_Device_GetFrameNumber()) {
347             if (!(timeout--))
348                 return -1;
349             prevFN = USB_Device_GetFrameNumber();
350         }
351     }
352
353     Endpoint_Write_8(c);
354
355     // send when packet is full
356     if (!Endpoint_IsReadWriteAllowed())
357         Endpoint_ClearIN();
358
359     return 0;
360 }