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
XBOXOLD.cpp
00001 /* Copyright (C) 2013 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 "XBOXOLD.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 controller 00022 00023 /** Buttons on the controllers */ 00024 const uint8_t XBOXOLD_BUTTONS[] PROGMEM = { 00025 0x01, // UP 00026 0x08, // RIGHT 00027 0x02, // DOWN 00028 0x04, // LEFT 00029 00030 0x20, // BACK 00031 0x10, // START 00032 0x40, // L3 00033 0x80, // R3 00034 00035 // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons 00036 4, // BLACK 00037 5, // WHTIE 00038 6, // L1 00039 7, // R1 00040 00041 1, // B 00042 0, // A 00043 2, // X 00044 3, // Y 00045 }; 00046 00047 XBOXOLD::XBOXOLD(Usb *p) : 00048 pUsb(p), // pointer to USB class instance - mandatory 00049 bAddress(0), // device address - mandatory 00050 bPollEnable(false) { // don't start polling before dongle is connected 00051 for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) { 00052 epInfo[i].epAddr = 0; 00053 epInfo[i].maxPktSize = (i) ? 0 : 8; 00054 epInfo[i].bmSndToggle = 0; 00055 epInfo[i].bmRcvToggle = 0; 00056 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; 00057 } 00058 00059 if(pUsb) // register in USB subsystem 00060 pUsb->RegisterDeviceClass(this); //set devConfig[] entry 00061 } 00062 00063 uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) { 00064 uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; 00065 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00066 uint8_t rcode; 00067 UsbDevice *p = NULL; 00068 EpInfo *oldep_ptr = NULL; 00069 uint16_t PID; 00070 uint16_t VID; 00071 00072 // get memory address of USB device address pool 00073 AddressPool &addrPool = pUsb->GetAddressPool(); 00074 #ifdef EXTRADEBUG 00075 Notify(PSTR("\r\nXBOXUSB Init"), 0x80); 00076 #endif 00077 // check if address has already been assigned to an instance 00078 if(bAddress) { 00079 #ifdef DEBUG_USB_HOST 00080 Notify(PSTR("\r\nAddress in use"), 0x80); 00081 #endif 00082 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00083 } 00084 00085 // Get pointer to pseudo device with address 0 assigned 00086 p = addrPool.GetUsbDevicePtr(0); 00087 00088 if(!p) { 00089 #ifdef DEBUG_USB_HOST 00090 Notify(PSTR("\r\nAddress not found"), 0x80); 00091 #endif 00092 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00093 } 00094 00095 if(!p->epinfo) { 00096 #ifdef DEBUG_USB_HOST 00097 Notify(PSTR("\r\nepinfo is null"), 0x80); 00098 #endif 00099 return USB_ERROR_EPINFO_IS_NULL; 00100 } 00101 00102 // Save old pointer to EP_RECORD of address 0 00103 oldep_ptr = p->epinfo; 00104 00105 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00106 p->epinfo = epInfo; 00107 00108 p->lowspeed = lowspeed; 00109 00110 // Get device descriptor 00111 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data 00112 // Restore p->epinfo 00113 p->epinfo = oldep_ptr; 00114 00115 if(rcode) 00116 goto FailGetDevDescr; 00117 00118 VID = udd->idVendor; 00119 PID = udd->idProduct; 00120 00121 if((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_OLD_PID1 && PID != XBOX_OLD_PID2 && PID != XBOX_OLD_PID3 && PID != XBOX_OLD_PID4)) // Check if VID and PID match 00122 goto FailUnknownDevice; 00123 00124 // Allocate new address according to device class 00125 bAddress = addrPool.AllocAddress(parent, false, port); 00126 00127 if(!bAddress) 00128 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00129 00130 // Extract Max Packet Size from device descriptor 00131 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00132 00133 // Assign new address to the device 00134 rcode = pUsb->setAddr(0, 0, bAddress); 00135 if(rcode) { 00136 p->lowspeed = false; 00137 addrPool.FreeAddress(bAddress); 00138 bAddress = 0; 00139 #ifdef DEBUG_USB_HOST 00140 Notify(PSTR("\r\nsetAddr: "), 0x80); 00141 D_PrintHex<uint8_t > (rcode, 0x80); 00142 #endif 00143 return rcode; 00144 } 00145 #ifdef EXTRADEBUG 00146 Notify(PSTR("\r\nAddr: "), 0x80); 00147 D_PrintHex<uint8_t > (bAddress, 0x80); 00148 #endif 00149 //wait_ms(300); // Spec says you should wait at least 200ms 00150 00151 p->lowspeed = false; 00152 00153 //get pointer to assigned address record 00154 p = addrPool.GetUsbDevicePtr(bAddress); 00155 if(!p) 00156 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00157 00158 p->lowspeed = lowspeed; 00159 00160 // Assign epInfo to epinfo pointer - only EP0 is known 00161 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); 00162 if(rcode) 00163 goto FailSetDevTblEntry; 00164 00165 /* The application will work in reduced host mode, so we can save program and data 00166 memory space. After verifying the VID we will use known values for the 00167 configuration values for device, interface, endpoints and HID for the XBOX controllers */ 00168 00169 /* Initialize data structures for endpoints of device */ 00170 epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX report endpoint 00171 epInfo[ XBOX_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; 00172 epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints 00173 epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; 00174 epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = 0; 00175 epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = 0; 00176 epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX output endpoint 00177 epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; 00178 epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints 00179 epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; 00180 epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = 0; 00181 epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = 0; 00182 00183 rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo); 00184 if(rcode) 00185 goto FailSetDevTblEntry; 00186 00187 wait_ms(200); // Give time for address change 00188 00189 rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1); 00190 if(rcode) 00191 goto FailSetConfDescr; 00192 00193 #ifdef DEBUG_USB_HOST 00194 Notify(PSTR("\r\nXbox Controller Connected\r\n"), 0x80); 00195 #endif 00196 if(pFuncOnInit) 00197 pFuncOnInit(); // Call the user function 00198 XboxConnected = true; 00199 bPollEnable = true; 00200 return 0; // Successful configuration 00201 00202 /* Diagnostic messages */ 00203 FailGetDevDescr: 00204 #ifdef DEBUG_USB_HOST 00205 NotifyFailGetDevDescr(); 00206 goto Fail; 00207 #endif 00208 00209 FailSetDevTblEntry: 00210 #ifdef DEBUG_USB_HOST 00211 NotifyFailSetDevTblEntry(); 00212 goto Fail; 00213 #endif 00214 00215 FailSetConfDescr: 00216 #ifdef DEBUG_USB_HOST 00217 NotifyFailSetConfDescr(); 00218 #endif 00219 goto Fail; 00220 00221 FailUnknownDevice: 00222 #ifdef DEBUG_USB_HOST 00223 NotifyFailUnknownDevice(VID, PID); 00224 #endif 00225 rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00226 00227 Fail: 00228 #ifdef DEBUG_USB_HOST 00229 Notify(PSTR("\r\nXbox Init Failed, error code: "), 0x80); 00230 NotifyFail(rcode); 00231 #endif 00232 Release(); 00233 return rcode; 00234 } 00235 00236 /* Performs a cleanup after failed Init() attempt */ 00237 uint8_t XBOXOLD::Release() { 00238 XboxConnected = false; 00239 pUsb->GetAddressPool().FreeAddress(bAddress); 00240 bAddress = 0; 00241 bPollEnable = false; 00242 return 0; 00243 } 00244 00245 uint8_t XBOXOLD::Poll() { 00246 if(!bPollEnable) 00247 return 0; 00248 uint16_t BUFFER_SIZE = EP_MAXPKTSIZE; 00249 pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1 00250 readReport(); 00251 #ifdef PRINTREPORT 00252 printReport(BUFFER_SIZE); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller 00253 #endif 00254 return 0; 00255 } 00256 00257 void XBOXOLD::readReport() { 00258 ButtonState = readBuf[2]; 00259 00260 for(uint8_t i = 0; i < sizeof (buttonValues); i++) 00261 buttonValues[i] = readBuf[i + 4]; // A, B, X, Y, BLACK, WHITE, L1, and R1 00262 00263 hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[12] << 8) | readBuf[13]); 00264 hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[14] << 8) | readBuf[15]); 00265 hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[16] << 8) | readBuf[17]); 00266 hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[18] << 8) | readBuf[19]); 00267 00268 //Notify(PSTR("\r\nButtonState"), 0x80); 00269 //PrintHex<uint8_t>(ButtonState, 0x80); 00270 00271 if(ButtonState != OldButtonState || memcmp(buttonValues, oldButtonValues, sizeof (buttonValues)) != 0) { 00272 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable 00273 OldButtonState = ButtonState; 00274 00275 for(uint8_t i = 0; i < sizeof (buttonValues); i++) { 00276 if(oldButtonValues[i] == 0 && buttonValues[i] != 0) 00277 buttonClicked[i] = true; // Update A, B, X, Y, BLACK, WHITE, L1, and R1 click state 00278 oldButtonValues[i] = buttonValues[i]; 00279 } 00280 } 00281 } 00282 00283 void XBOXOLD::printReport(uint16_t length __attribute__((unused))) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller 00284 #ifdef PRINTREPORT 00285 if(readBuf == NULL) 00286 return; 00287 for(uint8_t i = 0; i < length; i++) { 00288 D_PrintHex<uint8_t > (readBuf[i], 0x80); 00289 Notify(PSTR(" "), 0x80); 00290 } 00291 Notify(PSTR("\r\n"), 0x80); 00292 #endif 00293 } 00294 00295 uint8_t XBOXOLD::getButtonPress(ButtonEnum b) { 00296 uint8_t button = pgm_read_byte(&XBOXOLD_BUTTONS[(uint8_t)b]); 00297 if(b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons 00298 return buttonValues[button]; // Analog buttons 00299 return (ButtonState & button); // Digital buttons 00300 } 00301 00302 bool XBOXOLD::getButtonClick(ButtonEnum b) { 00303 uint8_t button = pgm_read_byte(&XBOXOLD_BUTTONS[(uint8_t)b]); 00304 if(b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons 00305 if(buttonClicked[button]) { 00306 buttonClicked[button] = false; 00307 return true; 00308 } 00309 return false; 00310 } 00311 00312 bool click = (ButtonClickState & button); 00313 ButtonClickState &= ~button; // clear "click" event 00314 return click; 00315 } 00316 00317 int16_t XBOXOLD::getAnalogHat(AnalogHatEnum a) { 00318 return hatValue[a]; 00319 } 00320 00321 /* Xbox Controller commands */ 00322 void XBOXOLD::XboxCommand(uint8_t* data, uint16_t nbytes) { 00323 //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) 00324 pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL); 00325 } 00326 00327 void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) { 00328 uint8_t writeBuf[6]; 00329 00330 writeBuf[0] = 0x00; 00331 writeBuf[1] = 0x06; 00332 writeBuf[2] = 0x00; 00333 writeBuf[3] = rValue; // small weight 00334 writeBuf[4] = 0x00; 00335 writeBuf[5] = lValue; // big weight 00336 00337 XboxCommand(writeBuf, 6); 00338 }
Generated on Tue Jul 12 2022 18:12:05 by
1.7.2