Clean up excessive whitespace at the end of each line using the wspurify tool made...
[pub/USBasp.git] / Demos / Device / LowLevel / Mouse / Mouse.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2010.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all 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 Mouse demo. This file contains the main tasks of the demo and
34 * is responsible for the initial application hardware configuration.
35 */
36
37 #include "Mouse.h"
38
39 /** Indicates what report mode the host has requested, true for normal HID reporting mode, false for special boot
40 * protocol reporting mode.
41 */
42 bool UsingReportProtocol = true;
43
44 /** Current Idle period. This is set by the host via a Set Idle HID class request to silence the device's reports
45 * for either the entire idle duration, or until the report status changes (e.g. the user moves the mouse).
46 */
47 uint16_t IdleCount = HID_IDLE_CHANGESONLY;
48
49 /** Current Idle period remaining. When the IdleCount value is set, this tracks the remaining number of idle
50 * milliseconds. This is separate to the IdleCount timer and is incremented and compared as the host may request
51 * the current idle period via a Get Idle HID class request, thus its value must be preserved.
52 */
53 uint16_t IdleMSRemaining = 0;
54
55
56 /** Main program entry point. This routine configures the hardware required by the application, then
57 * enters a loop to run the application tasks in sequence.
58 */
59 int main(void)
60 {
61 SetupHardware();
62
63 LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
64 sei();
65
66 for (;;)
67 {
68 Mouse_Task();
69 USB_USBTask();
70 }
71 }
72
73 /** Configures the board hardware and chip peripherals for the demo's functionality. */
74 void SetupHardware(void)
75 {
76 /* Disable watchdog if enabled by bootloader/fuses */
77 MCUSR &= ~(1 << WDRF);
78 wdt_disable();
79
80 /* Disable clock division */
81 clock_prescale_set(clock_div_1);
82
83 /* Hardware Initialization */
84 Joystick_Init();
85 LEDs_Init();
86 Buttons_Init();
87 USB_Init();
88 }
89
90 /** Event handler for the USB_Connect event. This indicates that the device is enumerating via the status LEDs and
91 * starts the library USB task to begin the enumeration and USB management process.
92 */
93 void EVENT_USB_Device_Connect(void)
94 {
95 /* Indicate USB enumerating */
96 LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
97
98 /* Default to report protocol on connect */
99 UsingReportProtocol = true;
100 }
101
102 /** Event handler for the USB_Disconnect event. This indicates that the device is no longer connected to a host via
103 * the status LEDs and stops the USB management and Mouse reporting tasks.
104 */
105 void EVENT_USB_Device_Disconnect(void)
106 {
107 /* Indicate USB not ready */
108 LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
109 }
110
111 /** Event handler for the USB_ConfigurationChanged event. This is fired when the host sets the current configuration
112 * of the USB device after enumeration - the device endpoints are configured and the mouse reporting task started.
113 */
114 void EVENT_USB_Device_ConfigurationChanged(void)
115 {
116 bool ConfigSuccess = true;
117
118 /* Setup HID Report Endpoint */
119 ConfigSuccess &= Endpoint_ConfigureEndpoint(MOUSE_EPNUM, EP_TYPE_INTERRUPT, ENDPOINT_DIR_IN,
120 MOUSE_EPSIZE, ENDPOINT_BANK_SINGLE);
121
122 /* Turn on Start-of-Frame events for tracking HID report period exiry */
123 USB_Device_EnableSOFEvents();
124
125 /* Indicate endpoint configuration success or failure */
126 LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
127 }
128
129 /** Event handler for the USB_UnhandledControlRequest event. This is used to catch standard and class specific
130 * control requests that are not handled internally by the USB library (including the HID commands, which are
131 * all issued via the control endpoint), so that they can be handled appropriately for the application.
132 */
133 void EVENT_USB_Device_UnhandledControlRequest(void)
134 {
135 /* Handle HID Class specific requests */
136 switch (USB_ControlRequest.bRequest)
137 {
138 case REQ_GetReport:
139 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
140 {
141 USB_MouseReport_Data_t MouseReportData;
142
143 /* Create the next mouse report for transmission to the host */
144 CreateMouseReport(&MouseReportData);
145
146 Endpoint_ClearSETUP();
147
148 /* Write the report data to the control endpoint */
149 Endpoint_Write_Control_Stream_LE(&MouseReportData, sizeof(MouseReportData));
150 Endpoint_ClearOUT();
151
152 /* Clear the report data afterwards */
153 memset(&MouseReportData, 0, sizeof(MouseReportData));
154 }
155
156 break;
157 case REQ_GetProtocol:
158 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
159 {
160 Endpoint_ClearSETUP();
161
162 /* Write the current protocol flag to the host */
163 Endpoint_Write_Byte(UsingReportProtocol);
164
165 Endpoint_ClearIN();
166 Endpoint_ClearStatusStage();
167 }
168
169 break;
170 case REQ_SetProtocol:
171 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
172 {
173 Endpoint_ClearSETUP();
174 Endpoint_ClearStatusStage();
175
176 /* Set or clear the flag depending on what the host indicates that the current Protocol should be */
177 UsingReportProtocol = (USB_ControlRequest.wValue != 0);
178 }
179
180 break;
181 case REQ_SetIdle:
182 if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE))
183 {
184 Endpoint_ClearSETUP();
185 Endpoint_ClearStatusStage();
186
187 /* Get idle period in MSB, must multiply by 4 to get the duration in milliseconds */
188 IdleCount = ((USB_ControlRequest.wValue & 0xFF00) >> 6);
189 }
190
191 break;
192 case REQ_GetIdle:
193 if (USB_ControlRequest.bmRequestType == (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE))
194 {
195 Endpoint_ClearSETUP();
196
197 /* Write the current idle duration to the host, must be divided by 4 before sent to host */
198 Endpoint_Write_Byte(IdleCount >> 2);
199
200 Endpoint_ClearIN();
201 Endpoint_ClearStatusStage();
202 }
203
204 break;
205 }
206 }
207
208 /** Event handler for the USB device Start Of Frame event. */
209 void EVENT_USB_Device_StartOfFrame(void)
210 {
211 /* One millisecond has elapsed, decrement the idle time remaining counter if it has not already elapsed */
212 if (IdleMSRemaining)
213 IdleMSRemaining--;
214 }
215
216 /** Fills the given HID report data structure with the next HID report to send to the host.
217 *
218 * \param[out] ReportData Pointer to a HID report data structure to be filled
219 */
220 void CreateMouseReport(USB_MouseReport_Data_t* const ReportData)
221 {
222 uint8_t JoyStatus_LCL = Joystick_GetStatus();
223 uint8_t ButtonStatus_LCL = Buttons_GetStatus();
224
225 /* Clear the report contents */
226 memset(ReportData, 0, sizeof(USB_MouseReport_Data_t));
227
228 if (JoyStatus_LCL & JOY_UP)
229 ReportData->Y = -1;
230 else if (JoyStatus_LCL & JOY_DOWN)
231 ReportData->Y = 1;
232
233 if (JoyStatus_LCL & JOY_LEFT)
234 ReportData->X = -1;
235 else if (JoyStatus_LCL & JOY_RIGHT)
236 ReportData->X = 1;
237
238 if (JoyStatus_LCL & JOY_PRESS)
239 ReportData->Button = (1 << 0);
240
241 if (ButtonStatus_LCL & BUTTONS_BUTTON1)
242 ReportData->Button |= (1 << 1);
243 }
244
245 /** Sends the next HID report to the host, via the keyboard data endpoint. */
246 void SendNextReport(void)
247 {
248 static USB_MouseReport_Data_t PrevMouseReportData;
249 USB_MouseReport_Data_t MouseReportData;
250 bool SendReport;
251
252 /* Create the next mouse report for transmission to the host */
253 CreateMouseReport(&MouseReportData);
254
255 /* Check to see if the report data has changed - if so a report MUST be sent */
256 SendReport = (memcmp(&PrevMouseReportData, &MouseReportData, sizeof(USB_MouseReport_Data_t)) != 0);
257
258 /* Override the check if the Y or X values are non-zero - we want continuous movement while the joystick
259 * is being held down (via continuous reports), otherwise the cursor will only move once per joystick toggle */
260 if ((MouseReportData.Y != 0) || (MouseReportData.X != 0))
261 SendReport = true;
262
263 /* Check if the idle period is set and has elapsed */
264 if ((IdleCount != HID_IDLE_CHANGESONLY) && (!(IdleMSRemaining)))
265 {
266 /* Reset the idle time remaining counter */
267 IdleMSRemaining = IdleCount;
268
269 /* Idle period is set and has elapsed, must send a report to the host */
270 SendReport = true;
271 }
272
273 /* Select the Mouse Report Endpoint */
274 Endpoint_SelectEndpoint(MOUSE_EPNUM);
275
276 /* Check if Mouse Endpoint Ready for Read/Write and if we should send a new report */
277 if (Endpoint_IsReadWriteAllowed() && SendReport)
278 {
279 /* Save the current report data for later comparison to check for changes */
280 PrevMouseReportData = MouseReportData;
281
282 /* Write Mouse Report Data */
283 Endpoint_Write_Stream_LE(&MouseReportData, sizeof(MouseReportData));
284
285 /* Finalize the stream transfer to send the last packet */
286 Endpoint_ClearIN();
287 }
288 }
289
290 /** Task to manage HID report generation and transmission to the host, when in report mode. */
291 void Mouse_Task(void)
292 {
293 /* Device must be connected and configured for the task to run */
294 if (USB_DeviceState != DEVICE_STATE_Configured)
295 return;
296
297 /* Send the next mouse report to the host */
298 SendNextReport();
299 }
300