All comments in the library, bootloaders, demos and projects have now been spell...
[pub/USBasp.git] / Demos / Device / GenericHID / GenericHID.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
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * Main source file for the GenericHID demo. This file contains the main tasks of the demo and
34 * is responsible for the initial application hardware configuration.
35 */
36
37 #include "GenericHID.h"
38
39 /* Project Tags, for reading out using the ButtLoad project */
40 BUTTLOADTAG(ProjName, "LUFA GenHID App");
41 BUTTLOADTAG(BuildTime, __TIME__);
42 BUTTLOADTAG(BuildDate, __DATE__);
43 BUTTLOADTAG(LUFAVersion, "LUFA V" LUFA_VERSION_STRING);
44
45 /* Scheduler Task List */
46 TASK_LIST
47 {
48 #if !defined(INTERRUPT_CONTROL_ENDPOINT)
49 { Task: USB_USBTask , TaskStatus: TASK_STOP },
50 #endif
51
52 #if !defined(INTERRUPT_DATA_ENDPOINT)
53 { Task: USB_HID_Report , TaskStatus: TASK_STOP },
54 #endif
55 };
56
57 /** Static buffer to hold the last received report from the host, so that it can be echoed back in the next sent report */
58 static uint8_t LastReceived[GENERIC_REPORT_SIZE];
59
60
61 /** Main program entry point. This routine configures the hardware required by the application, then
62 * starts the scheduler to run the USB management task.
63 */
64 int main(void)
65 {
66 /* Disable watchdog if enabled by bootloader/fuses */
67 MCUSR &= ~(1 << WDRF);
68 wdt_disable();
69
70 /* Disable clock division */
71 clock_prescale_set(clock_div_1);
72
73 /* Indicate USB not ready */
74 UpdateStatus(Status_USBNotReady);
75
76 /* Initialize Scheduler so that it can be used */
77 Scheduler_Init();
78
79 /* Initialize USB Subsystem */
80 USB_Init();
81
82 /* Scheduling - routine never returns, so put this last in the main function */
83 Scheduler_Start();
84 }
85
86 /** Event handler for the USB_Reset event. This fires when the USB interface is reset by the USB host, before the
87 * enumeration process begins, and enables the control endpoint interrupt so that control requests can be handled
88 * asynchronously when they arrive rather than when the control endpoint is polled manually.
89 */
90 EVENT_HANDLER(USB_Reset)
91 {
92 #if defined(INTERRUPT_CONTROL_ENDPOINT)
93 /* Select the control endpoint */
94 Endpoint_SelectEndpoint(ENDPOINT_CONTROLEP);
95
96 /* Enable the endpoint SETUP interrupt ISR for the control endpoint */
97 USB_INT_Enable(ENDPOINT_INT_SETUP);
98 #endif
99 }
100
101 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
102 * starts the library USB task to begin the enumeration and USB management process.
103 */
104 EVENT_HANDLER(USB_Connect)
105 {
106 /* Indicate USB enumerating */
107 UpdateStatus(Status_USBEnumerating);
108 }
109
110 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
111 * the status LEDs and stops the USB management task.
112 */
113 EVENT_HANDLER(USB_Disconnect)
114 {
115 /* Indicate USB not ready */
116 UpdateStatus(Status_USBNotReady);
117 }
118
119 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
120 * of the USB device after enumeration, and configures the generic HID device endpoints.
121 */
122 EVENT_HANDLER(USB_ConfigurationChanged)
123 {
124 /* Setup Generic IN Report Endpoint */
125 Endpoint_ConfigureEndpoint(GENERIC_IN_EPNUM, EP_TYPE_INTERRUPT,
126 ENDPOINT_DIR_IN, GENERIC_EPSIZE,
127 ENDPOINT_BANK_SINGLE);
128
129 #if defined(INTERRUPT_DATA_ENDPOINT)
130 /* Enable the endpoint IN interrupt ISR for the report endpoint */
131 USB_INT_Enable(ENDPOINT_INT_IN);
132 #endif
133
134 /* Setup Generic OUT Report Endpoint */
135 Endpoint_ConfigureEndpoint(GENERIC_OUT_EPNUM, EP_TYPE_INTERRUPT,
136 ENDPOINT_DIR_OUT, GENERIC_EPSIZE,
137 ENDPOINT_BANK_SINGLE);
138
139 #if defined(INTERRUPT_DATA_ENDPOINT)
140 /* Enable the endpoint OUT interrupt ISR for the report endpoint */
141 USB_INT_Enable(ENDPOINT_INT_OUT);
142 #endif
143
144 /* Indicate USB connected and ready */
145 UpdateStatus(Status_USBReady);
146 }
147
148 /** Event handler for the USB_UnhandledControlPacket event. This is used to catch standard and class specific
149 * control requests that are not handled internally by the USB library (including the HID commands, which are
150 * all issued via the control endpoint), so that they can be handled appropriately for the application.
151 */
152 EVENT_HANDLER(USB_UnhandledControlPacket)
153 {
154 /* Handle HID Class specific requests */
155 switch (bRequest)
156 {
157 case REQ_GetReport:
158 if (bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
159 {
160 Endpoint_ClearSetupReceived();
161
162 uint8_t GenericData[GENERIC_REPORT_SIZE];
163
164 CreateGenericHIDReport(GenericData);
165
166 /* Write the report data to the control endpoint */
167 Endpoint_Write_Control_Stream_LE(&GenericData, sizeof(GenericData));
168
169 /* Finalize the stream transfer to send the last packet or clear the host abort */
170 Endpoint_ClearSetupOUT();
171 }
172
173 break;
174 case REQ_SetReport:
175 if (bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
176 {
177 Endpoint_ClearSetupReceived();
178
179 /* Wait until the generic report has been sent by the host */
180 while (!(Endpoint_IsSetupOUTReceived()));
181
182 uint8_t GenericData[GENERIC_REPORT_SIZE];
183
184 Endpoint_Read_Control_Stream(&GenericData, sizeof(GenericData));
185
186 ProcessGenericHIDReport(GenericData);
187
188 /* Clear the endpoint data */
189 Endpoint_ClearSetupOUT();
190
191 /* Wait until the host is ready to receive the request confirmation */
192 while (!(Endpoint_IsSetupINReady()));
193
194 /* Handshake the request by sending an empty IN packet */
195 Endpoint_ClearSetupIN();
196 }
197
198 break;
199 }
200 }
201
202 /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
203 * log to a serial port, or anything else that is suitable for status updates.
204 *
205 * \param CurrentStatus Current status of the system, from the GenericHID_StatusCodes_t enum
206 */
207 void UpdateStatus(uint8_t CurrentStatus)
208 {
209 uint8_t LEDMask = LEDS_NO_LEDS;
210
211 /* Set the LED mask to the appropriate LED mask based on the given status code */
212 switch (CurrentStatus)
213 {
214 case Status_USBNotReady:
215 LEDMask = (LEDS_LED1);
216 break;
217 case Status_USBEnumerating:
218 LEDMask = (LEDS_LED1 | LEDS_LED2);
219 break;
220 case Status_USBReady:
221 LEDMask = (LEDS_LED2 | LEDS_LED4);
222 break;
223 }
224
225 /* Set the board LEDs to the new LED mask */
226 LEDs_SetAllLEDs(LEDMask);
227 }
228
229 /** Function to process the lest received report from the host.
230 *
231 * \param DataArray Pointer to a buffer where the last report data is stored
232 */
233 void ProcessGenericHIDReport(uint8_t* DataArray)
234 {
235 /*
236 This is where you need to process the reports being sent from the host to the device.
237 DataArray is an array holding the last report from the host. This function is called
238 each time the host has sent a report to the device.
239 */
240
241 for (uint8_t i = 0; i < GENERIC_REPORT_SIZE; i++)
242 LastReceived[i] = DataArray[i];
243 }
244
245 /** Function to create the next report to send back to the host at the next reporting interval.
246 *
247 * \param DataArray Pointer to a buffer where the next report data should be stored
248 */
249 void CreateGenericHIDReport(uint8_t* DataArray)
250 {
251 /*
252 This is where you need to create reports to be sent to the host from the device. This
253 function is called each time the host is ready to accept a new report. DataArray is
254 an array to hold the report to the host.
255 */
256
257 for (uint8_t i = 0; i < GENERIC_REPORT_SIZE; i++)
258 DataArray[i] = LastReceived[i];
259 }
260
261 #if !defined(INTERRUPT_DATA_ENDPOINT)
262 TASK(USB_HID_Report)
263 {
264 /* Check if the USB system is connected to a host */
265 if (USB_IsConnected)
266 {
267 Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM);
268
269 if (Endpoint_ReadWriteAllowed())
270 {
271 /* Create a temporary buffer to hold the read in report from the host */
272 uint8_t GenericData[GENERIC_REPORT_SIZE];
273
274 /* Read Generic Report Data */
275 Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData));
276
277 /* Process Generic Report Data */
278 ProcessGenericHIDReport(GenericData);
279
280 /* Finalize the stream transfer to send the last packet */
281 Endpoint_ClearCurrentBank();
282 }
283
284 Endpoint_SelectEndpoint(GENERIC_IN_EPNUM);
285
286 if (Endpoint_ReadWriteAllowed())
287 {
288 /* Create a temporary buffer to hold the report to send to the host */
289 uint8_t GenericData[GENERIC_REPORT_SIZE];
290
291 /* Create Generic Report Data */
292 CreateGenericHIDReport(GenericData);
293
294 /* Write Generic Report Data */
295 Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData));
296
297 /* Finalize the stream transfer to send the last packet */
298 Endpoint_ClearCurrentBank();
299 }
300 }
301 }
302 #endif
303
304 /** ISR for the general Pipe/Endpoint interrupt vector. This ISR fires when an endpoint's status changes (such as
305 * a packet has been received) on an endpoint with its corresponding ISR enabling bits set. This is used to send
306 * HID packets to the host each time the HID interrupt endpoints polling period elapses, as managed by the USB
307 * controller.
308 */
309 ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
310 {
311 /* Save previously selected endpoint before selecting a new endpoint */
312 uint8_t PrevSelectedEndpoint = Endpoint_GetCurrentEndpoint();
313
314 #if defined(INTERRUPT_CONTROL_ENDPOINT)
315 /* Check if the control endpoint has received a request */
316 if (Endpoint_HasEndpointInterrupted(ENDPOINT_CONTROLEP))
317 {
318 /* Clear the endpoint interrupt */
319 Endpoint_ClearEndpointInterrupt(ENDPOINT_CONTROLEP);
320
321 /* Process the control request */
322 USB_USBTask();
323
324 /* Handshake the endpoint setup interrupt - must be after the call to USB_USBTask() */
325 USB_INT_Clear(ENDPOINT_INT_SETUP);
326 }
327 #endif
328
329 #if defined(INTERRUPT_DATA_ENDPOINT)
330 /* Check if Generic IN endpoint has interrupted */
331 if (Endpoint_HasEndpointInterrupted(GENERIC_IN_EPNUM))
332 {
333 /* Select the Generic IN Report Endpoint */
334 Endpoint_SelectEndpoint(GENERIC_IN_EPNUM);
335
336 /* Clear the endpoint IN interrupt flag */
337 USB_INT_Clear(ENDPOINT_INT_IN);
338
339 /* Clear the Generic IN Report endpoint interrupt and select the endpoint */
340 Endpoint_ClearEndpointInterrupt(GENERIC_IN_EPNUM);
341
342 /* Create a temporary buffer to hold the report to send to the host */
343 uint8_t GenericData[GENERIC_REPORT_SIZE];
344
345 /* Create Generic Report Data */
346 CreateGenericHIDReport(GenericData);
347
348 /* Write Generic Report Data */
349 Endpoint_Write_Stream_LE(&GenericData, sizeof(GenericData));
350
351 /* Finalize the stream transfer to send the last packet */
352 Endpoint_ClearCurrentBank();
353 }
354
355 /* Check if Generic OUT endpoint has interrupted */
356 if (Endpoint_HasEndpointInterrupted(GENERIC_OUT_EPNUM))
357 {
358 /* Select the Generic OUT Report Endpoint */
359 Endpoint_SelectEndpoint(GENERIC_OUT_EPNUM);
360
361 /* Clear the endpoint OUT Interrupt flag */
362 USB_INT_Clear(ENDPOINT_INT_OUT);
363
364 /* Clear the Generic OUT Report endpoint interrupt and select the endpoint */
365 Endpoint_ClearEndpointInterrupt(GENERIC_OUT_EPNUM);
366
367 /* Create a temporary buffer to hold the read in report from the host */
368 uint8_t GenericData[GENERIC_REPORT_SIZE];
369
370 /* Read Generic Report Data */
371 Endpoint_Read_Stream_LE(&GenericData, sizeof(GenericData));
372
373 /* Process Generic Report Data */
374 ProcessGenericHIDReport(GenericData);
375
376 /* Finalize the stream transfer to send the last packet */
377 Endpoint_ClearCurrentBank();
378 }
379 #endif
380
381 /* Restore previously selected endpoint */
382 Endpoint_SelectEndpoint(PrevSelectedEndpoint);
383 }