Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: UsbHostMAX3421E_Hello
XBOXUSB.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 00018 #include "XBOXUSB.h" 00019 // To enable serial debugging see "settings.h" 00020 //#define EXTRADEBUG // Uncomment to get even more debugging data 00021 //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller 00022 00023 XBOXUSB::XBOXUSB(Usb *p) : 00024 pUsb(p), // pointer to USB class instance - mandatory 00025 bAddress(0), // device address - mandatory 00026 bPollEnable(false) { // don't start polling before dongle is connected 00027 for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) { 00028 epInfo[i].epAddr = 0; 00029 epInfo[i].maxPktSize = (i) ? 0 : 8; 00030 epInfo[i].bmSndToggle = 0; 00031 epInfo[i].bmRcvToggle = 0; 00032 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; 00033 } 00034 00035 if(pUsb) // register in USB subsystem 00036 pUsb->RegisterDeviceClass(this); //set devConfig[] entry 00037 } 00038 00039 uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) { 00040 uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; 00041 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00042 uint8_t rcode; 00043 UsbDevice *p = NULL; 00044 EpInfo *oldep_ptr = NULL; 00045 uint16_t PID; 00046 uint16_t VID; 00047 00048 // get memory address of USB device address pool 00049 AddressPool &addrPool = pUsb->GetAddressPool(); 00050 #ifdef EXTRADEBUG 00051 Notify(PSTR("\r\nXBOXUSB Init"), 0x80); 00052 #endif 00053 // check if address has already been assigned to an instance 00054 if(bAddress) { 00055 #ifdef DEBUG_USB_HOST 00056 Notify(PSTR("\r\nAddress in use"), 0x80); 00057 #endif 00058 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00059 } 00060 00061 // Get pointer to pseudo device with address 0 assigned 00062 p = addrPool.GetUsbDevicePtr(0); 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 // Save old pointer to EP_RECORD of address 0 00079 oldep_ptr = p->epinfo; 00080 00081 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00082 p->epinfo = epInfo; 00083 00084 p->lowspeed = lowspeed; 00085 00086 // Get device descriptor 00087 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data 00088 // Restore p->epinfo 00089 p->epinfo = oldep_ptr; 00090 00091 if(rcode) 00092 goto FailGetDevDescr; 00093 00094 VID = udd->idVendor; 00095 PID = udd->idProduct; 00096 00097 if(VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID && VID != GAMESTOP_VID) // Check VID 00098 goto FailUnknownDevice; 00099 if(PID == XBOX_WIRELESS_PID) { 00100 #ifdef DEBUG_USB_HOST 00101 Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"), 0x80); 00102 #endif 00103 goto FailUnknownDevice; 00104 } else if(PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { 00105 #ifdef DEBUG_USB_HOST 00106 Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80); 00107 #endif 00108 goto FailUnknownDevice; 00109 } else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID && PID != AFTERGLOW_WIRED_PID && PID != JOYTECH_WIRED_PID) // Check PID 00110 goto FailUnknownDevice; 00111 00112 // Allocate new address according to device class 00113 bAddress = addrPool.AllocAddress(parent, false, port); 00114 00115 if(!bAddress) 00116 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00117 00118 // Extract Max Packet Size from device descriptor 00119 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00120 00121 // Assign new address to the device 00122 rcode = pUsb->setAddr(0, 0, bAddress); 00123 if(rcode) { 00124 p->lowspeed = false; 00125 addrPool.FreeAddress(bAddress); 00126 bAddress = 0; 00127 #ifdef DEBUG_USB_HOST 00128 Notify(PSTR("\r\nsetAddr: "), 0x80); 00129 D_PrintHex<uint8_t > (rcode, 0x80); 00130 #endif 00131 return rcode; 00132 } 00133 #ifdef EXTRADEBUG 00134 Notify(PSTR("\r\nAddr: "), 0x80); 00135 D_PrintHex<uint8_t > (bAddress, 0x80); 00136 #endif 00137 //wait_ms(300); // Spec says you should wait at least 200ms 00138 00139 p->lowspeed = false; 00140 00141 //get pointer to assigned address record 00142 p = addrPool.GetUsbDevicePtr(bAddress); 00143 if(!p) 00144 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00145 00146 p->lowspeed = lowspeed; 00147 00148 // Assign epInfo to epinfo pointer - only EP0 is known 00149 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); 00150 if(rcode) 00151 goto FailSetDevTblEntry; 00152 00153 /* The application will work in reduced host mode, so we can save program and data 00154 memory space. After verifying the VID we will use known values for the 00155 configuration values for device, interface, endpoints and HID for the XBOX360 Controllers */ 00156 00157 /* Initialize data structures for endpoints of device */ 00158 epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 report endpoint 00159 epInfo[ XBOX_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; 00160 epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints 00161 epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; 00162 epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = 0; 00163 epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = 0; 00164 epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint 00165 epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; 00166 epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints 00167 epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; 00168 epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = 0; 00169 epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = 0; 00170 00171 rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); 00172 if(rcode) 00173 goto FailSetDevTblEntry; 00174 00175 wait_ms(200); // Give time for address change 00176 00177 rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1); 00178 if(rcode) 00179 goto FailSetConfDescr; 00180 00181 #ifdef DEBUG_USB_HOST 00182 Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80); 00183 #endif 00184 onInit(); 00185 Xbox360Connected = true; 00186 bPollEnable = true; 00187 return 0; // Successful configuration 00188 00189 /* Diagnostic messages */ 00190 FailGetDevDescr: 00191 #ifdef DEBUG_USB_HOST 00192 NotifyFailGetDevDescr(); 00193 goto Fail; 00194 #endif 00195 00196 FailSetDevTblEntry: 00197 #ifdef DEBUG_USB_HOST 00198 NotifyFailSetDevTblEntry(); 00199 goto Fail; 00200 #endif 00201 00202 FailSetConfDescr: 00203 #ifdef DEBUG_USB_HOST 00204 NotifyFailSetConfDescr(); 00205 #endif 00206 goto Fail; 00207 00208 FailUnknownDevice: 00209 #ifdef DEBUG_USB_HOST 00210 NotifyFailUnknownDevice(VID, PID); 00211 #endif 00212 rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00213 00214 Fail: 00215 #ifdef DEBUG_USB_HOST 00216 Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80); 00217 NotifyFail(rcode); 00218 #endif 00219 Release(); 00220 return rcode; 00221 } 00222 00223 /* Performs a cleanup after failed Init() attempt */ 00224 uint8_t XBOXUSB::Release() { 00225 Xbox360Connected = false; 00226 pUsb->GetAddressPool().FreeAddress(bAddress); 00227 bAddress = 0; 00228 bPollEnable = false; 00229 return 0; 00230 } 00231 00232 uint8_t XBOXUSB::Poll() { 00233 if(!bPollEnable) 00234 return 0; 00235 uint16_t BUFFER_SIZE = EP_MAXPKTSIZE; 00236 pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1 00237 readReport(); 00238 #ifdef PRINTREPORT 00239 printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller 00240 #endif 00241 return 0; 00242 } 00243 00244 void XBOXUSB::readReport() { 00245 if(readBuf == NULL) 00246 return; 00247 if(readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports 00248 return; 00249 } 00250 00251 ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24)); 00252 00253 hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]); 00254 hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]); 00255 hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); 00256 hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); 00257 00258 //Notify(PSTR("\r\nButtonState"), 0x80); 00259 //PrintHex<uint32_t>(ButtonState, 0x80); 00260 00261 if(ButtonState != OldButtonState) { 00262 ButtonClickState = (ButtonState >> 16) & ((~OldButtonState) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2 00263 if(((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons 00264 R2Clicked = true; 00265 if((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0) 00266 L2Clicked = true; 00267 OldButtonState = ButtonState; 00268 } 00269 } 00270 00271 void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller 00272 #ifdef PRINTREPORT 00273 if(readBuf == NULL) 00274 return; 00275 for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) { 00276 D_PrintHex<uint8_t > (readBuf[i], 0x80); 00277 Notify(PSTR(" "), 0x80); 00278 } 00279 Notify(PSTR("\r\n"), 0x80); 00280 #endif 00281 } 00282 00283 uint8_t XBOXUSB::getButtonPress(ButtonEnum b) { 00284 if(b == L2) // These are analog buttons 00285 return (uint8_t)(ButtonState >> 8); 00286 else if(b == R2) 00287 return (uint8_t)ButtonState; 00288 return (bool)(ButtonState & ((uint32_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]) << 16)); 00289 } 00290 00291 bool XBOXUSB::getButtonClick(ButtonEnum b) { 00292 if(b == L2) { 00293 if(L2Clicked) { 00294 L2Clicked = false; 00295 return true; 00296 } 00297 return false; 00298 } else if(b == R2) { 00299 if(R2Clicked) { 00300 R2Clicked = false; 00301 return true; 00302 } 00303 return false; 00304 } 00305 uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]); 00306 bool click = (ButtonClickState & button); 00307 ButtonClickState &= ~button; // clear "click" event 00308 return click; 00309 } 00310 00311 int16_t XBOXUSB::getAnalogHat(AnalogHatEnum a) { 00312 return hatValue[a]; 00313 } 00314 00315 /* Xbox Controller commands */ 00316 void XBOXUSB::XboxCommand(uint8_t* data, uint16_t nbytes) { 00317 //bmRequest = Host to device (0x00) | Class (0x20) | Interface (0x01) = 0x21, bRequest = Set Report (0x09), Report ID (0x00), Report Type (Output 0x02), interface (0x00), datalength, datalength, data) 00318 pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL); 00319 } 00320 00321 void XBOXUSB::setLedRaw(uint8_t value) { 00322 writeBuf[0] = 0x01; 00323 writeBuf[1] = 0x03; 00324 writeBuf[2] = value; 00325 00326 XboxCommand(writeBuf, 3); 00327 } 00328 00329 void XBOXUSB::setLedOn(LEDEnum led) { 00330 if(led == OFF) 00331 setLedRaw(0); 00332 else if(led != ALL) // All LEDs can't be on a the same time 00333 setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]) + 4); 00334 } 00335 00336 void XBOXUSB::setLedBlink(LEDEnum led) { 00337 setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led])); 00338 } 00339 00340 void XBOXUSB::setLedMode(LEDModeEnum ledMode) { // This function is used to do some special LED stuff the controller supports 00341 setLedRaw((uint8_t)ledMode); 00342 } 00343 00344 void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) { 00345 writeBuf[0] = 0x00; 00346 writeBuf[1] = 0x08; 00347 writeBuf[2] = 0x00; 00348 writeBuf[3] = lValue; // big weight 00349 writeBuf[4] = rValue; // small weight 00350 writeBuf[5] = 0x00; 00351 writeBuf[6] = 0x00; 00352 writeBuf[7] = 0x00; 00353 00354 XboxCommand(writeBuf, 8); 00355 } 00356 00357 void XBOXUSB::onInit() { 00358 if(pFuncOnInit) 00359 pFuncOnInit(); // Call the user function 00360 else 00361 setLedOn(static_cast<LEDEnum>(LED1)); 00362 }
Generated on Tue Jul 12 2022 18:12:05 by
