您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
此仓库已存档。您可以查看文件和克隆,但不能推送或创建工单/合并请求。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
  2. Copyright (C) 2015 guruthree
  3. This software may be distributed and modified under the terms of the GNU
  4. General Public License version 2 (GPL2) as published by the Free Software
  5. Foundation and appearing in the file GPL2.TXT included in the packaging of
  6. this file. Please note that GPL2 Section 2[b] requires that all works based
  7. on this software must also be made publicly available under the terms of
  8. the GPL2 ("Copyleft").
  9. Contact information
  10. -------------------
  11. Kristian Lauszus, TKJ Electronics
  12. Web : http://www.tkjelectronics.com
  13. e-mail : [email protected]
  14. guruthree
  15. Web : https://github.com/guruthree/
  16. */
  17. #include "XBOXONE.h"
  18. // To enable serial debugging see "settings.h"
  19. //#define EXTRADEBUG // Uncomment to get even more debugging data
  20. //#define PRINTREPORT // Uncomment to print the report send by the Xbox ONE Controller
  21. XBOXONE::XBOXONE(USB *p) :
  22. pUsb(p), // pointer to USB class instance - mandatory
  23. bAddress(0), // device address - mandatory
  24. bPollEnable(false) { // don't start polling before dongle is connected
  25. for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
  26. epInfo[i].epAddr = 0;
  27. epInfo[i].maxPktSize = (i) ? 0 : 8;
  28. epInfo[i].epAttribs = 0;
  29. epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
  30. }
  31. if(pUsb) // register in USB subsystem
  32. pUsb->RegisterDeviceClass(this); //set devConfig[] entry
  33. }
  34. uint8_t XBOXONE::Init(uint8_t parent, uint8_t port, bool lowspeed) {
  35. uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
  36. USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
  37. uint8_t rcode;
  38. UsbDevice *p = NULL;
  39. EpInfo *oldep_ptr = NULL;
  40. uint16_t PID;
  41. uint16_t VID;
  42. // get memory address of USB device address pool
  43. AddressPool &addrPool = pUsb->GetAddressPool();
  44. #ifdef EXTRADEBUG
  45. Notify(PSTR("\r\nXBOXONE Init"), 0x80);
  46. #endif
  47. // check if address has already been assigned to an instance
  48. if(bAddress) {
  49. #ifdef DEBUG_USB_HOST
  50. Notify(PSTR("\r\nAddress in use"), 0x80);
  51. #endif
  52. return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
  53. }
  54. // Get pointer to pseudo device with address 0 assigned
  55. p = addrPool.GetUsbDevicePtr(0);
  56. if(!p) {
  57. #ifdef DEBUG_USB_HOST
  58. Notify(PSTR("\r\nAddress not found"), 0x80);
  59. #endif
  60. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  61. }
  62. if(!p->epinfo) {
  63. #ifdef DEBUG_USB_HOST
  64. Notify(PSTR("\r\nepinfo is null"), 0x80);
  65. #endif
  66. return USB_ERROR_EPINFO_IS_NULL;
  67. }
  68. // Save old pointer to EP_RECORD of address 0
  69. oldep_ptr = p->epinfo;
  70. // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
  71. p->epinfo = epInfo;
  72. p->lowspeed = lowspeed;
  73. // Get device descriptor
  74. rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
  75. // Restore p->epinfo
  76. p->epinfo = oldep_ptr;
  77. if(rcode)
  78. goto FailGetDevDescr;
  79. VID = udd->idVendor;
  80. PID = udd->idProduct;
  81. if(!VIDPIDOK(VID, PID)) // Check VID
  82. goto FailUnknownDevice;
  83. // Allocate new address according to device class
  84. bAddress = addrPool.AllocAddress(parent, false, port);
  85. if(!bAddress)
  86. return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
  87. // Extract Max Packet Size from device descriptor
  88. epInfo[0].maxPktSize = udd->bMaxPacketSize0;
  89. // Assign new address to the device
  90. rcode = pUsb->setAddr(0, 0, bAddress);
  91. if(rcode) {
  92. p->lowspeed = false;
  93. addrPool.FreeAddress(bAddress);
  94. bAddress = 0;
  95. #ifdef DEBUG_USB_HOST
  96. Notify(PSTR("\r\nsetAddr: "), 0x80);
  97. D_PrintHex<uint8_t > (rcode, 0x80);
  98. #endif
  99. return rcode;
  100. }
  101. #ifdef EXTRADEBUG
  102. Notify(PSTR("\r\nAddr: "), 0x80);
  103. D_PrintHex<uint8_t > (bAddress, 0x80);
  104. #endif
  105. //delay(300); // Spec says you should wait at least 200ms
  106. p->lowspeed = false;
  107. //get pointer to assigned address record
  108. p = addrPool.GetUsbDevicePtr(bAddress);
  109. if(!p)
  110. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  111. p->lowspeed = lowspeed;
  112. // Assign epInfo to epinfo pointer - only EP0 is known
  113. rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
  114. if(rcode)
  115. goto FailSetDevTblEntry;
  116. /* The application will work in reduced host mode, so we can save program and data
  117. memory space. After verifying the VID we will use known values for the
  118. configuration values for device, interface, endpoints and HID for the XBOXONE Controllers */
  119. /* Initialize data structures for endpoints of device */
  120. epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x01; // XBOX one output endpoint
  121. epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  122. epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  123. epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
  124. epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = 0;
  125. epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = 0;
  126. epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX one input endpoint
  127. epInfo[ XBOX_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  128. epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  129. epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE;
  130. epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = 0;
  131. epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = 0;
  132. rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
  133. if(rcode)
  134. goto FailSetDevTblEntry;
  135. delay(200); // Give time for address change
  136. rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
  137. if(rcode)
  138. goto FailSetConfDescr;
  139. #ifdef DEBUG_USB_HOST
  140. Notify(PSTR("\r\nXbox One Controller Connected\r\n"), 0x80);
  141. #endif
  142. delay(200); // let things settle
  143. // initialize the controller for input
  144. writeBuf[0] = 0x05;
  145. writeBuf[1] = 0x20;
  146. rcode = XboxCommand(writeBuf, 2);
  147. if (rcode)
  148. goto Fail;
  149. onInit();
  150. XboxOneConnected = true;
  151. bPollEnable = true;
  152. return 0; // Successful configuration
  153. /* Diagnostic messages */
  154. FailGetDevDescr:
  155. #ifdef DEBUG_USB_HOST
  156. NotifyFailGetDevDescr();
  157. goto Fail;
  158. #endif
  159. FailSetDevTblEntry:
  160. #ifdef DEBUG_USB_HOST
  161. NotifyFailSetDevTblEntry();
  162. goto Fail;
  163. #endif
  164. FailSetConfDescr:
  165. #ifdef DEBUG_USB_HOST
  166. NotifyFailSetConfDescr();
  167. #endif
  168. goto Fail;
  169. FailUnknownDevice:
  170. #ifdef DEBUG_USB_HOST
  171. NotifyFailUnknownDevice(VID, PID);
  172. #endif
  173. rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  174. Fail:
  175. #ifdef DEBUG_USB_HOST
  176. Notify(PSTR("\r\nXbox One Init Failed, error code: "), 0x80);
  177. NotifyFail(rcode);
  178. #endif
  179. Release();
  180. return rcode;
  181. }
  182. /* Performs a cleanup after failed Init() attempt */
  183. uint8_t XBOXONE::Release() {
  184. XboxOneConnected = false;
  185. pUsb->GetAddressPool().FreeAddress(bAddress);
  186. bAddress = 0;
  187. bPollEnable = false;
  188. #ifdef DEBUG_USB_HOST
  189. Notify(PSTR("\r\nXbox One Controller Disconnected\r\n"), 0x80);
  190. #endif
  191. return 0;
  192. }
  193. uint8_t XBOXONE::Poll() {
  194. if(!bPollEnable)
  195. return 0;
  196. uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
  197. uint8_t rcode = pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf);
  198. if (!rcode) {
  199. readReport();
  200. #ifdef PRINTREPORT
  201. printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
  202. #endif
  203. }
  204. #ifdef DEBUG_USB_HOST
  205. else if (rcode != 0x04) { // not a matter of no update to send
  206. Notify(PSTR("\r\nXbox One Poll Failed, error code: "), 0x80);
  207. NotifyFail(rcode);
  208. }
  209. #endif
  210. return rcode;
  211. }
  212. void XBOXONE::readReport() {
  213. if(readBuf == NULL)
  214. return;
  215. if(readBuf[0] == 0x07) {
  216. // The XBOX button has a separate message
  217. if(readBuf[4] == 1)
  218. ButtonState |= XBOX_BUTTONS[XBOX];
  219. else
  220. ButtonState &= ~XBOX_BUTTONS[XBOX];
  221. }
  222. if(readBuf[0] != 0x20) { // Check if it's the correct report, otherwise return - the controller also sends different status reports
  223. #ifdef EXTRADEBUG
  224. Notify(PSTR("\r\nXbox Poll: "), 0x80);
  225. D_PrintHex<uint8_t > (readBuf[0], 0x80); // 0x03 is a heart beat report!
  226. #endif
  227. return;
  228. }
  229. uint16_t xbox = ButtonState & XBOX_BUTTONS[XBOX]; // Since the XBOX button is separate, save it and add it back in
  230. // xbox button from before, dpad, abxy, start/back, sync, stick click, shoulder buttons
  231. 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);
  232. triggerValue[0] = (uint16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]);
  233. triggerValue[1] = (uint16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]);
  234. hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
  235. hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
  236. hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
  237. hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
  238. //Notify(PSTR("\r\nButtonState"), 0x80);
  239. //PrintHex<uint16_t>(ButtonState, 0x80);
  240. if(ButtonState != OldButtonState) {
  241. ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
  242. OldButtonState = ButtonState;
  243. }
  244. // Handle click detection for triggers
  245. if(triggerValue[0] != 0 && triggerValueOld[0] == 0)
  246. L2Clicked = true;
  247. triggerValueOld[0] = triggerValue[0];
  248. if(triggerValue[1] != 0 && triggerValueOld[1] == 0)
  249. R2Clicked = true;
  250. triggerValueOld[1] = triggerValue[1];
  251. }
  252. void XBOXONE::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox ONE Controller
  253. #ifdef PRINTREPORT
  254. if(readBuf == NULL)
  255. return;
  256. for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
  257. D_PrintHex<uint8_t > (readBuf[i], 0x80);
  258. Notify(PSTR(" "), 0x80);
  259. }
  260. Notify(PSTR("\r\n"), 0x80);
  261. #endif
  262. }
  263. uint16_t XBOXONE::getButtonPress(ButtonEnum b) {
  264. if(b == L2) // These are analog buttons
  265. return triggerValue[0];
  266. else if(b == R2)
  267. return triggerValue[1];
  268. return (bool)(ButtonState & ((uint16_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b])));
  269. }
  270. bool XBOXONE::getButtonClick(ButtonEnum b) {
  271. if(b == L2) {
  272. if(L2Clicked) {
  273. L2Clicked = false;
  274. return true;
  275. }
  276. return false;
  277. } else if(b == R2) {
  278. if(R2Clicked) {
  279. R2Clicked = false;
  280. return true;
  281. }
  282. return false;
  283. }
  284. uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
  285. bool click = (ButtonClickState & button);
  286. ButtonClickState &= ~button; // clear "click" event
  287. return click;
  288. }
  289. int16_t XBOXONE::getAnalogHat(AnalogHatEnum a) {
  290. return hatValue[a];
  291. }
  292. /* Xbox Controller commands */
  293. uint8_t XBOXONE::XboxCommand(uint8_t* data, uint16_t nbytes) {
  294. uint8_t rcode = pUsb->outTransfer(bAddress, epInfo[ XBOX_OUTPUT_PIPE ].epAddr, nbytes, data);
  295. #ifdef DEBUG_USB_HOST
  296. Notify(PSTR("\r\nXboxCommand, Return: "), 0x80);
  297. D_PrintHex<uint8_t > (rcode, 0x80);
  298. #endif
  299. return rcode;
  300. }
  301. void XBOXONE::onInit() {
  302. // a short buzz to show the controller is active
  303. writeBuf[0] = 0x09;
  304. writeBuf[1] = 0x08;
  305. writeBuf[2] = 0x00;
  306. writeBuf[3] = 0x09;
  307. writeBuf[4] = 0x00;
  308. writeBuf[5] = 0x0f;
  309. writeBuf[6] = 0x04;
  310. writeBuf[7] = 0x04;
  311. writeBuf[8] = 0x20;
  312. writeBuf[9] = 0x20;
  313. writeBuf[10] = 0x80;
  314. XboxCommand(writeBuf, 11);
  315. if(pFuncOnInit)
  316. pFuncOnInit(); // Call the user function
  317. }