diff options
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/XBOXRECV.cpp')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/XBOXRECV.cpp | 583 |
1 files changed, 583 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/XBOXRECV.cpp b/lib/usbhost/USB_Host_Shield_2.0/XBOXRECV.cpp new file mode 100644 index 000000000..41f1ff581 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/XBOXRECV.cpp | |||
@@ -0,0 +1,583 @@ | |||
1 | /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved. | ||
2 | |||
3 | This software may be distributed and modified under the terms of the GNU | ||
4 | General Public License version 2 (GPL2) as published by the Free Software | ||
5 | Foundation and appearing in the file GPL2.TXT included in the packaging of | ||
6 | this file. Please note that GPL2 Section 2[b] requires that all works based | ||
7 | on this software must also be made publicly available under the terms of | ||
8 | the GPL2 ("Copyleft"). | ||
9 | |||
10 | Contact information | ||
11 | ------------------- | ||
12 | |||
13 | Kristian Lauszus, TKJ Electronics | ||
14 | Web : http://www.tkjelectronics.com | ||
15 | e-mail : kristianl@tkjelectronics.com | ||
16 | |||
17 | getBatteryLevel and checkStatus functions made by timstamp.co.uk found using BusHound from Perisoft.net | ||
18 | */ | ||
19 | |||
20 | #include "XBOXRECV.h" | ||
21 | // To enable serial debugging see "settings.h" | ||
22 | //#define EXTRADEBUG // Uncomment to get even more debugging data | ||
23 | //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller | ||
24 | |||
25 | XBOXRECV::XBOXRECV(USB *p) : | ||
26 | pUsb(p), // pointer to USB class instance - mandatory | ||
27 | bAddress(0), // device address - mandatory | ||
28 | bPollEnable(false) { // don't start polling before dongle is connected | ||
29 | for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) { | ||
30 | epInfo[i].epAddr = 0; | ||
31 | epInfo[i].maxPktSize = (i) ? 0 : 8; | ||
32 | epInfo[i].epAttribs = 0; | ||
33 | epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; | ||
34 | } | ||
35 | |||
36 | if(pUsb) // register in USB subsystem | ||
37 | pUsb->RegisterDeviceClass(this); //set devConfig[] entry | ||
38 | } | ||
39 | |||
40 | uint8_t XBOXRECV::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) { | ||
41 | const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR); | ||
42 | uint8_t buf[constBufSize]; | ||
43 | USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); | ||
44 | uint8_t rcode; | ||
45 | UsbDevice *p = NULL; | ||
46 | EpInfo *oldep_ptr = NULL; | ||
47 | uint16_t PID, VID; | ||
48 | |||
49 | AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool | ||
50 | #ifdef EXTRADEBUG | ||
51 | Notify(PSTR("\r\nXBOXRECV Init"), 0x80); | ||
52 | #endif | ||
53 | |||
54 | if(bAddress) { // Check if address has already been assigned to an instance | ||
55 | #ifdef DEBUG_USB_HOST | ||
56 | Notify(PSTR("\r\nAddress in use"), 0x80); | ||
57 | #endif | ||
58 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||
59 | } | ||
60 | |||
61 | p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned | ||
62 | |||
63 | if(!p) { | ||
64 | #ifdef DEBUG_USB_HOST | ||
65 | Notify(PSTR("\r\nAddress not found"), 0x80); | ||
66 | #endif | ||
67 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
68 | } | ||
69 | |||
70 | if(!p->epinfo) { | ||
71 | #ifdef DEBUG_USB_HOST | ||
72 | Notify(PSTR("\r\nepinfo is null"), 0x80); | ||
73 | #endif | ||
74 | return USB_ERROR_EPINFO_IS_NULL; | ||
75 | } | ||
76 | |||
77 | oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0 | ||
78 | p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence | ||
79 | p->lowspeed = lowspeed; | ||
80 | |||
81 | rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data | ||
82 | |||
83 | p->epinfo = oldep_ptr; // Restore p->epinfo | ||
84 | |||
85 | if(rcode) | ||
86 | goto FailGetDevDescr; | ||
87 | |||
88 | VID = udd->idVendor; | ||
89 | PID = udd->idProduct; | ||
90 | |||
91 | if((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID)) { // Check if it's a Xbox receiver using the Vendor ID and Product ID | ||
92 | #ifdef DEBUG_USB_HOST | ||
93 | Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80); | ||
94 | #endif | ||
95 | goto FailUnknownDevice; | ||
96 | } | ||
97 | |||
98 | bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class | ||
99 | |||
100 | if(!bAddress) { | ||
101 | #ifdef DEBUG_USB_HOST | ||
102 | Notify(PSTR("\r\nOut of address space"), 0x80); | ||
103 | #endif | ||
104 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; | ||
105 | } | ||
106 | |||
107 | epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor | ||
108 | |||
109 | delay(20); // Wait a little before resetting device | ||
110 | |||
111 | return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET; | ||
112 | |||
113 | /* Diagnostic messages */ | ||
114 | FailGetDevDescr: | ||
115 | #ifdef DEBUG_USB_HOST | ||
116 | NotifyFailGetDevDescr(rcode); | ||
117 | #endif | ||
118 | if(rcode != hrJERR) | ||
119 | rcode = USB_ERROR_FailGetDevDescr; | ||
120 | goto Fail; | ||
121 | |||
122 | FailUnknownDevice: | ||
123 | #ifdef DEBUG_USB_HOST | ||
124 | NotifyFailUnknownDevice(VID, PID); | ||
125 | #endif | ||
126 | rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||
127 | |||
128 | Fail: | ||
129 | #ifdef DEBUG_USB_HOST | ||
130 | Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80); | ||
131 | NotifyFail(rcode); | ||
132 | #endif | ||
133 | Release(); | ||
134 | return rcode; | ||
135 | }; | ||
136 | |||
137 | uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) { | ||
138 | uint8_t rcode; | ||
139 | |||
140 | AddressPool &addrPool = pUsb->GetAddressPool(); | ||
141 | #ifdef EXTRADEBUG | ||
142 | Notify(PSTR("\r\nBTD Init"), 0x80); | ||
143 | #endif | ||
144 | UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record | ||
145 | |||
146 | if(!p) { | ||
147 | #ifdef DEBUG_USB_HOST | ||
148 | Notify(PSTR("\r\nAddress not found"), 0x80); | ||
149 | #endif | ||
150 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
151 | } | ||
152 | |||
153 | delay(300); // Assign new address to the device | ||
154 | |||
155 | rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device | ||
156 | if(rcode) { | ||
157 | #ifdef DEBUG_USB_HOST | ||
158 | Notify(PSTR("\r\nsetAddr: "), 0x80); | ||
159 | D_PrintHex<uint8_t > (rcode, 0x80); | ||
160 | #endif | ||
161 | p->lowspeed = false; | ||
162 | goto Fail; | ||
163 | } | ||
164 | #ifdef EXTRADEBUG | ||
165 | Notify(PSTR("\r\nAddr: "), 0x80); | ||
166 | D_PrintHex<uint8_t > (bAddress, 0x80); | ||
167 | #endif | ||
168 | |||
169 | p->lowspeed = false; | ||
170 | |||
171 | p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record | ||
172 | if(!p) { | ||
173 | #ifdef DEBUG_USB_HOST | ||
174 | Notify(PSTR("\r\nAddress not found"), 0x80); | ||
175 | #endif | ||
176 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
177 | } | ||
178 | |||
179 | p->lowspeed = lowspeed; | ||
180 | |||
181 | rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known | ||
182 | if(rcode) | ||
183 | goto FailSetDevTblEntry; | ||
184 | |||
185 | /* The application will work in reduced host mode, so we can save program and data | ||
186 | memory space. After verifying the VID we will use known values for the | ||
187 | configuration values for device, interface, endpoints and HID for the XBOX360 Wireless receiver */ | ||
188 | |||
189 | /* Initialize data structures for endpoints of device */ | ||
190 | epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms | ||
191 | epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
192 | epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
193 | epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE; | ||
194 | epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = 0; | ||
195 | epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = 0; | ||
196 | epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms | ||
197 | epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
198 | epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
199 | epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE; | ||
200 | epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = 0; | ||
201 | epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = 0; | ||
202 | |||
203 | epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms | ||
204 | epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
205 | epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
206 | epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE; | ||
207 | epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = 0; | ||
208 | epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = 0; | ||
209 | epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms | ||
210 | epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
211 | epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
212 | epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE; | ||
213 | epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = 0; | ||
214 | epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = 0; | ||
215 | |||
216 | epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms | ||
217 | epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
218 | epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
219 | epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE; | ||
220 | epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = 0; | ||
221 | epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = 0; | ||
222 | epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms | ||
223 | epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
224 | epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
225 | epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE; | ||
226 | epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = 0; | ||
227 | epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = 0; | ||
228 | |||
229 | epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms | ||
230 | epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
231 | epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
232 | epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE; | ||
233 | epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = 0; | ||
234 | epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = 0; | ||
235 | epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms | ||
236 | epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
237 | epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
238 | epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE; | ||
239 | epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = 0; | ||
240 | epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = 0; | ||
241 | |||
242 | rcode = pUsb->setEpInfoEntry(bAddress, 9, epInfo); | ||
243 | if(rcode) | ||
244 | goto FailSetDevTblEntry; | ||
245 | |||
246 | delay(200); //Give time for address change | ||
247 | |||
248 | rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1); | ||
249 | if(rcode) | ||
250 | goto FailSetConfDescr; | ||
251 | |||
252 | #ifdef DEBUG_USB_HOST | ||
253 | Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80); | ||
254 | #endif | ||
255 | XboxReceiverConnected = true; | ||
256 | bPollEnable = true; | ||
257 | checkStatusTimer = 0; // Reset timer | ||
258 | return 0; // Successful configuration | ||
259 | |||
260 | /* Diagnostic messages */ | ||
261 | FailSetDevTblEntry: | ||
262 | #ifdef DEBUG_USB_HOST | ||
263 | NotifyFailSetDevTblEntry(); | ||
264 | goto Fail; | ||
265 | #endif | ||
266 | |||
267 | FailSetConfDescr: | ||
268 | #ifdef DEBUG_USB_HOST | ||
269 | NotifyFailSetConfDescr(); | ||
270 | #endif | ||
271 | |||
272 | Fail: | ||
273 | #ifdef DEBUG_USB_HOST | ||
274 | Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80); | ||
275 | NotifyFail(rcode); | ||
276 | #endif | ||
277 | Release(); | ||
278 | return rcode; | ||
279 | } | ||
280 | |||
281 | /* Performs a cleanup after failed Init() attempt */ | ||
282 | uint8_t XBOXRECV::Release() { | ||
283 | XboxReceiverConnected = false; | ||
284 | for(uint8_t i = 0; i < 4; i++) | ||
285 | Xbox360Connected[i] = 0x00; | ||
286 | pUsb->GetAddressPool().FreeAddress(bAddress); | ||
287 | bAddress = 0; | ||
288 | bPollEnable = false; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | uint8_t XBOXRECV::Poll() { | ||
293 | if(!bPollEnable) | ||
294 | return 0; | ||
295 | if(!checkStatusTimer || ((millis() - checkStatusTimer) > 3000)) { // Run checkStatus every 3 seconds | ||
296 | checkStatusTimer = millis(); | ||
297 | checkStatus(); | ||
298 | } | ||
299 | |||
300 | uint8_t inputPipe; | ||
301 | uint16_t bufferSize; | ||
302 | for(uint8_t i = 0; i < 4; i++) { | ||
303 | if(i == 0) | ||
304 | inputPipe = XBOX_INPUT_PIPE_1; | ||
305 | else if(i == 1) | ||
306 | inputPipe = XBOX_INPUT_PIPE_2; | ||
307 | else if(i == 2) | ||
308 | inputPipe = XBOX_INPUT_PIPE_3; | ||
309 | else | ||
310 | inputPipe = XBOX_INPUT_PIPE_4; | ||
311 | |||
312 | bufferSize = EP_MAXPKTSIZE; // This is the maximum number of bytes we want to receive | ||
313 | pUsb->inTransfer(bAddress, epInfo[ inputPipe ].epAddr, &bufferSize, readBuf); | ||
314 | if(bufferSize > 0) { // The number of received bytes | ||
315 | #ifdef EXTRADEBUG | ||
316 | Notify(PSTR("Bytes Received: "), 0x80); | ||
317 | D_PrintHex<uint16_t > (bufferSize, 0x80); | ||
318 | Notify(PSTR("\r\n"), 0x80); | ||
319 | #endif | ||
320 | readReport(i); | ||
321 | #ifdef PRINTREPORT | ||
322 | printReport(i, bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller | ||
323 | #endif | ||
324 | } | ||
325 | } | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | void XBOXRECV::readReport(uint8_t controller) { | ||
330 | if(readBuf == NULL) | ||
331 | return; | ||
332 | // This report is send when a controller is connected and disconnected | ||
333 | if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) { | ||
334 | Xbox360Connected[controller] = readBuf[1]; | ||
335 | #ifdef DEBUG_USB_HOST | ||
336 | Notify(PSTR("Controller "), 0x80); | ||
337 | Notify(controller, 0x80); | ||
338 | #endif | ||
339 | if(Xbox360Connected[controller]) { | ||
340 | #ifdef DEBUG_USB_HOST | ||
341 | const char* str = 0; | ||
342 | switch(readBuf[1]) { | ||
343 | case 0x80: str = PSTR(" as controller\r\n"); | ||
344 | break; | ||
345 | case 0x40: str = PSTR(" as headset\r\n"); | ||
346 | break; | ||
347 | case 0xC0: str = PSTR(" as controller+headset\r\n"); | ||
348 | break; | ||
349 | } | ||
350 | Notify(PSTR(": connected"), 0x80); | ||
351 | Notify(str, 0x80); | ||
352 | #endif | ||
353 | onInit(controller); | ||
354 | } | ||
355 | #ifdef DEBUG_USB_HOST | ||
356 | else | ||
357 | Notify(PSTR(": disconnected\r\n"), 0x80); | ||
358 | #endif | ||
359 | return; | ||
360 | } | ||
361 | // Controller status report | ||
362 | if(readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) { | ||
363 | controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4]; | ||
364 | return; | ||
365 | } | ||
366 | if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports | ||
367 | return; | ||
368 | |||
369 | // A controller must be connected if it's sending data | ||
370 | if(!Xbox360Connected[controller]) | ||
371 | Xbox360Connected[controller] |= 0x80; | ||
372 | |||
373 | ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24)); | ||
374 | |||
375 | hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); | ||
376 | hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); | ||
377 | hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]); | ||
378 | hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]); | ||
379 | |||
380 | //Notify(PSTR("\r\nButtonState: "), 0x80); | ||
381 | //PrintHex<uint32_t>(ButtonState[controller], 0x80); | ||
382 | |||
383 | if(ButtonState[controller] != OldButtonState[controller]) { | ||
384 | buttonStateChanged[controller] = true; | ||
385 | ButtonClickState[controller] = (ButtonState[controller] >> 16) & ((~OldButtonState[controller]) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2 | ||
386 | if(((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons | ||
387 | R2Clicked[controller] = true; | ||
388 | if((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0) | ||
389 | L2Clicked[controller] = true; | ||
390 | OldButtonState[controller] = ButtonState[controller]; | ||
391 | } | ||
392 | } | ||
393 | |||
394 | void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller | ||
395 | #ifdef PRINTREPORT | ||
396 | if(readBuf == NULL) | ||
397 | return; | ||
398 | Notify(PSTR("Controller "), 0x80); | ||
399 | Notify(controller, 0x80); | ||
400 | Notify(PSTR(": "), 0x80); | ||
401 | for(uint8_t i = 0; i < nBytes; i++) { | ||
402 | D_PrintHex<uint8_t > (readBuf[i], 0x80); | ||
403 | Notify(PSTR(" "), 0x80); | ||
404 | } | ||
405 | Notify(PSTR("\r\n"), 0x80); | ||
406 | #endif | ||
407 | } | ||
408 | |||
409 | uint8_t XBOXRECV::getButtonPress(ButtonEnum b, uint8_t controller) { | ||
410 | if(b == L2) // These are analog buttons | ||
411 | return (uint8_t)(ButtonState[controller] >> 8); | ||
412 | else if(b == R2) | ||
413 | return (uint8_t)ButtonState[controller]; | ||
414 | return (bool)(ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]) << 16)); | ||
415 | } | ||
416 | |||
417 | bool XBOXRECV::getButtonClick(ButtonEnum b, uint8_t controller) { | ||
418 | if(b == L2) { | ||
419 | if(L2Clicked[controller]) { | ||
420 | L2Clicked[controller] = false; | ||
421 | return true; | ||
422 | } | ||
423 | return false; | ||
424 | } else if(b == R2) { | ||
425 | if(R2Clicked[controller]) { | ||
426 | R2Clicked[controller] = false; | ||
427 | return true; | ||
428 | } | ||
429 | return false; | ||
430 | } | ||
431 | uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]); | ||
432 | bool click = (ButtonClickState[controller] & button); | ||
433 | ButtonClickState[controller] &= ~button; // clear "click" event | ||
434 | return click; | ||
435 | } | ||
436 | |||
437 | int16_t XBOXRECV::getAnalogHat(AnalogHatEnum a, uint8_t controller) { | ||
438 | return hatValue[controller][a]; | ||
439 | } | ||
440 | |||
441 | bool XBOXRECV::buttonChanged(uint8_t controller) { | ||
442 | bool state = buttonStateChanged[controller]; | ||
443 | buttonStateChanged[controller] = false; | ||
444 | return state; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | ControllerStatus Breakdown | ||
449 | ControllerStatus[controller] & 0x0001 // 0 | ||
450 | ControllerStatus[controller] & 0x0002 // normal batteries, no rechargeable battery pack | ||
451 | ControllerStatus[controller] & 0x0004 // controller starting up / settling | ||
452 | ControllerStatus[controller] & 0x0008 // headset adapter plugged in, but no headphones connected (mute?) | ||
453 | ControllerStatus[controller] & 0x0010 // 0 | ||
454 | ControllerStatus[controller] & 0x0020 // 1 | ||
455 | ControllerStatus[controller] & 0x0040 // battery level (high bit) | ||
456 | ControllerStatus[controller] & 0x0080 // battery level (low bit) | ||
457 | ControllerStatus[controller] & 0x0100 // 1 | ||
458 | ControllerStatus[controller] & 0x0200 // 1 | ||
459 | ControllerStatus[controller] & 0x0400 // headset adapter plugged in | ||
460 | ControllerStatus[controller] & 0x0800 // 0 | ||
461 | ControllerStatus[controller] & 0x1000 // 1 | ||
462 | ControllerStatus[controller] & 0x2000 // 0 | ||
463 | ControllerStatus[controller] & 0x4000 // 0 | ||
464 | ControllerStatus[controller] & 0x8000 // 0 | ||
465 | */ | ||
466 | uint8_t XBOXRECV::getBatteryLevel(uint8_t controller) { | ||
467 | return ((controllerStatus[controller] & 0x00C0) >> 6); | ||
468 | } | ||
469 | |||
470 | void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) { | ||
471 | #ifdef EXTRADEBUG | ||
472 | uint8_t rcode; | ||
473 | #endif | ||
474 | uint8_t outputPipe; | ||
475 | switch(controller) { | ||
476 | case 0: outputPipe = XBOX_OUTPUT_PIPE_1; | ||
477 | break; | ||
478 | case 1: outputPipe = XBOX_OUTPUT_PIPE_2; | ||
479 | break; | ||
480 | case 2: outputPipe = XBOX_OUTPUT_PIPE_3; | ||
481 | break; | ||
482 | case 3: outputPipe = XBOX_OUTPUT_PIPE_4; | ||
483 | break; | ||
484 | default: | ||
485 | return; | ||
486 | } | ||
487 | #ifdef EXTRADEBUG | ||
488 | rcode = | ||
489 | #endif | ||
490 | pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data); | ||
491 | #ifdef EXTRADEBUG | ||
492 | if(rcode) | ||
493 | Notify(PSTR("Error sending Xbox message\r\n"), 0x80); | ||
494 | #endif | ||
495 | } | ||
496 | |||
497 | void XBOXRECV::disconnect(uint8_t controller) { | ||
498 | writeBuf[0] = 0x00; | ||
499 | writeBuf[1] = 0x00; | ||
500 | writeBuf[2] = 0x08; | ||
501 | writeBuf[3] = 0xC0; | ||
502 | |||
503 | XboxCommand(controller, writeBuf, 4); | ||
504 | } | ||
505 | |||
506 | void XBOXRECV::setLedRaw(uint8_t value, uint8_t controller) { | ||
507 | writeBuf[0] = 0x00; | ||
508 | writeBuf[1] = 0x00; | ||
509 | writeBuf[2] = 0x08; | ||
510 | writeBuf[3] = value | 0x40; | ||
511 | |||
512 | XboxCommand(controller, writeBuf, 4); | ||
513 | } | ||
514 | |||
515 | void XBOXRECV::setLedOn(LEDEnum led, uint8_t controller) { | ||
516 | if(led == OFF) | ||
517 | setLedRaw(0, controller); | ||
518 | else if(led != ALL) // All LEDs can't be on a the same time | ||
519 | setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]) + 4, controller); | ||
520 | } | ||
521 | |||
522 | void XBOXRECV::setLedBlink(LEDEnum led, uint8_t controller) { | ||
523 | setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]), controller); | ||
524 | } | ||
525 | |||
526 | void XBOXRECV::setLedMode(LEDModeEnum ledMode, uint8_t controller) { // This function is used to do some speciel LED stuff the controller supports | ||
527 | setLedRaw((uint8_t)ledMode, controller); | ||
528 | } | ||
529 | |||
530 | /* PC runs this at interval of approx 2 seconds | ||
531 | Thanks to BusHound from Perisoft.net for the Windows USB Analysis output | ||
532 | Found by timstamp.co.uk | ||
533 | */ | ||
534 | void XBOXRECV::checkStatus() { | ||
535 | if(!bPollEnable) | ||
536 | return; | ||
537 | // Get controller info | ||
538 | writeBuf[0] = 0x08; | ||
539 | writeBuf[1] = 0x00; | ||
540 | writeBuf[2] = 0x0f; | ||
541 | writeBuf[3] = 0xc0; | ||
542 | for(uint8_t i = 0; i < 4; i++) { | ||
543 | XboxCommand(i, writeBuf, 4); | ||
544 | } | ||
545 | // Get battery status | ||
546 | writeBuf[0] = 0x00; | ||
547 | writeBuf[1] = 0x00; | ||
548 | writeBuf[2] = 0x00; | ||
549 | writeBuf[3] = 0x40; | ||
550 | for(uint8_t i = 0; i < 4; i++) { | ||
551 | if(Xbox360Connected[i]) | ||
552 | XboxCommand(i, writeBuf, 4); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) { | ||
557 | writeBuf[0] = 0x00; | ||
558 | writeBuf[1] = 0x01; | ||
559 | writeBuf[2] = 0x0f; | ||
560 | writeBuf[3] = 0xc0; | ||
561 | writeBuf[4] = 0x00; | ||
562 | writeBuf[5] = lValue; // big weight | ||
563 | writeBuf[6] = rValue; // small weight | ||
564 | |||
565 | XboxCommand(controller, writeBuf, 7); | ||
566 | } | ||
567 | |||
568 | void XBOXRECV::onInit(uint8_t controller) { | ||
569 | if(pFuncOnInit) | ||
570 | pFuncOnInit(); // Call the user function | ||
571 | else { | ||
572 | LEDEnum led; | ||
573 | if(controller == 0) | ||
574 | led = LED1; | ||
575 | else if(controller == 1) | ||
576 | led = LED2; | ||
577 | else if(controller == 2) | ||
578 | led = LED3; | ||
579 | else | ||
580 | led = LED4; | ||
581 | setLedOn(led, controller); | ||
582 | } | ||
583 | } | ||