]> git.friedersdorff.com Git - max/tmk_keyboard.git/blob - tmk_core/protocol/usb_hid/USB_Host_Shield_2.0/XBOXRECV.cpp
lufa: usb-usb: Use LUFA startup instead of cusotom
[max/tmk_keyboard.git] / tmk_core / protocol / usb_hid / USB_Host_Shield_2.0 / XBOXRECV.cpp
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 }