一関 Aチーム / ArduinoUsbHostShield
Committer:
kotakku
Date:
Sat Jan 18 15:06:35 2020 +0000
Revision:
0:b1ce54272580
1.0.0 first commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kotakku 0:b1ce54272580 1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
kotakku 0:b1ce54272580 2 Copyright (C) 2015 guruthree
kotakku 0:b1ce54272580 3
kotakku 0:b1ce54272580 4 This software may be distributed and modified under the terms of the GNU
kotakku 0:b1ce54272580 5 General Public License version 2 (GPL2) as published by the Free Software
kotakku 0:b1ce54272580 6 Foundation and appearing in the file GPL2.TXT included in the packaging of
kotakku 0:b1ce54272580 7 this file. Please note that GPL2 Section 2[b] requires that all works based
kotakku 0:b1ce54272580 8 on this software must also be made publicly available under the terms of
kotakku 0:b1ce54272580 9 the GPL2 ("Copyleft").
kotakku 0:b1ce54272580 10
kotakku 0:b1ce54272580 11 Contact information
kotakku 0:b1ce54272580 12 -------------------
kotakku 0:b1ce54272580 13
kotakku 0:b1ce54272580 14 Kristian Lauszus, TKJ Electronics
kotakku 0:b1ce54272580 15 Web : http://www.tkjelectronics.com
kotakku 0:b1ce54272580 16 e-mail : kristianl@tkjelectronics.com
kotakku 0:b1ce54272580 17
kotakku 0:b1ce54272580 18 guruthree
kotakku 0:b1ce54272580 19 Web : https://github.com/guruthree/
kotakku 0:b1ce54272580 20 */
kotakku 0:b1ce54272580 21
kotakku 0:b1ce54272580 22 #include "XBOXONE.h"
kotakku 0:b1ce54272580 23 // To enable serial debugging see "settings.h"
kotakku 0:b1ce54272580 24 //#define EXTRADEBUG // Uncomment to get even more debugging data
kotakku 0:b1ce54272580 25 //#define PRINTREPORT // Uncomment to print the report send by the Xbox ONE Controller
kotakku 0:b1ce54272580 26
kotakku 0:b1ce54272580 27 XBOXONE::XBOXONE(USB *p) :
kotakku 0:b1ce54272580 28 pUsb(p), // pointer to USB class instance - mandatory
kotakku 0:b1ce54272580 29 bAddress(0), // device address - mandatory
kotakku 0:b1ce54272580 30 bNumEP(1), // If config descriptor needs to be parsed
kotakku 0:b1ce54272580 31 qNextPollTime(0), // Reset NextPollTime
kotakku 0:b1ce54272580 32 pollInterval(0),
kotakku 0:b1ce54272580 33 bPollEnable(false) { // don't start polling before dongle is connected
kotakku 0:b1ce54272580 34 for(uint8_t i = 0; i < XBOX_ONE_MAX_ENDPOINTS; i++) {
kotakku 0:b1ce54272580 35 epInfo[i].epAddr = 0;
kotakku 0:b1ce54272580 36 epInfo[i].maxPktSize = (i) ? 0 : 8;
kotakku 0:b1ce54272580 37 epInfo[i].bmSndToggle = 0;
kotakku 0:b1ce54272580 38 epInfo[i].bmRcvToggle = 0;
kotakku 0:b1ce54272580 39 epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
kotakku 0:b1ce54272580 40 }
kotakku 0:b1ce54272580 41
kotakku 0:b1ce54272580 42 if(pUsb) // register in USB subsystem
kotakku 0:b1ce54272580 43 pUsb->RegisterDeviceClass(this); //set devConfig[] entry
kotakku 0:b1ce54272580 44 }
kotakku 0:b1ce54272580 45
kotakku 0:b1ce54272580 46 uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) {
kotakku 0:b1ce54272580 47 uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
kotakku 0:b1ce54272580 48 USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
kotakku 0:b1ce54272580 49 uint8_t rcode;
kotakku 0:b1ce54272580 50 UsbDevice *p = NULL;
kotakku 0:b1ce54272580 51 EpInfo *oldep_ptr = NULL;
kotakku 0:b1ce54272580 52 uint16_t PID, VID;
kotakku 0:b1ce54272580 53 uint8_t num_of_conf; // Number of configurations
kotakku 0:b1ce54272580 54
kotakku 0:b1ce54272580 55 // get memory address of USB device address pool
kotakku 0:b1ce54272580 56 AddressPool &addrPool = pUsb->GetAddressPool();
kotakku 0:b1ce54272580 57 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 58 Notify(PSTR("\r\nXBOXONE Init"), 0x80);
kotakku 0:b1ce54272580 59 #endif
kotakku 0:b1ce54272580 60 // check if address has already been assigned to an instance
kotakku 0:b1ce54272580 61 if(bAddress) {
kotakku 0:b1ce54272580 62 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 63 Notify(PSTR("\r\nAddress in use"), 0x80);
kotakku 0:b1ce54272580 64 #endif
kotakku 0:b1ce54272580 65 return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
kotakku 0:b1ce54272580 66 }
kotakku 0:b1ce54272580 67
kotakku 0:b1ce54272580 68 // Get pointer to pseudo device with address 0 assigned
kotakku 0:b1ce54272580 69 p = addrPool.GetUsbDevicePtr(0);
kotakku 0:b1ce54272580 70
kotakku 0:b1ce54272580 71 if(!p) {
kotakku 0:b1ce54272580 72 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 73 Notify(PSTR("\r\nAddress not found"), 0x80);
kotakku 0:b1ce54272580 74 #endif
kotakku 0:b1ce54272580 75 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
kotakku 0:b1ce54272580 76 }
kotakku 0:b1ce54272580 77
kotakku 0:b1ce54272580 78 if(!p->epinfo) {
kotakku 0:b1ce54272580 79 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 80 Notify(PSTR("\r\nepinfo is null"), 0x80);
kotakku 0:b1ce54272580 81 #endif
kotakku 0:b1ce54272580 82 return USB_ERROR_EPINFO_IS_NULL;
kotakku 0:b1ce54272580 83 }
kotakku 0:b1ce54272580 84
kotakku 0:b1ce54272580 85 // Save old pointer to EP_RECORD of address 0
kotakku 0:b1ce54272580 86 oldep_ptr = p->epinfo;
kotakku 0:b1ce54272580 87
kotakku 0:b1ce54272580 88 // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
kotakku 0:b1ce54272580 89 p->epinfo = epInfo;
kotakku 0:b1ce54272580 90
kotakku 0:b1ce54272580 91 p->lowspeed = lowspeed;
kotakku 0:b1ce54272580 92
kotakku 0:b1ce54272580 93 // Get device descriptor
kotakku 0:b1ce54272580 94 rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
kotakku 0:b1ce54272580 95 // Restore p->epinfo
kotakku 0:b1ce54272580 96 p->epinfo = oldep_ptr;
kotakku 0:b1ce54272580 97
kotakku 0:b1ce54272580 98 if(rcode)
kotakku 0:b1ce54272580 99 goto FailGetDevDescr;
kotakku 0:b1ce54272580 100
kotakku 0:b1ce54272580 101 VID = udd->idVendor;
kotakku 0:b1ce54272580 102 PID = udd->idProduct;
kotakku 0:b1ce54272580 103
kotakku 0:b1ce54272580 104 if(!VIDPIDOK(VID, PID)) // Check VID
kotakku 0:b1ce54272580 105 goto FailUnknownDevice;
kotakku 0:b1ce54272580 106
kotakku 0:b1ce54272580 107 // Allocate new address according to device class
kotakku 0:b1ce54272580 108 bAddress = addrPool.AllocAddress(parent, false, port);
kotakku 0:b1ce54272580 109
kotakku 0:b1ce54272580 110 if(!bAddress)
kotakku 0:b1ce54272580 111 return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
kotakku 0:b1ce54272580 112
kotakku 0:b1ce54272580 113 // Extract Max Packet Size from device descriptor
kotakku 0:b1ce54272580 114 epInfo[0].maxPktSize = udd->bMaxPacketSize0;
kotakku 0:b1ce54272580 115
kotakku 0:b1ce54272580 116 // Assign new address to the device
kotakku 0:b1ce54272580 117 rcode = pUsb->setAddr(0, 0, bAddress);
kotakku 0:b1ce54272580 118 if(rcode) {
kotakku 0:b1ce54272580 119 p->lowspeed = false;
kotakku 0:b1ce54272580 120 addrPool.FreeAddress(bAddress);
kotakku 0:b1ce54272580 121 bAddress = 0;
kotakku 0:b1ce54272580 122 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 123 Notify(PSTR("\r\nsetAddr: "), 0x80);
kotakku 0:b1ce54272580 124 D_PrintHex<uint8_t > (rcode, 0x80);
kotakku 0:b1ce54272580 125 #endif
kotakku 0:b1ce54272580 126 return rcode;
kotakku 0:b1ce54272580 127 }
kotakku 0:b1ce54272580 128 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 129 Notify(PSTR("\r\nAddr: "), 0x80);
kotakku 0:b1ce54272580 130 D_PrintHex<uint8_t > (bAddress, 0x80);
kotakku 0:b1ce54272580 131 #endif
kotakku 0:b1ce54272580 132 //delay(300); // Spec says you should wait at least 200ms
kotakku 0:b1ce54272580 133
kotakku 0:b1ce54272580 134 p->lowspeed = false;
kotakku 0:b1ce54272580 135
kotakku 0:b1ce54272580 136 //get pointer to assigned address record
kotakku 0:b1ce54272580 137 p = addrPool.GetUsbDevicePtr(bAddress);
kotakku 0:b1ce54272580 138 if(!p)
kotakku 0:b1ce54272580 139 return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
kotakku 0:b1ce54272580 140
kotakku 0:b1ce54272580 141 p->lowspeed = lowspeed;
kotakku 0:b1ce54272580 142
kotakku 0:b1ce54272580 143 // Assign epInfo to epinfo pointer - only EP0 is known
kotakku 0:b1ce54272580 144 rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
kotakku 0:b1ce54272580 145 if(rcode)
kotakku 0:b1ce54272580 146 goto FailSetDevTblEntry;
kotakku 0:b1ce54272580 147
kotakku 0:b1ce54272580 148 num_of_conf = udd->bNumConfigurations; // Number of configurations
kotakku 0:b1ce54272580 149
kotakku 0:b1ce54272580 150 USBTRACE2("NC:", num_of_conf);
kotakku 0:b1ce54272580 151
kotakku 0:b1ce54272580 152 // Check if attached device is a Xbox One controller and fill endpoint data structure
kotakku 0:b1ce54272580 153 for(uint8_t i = 0; i < num_of_conf; i++) {
kotakku 0:b1ce54272580 154 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
kotakku 0:b1ce54272580 155 rcode = pUsb->getConfDescr(bAddress, 0, i, &confDescrParser);
kotakku 0:b1ce54272580 156 if(rcode) // Check error code
kotakku 0:b1ce54272580 157 goto FailGetConfDescr;
kotakku 0:b1ce54272580 158 if(bNumEP >= XBOX_ONE_MAX_ENDPOINTS) // All endpoints extracted
kotakku 0:b1ce54272580 159 break;
kotakku 0:b1ce54272580 160 }
kotakku 0:b1ce54272580 161
kotakku 0:b1ce54272580 162 if(bNumEP < XBOX_ONE_MAX_ENDPOINTS)
kotakku 0:b1ce54272580 163 goto FailUnknownDevice;
kotakku 0:b1ce54272580 164
kotakku 0:b1ce54272580 165 rcode = pUsb->setEpInfoEntry(bAddress, bNumEP, epInfo);
kotakku 0:b1ce54272580 166 if(rcode)
kotakku 0:b1ce54272580 167 goto FailSetDevTblEntry;
kotakku 0:b1ce54272580 168
kotakku 0:b1ce54272580 169 delay(200); // Give time for address change
kotakku 0:b1ce54272580 170
kotakku 0:b1ce54272580 171 rcode = pUsb->setConf(bAddress, epInfo[ XBOX_ONE_CONTROL_PIPE ].epAddr, bConfNum);
kotakku 0:b1ce54272580 172 if(rcode)
kotakku 0:b1ce54272580 173 goto FailSetConfDescr;
kotakku 0:b1ce54272580 174
kotakku 0:b1ce54272580 175 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 176 Notify(PSTR("\r\nXbox One Controller Connected\r\n"), 0x80);
kotakku 0:b1ce54272580 177 #endif
kotakku 0:b1ce54272580 178
kotakku 0:b1ce54272580 179 delay(200); // let things settle
kotakku 0:b1ce54272580 180
kotakku 0:b1ce54272580 181 // Initialize the controller for input
kotakku 0:b1ce54272580 182 cmdCounter = 0; // Reset the counter used when sending out the commands
kotakku 0:b1ce54272580 183 uint8_t writeBuf[5];
kotakku 0:b1ce54272580 184 writeBuf[0] = 0x05;
kotakku 0:b1ce54272580 185 writeBuf[1] = 0x20;
kotakku 0:b1ce54272580 186 // Byte 2 is set in "XboxCommand"
kotakku 0:b1ce54272580 187 writeBuf[3] = 0x01;
kotakku 0:b1ce54272580 188 writeBuf[4] = 0x00;
kotakku 0:b1ce54272580 189 rcode = XboxCommand(writeBuf, 5);
kotakku 0:b1ce54272580 190 if (rcode)
kotakku 0:b1ce54272580 191 goto Fail;
kotakku 0:b1ce54272580 192
kotakku 0:b1ce54272580 193 onInit();
kotakku 0:b1ce54272580 194 XboxOneConnected = true;
kotakku 0:b1ce54272580 195 bPollEnable = true;
kotakku 0:b1ce54272580 196 return 0; // Successful configuration
kotakku 0:b1ce54272580 197
kotakku 0:b1ce54272580 198 /* Diagnostic messages */
kotakku 0:b1ce54272580 199 FailGetDevDescr:
kotakku 0:b1ce54272580 200 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 201 NotifyFailGetDevDescr();
kotakku 0:b1ce54272580 202 goto Fail;
kotakku 0:b1ce54272580 203 #endif
kotakku 0:b1ce54272580 204
kotakku 0:b1ce54272580 205 FailSetDevTblEntry:
kotakku 0:b1ce54272580 206 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 207 NotifyFailSetDevTblEntry();
kotakku 0:b1ce54272580 208 goto Fail;
kotakku 0:b1ce54272580 209 #endif
kotakku 0:b1ce54272580 210
kotakku 0:b1ce54272580 211 FailGetConfDescr:
kotakku 0:b1ce54272580 212 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 213 NotifyFailGetConfDescr();
kotakku 0:b1ce54272580 214 goto Fail;
kotakku 0:b1ce54272580 215 #endif
kotakku 0:b1ce54272580 216
kotakku 0:b1ce54272580 217 FailSetConfDescr:
kotakku 0:b1ce54272580 218 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 219 NotifyFailSetConfDescr();
kotakku 0:b1ce54272580 220 #endif
kotakku 0:b1ce54272580 221 goto Fail;
kotakku 0:b1ce54272580 222
kotakku 0:b1ce54272580 223 FailUnknownDevice:
kotakku 0:b1ce54272580 224 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 225 NotifyFailUnknownDevice(VID, PID);
kotakku 0:b1ce54272580 226 #endif
kotakku 0:b1ce54272580 227 rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
kotakku 0:b1ce54272580 228
kotakku 0:b1ce54272580 229 Fail:
kotakku 0:b1ce54272580 230 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 231 Notify(PSTR("\r\nXbox One Init Failed, error code: "), 0x80);
kotakku 0:b1ce54272580 232 NotifyFail(rcode);
kotakku 0:b1ce54272580 233 #endif
kotakku 0:b1ce54272580 234 Release();
kotakku 0:b1ce54272580 235 return rcode;
kotakku 0:b1ce54272580 236 }
kotakku 0:b1ce54272580 237
kotakku 0:b1ce54272580 238 /* Extracts endpoint information from config descriptor */
kotakku 0:b1ce54272580 239 void XBOXONE::EndpointXtract(uint8_t conf,
kotakku 0:b1ce54272580 240 uint8_t iface __attribute__((unused)),
kotakku 0:b1ce54272580 241 uint8_t alt __attribute__((unused)),
kotakku 0:b1ce54272580 242 uint8_t proto __attribute__((unused)),
kotakku 0:b1ce54272580 243 const USB_ENDPOINT_DESCRIPTOR *pep)
kotakku 0:b1ce54272580 244 {
kotakku 0:b1ce54272580 245
kotakku 0:b1ce54272580 246 bConfNum = conf;
kotakku 0:b1ce54272580 247 uint8_t index;
kotakku 0:b1ce54272580 248
kotakku 0:b1ce54272580 249 if((pep->bmAttributes & bmUSB_TRANSFER_TYPE) == USB_TRANSFER_TYPE_INTERRUPT) { // Interrupt endpoint
kotakku 0:b1ce54272580 250 index = (pep->bEndpointAddress & 0x80) == 0x80 ? XBOX_ONE_INPUT_PIPE : XBOX_ONE_OUTPUT_PIPE; // Set the endpoint index
kotakku 0:b1ce54272580 251 } else
kotakku 0:b1ce54272580 252 return;
kotakku 0:b1ce54272580 253
kotakku 0:b1ce54272580 254 // Fill the rest of endpoint data structure
kotakku 0:b1ce54272580 255 epInfo[index].epAddr = (pep->bEndpointAddress & 0x0F);
kotakku 0:b1ce54272580 256 epInfo[index].maxPktSize = (uint8_t)pep->wMaxPacketSize;
kotakku 0:b1ce54272580 257 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 258 PrintEndpointDescriptor(pep);
kotakku 0:b1ce54272580 259 #endif
kotakku 0:b1ce54272580 260 if(pollInterval < pep->bInterval) // Set the polling interval as the largest polling interval obtained from endpoints
kotakku 0:b1ce54272580 261 pollInterval = pep->bInterval;
kotakku 0:b1ce54272580 262 bNumEP++;
kotakku 0:b1ce54272580 263 }
kotakku 0:b1ce54272580 264
kotakku 0:b1ce54272580 265 void XBOXONE::PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR* ep_ptr
kotakku 0:b1ce54272580 266 __attribute__((unused)))
kotakku 0:b1ce54272580 267 {
kotakku 0:b1ce54272580 268 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 269 Notify(PSTR("\r\nEndpoint descriptor:"), 0x80);
kotakku 0:b1ce54272580 270 Notify(PSTR("\r\nLength:\t\t"), 0x80);
kotakku 0:b1ce54272580 271 D_PrintHex<uint8_t > (ep_ptr->bLength, 0x80);
kotakku 0:b1ce54272580 272 Notify(PSTR("\r\nType:\t\t"), 0x80);
kotakku 0:b1ce54272580 273 D_PrintHex<uint8_t > (ep_ptr->bDescriptorType, 0x80);
kotakku 0:b1ce54272580 274 Notify(PSTR("\r\nAddress:\t"), 0x80);
kotakku 0:b1ce54272580 275 D_PrintHex<uint8_t > (ep_ptr->bEndpointAddress, 0x80);
kotakku 0:b1ce54272580 276 Notify(PSTR("\r\nAttributes:\t"), 0x80);
kotakku 0:b1ce54272580 277 D_PrintHex<uint8_t > (ep_ptr->bmAttributes, 0x80);
kotakku 0:b1ce54272580 278 Notify(PSTR("\r\nMaxPktSize:\t"), 0x80);
kotakku 0:b1ce54272580 279 D_PrintHex<uint16_t > (ep_ptr->wMaxPacketSize, 0x80);
kotakku 0:b1ce54272580 280 Notify(PSTR("\r\nPoll Intrv:\t"), 0x80);
kotakku 0:b1ce54272580 281 D_PrintHex<uint8_t > (ep_ptr->bInterval, 0x80);
kotakku 0:b1ce54272580 282 #endif
kotakku 0:b1ce54272580 283 }
kotakku 0:b1ce54272580 284
kotakku 0:b1ce54272580 285 /* Performs a cleanup after failed Init() attempt */
kotakku 0:b1ce54272580 286 uint8_t XBOXONE::Release() {
kotakku 0:b1ce54272580 287 XboxOneConnected = false;
kotakku 0:b1ce54272580 288 pUsb->GetAddressPool().FreeAddress(bAddress);
kotakku 0:b1ce54272580 289 bAddress = 0; // Clear device address
kotakku 0:b1ce54272580 290 bNumEP = 1; // Must have to be reset to 1
kotakku 0:b1ce54272580 291 qNextPollTime = 0; // Reset next poll time
kotakku 0:b1ce54272580 292 pollInterval = 0;
kotakku 0:b1ce54272580 293 bPollEnable = false;
kotakku 0:b1ce54272580 294 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 295 Notify(PSTR("\r\nXbox One Controller Disconnected\r\n"), 0x80);
kotakku 0:b1ce54272580 296 #endif
kotakku 0:b1ce54272580 297 return 0;
kotakku 0:b1ce54272580 298 }
kotakku 0:b1ce54272580 299
kotakku 0:b1ce54272580 300 uint8_t XBOXONE::Poll() {
kotakku 0:b1ce54272580 301 uint8_t rcode = 0;
kotakku 0:b1ce54272580 302
kotakku 0:b1ce54272580 303 if(!bPollEnable)
kotakku 0:b1ce54272580 304 return 0;
kotakku 0:b1ce54272580 305
kotakku 0:b1ce54272580 306 if((int32_t)((uint32_t)millis() - qNextPollTime) >= 0L) { // Do not poll if shorter than polling interval
kotakku 0:b1ce54272580 307 qNextPollTime = (uint32_t)millis() + pollInterval; // Set new poll time
kotakku 0:b1ce54272580 308 uint16_t length = (uint16_t)epInfo[ XBOX_ONE_INPUT_PIPE ].maxPktSize; // Read the maximum packet size from the endpoint
kotakku 0:b1ce54272580 309 uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ XBOX_ONE_INPUT_PIPE ].epAddr, &length, readBuf, pollInterval);
kotakku 0:b1ce54272580 310 if(!rcode) {
kotakku 0:b1ce54272580 311 readReport();
kotakku 0:b1ce54272580 312 #ifdef PRINTREPORT // Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
kotakku 0:b1ce54272580 313 for(uint8_t i = 0; i < length; i++) {
kotakku 0:b1ce54272580 314 D_PrintHex<uint8_t > (readBuf[i], 0x80);
kotakku 0:b1ce54272580 315 Notify(PSTR(" "), 0x80);
kotakku 0:b1ce54272580 316 }
kotakku 0:b1ce54272580 317 Notify(PSTR("\r\n"), 0x80);
kotakku 0:b1ce54272580 318 #endif
kotakku 0:b1ce54272580 319 }
kotakku 0:b1ce54272580 320 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 321 else if(rcode != hrNAK) { // Not a matter of no update to send
kotakku 0:b1ce54272580 322 Notify(PSTR("\r\nXbox One Poll Failed, error code: "), 0x80);
kotakku 0:b1ce54272580 323 NotifyFail(rcode);
kotakku 0:b1ce54272580 324 }
kotakku 0:b1ce54272580 325 #endif
kotakku 0:b1ce54272580 326 }
kotakku 0:b1ce54272580 327 return rcode;
kotakku 0:b1ce54272580 328 }
kotakku 0:b1ce54272580 329
kotakku 0:b1ce54272580 330 void XBOXONE::readReport() {
kotakku 0:b1ce54272580 331 if(readBuf[0] == 0x07) {
kotakku 0:b1ce54272580 332 // The XBOX button has a separate message
kotakku 0:b1ce54272580 333 if(readBuf[4] == 1)
kotakku 0:b1ce54272580 334 ButtonState |= pgm_read_word(&XBOX_BUTTONS[XBOX]);
kotakku 0:b1ce54272580 335 else
kotakku 0:b1ce54272580 336 ButtonState &= ~pgm_read_word(&XBOX_BUTTONS[XBOX]);
kotakku 0:b1ce54272580 337
kotakku 0:b1ce54272580 338 if(ButtonState != OldButtonState) {
kotakku 0:b1ce54272580 339 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
kotakku 0:b1ce54272580 340 OldButtonState = ButtonState;
kotakku 0:b1ce54272580 341 }
kotakku 0:b1ce54272580 342 }
kotakku 0:b1ce54272580 343 if(readBuf[0] != 0x20) { // Check if it's the correct report, otherwise return - the controller also sends different status reports
kotakku 0:b1ce54272580 344 #ifdef EXTRADEBUG
kotakku 0:b1ce54272580 345 Notify(PSTR("\r\nXbox Poll: "), 0x80);
kotakku 0:b1ce54272580 346 D_PrintHex<uint8_t > (readBuf[0], 0x80); // 0x03 is a heart beat report!
kotakku 0:b1ce54272580 347 #endif
kotakku 0:b1ce54272580 348 return;
kotakku 0:b1ce54272580 349 }
kotakku 0:b1ce54272580 350
kotakku 0:b1ce54272580 351 uint16_t xbox = ButtonState & pgm_read_word(&XBOX_BUTTONS[XBOX]); // Since the XBOX button is separate, save it and add it back in
kotakku 0:b1ce54272580 352 // xbox button from before, dpad, abxy, start/back, sync, stick click, shoulder buttons
kotakku 0:b1ce54272580 353 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);
kotakku 0:b1ce54272580 354
kotakku 0:b1ce54272580 355 triggerValue[0] = (uint16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]);
kotakku 0:b1ce54272580 356 triggerValue[1] = (uint16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]);
kotakku 0:b1ce54272580 357
kotakku 0:b1ce54272580 358 hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
kotakku 0:b1ce54272580 359 hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
kotakku 0:b1ce54272580 360 hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
kotakku 0:b1ce54272580 361 hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
kotakku 0:b1ce54272580 362
kotakku 0:b1ce54272580 363 //Notify(PSTR("\r\nButtonState"), 0x80);
kotakku 0:b1ce54272580 364 //PrintHex<uint16_t>(ButtonState, 0x80);
kotakku 0:b1ce54272580 365
kotakku 0:b1ce54272580 366 if(ButtonState != OldButtonState) {
kotakku 0:b1ce54272580 367 ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
kotakku 0:b1ce54272580 368 OldButtonState = ButtonState;
kotakku 0:b1ce54272580 369 }
kotakku 0:b1ce54272580 370
kotakku 0:b1ce54272580 371 // Handle click detection for triggers
kotakku 0:b1ce54272580 372 if(triggerValue[0] != 0 && triggerValueOld[0] == 0)
kotakku 0:b1ce54272580 373 L2Clicked = true;
kotakku 0:b1ce54272580 374 triggerValueOld[0] = triggerValue[0];
kotakku 0:b1ce54272580 375 if(triggerValue[1] != 0 && triggerValueOld[1] == 0)
kotakku 0:b1ce54272580 376 R2Clicked = true;
kotakku 0:b1ce54272580 377 triggerValueOld[1] = triggerValue[1];
kotakku 0:b1ce54272580 378 }
kotakku 0:b1ce54272580 379
kotakku 0:b1ce54272580 380 uint16_t XBOXONE::getButtonPress(ButtonEnum b) {
kotakku 0:b1ce54272580 381 if(b == L2) // These are analog buttons
kotakku 0:b1ce54272580 382 return triggerValue[0];
kotakku 0:b1ce54272580 383 else if(b == R2)
kotakku 0:b1ce54272580 384 return triggerValue[1];
kotakku 0:b1ce54272580 385 return (bool)(ButtonState & ((uint16_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b])));
kotakku 0:b1ce54272580 386 }
kotakku 0:b1ce54272580 387
kotakku 0:b1ce54272580 388 bool XBOXONE::getButtonClick(ButtonEnum b) {
kotakku 0:b1ce54272580 389 if(b == L2) {
kotakku 0:b1ce54272580 390 if(L2Clicked) {
kotakku 0:b1ce54272580 391 L2Clicked = false;
kotakku 0:b1ce54272580 392 return true;
kotakku 0:b1ce54272580 393 }
kotakku 0:b1ce54272580 394 return false;
kotakku 0:b1ce54272580 395 } else if(b == R2) {
kotakku 0:b1ce54272580 396 if(R2Clicked) {
kotakku 0:b1ce54272580 397 R2Clicked = false;
kotakku 0:b1ce54272580 398 return true;
kotakku 0:b1ce54272580 399 }
kotakku 0:b1ce54272580 400 return false;
kotakku 0:b1ce54272580 401 }
kotakku 0:b1ce54272580 402 uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
kotakku 0:b1ce54272580 403 bool click = (ButtonClickState & button);
kotakku 0:b1ce54272580 404 ButtonClickState &= ~button; // Clear "click" event
kotakku 0:b1ce54272580 405 return click;
kotakku 0:b1ce54272580 406 }
kotakku 0:b1ce54272580 407
kotakku 0:b1ce54272580 408 int16_t XBOXONE::getAnalogHat(AnalogHatEnum a) {
kotakku 0:b1ce54272580 409 return hatValue[a];
kotakku 0:b1ce54272580 410 }
kotakku 0:b1ce54272580 411
kotakku 0:b1ce54272580 412 /* Xbox Controller commands */
kotakku 0:b1ce54272580 413 uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) {
kotakku 0:b1ce54272580 414 data[2] = cmdCounter++; // Increment the output command counter
kotakku 0:b1ce54272580 415 uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_ONE_OUTPUT_PIPE ].epAddr, nbytes, data);
kotakku 0:b1ce54272580 416 #ifdef DEBUG_USB_HOST
kotakku 0:b1ce54272580 417 Notify(PSTR("\r\nXboxCommand, Return: "), 0x80);
kotakku 0:b1ce54272580 418 D_PrintHex<uint8_t > (rcode, 0x80);
kotakku 0:b1ce54272580 419 #endif
kotakku 0:b1ce54272580 420 return rcode;
kotakku 0:b1ce54272580 421 }
kotakku 0:b1ce54272580 422
kotakku 0:b1ce54272580 423 // The Xbox One packets are described at: https://github.com/quantus/xbox-one-controller-protocol
kotakku 0:b1ce54272580 424 void XBOXONE::onInit() {
kotakku 0:b1ce54272580 425 // A short buzz to show the controller is active
kotakku 0:b1ce54272580 426 uint8_t writeBuf[13];
kotakku 0:b1ce54272580 427
kotakku 0:b1ce54272580 428 // Activate rumble
kotakku 0:b1ce54272580 429 writeBuf[0] = 0x09;
kotakku 0:b1ce54272580 430 writeBuf[1] = 0x00;
kotakku 0:b1ce54272580 431 // Byte 2 is set in "XboxCommand"
kotakku 0:b1ce54272580 432
kotakku 0:b1ce54272580 433 // Single rumble effect
kotakku 0:b1ce54272580 434 writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has)
kotakku 0:b1ce54272580 435 writeBuf[4] = 0x00; // Mode
kotakku 0:b1ce54272580 436 writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R)
kotakku 0:b1ce54272580 437 writeBuf[6] = 0x04; // lT force
kotakku 0:b1ce54272580 438 writeBuf[7] = 0x04; // rT force
kotakku 0:b1ce54272580 439 writeBuf[8] = 0x20; // L force
kotakku 0:b1ce54272580 440 writeBuf[9] = 0x20; // R force
kotakku 0:b1ce54272580 441 writeBuf[10] = 0x80; // Length of pulse
kotakku 0:b1ce54272580 442 writeBuf[11] = 0x00; // Off period
kotakku 0:b1ce54272580 443 writeBuf[12] = 0x00; // Repeat count
kotakku 0:b1ce54272580 444 XboxCommand(writeBuf, 13);
kotakku 0:b1ce54272580 445
kotakku 0:b1ce54272580 446 if(pFuncOnInit)
kotakku 0:b1ce54272580 447 pFuncOnInit(); // Call the user function
kotakku 0:b1ce54272580 448 }
kotakku 0:b1ce54272580 449
kotakku 0:b1ce54272580 450 void XBOXONE::setRumbleOff() {
kotakku 0:b1ce54272580 451 uint8_t writeBuf[13];
kotakku 0:b1ce54272580 452
kotakku 0:b1ce54272580 453 // Activate rumble
kotakku 0:b1ce54272580 454 writeBuf[0] = 0x09;
kotakku 0:b1ce54272580 455 writeBuf[1] = 0x00;
kotakku 0:b1ce54272580 456 // Byte 2 is set in "XboxCommand"
kotakku 0:b1ce54272580 457
kotakku 0:b1ce54272580 458 // Continuous rumble effect
kotakku 0:b1ce54272580 459 writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has)
kotakku 0:b1ce54272580 460 writeBuf[4] = 0x00; // Mode
kotakku 0:b1ce54272580 461 writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R)
kotakku 0:b1ce54272580 462 writeBuf[6] = 0x00; // lT force
kotakku 0:b1ce54272580 463 writeBuf[7] = 0x00; // rT force
kotakku 0:b1ce54272580 464 writeBuf[8] = 0x00; // L force
kotakku 0:b1ce54272580 465 writeBuf[9] = 0x00; // R force
kotakku 0:b1ce54272580 466 writeBuf[10] = 0x00; // On period
kotakku 0:b1ce54272580 467 writeBuf[11] = 0x00; // Off period
kotakku 0:b1ce54272580 468 writeBuf[12] = 0x00; // Repeat count
kotakku 0:b1ce54272580 469 XboxCommand(writeBuf, 13);
kotakku 0:b1ce54272580 470 }
kotakku 0:b1ce54272580 471
kotakku 0:b1ce54272580 472 void XBOXONE::setRumbleOn(uint8_t leftTrigger, uint8_t rightTrigger, uint8_t leftMotor, uint8_t rightMotor) {
kotakku 0:b1ce54272580 473 uint8_t writeBuf[13];
kotakku 0:b1ce54272580 474
kotakku 0:b1ce54272580 475 // Activate rumble
kotakku 0:b1ce54272580 476 writeBuf[0] = 0x09;
kotakku 0:b1ce54272580 477 writeBuf[1] = 0x00;
kotakku 0:b1ce54272580 478 // Byte 2 is set in "XboxCommand"
kotakku 0:b1ce54272580 479
kotakku 0:b1ce54272580 480 // Continuous rumble effect
kotakku 0:b1ce54272580 481 writeBuf[3] = 0x09; // Substructure (what substructure rest of this packet has)
kotakku 0:b1ce54272580 482 writeBuf[4] = 0x00; // Mode
kotakku 0:b1ce54272580 483 writeBuf[5] = 0x0F; // Rumble mask (what motors are activated) (0000 lT rT L R)
kotakku 0:b1ce54272580 484 writeBuf[6] = leftTrigger; // lT force
kotakku 0:b1ce54272580 485 writeBuf[7] = rightTrigger; // rT force
kotakku 0:b1ce54272580 486 writeBuf[8] = leftMotor; // L force
kotakku 0:b1ce54272580 487 writeBuf[9] = rightMotor; // R force
kotakku 0:b1ce54272580 488 writeBuf[10] = 0xFF; // On period
kotakku 0:b1ce54272580 489 writeBuf[11] = 0x00; // Off period
kotakku 0:b1ce54272580 490 writeBuf[12] = 0xFF; // Repeat count
kotakku 0:b1ce54272580 491 XboxCommand(writeBuf, 13);
kotakku 0:b1ce54272580 492 }
kotakku 0:b1ce54272580 493