The USB_Host_SendControlRequest() function no longer automatically selects the Contro...
[pub/USBasp.git] / Demos / Host / MouseHost / MouseHost.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 MouseHost demo. This file contains the main tasks of
34 * the demo and is responsible for the initial application hardware configuration.
35 */
36
37 #include "MouseHost.h"
38
39 /* Project Tags, for reading out using the ButtLoad project */
40 BUTTLOADTAG(ProjName, "LUFA Mouse Host 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 { Task: USB_USBTask , TaskStatus: TASK_STOP },
49 { Task: USB_Mouse_Host , TaskStatus: TASK_STOP },
50 };
51
52
53 /** Main program entry point. This routine configures the hardware required by the application, then
54 * starts the scheduler to run the application tasks.
55 */
56 int main(void)
57 {
58 /* Disable watchdog if enabled by bootloader/fuses */
59 MCUSR &= ~(1 << WDRF);
60 wdt_disable();
61
62 /* Disable clock division */
63 clock_prescale_set(clock_div_1);
64
65 /* Hardware Initialization */
66 SerialStream_Init(9600, false);
67 LEDs_Init();
68
69 /* Indicate USB not ready */
70 UpdateStatus(Status_USBNotReady);
71
72 /* Initialize Scheduler so that it can be used */
73 Scheduler_Init();
74
75 /* Initialize USB Subsystem */
76 USB_Init();
77
78 /* Start-up message */
79 puts_P(PSTR(ESC_RESET ESC_BG_WHITE ESC_INVERSE_ON ESC_ERASE_DISPLAY
80 "Mouse Host Demo running.\r\n" ESC_INVERSE_OFF));
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_DeviceAttached event. This indicates that a device has been attached to the host, and
87 * starts the library USB task to begin the enumeration and USB management process.
88 */
89 EVENT_HANDLER(USB_DeviceAttached)
90 {
91 puts_P(PSTR("Device Attached.\r\n"));
92 UpdateStatus(Status_USBEnumerating);
93
94 /* Start USB management task to enumerate the device */
95 Scheduler_SetTaskMode(USB_USBTask, TASK_RUN);
96 }
97
98 /** Event handler for the USB_DeviceUnattached event. This indicates that a device has been removed from the host, and
99 * stops the library USB task management process.
100 */
101 EVENT_HANDLER(USB_DeviceUnattached)
102 {
103 /* Stop mouse and USB management task */
104 Scheduler_SetTaskMode(USB_USBTask, TASK_STOP);
105 Scheduler_SetTaskMode(USB_Mouse_Host, TASK_STOP);
106
107 puts_P(PSTR("Device Unattached.\r\n"));
108 UpdateStatus(Status_USBNotReady);
109 }
110
111 /** Event handler for the USB_DeviceEnumerationComplete event. This indicates that a device has been successfully
112 * enumerated by the host and is now ready to be used by the application.
113 */
114 EVENT_HANDLER(USB_DeviceEnumerationComplete)
115 {
116 /* Start Mouse Host task */
117 Scheduler_SetTaskMode(USB_Mouse_Host, TASK_RUN);
118
119 /* Indicate device enumeration complete */
120 UpdateStatus(Status_USBReady);
121 }
122
123 /** Event handler for the USB_HostError event. This indicates that a hardware error occurred while in host mode. */
124 EVENT_HANDLER(USB_HostError)
125 {
126 USB_ShutDown();
127
128 puts_P(PSTR(ESC_BG_RED "Host Mode Error\r\n"));
129 printf_P(PSTR(" -- Error Code %d\r\n"), ErrorCode);
130
131 UpdateStatus(Status_HardwareError);
132 for(;;);
133 }
134
135 /** Event handler for the USB_DeviceEnumerationFailed event. This indicates that a problem occurred while
136 * enumerating an attached USB device.
137 */
138 EVENT_HANDLER(USB_DeviceEnumerationFailed)
139 {
140 puts_P(PSTR(ESC_BG_RED "Dev Enum Error\r\n"));
141 printf_P(PSTR(" -- Error Code %d\r\n"), ErrorCode);
142 printf_P(PSTR(" -- Sub Error Code %d\r\n"), SubErrorCode);
143 printf_P(PSTR(" -- In State %d\r\n"), USB_HostState);
144
145 UpdateStatus(Status_EnumerationError);
146 }
147
148 /** Function to manage status updates to the user. This is done via LEDs on the given board, if available, but may be changed to
149 * log to a serial port, or anything else that is suitable for status updates.
150 *
151 * \param CurrentStatus Current status of the system, from the MouseHost_StatusCodes_t enum
152 */
153 void UpdateStatus(uint8_t CurrentStatus)
154 {
155 uint8_t LEDMask = LEDS_NO_LEDS;
156
157 /* Set the LED mask to the appropriate LED mask based on the given status code */
158 switch (CurrentStatus)
159 {
160 case Status_USBNotReady:
161 LEDMask = (LEDS_LED1);
162 break;
163 case Status_USBEnumerating:
164 LEDMask = (LEDS_LED1 | LEDS_LED2);
165 break;
166 case Status_USBReady:
167 LEDMask = (LEDS_LED2);
168 break;
169 case Status_EnumerationError:
170 case Status_HardwareError:
171 LEDMask = (LEDS_LED1 | LEDS_LED3);
172 break;
173 }
174
175 /* Set the board LEDs to the new LED mask */
176 LEDs_SetAllLEDs(LEDMask);
177 }
178
179 /** Reads in and processes the next report from the attached device, displaying the report
180 * contents on the board LEDs and via the serial port.
181 */
182 void ReadNextReport(void)
183 {
184 USB_MouseReport_Data_t MouseReport;
185 uint8_t LEDMask = LEDS_NO_LEDS;
186
187 /* Select mouse data pipe */
188 Pipe_SelectPipe(MOUSE_DATAPIPE);
189
190 #if !defined(INTERRUPT_DATA_PIPE)
191 /* Unfreeze mouse data pipe */
192 Pipe_Unfreeze();
193 #endif
194
195 /* Ensure pipe contains data and is ready to be read before continuing */
196 if (!(Pipe_ReadWriteAllowed()))
197 {
198 #if !defined(INTERRUPT_DATA_PIPE)
199 /* Refreeze mouse data pipe */
200 Pipe_Freeze();
201 #endif
202
203 return;
204 }
205
206 /* Read in mouse report data */
207 Pipe_Read_Stream_LE(&MouseReport, sizeof(MouseReport));
208
209 /* Clear the IN endpoint, ready for next data packet */
210 Pipe_ClearCurrentBank();
211
212 /* Alter status LEDs according to mouse X movement */
213 if (MouseReport.X > 0)
214 LEDMask |= LEDS_LED1;
215 else if (MouseReport.X < 0)
216 LEDMask |= LEDS_LED2;
217
218 /* Alter status LEDs according to mouse Y movement */
219 if (MouseReport.Y > 0)
220 LEDMask |= LEDS_LED3;
221 else if (MouseReport.Y < 0)
222 LEDMask |= LEDS_LED4;
223
224 /* Alter status LEDs according to mouse button position */
225 if (MouseReport.Button)
226 LEDMask = LEDS_ALL_LEDS;
227
228 LEDs_SetAllLEDs(LEDMask);
229
230 /* Print mouse report data through the serial port */
231 printf_P(PSTR("dX:%2d dY:%2d Button:%d\r\n"), MouseReport.X,
232 MouseReport.Y,
233 MouseReport.Button);
234
235 #if !defined(INTERRUPT_DATA_PIPE)
236 /* Refreeze mouse data pipe */
237 Pipe_Freeze();
238 #endif
239 }
240
241 /** Task to set the configuration of the attached device after it has been enumerated, and to read and process
242 * HID reports from the device and display the results onto the board LEDs.
243 */
244 TASK(USB_Mouse_Host)
245 {
246 uint8_t ErrorCode;
247
248 /* Switch to determine what user-application handled host state the host state machine is in */
249 switch (USB_HostState)
250 {
251 case HOST_STATE_Addressed:
252 /* Standard request to set the device configuration to configuration 1 */
253 USB_HostRequest = (USB_Host_Request_Header_t)
254 {
255 bmRequestType: (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE),
256 bRequest: REQ_SetConfiguration,
257 wValue: 1,
258 wIndex: 0,
259 wLength: 0,
260 };
261
262 /* Select the control pipe for the request transfer */
263 Pipe_SelectPipe(PIPE_CONTROLPIPE);
264
265 /* Send the request, display error and wait for device detach if request fails */
266 if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
267 {
268 puts_P(PSTR("Control Error (Set Configuration).\r\n"));
269 printf_P(PSTR(" -- Error Code: %d\r\n"), ErrorCode);
270
271 /* Indicate error status */
272 UpdateStatus(Status_EnumerationError);
273
274 /* Wait until USB device disconnected */
275 while (USB_IsConnected);
276 break;
277 }
278
279 USB_HostState = HOST_STATE_Configured;
280 break;
281 case HOST_STATE_Configured:
282 puts_P(PSTR("Getting Config Data.\r\n"));
283
284 /* Get and process the configuration descriptor data */
285 if ((ErrorCode = ProcessConfigurationDescriptor()) != SuccessfulConfigRead)
286 {
287 if (ErrorCode == ControlError)
288 puts_P(PSTR("Control Error (Get Configuration).\r\n"));
289 else
290 puts_P(PSTR("Invalid Device.\r\n"));
291
292 printf_P(PSTR(" -- Error Code: %d\r\n"), ErrorCode);
293
294 /* Indicate error status */
295 UpdateStatus(Status_EnumerationError);
296
297 /* Wait until USB device disconnected */
298 while (USB_IsConnected);
299 break;
300 }
301
302 /* HID class request to set the mouse protocol to the Boot Protocol */
303 USB_HostRequest = (USB_Host_Request_Header_t)
304 {
305 bmRequestType: (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
306 bRequest: REQ_SetProtocol,
307 wValue: 0,
308 wIndex: 0,
309 wLength: 0,
310 };
311
312 /* Select the control pipe for the request transfer */
313 Pipe_SelectPipe(PIPE_CONTROLPIPE);
314
315 /* Send the request, display error and wait for device detach if request fails */
316 if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
317 {
318 puts_P(PSTR("Control Error (Set Protocol).\r\n"));
319 printf_P(PSTR(" -- Error Code: %d\r\n"), ErrorCode);
320
321 /* Indicate error status */
322 UpdateStatus(Status_EnumerationError);
323
324 /* Wait until USB device disconnected */
325 while (USB_IsConnected);
326 break;
327 }
328
329 #if defined(INTERRUPT_DATA_PIPE)
330 /* Select and unfreeze mouse data pipe */
331 Pipe_SelectPipe(MOUSE_DATAPIPE);
332 Pipe_Unfreeze();
333 #endif
334
335 puts_P(PSTR("Mouse Enumerated.\r\n"));
336
337 USB_HostState = HOST_STATE_Ready;
338 break;
339 #if !defined(INTERRUPT_DATA_PIPE)
340 case HOST_STATE_Ready:
341 /* If a report has been received, read and process it */
342 ReadNextReport();
343
344 break;
345 #endif
346 }
347 }
348
349 #if defined(INTERRUPT_DATA_PIPE)
350 /** Interrupt handler for the Endpoint/Pipe interrupt vector. This interrupt fires each time an enabled
351 * pipe interrupt occurs on a pipe which has had that interrupt enabled.
352 */
353 ISR(ENDPOINT_PIPE_vect, ISR_BLOCK)
354 {
355 /* Save previously selected pipe before selecting a new pipe */
356 uint8_t PrevSelectedPipe = Pipe_GetCurrentPipe();
357
358 /* Check to see if the mouse data pipe has caused the interrupt */
359 if (Pipe_HasPipeInterrupted(MOUSE_DATAPIPE))
360 {
361 /* Clear the pipe interrupt, and select the mouse pipe */
362 Pipe_ClearPipeInterrupt(MOUSE_DATAPIPE);
363 Pipe_SelectPipe(MOUSE_DATAPIPE);
364
365 /* Check to see if the pipe IN interrupt has fired */
366 if (USB_INT_HasOccurred(PIPE_INT_IN) && USB_INT_IsEnabled(PIPE_INT_IN))
367 {
368 /* Clear interrupt flag */
369 USB_INT_Clear(PIPE_INT_IN);
370
371 /* Read and process the next report from the device */
372 ReadNextReport();
373 }
374 }
375
376 /* Restore previously selected pipe */
377 Pipe_SelectPipe(PrevSelectedPipe);
378 }
379 #endif