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
XBOXONE.cpp
00001 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved. 00002 Copyright (C) 2015 guruthree 00003 00004 This software may be distributed and modified under the terms of the GNU 00005 General Public License version 2 (GPL2) as published by the Free Software 00006 Foundation and appearing in the file GPL2.TXT included in the packaging of 00007 this file. Please note that GPL2 Section 2[b] requires that all works based 00008 on this software must also be made publicly available under the terms of 00009 the GPL2 ("Copyleft"). 00010 00011 Contact information 00012 ------------------- 00013 00014 Kristian Lauszus, TKJ Electronics 00015 Web : http://www.tkjelectronics.com 00016 e-mail : kristianl@tkjelectronics.com 00017 00018 guruthree 00019 Web : https://github.com/guruthree/ 00020 */ 00021 00022 #include "XBOXONE.h" 00023 // To enable serial debugging see "settings.h" 00024 //#define EXTRADEBUG // Uncomment to get even more debugging data 00025 //#define PRINTREPORT // Uncomment to print the report send by the Xbox ONE Controller 00026 00027 XBOXONE::XBOXONE(Usb *p) : 00028 pUsb(p), // pointer to USB class instance - mandatory 00029 bAddress(0), // device address - mandatory 00030 bNumEP(1), // If config descriptor needs to be parsed 00031 qNextPollTime(0), // Reset NextPollTime 00032 pollInterval(0), 00033 bPollEnable(false) { // don't start polling before dongle is connected 00034 for(uint8_t i = 0; i < XBOX_ONE_MAX_ENDPOINTS; i++) { 00035 epInfo[i].epAddr = 0; 00036 epInfo[i].maxPktSize = (i) ? 0 : 8; 00037 epInfo[i].bmSndToggle = 0; 00038 epInfo[i].bmRcvToggle = 0; 00039 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; 00040 } 00041 00042 if(pUsb) // register in USB subsystem 00043 pUsb->RegisterDeviceClass(this); //set devConfig[] entry 00044 } 00045 00046 uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) { 00047 uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)]; 00048 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf); 00049 uint8_t rcode; 00050 UsbDevice *p = NULL; 00051 EpInfo *oldep_ptr = NULL; 00052 uint16_t PID, VID; 00053 uint8_t num_of_conf; // Number of configurations 00054 00055 // get memory address of USB device address pool 00056 AddressPool &addrPool = pUsb->GetAddressPool(); 00057 #ifdef EXTRADEBUG 00058 Notify(PSTR("\r\nXBOXONE Init"), 0x80); 00059 #endif 00060 // check if address has already been assigned to an instance 00061 if(bAddress) { 00062 #ifdef DEBUG_USB_HOST 00063 Notify(PSTR("\r\nAddress in use"), 0x80); 00064 #endif 00065 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; 00066 } 00067 00068 // Get pointer to pseudo device with address 0 assigned 00069 p = addrPool.GetUsbDevicePtr(0); 00070 00071 if(!p) { 00072 #ifdef DEBUG_USB_HOST 00073 Notify(PSTR("\r\nAddress not found"), 0x80); 00074 #endif 00075 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00076 } 00077 00078 if(!p->epinfo) { 00079 #ifdef DEBUG_USB_HOST 00080 Notify(PSTR("\r\nepinfo is null"), 0x80); 00081 #endif 00082 return USB_ERROR_EPINFO_IS_NULL; 00083 } 00084 00085 // Save old pointer to EP_RECORD of address 0 00086 oldep_ptr = p->epinfo; 00087 00088 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence 00089 p->epinfo = epInfo; 00090 00091 p->lowspeed = lowspeed; 00092 00093 // Get device descriptor 00094 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data 00095 // Restore p->epinfo 00096 p->epinfo = oldep_ptr; 00097 00098 if(rcode) 00099 goto FailGetDevDescr; 00100 00101 VID = udd->idVendor; 00102 PID = udd->idProduct; 00103 00104 if(!VIDPIDOK(VID, PID)) // Check VID 00105 goto FailUnknownDevice; 00106 00107 // Allocate new address according to device class 00108 bAddress = addrPool.AllocAddress(parent, false, port); 00109 00110 if(!bAddress) 00111 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; 00112 00113 // Extract Max Packet Size from device descriptor 00114 epInfo[0].maxPktSize = udd->bMaxPacketSize0; 00115 00116 // Assign new address to the device 00117 rcode = pUsb->setAddr(0, 0, bAddress); 00118 if(rcode) { 00119 p->lowspeed = false; 00120 addrPool.FreeAddress(bAddress); 00121 bAddress = 0; 00122 #ifdef DEBUG_USB_HOST 00123 Notify(PSTR("\r\nsetAddr: "), 0x80); 00124 D_PrintHex<uint8_t > (rcode, 0x80); 00125 #endif 00126 return rcode; 00127 } 00128 #ifdef EXTRADEBUG 00129 Notify(PSTR("\r\nAddr: "), 0x80); 00130 D_PrintHex<uint8_t > (bAddress, 0x80); 00131 #endif 00132 //wait_ms(300); // Spec says you should wait at least 200ms 00133 00134 p->lowspeed = false; 00135 00136 //get pointer to assigned address record 00137 p = addrPool.GetUsbDevicePtr(bAddress); 00138 if(!p) 00139 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; 00140 00141 p->lowspeed = lowspeed; 00142 00143 // Assign epInfo to epinfo pointer - only EP0 is known 00144 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); 00145 if(rcode) 00146 goto FailSetDevTblEntry; 00147 00148 num_of_conf = udd->bNumConfigurations; // Number of configurations 00149 00150 USBTRACE2("NC:", num_of_conf); 00151 00152 // Check if attached device is a Xbox One controller and fill endpoint data structure 00153 for(uint8_t i = 0; i < num_of_conf; i++) { 00154 ConfigDescParser<0, 0, 0, 0> confDescrParser(this); // Allow all devices, as we have already verified that it is a Xbox One controller from the VID and PID 00155 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser); 00156 if(rcode) // Check error code 00157 goto FailGetConfDescr; 00158 if(bNumEP >= XBOX_ONE_MAX_ENDPOINTS) // All endpoints extracted 00159 break; 00160 } 00161 00162 if(bNumEP < XBOX_ONE_MAX_ENDPOINTS) 00163 goto FailUnknownDevice; 00164 00165 rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo); 00166 if(rcode) 00167 goto FailSetDevTblEntry; 00168 00169 wait_ms(200); // Give time for address change 00170 00171 rcode = pUsb->setConf(bAddress, epInfo[ XBOX_ONE_CONTROL_PIPE ].epAddr, bConfNum); 00172 if(rcode) 00173 goto FailSetConfDescr; 00174 00175 #ifdef DEBUG_USB_HOST 00176 Notify(PSTR("\r\nXbox One Controller Connected\r\n"), 0x80); 00177 #endif 00178 00179 wait_ms(200); // let things settle 00180 00181 // Initialize the controller for input 00182 cmdCounter = 0; // Reset the counter used when sending out the commands 00183 uint8_t writeBuf[5]; 00184 writeBuf[0] = 0x05; 00185 writeBuf[1] = 0x20; 00186 // Byte 2 is set in "XboxCommand" 00187 writeBuf[3] = 0x01; 00188 writeBuf[4] = 0x00; 00189 rcode = XboxCommand(writeBuf, 5); 00190 if (rcode) 00191 goto Fail; 00192 00193 onInit(); 00194 XboxOneConnected = true; 00195 bPollEnable = true; 00196 return 0; // Successful configuration 00197 00198 /* Diagnostic messages */ 00199 FailGetDevDescr: 00200 #ifdef DEBUG_USB_HOST 00201 NotifyFailGetDevDescr(); 00202 goto Fail; 00203 #endif 00204 00205 FailSetDevTblEntry: 00206 #ifdef DEBUG_USB_HOST 00207 NotifyFailSetDevTblEntry(); 00208 goto Fail; 00209 #endif 00210 00211 FailGetConfDescr: 00212 #ifdef DEBUG_USB_HOST 00213 NotifyFailGetConfDescr(); 00214 goto Fail; 00215 #endif 00216 00217 FailSetConfDescr: 00218 #ifdef DEBUG_USB_HOST 00219 NotifyFailSetConfDescr(); 00220 #endif 00221 goto Fail; 00222 00223 FailUnknownDevice: 00224 #ifdef DEBUG_USB_HOST 00225 NotifyFailUnknownDevice(VID, PID); 00226 #endif 00227 rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; 00228 00229 Fail: 00230 #ifdef DEBUG_USB_HOST 00231 Notify(PSTR("\r\nXbox One Init Failed, error code: "), 0x80); 00232 NotifyFail(rcode); 00233 #endif 00234 Release(); 00235 return rcode; 00236 } 00237 00238 /* Extracts endpoint information from config descriptor */ 00239 void XBOXONE::EndpointXtract(uint8_t conf, 00240 uint8_t iface __attribute__((unused)), 00241 uint8_t alt __attribute__((unused)), 00242 uint8_t proto __attribute__((unused)), 00243 const USB_ENDPOINT_DESCRIPTOR *pep) 00244 { 00245 00246 bConfNum = conf; 00247 uint8_t index; 00248 00249 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT) { // Interrupt endpoint 00250 index = (pep->bEndpointAddress & 0x80) == 0x80 ? XBOX_ONE_INPUT_PIPE : XBOX_ONE_OUTPUT_PIPE; // Set the endpoint index 00251 } else 00252 return; 00253 00254 // Fill the rest of endpoint data structure 00255 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F); 00256 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize; 00257 #ifdef EXTRADEBUG 00258 PrintEndpointDescriptor(pep); 00259 #endif 00260 if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints 00261 pollInterval = pep->bInterval; 00262 bNumEP++; 00263 } 00264 00265 void XBOXONE::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr 00266 __attribute__((unused))) 00267 { 00268 #ifdef EXTRADEBUG 00269 Notify(PSTR("\r\nEndpoint descriptor:"), 0x80); 00270 Notify(PSTR("\r\nLength:\t\t"), 0x80); 00271 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80); 00272 Notify(PSTR("\r\nType:\t\t"), 0x80); 00273 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80); 00274 Notify(PSTR("\r\nAddress:\t"), 0x80); 00275 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80); 00276 Notify(PSTR("\r\nAttributes:\t"), 0x80); 00277 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80); 00278 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80); 00279 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80); 00280 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80); 00281 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80); 00282 #endif 00283 } 00284 00285 /* Performs a cleanup after failed Init() attempt */ 00286 uint8_t XBOXONE::Release() { 00287 XboxOneConnected = false; 00288 pUsb->GetAddressPool().FreeAddress(bAddress); 00289 bAddress = 0; // Clear device address 00290 bNumEP = 1; // Must have to be reset to 1 00291 qNextPollTime = 0; // Reset next poll time 00292 pollInterval = 0; 00293 bPollEnable = false; 00294 #ifdef DEBUG_USB_HOST 00295 Notify(PSTR("\r\nXbox One Controller Disconnected\r\n"), 0x80); 00296 #endif 00297 return 0; 00298 } 00299 00300 uint8_t XBOXONE::Poll() { 00301 uint8_t rcode = 0; 00302 00303 if(!bPollEnable) 00304 return 0; 00305 00306 if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Do not poll if shorter than polling interval 00307 qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time 00308 uint16_t length = (uint16_t)epInfo[ XBOX_ONE_INPUT_PIPE ].maxPktSize; // Read the maximum packet size from the endpoint 00309 uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ XBOX_ONE_INPUT_PIPE ].epAddr, &length, readBuf, pollInterval); 00310 if(!rcode) { 00311 readReport(); 00312 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller 00313 for(uint8_t i = 0; i < length; i++) { 00314 D_PrintHex<uint8_t > (readBuf[i], 0x80); 00315 Notify(PSTR(" "), 0x80); 00316 } 00317 Notify(PSTR("\r\n"), 0x80); 00318 #endif 00319 } 00320 #ifdef DEBUG_USB_HOST 00321 else if(rcode != hrNAK) { // Not a matter of no update to send 00322 Notify(PSTR("\r\nXbox One Poll Failed, error code: "), 0x80); 00323 NotifyFail(rcode); 00324 } 00325 #endif 00326 } 00327 return rcode; 00328 } 00329 00330 void XBOXONE::readReport() { 00331 if(readBuf[0] == 0x07) { 00332 // The XBOX button has a separate message 00333 if(readBuf[4] == 1) 00334 ButtonState |= pgm_read_word(&XBOX_BUTTONS[XBOX]); 00335 else 00336 ButtonState &= ~pgm_read_word(&XBOX_BUTTONS[XBOX]); 00337 00338 if(ButtonState != OldButtonState) { 00339 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable 00340 OldButtonState = ButtonState; 00341 } 00342 } 00343 if(readBuf[0] != 0x20) { // Check if it's the correct report, otherwise return - the controller also sends different status reports 00344 #ifdef EXTRADEBUG 00345 Notify(PSTR("\r\nXbox Poll: "), 0x80); 00346 D_PrintHex<uint8_t > (readBuf[0], 0x80); // 0x03 is a heart beat report! 00347 #endif 00348 return; 00349 } 00350 00351 uint16_t xbox = ButtonState & pgm_read_word(&XBOX_BUTTONS[XBOX]); // Since the XBOX button is separate, save it and add it back in 00352 // xbox button from before, dpad, abxy, start/back, sync, stick click, shoulder buttons 00353 ButtonState = xbox | (((uint16_t)readBuf[5] & 0xF) << 8) | (readBuf[4] & 0xF0) | (((uint16_t)readBuf[4] & 0x0C) << 10) | ((readBuf[4] & 0x01) << 3) | (((uint16_t)readBuf[5] & 0xC0) << 8) | ((readBuf[5] & 0x30) >> 4); 00354 00355 triggerValue[0] = (uint16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]); 00356 triggerValue[1] = (uint16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]); 00357 00358 hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]); 00359 hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]); 00360 hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]); 00361 hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]); 00362 00363 //Notify(PSTR("\r\nButtonState"), 0x80); 00364 //PrintHex<uint16_t>(ButtonState, 0x80); 00365 00366 if(ButtonState != OldButtonState) { 00367 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable 00368 OldButtonState = ButtonState; 00369 } 00370 00371 // Handle click detection for triggers 00372 if(triggerValue[0] != 0 && triggerValueOld[0] == 0) 00373 L2Clicked = true; 00374 triggerValueOld[0] = triggerValue[0]; 00375 if(triggerValue[1] != 0 && triggerValueOld[1] == 0) 00376 R2Clicked = true; 00377 triggerValueOld[1] = triggerValue[1]; 00378 } 00379 00380 uint16_t XBOXONE::getButtonPress(ButtonEnum b) { 00381 if(b == L2) // These are analog buttons 00382 return triggerValue[0]; 00383 else if(b == R2) 00384 return triggerValue[1]; 00385 return (bool)(ButtonState & ((uint16_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]))); 00386 } 00387 00388 bool XBOXONE::getButtonClick(ButtonEnum b) { 00389 if(b == L2) { 00390 if(L2Clicked) { 00391 L2Clicked = false; 00392 return true; 00393 } 00394 return false; 00395 } else if(b == R2) { 00396 if(R2Clicked) { 00397 R2Clicked = false; 00398 return true; 00399 } 00400 return false; 00401 } 00402 uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]); 00403 bool click = (ButtonClickState & button); 00404 ButtonClickState &= ~button; // Clear "click" event 00405 return click; 00406 } 00407 00408 int16_t XBOXONE::getAnalogHat(AnalogHatEnum a) { 00409 return hatValue[a]; 00410 } 00411 00412 /* Xbox Controller commands */ 00413 uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) { 00414 data[2] = cmdCounter++; // Increment the output command counter 00415 uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_ONE_OUTPUT_PIPE ].epAddr, nbytes, data); 00416 #ifdef DEBUG_USB_HOST 00417 Notify(PSTR("\r\nXboxCommand, Return: "), 0x80); 00418 D_PrintHex<uint8_t > (rcode, 0x80); 00419 #endif 00420 return rcode; 00421 } 00422 00423 // The Xbox One packets are described at: https://github.com/quantus/xbox-one-controller-protocol 00424 void XBOXONE::onInit() { 00425 // A short buzz to show the controller is active 00426 uint8_t writeBuf[13]; 00427 00428 // Activate rumble 00429 writeBuf[0] = 0x09; 00430 writeBuf[1] = 0x00; 00431 // Byte 2 is set in "XboxCommand" 00432 00433 // Single rumble effect 00434 writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has) 00435 writeBuf[4] = 0x00; // Mode 00436 writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R) 00437 writeBuf[6] = 0x04; // lT force 00438 writeBuf[7] = 0x04; // rT force 00439 writeBuf[8] = 0x20; // L force 00440 writeBuf[9] = 0x20; // R force 00441 writeBuf[10] = 0x80; // Length of pulse 00442 writeBuf[11] = 0x00; // Off period 00443 writeBuf[12] = 0x00; // Repeat count 00444 XboxCommand(writeBuf, 13); 00445 00446 if(pFuncOnInit) 00447 pFuncOnInit(); // Call the user function 00448 } 00449 00450 void XBOXONE::setRumbleOff() { 00451 uint8_t writeBuf[13]; 00452 00453 // Activate rumble 00454 writeBuf[0] = 0x09; 00455 writeBuf[1] = 0x00; 00456 // Byte 2 is set in "XboxCommand" 00457 00458 // Continuous rumble effect 00459 writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has) 00460 writeBuf[4] = 0x00; // Mode 00461 writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R) 00462 writeBuf[6] = 0x00; // lT force 00463 writeBuf[7] = 0x00; // rT force 00464 writeBuf[8] = 0x00; // L force 00465 writeBuf[9] = 0x00; // R force 00466 writeBuf[10] = 0x00; // On period 00467 writeBuf[11] = 0x00; // Off period 00468 writeBuf[12] = 0x00; // Repeat count 00469 XboxCommand(writeBuf, 13); 00470 } 00471 00472 void XBOXONE::setRumbleOn(uint8_t leftTrigger, uint8_t rightTrigger, uint8_t leftMotor, uint8_t rightMotor) { 00473 uint8_t writeBuf[13]; 00474 00475 // Activate rumble 00476 writeBuf[0] = 0x09; 00477 writeBuf[1] = 0x00; 00478 // Byte 2 is set in "XboxCommand" 00479 00480 // Continuous rumble effect 00481 writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has) 00482 writeBuf[4] = 0x00; // Mode 00483 writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R) 00484 writeBuf[6] = leftTrigger; // lT force 00485 writeBuf[7] = rightTrigger; // rT force 00486 writeBuf[8] = leftMotor; // L force 00487 writeBuf[9] = rightMotor; // R force 00488 writeBuf[10] = 0xFF; // On period 00489 writeBuf[11] = 0x00; // Off period 00490 writeBuf[12] = 0xFF; // Repeat count 00491 XboxCommand(writeBuf, 13); 00492 }
Generated on Tue Jul 12 2022 18:12:05 by
