Rename Drivers/AT90USBXXX to Drivers/Peripheral.
[pub/USBasp.git] / Demos / Device / KeyboardMouse / KeyboardMouse.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11 Copyright 2009 Denver Gingerich (denver [at] ossguy [dot] com)
12
13 Permission to use, copy, modify, and distribute this software
14 and its documentation for any purpose and without fee is hereby
15 granted, provided that the above copyright notice appear in all
16 copies and that both that the copyright notice and this
17 permission notice and warranty disclaimer appear in supporting
18 documentation, and that the name of the author not be used in
19 advertising or publicity pertaining to distribution of the
20 software without specific, written prior permission.
21
22 The author disclaim all warranties with regard to this
23 software, including all implied warranties of merchantability
24 and fitness. In no event shall the author be liable for any
25 special, indirect or consequential damages or any damages
26 whatsoever resulting from loss of use, data or profits, whether
27 in an action of contract, negligence or other tortious action,
28 arising out of or in connection with the use or performance of
29 this software.
30 */
31
32 /** \file
33 *
34 * Main source file for the KeyboardMouse demo. This file contains the main tasks of the demo and
35 * is responsible for the initial application hardware configuration.
36 */
37
38 #include "KeyboardMouse.h"
39
40 /* Scheduler Task List */
41 TASK_LIST
42 {
43 { Task: USB_USBTask , TaskStatus: TASK_STOP },
44 { Task: USB_Mouse , TaskStatus: TASK_RUN },
45 { Task: USB_Keyboard , TaskStatus: TASK_RUN },
46 };
47
48 /* Global Variables */
49 /** Global structure to hold the current keyboard interface HID report, for transmission to the host */
50 USB_KeyboardReport_Data_t KeyboardReportData;
51
52 /** Global structure to hold the current mouse interface HID report, for transmission to the host */
53 USB_MouseReport_Data_t MouseReportData;
54
55 /** Main program entry point. This routine configures the hardware required by the application, then
56 * starts the scheduler to run the USB management task.
57 */
58 int main(void)
59 {
60 /* Disable watchdog if enabled by bootloader/fuses */
61 MCUSR &= ~(1 << WDRF);
62 wdt_disable();
63
64 /* Disable clock division */
65 clock_prescale_set(clock_div_1);
66
67 /* Hardware Initialization */
68 Joystick_Init();
69 LEDs_Init();
70
71 /* Indicate USB not ready */
72 UpdateStatus(Status_USBNotReady);
73
74 /* Initialize Scheduler so that it can be used */
75 Scheduler_Init();
76
77 /* Initialize USB Subsystem */
78 USB_Init();
79
80 /* Scheduling - routine never returns, so put this last in the main function */
81 Scheduler_Start();
82 }
83
84 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
85 * starts the library USB task to begin the enumeration and USB management process.
86 */
87 EVENT_HANDLER(USB_Connect)
88 {
89 /* Start USB management task */
90 Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
91
92 /* Indicate USB enumerating */
93 UpdateStatus(Status_USBEnumerating);
94 }
95
96 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
97 * the status LEDs and stops the USB management task.
98 */
99 EVENT_HANDLER(USB_Disconnect)
100 {
101 /* Stop running HID reporting and USB management tasks */
102 Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
103
104 /* Indicate USB not ready */
105 UpdateStatus(Status_USBNotReady);
106 }
107
108 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
109 * of the USB device after enumeration, and configures the keyboard and mouse device endpoints.
110 */
111 EVENT_HANDLER(USB_ConfigurationChanged)
112 {
113 /* Setup Keyboard Report Endpoint */
114 Endpoint_ConfigureEndpoint(KEYBOARD_IN_EPNUM, EP_TYPE_INTERRUPT,
115 ENDPOINT_DIR_IN, HID_EPSIZE,
116 ENDPOINT_BANK_SINGLE);
117
118 /* Setup Keyboard LED Report Endpoint */
119 Endpoint_ConfigureEndpoint(KEYBOARD_OUT_EPNUM, EP_TYPE_INTERRUPT,
120 ENDPOINT_DIR_OUT, HID_EPSIZE,
121 ENDPOINT_BANK_SINGLE);
122
123 /* Setup Mouse Report Endpoint */
124 Endpoint_ConfigureEndpoint(MOUSE_IN_EPNUM, EP_TYPE_INTERRUPT,
125 ENDPOINT_DIR_IN, HID_EPSIZE,
126 ENDPOINT_BANK_SINGLE);
127
128 /* Indicate USB connected and ready */
129 UpdateStatus(Status_USBReady);
130 }
131
132 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
133 * control requests that are not handled internally by the USB library (including the HID commands, which are
134 * all issued via the control endpoint), so that they can be handled appropriately for the application.
135 */
136 EVENT_HANDLER(USB_UnhandledControlPacket)
137 {
138 uint8_t* ReportData;
139 uint8_t ReportSize;
140
141 /* Handle HID Class specific requests */
142 switch (bRequest)
143 {
144 case REQ_GetReport:
145 if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
146 {
147 Endpoint_Discard_Word();
148
149 uint16_t wIndex = Endpoint_Read_Word_LE();
150
151 /* Determine if it is the mouse or the keyboard data that is being requested */
152 if (!(wIndex))
153 {
154 ReportData = (uint8_t*)&KeyboardReportData;
155 ReportSize = sizeof(KeyboardReportData);
156 }
157 else
158 {
159 ReportData = (uint8_t*)&MouseReportData;
160 ReportSize = sizeof(MouseReportData);
161 }
162
163 /* Read in the number of bytes in the report to send to the host */
164 uint16_t wLength = Endpoint_Read_Word_LE();
165
166 /* If trying to send more bytes than exist to the host, clamp the value at the report size */
167 if (wLength > ReportSize)
168 wLength = ReportSize;
169
170 Endpoint_ClearControlSETUP();
171
172 /* Write the report data to the control endpoint */
173 Endpoint_Write_Control_Stream_LE(ReportData, wLength);
174
175 /* Clear the report data afterwards */
176 memset(ReportData, 0, ReportSize);
177
178 /* Finalize the stream transfer to send the last packet or clear the host abort */
179 Endpoint_ClearControlOUT();
180 }
181
182 break;
183 case REQ_SetReport:
184 if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
185 {
186 Endpoint_ClearControlSETUP();
187
188 /* Wait until the LED report has been sent by the host */
189 while (!(Endpoint_IsOUTReceived()));
190
191 /* Read in the LED report from the host */
192 uint8_t LEDStatus = Endpoint_Read_Byte();
193 uint8_t LEDMask = LEDS_LED2;
194
195 if (LEDStatus & 0x01) // NUM Lock
196 LEDMask |= LEDS_LED1;
197
198 if (LEDStatus & 0x02) // CAPS Lock
199 LEDMask |= LEDS_LED3;
200
201 if (LEDStatus & 0x04) // SCROLL Lock
202 LEDMask |= LEDS_LED4;
203
204 /* Set the status LEDs to the current HID LED status */
205 LEDs_SetAllLEDs(LEDMask);
206
207 /* Clear the endpoint data */
208 Endpoint_ClearControlOUT();
209
210 /* Acknowledge status stage */
211 while (!(Endpoint_IsINReady()));
212 Endpoint_ClearControlIN();
213 }
214
215 break;
216 }
217 }
218
219 /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
220 * log to a serial port, or anything else that is suitable for status updates.
221 *
222 * \param CurrentStatus Current status of the system, from the KeyboardMouse_StatusCodes_t enum
223 */
224 void UpdateStatus(uint8_t CurrentStatus)
225 {
226 uint8_t LEDMask = LEDS_NO_LEDS;
227
228 /* Set the LED mask to the appropriate LED mask based on the given status code */
229 switch (CurrentStatus)
230 {
231 case Status_USBNotReady:
232 LEDMask = (LEDS_LED1);
233 break;
234 case Status_USBEnumerating:
235 LEDMask = (LEDS_LED1 | LEDS_LED2);
236 break;
237 case Status_USBReady:
238 LEDMask = (LEDS_LED2 | LEDS_LED4);
239 break;
240 }
241
242 /* Set the board LEDs to the new LED mask */
243 LEDs_SetAllLEDs(LEDMask);
244 }
245
246 /** Keyboard task. This generates the next keyboard HID report for the host, and transmits it via the
247 * keyboard IN endpoint when the host is ready for more data. Additionally, it processes host LED status
248 * reports sent to the device via the keyboard OUT reporting endpoint.
249 */
250 TASK(USB_Keyboard)
251 {
252 uint8_t JoyStatus_LCL = Joystick_GetStatus();
253
254 /* Check if HWB is not pressed, if so mouse mode enabled */
255 if (!(HWB_GetStatus()))
256 {
257 if (JoyStatus_LCL & JOY_UP)
258 KeyboardReportData.KeyCode[0] = 0x04; // A
259 else if (JoyStatus_LCL & JOY_DOWN)
260 KeyboardReportData.KeyCode[0] = 0x05; // B
261
262 if (JoyStatus_LCL & JOY_LEFT)
263 KeyboardReportData.KeyCode[0] = 0x06; // C
264 else if (JoyStatus_LCL & JOY_RIGHT)
265 KeyboardReportData.KeyCode[0] = 0x07; // D
266
267 if (JoyStatus_LCL & JOY_PRESS)
268 KeyboardReportData.KeyCode[0] = 0x08; // E
269 }
270
271 /* Check if the USB system is connected to a host and report protocol mode is enabled */
272 if (USB_IsConnected)
273 {
274 /* Select the Keyboard Report Endpoint */
275 Endpoint_SelectEndpoint(KEYBOARD_IN_EPNUM);
276
277 /* Check if Keyboard Endpoint Ready for Read/Write */
278 if (Endpoint_IsReadWriteAllowed())
279 {
280 /* Write Keyboard Report Data */
281 Endpoint_Write_Stream_LE(&KeyboardReportData, sizeof(KeyboardReportData));
282
283 /* Finalize the stream transfer to send the last packet */
284 Endpoint_ClearIN();
285
286 /* Clear the report data afterwards */
287 memset(&KeyboardReportData, 0, sizeof(KeyboardReportData));
288 }
289
290 /* Select the Keyboard LED Report Endpoint */
291 Endpoint_SelectEndpoint(KEYBOARD_OUT_EPNUM);
292
293 /* Check if Keyboard LED Endpoint Ready for Read/Write */
294 if (Endpoint_IsReadWriteAllowed())
295 {
296 /* Read in the LED report from the host */
297 uint8_t LEDStatus = Endpoint_Read_Byte();
298 uint8_t LEDMask = LEDS_LED2;
299
300 if (LEDStatus & 0x01) // NUM Lock
301 LEDMask |= LEDS_LED1;
302
303 if (LEDStatus & 0x02) // CAPS Lock
304 LEDMask |= LEDS_LED3;
305
306 if (LEDStatus & 0x04) // SCROLL Lock
307 LEDMask |= LEDS_LED4;
308
309 /* Set the status LEDs to the current Keyboard LED status */
310 LEDs_SetAllLEDs(LEDMask);
311
312 /* Handshake the OUT Endpoint - clear endpoint and ready for next report */
313 Endpoint_ClearOUT();
314 }
315 }
316 }
317
318 /** Mouse task. This generates the next mouse HID report for the host, and transmits it via the
319 * mouse IN endpoint when the host is ready for more data.
320 */
321 TASK(USB_Mouse)
322 {
323 uint8_t JoyStatus_LCL = Joystick_GetStatus();
324
325 /* Check if HWB is pressed, if so mouse mode enabled */
326 if (HWB_GetStatus())
327 {
328 if (JoyStatus_LCL & JOY_UP)
329 MouseReportData.Y = 1;
330 else if (JoyStatus_LCL & JOY_DOWN)
331 MouseReportData.Y = -1;
332
333 if (JoyStatus_LCL & JOY_RIGHT)
334 MouseReportData.X = 1;
335 else if (JoyStatus_LCL & JOY_LEFT)
336 MouseReportData.X = -1;
337
338 if (JoyStatus_LCL & JOY_PRESS)
339 MouseReportData.Button = (1 << 0);
340 }
341
342 /* Check if the USB system is connected to a host and report protocol mode is enabled */
343 if (USB_IsConnected)
344 {
345 /* Select the Mouse Report Endpoint */
346 Endpoint_SelectEndpoint(MOUSE_IN_EPNUM);
347
348 /* Check if Mouse Endpoint Ready for Read/Write */
349 if (Endpoint_IsReadWriteAllowed())
350 {
351 /* Write Mouse Report Data */
352 Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));
353
354 /* Finalize the stream transfer to send the last packet */
355 Endpoint_ClearIN();
356
357 /* Clear the report data afterwards */
358 memset(&MouseReportData, 0, sizeof(MouseReportData));
359 }
360 }
361 }