Zoltan Hudak / UsbHostMAX3421E

Dependents:   UsbHostMAX3421E_Hello

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers XBOXRECV.cpp Source File

XBOXRECV.cpp

00001 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
00002 
00003  This software may be distributed and modified under the terms of the GNU
00004  General Public License version 2 (GPL2) as published by the Free Software
00005  Foundation and appearing in the file GPL2.TXT included in the packaging of
00006  this file. Please note that GPL2 Section 2[b] requires that all works based
00007  on this software must also be made publicly available under the terms of
00008  the GPL2 ("Copyleft").
00009 
00010  Contact information
00011  -------------------
00012 
00013  Kristian Lauszus, TKJ Electronics
00014  Web      :  http://www.tkjelectronics.com
00015  e-mail   :  kristianl@tkjelectronics.com
00016 
00017  getBatteryLevel and checkStatus functions made by timstamp.co.uk found using BusHound from Perisoft.net
00018  */
00019 
00020 #include "XBOXRECV.h"
00021 // To enable serial debugging see "settings.h"
00022 //#define EXTRADEBUG // Uncomment to get even more debugging data
00023 //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
00024 
00025 XBOXRECV::XBOXRECV(Usb *p) :
00026 pUsb(p), // pointer to USB class instance - mandatory
00027 bAddress(0), // device address - mandatory
00028 bPollEnable(false) { // don't start polling before dongle is connected
00029         for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
00030                 epInfo[i].epAddr = 0;
00031                 epInfo[i].maxPktSize = (i) ? 0 : 8;
00032                 epInfo[i].bmSndToggle = 0;
00033                 epInfo[i].bmRcvToggle = 0;
00034                 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
00035         }
00036 
00037         if(pUsb) // register in USB subsystem
00038                 pUsb->RegisterDeviceClass(this); //set devConfig[] entry
00039 }
00040 
00041 uint8_t XBOXRECV::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
00042         const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
00043         uint8_t buf[constBufSize];
00044         USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
00045         uint8_t rcode;
00046         UsbDevice *p = NULL;
00047         EpInfo *oldep_ptr = NULL;
00048         uint16_t PID, VID;
00049 
00050         AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool
00051 #ifdef EXTRADEBUG
00052         Notify(PSTR("\r\nXBOXRECV Init"), 0x80);
00053 #endif
00054 
00055         if(bAddress) { // Check if address has already been assigned to an instance
00056 #ifdef DEBUG_USB_HOST
00057                 Notify(PSTR("\r\nAddress in use"), 0x80);
00058 #endif
00059                 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
00060         }
00061 
00062         p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned
00063 
00064         if(!p) {
00065 #ifdef DEBUG_USB_HOST
00066                 Notify(PSTR("\r\nAddress not found"), 0x80);
00067 #endif
00068                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00069         }
00070 
00071         if(!p->epinfo) {
00072 #ifdef DEBUG_USB_HOST
00073                 Notify(PSTR("\r\nepinfo is null"), 0x80);
00074 #endif
00075                 return USB_ERROR_EPINFO_IS_NULL;
00076         }
00077 
00078         oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0
00079         p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
00080         p->lowspeed = lowspeed;
00081 
00082         rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
00083 
00084         p->epinfo = oldep_ptr; // Restore p->epinfo
00085 
00086         if(rcode)
00087                 goto FailGetDevDescr;
00088 
00089         VID = udd->idVendor;
00090         PID = udd->idProduct;
00091 
00092         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
00093 #ifdef DEBUG_USB_HOST
00094                 Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80);
00095 #endif
00096                 goto FailUnknownDevice;
00097         }
00098 
00099         bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class
00100 
00101         if(!bAddress) {
00102 #ifdef DEBUG_USB_HOST
00103                 Notify(PSTR("\r\nOut of address space"), 0x80);
00104 #endif
00105                 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
00106         }
00107 
00108         epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor
00109 
00110         wait_ms(20); // Wait a little before resetting device
00111 
00112         return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
00113 
00114         /* Diagnostic messages */
00115 FailGetDevDescr:
00116 #ifdef DEBUG_USB_HOST
00117         NotifyFailGetDevDescr(rcode);
00118 #endif
00119         if(rcode != hrJERR)
00120                 rcode = USB_ERROR_FailGetDevDescr;
00121         goto Fail;
00122 
00123 FailUnknownDevice:
00124 #ifdef DEBUG_USB_HOST
00125         NotifyFailUnknownDevice(VID, PID);
00126 #endif
00127         rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
00128 
00129 Fail:
00130 #ifdef DEBUG_USB_HOST
00131         Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
00132         NotifyFail(rcode);
00133 #endif
00134         Release();
00135         return rcode;
00136 };
00137 
00138 uint8_t XBOXRECV::Init(uint8_t parent __attribute__((unused)), uint8_t port __attribute__((unused)), bool lowspeed) {
00139         uint8_t rcode;
00140 
00141         AddressPool &addrPool = pUsb->GetAddressPool();
00142 #ifdef EXTRADEBUG
00143         Notify(PSTR("\r\nBTD Init"), 0x80);
00144 #endif
00145         UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
00146 
00147         if(!p) {
00148 #ifdef DEBUG_USB_HOST
00149                 Notify(PSTR("\r\nAddress not found"), 0x80);
00150 #endif
00151                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00152         }
00153 
00154         wait_ms(300); // Assign new address to the device
00155 
00156         rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device
00157         if(rcode) {
00158 #ifdef DEBUG_USB_HOST
00159                 Notify(PSTR("\r\nsetAddr: "), 0x80);
00160                 D_PrintHex<uint8_t > (rcode, 0x80);
00161 #endif
00162                 p->lowspeed = false;
00163                 goto Fail;
00164         }
00165 #ifdef EXTRADEBUG
00166         Notify(PSTR("\r\nAddr: "), 0x80);
00167         D_PrintHex<uint8_t > (bAddress, 0x80);
00168 #endif
00169 
00170         p->lowspeed = false;
00171 
00172         p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
00173         if(!p) {
00174 #ifdef DEBUG_USB_HOST
00175                 Notify(PSTR("\r\nAddress not found"), 0x80);
00176 #endif
00177                 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
00178         }
00179 
00180         p->lowspeed = lowspeed;
00181 
00182         rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
00183         if(rcode)
00184                 goto FailSetDevTblEntry;
00185 
00186         /* The application will work in reduced host mode, so we can save program and data
00187            memory space. After verifying the VID we will use known values for the
00188            configuration values for device, interface, endpoints and HID for the XBOX360 Wireless receiver */
00189 
00190         /* Initialize data structures for endpoints of device */
00191         epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms
00192         epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00193         epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00194         epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
00195         epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = 0;
00196         epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = 0;
00197         epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms
00198         epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00199         epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00200         epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
00201         epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = 0;
00202         epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = 0;
00203 
00204         epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms
00205         epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00206         epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00207         epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
00208         epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = 0;
00209         epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = 0;
00210         epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms
00211         epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00212         epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00213         epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
00214         epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = 0;
00215         epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = 0;
00216 
00217         epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms
00218         epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00219         epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00220         epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
00221         epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = 0;
00222         epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = 0;
00223         epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms
00224         epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00225         epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00226         epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
00227         epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = 0;
00228         epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = 0;
00229 
00230         epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms
00231         epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00232         epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00233         epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
00234         epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = 0;
00235         epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = 0;
00236         epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms
00237         epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
00238         epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
00239         epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
00240         epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = 0;
00241         epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = 0;
00242 
00243         rcode = pUsb->setEpInfoEntry(bAddress, 9, epInfo);
00244         if(rcode)
00245                 goto FailSetDevTblEntry;
00246 
00247         wait_ms(200); //Give time for address change
00248 
00249         rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
00250         if(rcode)
00251                 goto FailSetConfDescr;
00252 
00253 #ifdef DEBUG_USB_HOST
00254         Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80);
00255 #endif
00256         XboxReceiverConnected = true;
00257         bPollEnable = true;
00258         checkStatusTimer = 0; // Reset timer
00259         return 0; // Successful configuration
00260 
00261         /* Diagnostic messages */
00262 FailSetDevTblEntry:
00263 #ifdef DEBUG_USB_HOST
00264         NotifyFailSetDevTblEntry();
00265         goto Fail;
00266 #endif
00267 
00268 FailSetConfDescr:
00269 #ifdef DEBUG_USB_HOST
00270         NotifyFailSetConfDescr();
00271 #endif
00272 
00273 Fail:
00274 #ifdef DEBUG_USB_HOST
00275         Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
00276         NotifyFail(rcode);
00277 #endif
00278         Release();
00279         return rcode;
00280 }
00281 
00282 /* Performs a cleanup after failed Init() attempt */
00283 uint8_t XBOXRECV::Release() {
00284         XboxReceiverConnected = false;
00285         for(uint8_t i = 0; i < 4; i++)
00286                 Xbox360Connected[i] = 0x00;
00287         pUsb->GetAddressPool().FreeAddress(bAddress);
00288         bAddress = 0;
00289         bPollEnable = false;
00290         return 0;
00291 }
00292 
00293 uint8_t XBOXRECV::Poll() {
00294         if(!bPollEnable)
00295                 return 0;
00296         if(!checkStatusTimer || ((int32_t)((uint32_t)millis() - checkStatusTimer) > 3000)) { // Run checkStatus every 3 seconds
00297                 checkStatusTimer = (uint32_t)millis();
00298                 checkStatus();
00299         }
00300 
00301         uint8_t inputPipe;
00302         uint16_t bufferSize;
00303         for(uint8_t i = 0; i < 4; i++) {
00304                 if(i == 0)
00305                         inputPipe = XBOX_INPUT_PIPE_1;
00306                 else if(i == 1)
00307                         inputPipe = XBOX_INPUT_PIPE_2;
00308                 else if(i == 2)
00309                         inputPipe = XBOX_INPUT_PIPE_3;
00310                 else
00311                         inputPipe = XBOX_INPUT_PIPE_4;
00312 
00313                 bufferSize = EP_MAXPKTSIZE; // This is the maximum number of bytes we want to receive
00314                 pUsb->inTransfer(bAddress, epInfo[ inputPipe ].epAddr, &bufferSize, readBuf);
00315                 if(bufferSize > 0) { // The number of received bytes
00316 #ifdef EXTRADEBUG
00317                         Notify(PSTR("Bytes Received: "), 0x80);
00318                         D_PrintHex<uint16_t > (bufferSize, 0x80);
00319                         Notify(PSTR("\r\n"), 0x80);
00320 #endif
00321                         readReport(i);
00322 #ifdef PRINTREPORT
00323                         printReport(i, bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
00324 #endif
00325                 }
00326         }
00327         return 0;
00328 }
00329 
00330 void XBOXRECV::readReport(uint8_t controller) {
00331         if(readBuf == NULL)
00332                 return;
00333         // This report is send when a controller is connected and disconnected
00334         if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
00335                 Xbox360Connected[controller] = readBuf[1];
00336 #ifdef DEBUG_USB_HOST
00337                 Notify(PSTR("Controller "), 0x80);
00338                 Notify(controller, 0x80);
00339 #endif
00340                 if(Xbox360Connected[controller]) {
00341 #ifdef DEBUG_USB_HOST
00342                         const char* str = 0;
00343                         switch(readBuf[1]) {
00344                                 case 0x80: str = PSTR(" as controller\r\n");
00345                                         break;
00346                                 case 0x40: str = PSTR(" as headset\r\n");
00347                                         break;
00348                                 case 0xC0: str = PSTR(" as controller+headset\r\n");
00349                                         break;
00350                         }
00351                         Notify(PSTR(": connected"), 0x80);
00352                         Notify(str, 0x80);
00353 #endif
00354                         onInit(controller);
00355                 }
00356 #ifdef DEBUG_USB_HOST
00357                 else
00358                         Notify(PSTR(": disconnected\r\n"), 0x80);
00359 #endif
00360                 return;
00361         }
00362         // Controller status report
00363         if(readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) {
00364                 controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4];
00365                 return;
00366         }
00367         if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports
00368                 return;
00369 
00370         // A controller must be connected if it's sending data
00371         if(!Xbox360Connected[controller])
00372                 Xbox360Connected[controller] |= 0x80;
00373 
00374         ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24));
00375 
00376         hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
00377         hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
00378         hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
00379         hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
00380 
00381         //Notify(PSTR("\r\nButtonState: "), 0x80);
00382         //PrintHex<uint32_t>(ButtonState[controller], 0x80);
00383 
00384         if(ButtonState[controller] != OldButtonState[controller]) {
00385                 buttonStateChanged[controller] = true;
00386                 ButtonClickState[controller] = (ButtonState[controller] >> 16) & ((~OldButtonState[controller]) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2
00387                 if(((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons
00388                         R2Clicked[controller] = true;
00389                 if((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0)
00390                         L2Clicked[controller] = true;
00391                 OldButtonState[controller] = ButtonState[controller];
00392         }
00393 }
00394 
00395 void XBOXRECV::printReport(uint8_t controller __attribute__((unused)), uint8_t nBytes __attribute__((unused))) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
00396 #ifdef PRINTREPORT
00397         if(readBuf == NULL)
00398                 return;
00399         Notify(PSTR("Controller "), 0x80);
00400         Notify(controller, 0x80);
00401         Notify(PSTR(": "), 0x80);
00402         for(uint8_t i = 0; i < nBytes; i++) {
00403                 D_PrintHex<uint8_t > (readBuf[i], 0x80);
00404                 Notify(PSTR(" "), 0x80);
00405         }
00406         Notify(PSTR("\r\n"), 0x80);
00407 #endif
00408 }
00409 
00410 uint8_t XBOXRECV::getButtonPress(ButtonEnum b, uint8_t controller) {
00411         if(b == L2) // These are analog buttons
00412                 return (uint8_t)(ButtonState[controller] >> 8);
00413         else if(b == R2)
00414                 return (uint8_t)ButtonState[controller];
00415         return (bool)(ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]) << 16));
00416 }
00417 
00418 bool XBOXRECV::getButtonClick(ButtonEnum b, uint8_t controller) {
00419         if(b == L2) {
00420                 if(L2Clicked[controller]) {
00421                         L2Clicked[controller] = false;
00422                         return true;
00423                 }
00424                 return false;
00425         } else if(b == R2) {
00426                 if(R2Clicked[controller]) {
00427                         R2Clicked[controller] = false;
00428                         return true;
00429                 }
00430                 return false;
00431         }
00432         uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
00433         bool click = (ButtonClickState[controller] & button);
00434         ButtonClickState[controller] &= ~button; // clear "click" event
00435         return click;
00436 }
00437 
00438 int16_t XBOXRECV::getAnalogHat(AnalogHatEnum a, uint8_t controller) {
00439         return hatValue[controller][a];
00440 }
00441 
00442 bool XBOXRECV::buttonChanged(uint8_t controller) {
00443         bool state = buttonStateChanged[controller];
00444         buttonStateChanged[controller] = false;
00445         return state;
00446 }
00447 
00448 /*
00449 ControllerStatus Breakdown
00450 ControllerStatus[controller] & 0x0001   // 0
00451 ControllerStatus[controller] & 0x0002   // normal batteries, no rechargeable battery pack
00452 ControllerStatus[controller] & 0x0004   // controller starting up / settling
00453 ControllerStatus[controller] & 0x0008   // headset adapter plugged in, but no headphones connected (mute?)
00454 ControllerStatus[controller] & 0x0010   // 0
00455 ControllerStatus[controller] & 0x0020   // 1
00456 ControllerStatus[controller] & 0x0040   // battery level (high bit)
00457 ControllerStatus[controller] & 0x0080   // battery level (low bit)
00458 ControllerStatus[controller] & 0x0100   // 1
00459 ControllerStatus[controller] & 0x0200   // 1
00460 ControllerStatus[controller] & 0x0400   // headset adapter plugged in
00461 ControllerStatus[controller] & 0x0800   // 0
00462 ControllerStatus[controller] & 0x1000   // 1
00463 ControllerStatus[controller] & 0x2000   // 0
00464 ControllerStatus[controller] & 0x4000   // 0
00465 ControllerStatus[controller] & 0x8000   // 0
00466  */
00467 uint8_t XBOXRECV::getBatteryLevel(uint8_t controller) {
00468         return ((controllerStatus[controller] & 0x00C0) >> 6);
00469 }
00470 
00471 void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) {
00472 #ifdef EXTRADEBUG
00473         uint8_t rcode;
00474 #endif
00475         uint8_t outputPipe;
00476         switch(controller) {
00477                 case 0: outputPipe = XBOX_OUTPUT_PIPE_1;
00478                         break;
00479                 case 1: outputPipe = XBOX_OUTPUT_PIPE_2;
00480                         break;
00481                 case 2: outputPipe = XBOX_OUTPUT_PIPE_3;
00482                         break;
00483                 case 3: outputPipe = XBOX_OUTPUT_PIPE_4;
00484                         break;
00485                 default:
00486                         return;
00487         }
00488 #ifdef EXTRADEBUG
00489         rcode =
00490 #endif
00491                 pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data);
00492 #ifdef EXTRADEBUG
00493         if(rcode)
00494                 Notify(PSTR("Error sending Xbox message\r\n"), 0x80);
00495 #endif
00496 }
00497 
00498 void XBOXRECV::disconnect(uint8_t controller) {
00499         writeBuf[0] = 0x00;
00500         writeBuf[1] = 0x00;
00501         writeBuf[2] = 0x08;
00502         writeBuf[3] = 0xC0;
00503 
00504         XboxCommand(controller, writeBuf, 4);
00505 }
00506 
00507 void XBOXRECV::setLedRaw(uint8_t value, uint8_t controller) {
00508         writeBuf[0] = 0x00;
00509         writeBuf[1] = 0x00;
00510         writeBuf[2] = 0x08;
00511         writeBuf[3] = value | 0x40;
00512 
00513         XboxCommand(controller, writeBuf, 4);
00514 }
00515 
00516 void XBOXRECV::setLedOn(LEDEnum led, uint8_t controller) {
00517         if(led == OFF)
00518                 setLedRaw(0, controller);
00519         else if(led != ALL) // All LEDs can't be on a the same time
00520                 setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]) + 4, controller);
00521 }
00522 
00523 void XBOXRECV::setLedBlink(LEDEnum led, uint8_t controller) {
00524         setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]), controller);
00525 }
00526 
00527 void XBOXRECV::setLedMode(LEDModeEnum ledMode, uint8_t controller) { // This function is used to do some speciel LED stuff the controller supports
00528         setLedRaw((uint8_t)ledMode, controller);
00529 }
00530 
00531 /* PC runs this at interval of approx 2 seconds
00532 Thanks to BusHound from Perisoft.net for the Windows USB Analysis output
00533 Found by timstamp.co.uk
00534  */
00535 void XBOXRECV::checkStatus() {
00536         if(!bPollEnable)
00537                 return;
00538         // Get controller info
00539         writeBuf[0] = 0x08;
00540         writeBuf[1] = 0x00;
00541         writeBuf[2] = 0x0f;
00542         writeBuf[3] = 0xc0;
00543         for(uint8_t i = 0; i < 4; i++) {
00544                 XboxCommand(i, writeBuf, 4);
00545         }
00546         // Get battery status
00547         writeBuf[0] = 0x00;
00548         writeBuf[1] = 0x00;
00549         writeBuf[2] = 0x00;
00550         writeBuf[3] = 0x40;
00551         for(uint8_t i = 0; i < 4; i++) {
00552                 if(Xbox360Connected[i])
00553                         XboxCommand(i, writeBuf, 4);
00554         }
00555 }
00556 
00557 void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) {
00558         writeBuf[0] = 0x00;
00559         writeBuf[1] = 0x01;
00560         writeBuf[2] = 0x0f;
00561         writeBuf[3] = 0xc0;
00562         writeBuf[4] = 0x00;
00563         writeBuf[5] = lValue; // big weight
00564         writeBuf[6] = rValue; // small weight
00565 
00566         XboxCommand(controller, writeBuf, 7);
00567 }
00568 
00569 void XBOXRECV::onInit(uint8_t controller) {
00570         if(pFuncOnInit)
00571                 pFuncOnInit(); // Call the user function
00572         else {
00573                 LEDEnum led;
00574                 if(controller == 0)
00575                         led = static_cast<LEDEnum>(LED1);
00576                 else if(controller == 1)
00577                         led = static_cast<LEDEnum>(LED2);
00578                 else if(controller == 2)
00579                         led = static_cast<LEDEnum>(LED3);
00580                 else
00581                         led = static_cast<LEDEnum>(LED4);
00582                 setLedOn(led, controller);
00583         }
00584 }