You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
22 KiB

  1. /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
  2. This software may be distributed and modified under the terms of the GNU
  3. General Public License version 2 (GPL2) as published by the Free Software
  4. Foundation and appearing in the file GPL2.TXT included in the packaging of
  5. this file. Please note that GPL2 Section 2[b] requires that all works based
  6. on this software must also be made publicly available under the terms of
  7. the GPL2 ("Copyleft").
  8. Contact information
  9. -------------------
  10. Kristian Lauszus, TKJ Electronics
  11. Web : http://www.tkjelectronics.com
  12. e-mail : kristianl@tkjelectronics.com
  13. getBatteryLevel and checkStatus functions made by timstamp.co.uk found using BusHound from Perisoft.net
  14. */
  15. #include "XBOXRECV.h"
  16. // To enable serial debugging see "settings.h"
  17. //#define EXTRADEBUG // Uncomment to get even more debugging data
  18. //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
  19. XBOXRECV::XBOXRECV(USB *p) :
  20. pUsb(p), // pointer to USB class instance - mandatory
  21. bAddress(0), // device address - mandatory
  22. bPollEnable(false) { // don't start polling before dongle is connected
  23. for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
  24. epInfo[i].epAddr = 0;
  25. epInfo[i].maxPktSize = (i) ? 0 : 8;
  26. epInfo[i].epAttribs = 0;
  27. epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER;
  28. }
  29. if(pUsb) // register in USB subsystem
  30. pUsb->RegisterDeviceClass(this); //set devConfig[] entry
  31. }
  32. uint8_t XBOXRECV::ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed) {
  33. const uint8_t constBufSize = sizeof (USB_DEVICE_DESCRIPTOR);
  34. uint8_t buf[constBufSize];
  35. USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
  36. uint8_t rcode;
  37. UsbDevice *p = NULL;
  38. EpInfo *oldep_ptr = NULL;
  39. uint16_t PID, VID;
  40. AddressPool &addrPool = pUsb->GetAddressPool(); // Get memory address of USB device address pool
  41. #ifdef EXTRADEBUG
  42. Notify(PSTR("\r\nXBOXRECV Init"), 0x80);
  43. #endif
  44. if(bAddress) { // Check if address has already been assigned to an instance
  45. #ifdef DEBUG_USB_HOST
  46. Notify(PSTR("\r\nAddress in use"), 0x80);
  47. #endif
  48. return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE;
  49. }
  50. p = addrPool.GetUsbDevicePtr(0); // Get pointer to pseudo device with address 0 assigned
  51. if(!p) {
  52. #ifdef DEBUG_USB_HOST
  53. Notify(PSTR("\r\nAddress not found"), 0x80);
  54. #endif
  55. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  56. }
  57. if(!p->epinfo) {
  58. #ifdef DEBUG_USB_HOST
  59. Notify(PSTR("\r\nepinfo is null"), 0x80);
  60. #endif
  61. return USB_ERROR_EPINFO_IS_NULL;
  62. }
  63. oldep_ptr = p->epinfo; // Save old pointer to EP_RECORD of address 0
  64. p->epinfo = epInfo; // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
  65. p->lowspeed = lowspeed;
  66. rcode = pUsb->getDevDescr(0, 0, constBufSize, (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
  67. p->epinfo = oldep_ptr; // Restore p->epinfo
  68. if(rcode)
  69. goto FailGetDevDescr;
  70. VID = udd->idVendor;
  71. PID = udd->idProduct;
  72. if((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_WIRELESS_RECEIVER_PID && PID != XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID)) { // Check if it's a Xbox receiver using the Vendor ID and Product ID
  73. #ifdef DEBUG_USB_HOST
  74. Notify(PSTR("\r\nYou'll need a wireless receiver for this libary to work"), 0x80);
  75. #endif
  76. goto FailUnknownDevice;
  77. }
  78. bAddress = addrPool.AllocAddress(parent, false, port); // Allocate new address according to device class
  79. if(!bAddress) {
  80. #ifdef DEBUG_USB_HOST
  81. Notify(PSTR("\r\nOut of address space"), 0x80);
  82. #endif
  83. return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL;
  84. }
  85. epInfo[0].maxPktSize = udd->bMaxPacketSize0; // Extract Max Packet Size from device descriptor
  86. delay(20); // Wait a little before resetting device
  87. return USB_ERROR_CONFIG_REQUIRES_ADDITIONAL_RESET;
  88. /* Diagnostic messages */
  89. FailGetDevDescr:
  90. #ifdef DEBUG_USB_HOST
  91. NotifyFailGetDevDescr(rcode);
  92. #endif
  93. if(rcode != hrJERR)
  94. rcode = USB_ERROR_FailGetDevDescr;
  95. goto Fail;
  96. FailUnknownDevice:
  97. #ifdef DEBUG_USB_HOST
  98. NotifyFailUnknownDevice(VID, PID);
  99. #endif
  100. rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED;
  101. Fail:
  102. #ifdef DEBUG_USB_HOST
  103. Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
  104. NotifyFail(rcode);
  105. #endif
  106. Release();
  107. return rcode;
  108. };
  109. uint8_t XBOXRECV::Init(uint8_t parent, uint8_t port, bool lowspeed) {
  110. uint8_t rcode;
  111. AddressPool &addrPool = pUsb->GetAddressPool();
  112. #ifdef EXTRADEBUG
  113. Notify(PSTR("\r\nBTD Init"), 0x80);
  114. #endif
  115. UsbDevice *p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
  116. if(!p) {
  117. #ifdef DEBUG_USB_HOST
  118. Notify(PSTR("\r\nAddress not found"), 0x80);
  119. #endif
  120. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  121. }
  122. delay(300); // Assign new address to the device
  123. rcode = pUsb->setAddr(0, 0, bAddress); // Assign new address to the device
  124. if(rcode) {
  125. #ifdef DEBUG_USB_HOST
  126. Notify(PSTR("\r\nsetAddr: "), 0x80);
  127. D_PrintHex<uint8_t > (rcode, 0x80);
  128. #endif
  129. p->lowspeed = false;
  130. goto Fail;
  131. }
  132. #ifdef EXTRADEBUG
  133. Notify(PSTR("\r\nAddr: "), 0x80);
  134. D_PrintHex<uint8_t > (bAddress, 0x80);
  135. #endif
  136. p->lowspeed = false;
  137. p = addrPool.GetUsbDevicePtr(bAddress); // Get pointer to assigned address record
  138. if(!p) {
  139. #ifdef DEBUG_USB_HOST
  140. Notify(PSTR("\r\nAddress not found"), 0x80);
  141. #endif
  142. return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL;
  143. }
  144. p->lowspeed = lowspeed;
  145. rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo); // Assign epInfo to epinfo pointer - only EP0 is known
  146. if(rcode)
  147. goto FailSetDevTblEntry;
  148. /* The application will work in reduced host mode, so we can save program and data
  149. memory space. After verifying the VID we will use known values for the
  150. configuration values for device, interface, endpoints and HID for the XBOX360 Wireless receiver */
  151. /* Initialize data structures for endpoints of device */
  152. epInfo[ XBOX_INPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 report endpoint - poll interval 1ms
  153. epInfo[ XBOX_INPUT_PIPE_1 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  154. epInfo[ XBOX_INPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  155. epInfo[ XBOX_INPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
  156. epInfo[ XBOX_INPUT_PIPE_1 ].bmSndToggle = 0;
  157. epInfo[ XBOX_INPUT_PIPE_1 ].bmRcvToggle = 0;
  158. epInfo[ XBOX_OUTPUT_PIPE_1 ].epAddr = 0x01; // XBOX 360 output endpoint - poll interval 8ms
  159. epInfo[ XBOX_OUTPUT_PIPE_1 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  160. epInfo[ XBOX_OUTPUT_PIPE_1 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  161. epInfo[ XBOX_OUTPUT_PIPE_1 ].maxPktSize = EP_MAXPKTSIZE;
  162. epInfo[ XBOX_OUTPUT_PIPE_1 ].bmSndToggle = 0;
  163. epInfo[ XBOX_OUTPUT_PIPE_1 ].bmRcvToggle = 0;
  164. epInfo[ XBOX_INPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 report endpoint - poll interval 1ms
  165. epInfo[ XBOX_INPUT_PIPE_2 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  166. epInfo[ XBOX_INPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  167. epInfo[ XBOX_INPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
  168. epInfo[ XBOX_INPUT_PIPE_2 ].bmSndToggle = 0;
  169. epInfo[ XBOX_INPUT_PIPE_2 ].bmRcvToggle = 0;
  170. epInfo[ XBOX_OUTPUT_PIPE_2 ].epAddr = 0x03; // XBOX 360 output endpoint - poll interval 8ms
  171. epInfo[ XBOX_OUTPUT_PIPE_2 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  172. epInfo[ XBOX_OUTPUT_PIPE_2 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  173. epInfo[ XBOX_OUTPUT_PIPE_2 ].maxPktSize = EP_MAXPKTSIZE;
  174. epInfo[ XBOX_OUTPUT_PIPE_2 ].bmSndToggle = 0;
  175. epInfo[ XBOX_OUTPUT_PIPE_2 ].bmRcvToggle = 0;
  176. epInfo[ XBOX_INPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 report endpoint - poll interval 1ms
  177. epInfo[ XBOX_INPUT_PIPE_3 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  178. epInfo[ XBOX_INPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  179. epInfo[ XBOX_INPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
  180. epInfo[ XBOX_INPUT_PIPE_3 ].bmSndToggle = 0;
  181. epInfo[ XBOX_INPUT_PIPE_3 ].bmRcvToggle = 0;
  182. epInfo[ XBOX_OUTPUT_PIPE_3 ].epAddr = 0x05; // XBOX 360 output endpoint - poll interval 8ms
  183. epInfo[ XBOX_OUTPUT_PIPE_3 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  184. epInfo[ XBOX_OUTPUT_PIPE_3 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  185. epInfo[ XBOX_OUTPUT_PIPE_3 ].maxPktSize = EP_MAXPKTSIZE;
  186. epInfo[ XBOX_OUTPUT_PIPE_3 ].bmSndToggle = 0;
  187. epInfo[ XBOX_OUTPUT_PIPE_3 ].bmRcvToggle = 0;
  188. epInfo[ XBOX_INPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 report endpoint - poll interval 1ms
  189. epInfo[ XBOX_INPUT_PIPE_4 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  190. epInfo[ XBOX_INPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  191. epInfo[ XBOX_INPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
  192. epInfo[ XBOX_INPUT_PIPE_4 ].bmSndToggle = 0;
  193. epInfo[ XBOX_INPUT_PIPE_4 ].bmRcvToggle = 0;
  194. epInfo[ XBOX_OUTPUT_PIPE_4 ].epAddr = 0x07; // XBOX 360 output endpoint - poll interval 8ms
  195. epInfo[ XBOX_OUTPUT_PIPE_4 ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT;
  196. epInfo[ XBOX_OUTPUT_PIPE_4 ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
  197. epInfo[ XBOX_OUTPUT_PIPE_4 ].maxPktSize = EP_MAXPKTSIZE;
  198. epInfo[ XBOX_OUTPUT_PIPE_4 ].bmSndToggle = 0;
  199. epInfo[ XBOX_OUTPUT_PIPE_4 ].bmRcvToggle = 0;
  200. rcode = pUsb->setEpInfoEntry(bAddress, 9, epInfo);
  201. if(rcode)
  202. goto FailSetDevTblEntry;
  203. delay(200); //Give time for address change
  204. rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
  205. if(rcode)
  206. goto FailSetConfDescr;
  207. #ifdef DEBUG_USB_HOST
  208. Notify(PSTR("\r\nXbox Wireless Receiver Connected\r\n"), 0x80);
  209. #endif
  210. XboxReceiverConnected = true;
  211. bPollEnable = true;
  212. checkStatusTimer = 0; // Reset timer
  213. return 0; // Successful configuration
  214. /* Diagnostic messages */
  215. FailSetDevTblEntry:
  216. #ifdef DEBUG_USB_HOST
  217. NotifyFailSetDevTblEntry();
  218. goto Fail;
  219. #endif
  220. FailSetConfDescr:
  221. #ifdef DEBUG_USB_HOST
  222. NotifyFailSetConfDescr();
  223. #endif
  224. Fail:
  225. #ifdef DEBUG_USB_HOST
  226. Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
  227. NotifyFail(rcode);
  228. #endif
  229. Release();
  230. return rcode;
  231. }
  232. /* Performs a cleanup after failed Init() attempt */
  233. uint8_t XBOXRECV::Release() {
  234. XboxReceiverConnected = false;
  235. for(uint8_t i = 0; i < 4; i++)
  236. Xbox360Connected[i] = 0x00;
  237. pUsb->GetAddressPool().FreeAddress(bAddress);
  238. bAddress = 0;
  239. bPollEnable = false;
  240. return 0;
  241. }
  242. uint8_t XBOXRECV::Poll() {
  243. if(!bPollEnable)
  244. return 0;
  245. if(!checkStatusTimer || ((millis() - checkStatusTimer) > 3000)) { // Run checkStatus every 3 seconds
  246. checkStatusTimer = millis();
  247. checkStatus();
  248. }
  249. uint8_t inputPipe;
  250. uint16_t bufferSize;
  251. for(uint8_t i = 0; i < 4; i++) {
  252. if(i == 0)
  253. inputPipe = XBOX_INPUT_PIPE_1;
  254. else if(i == 1)
  255. inputPipe = XBOX_INPUT_PIPE_2;
  256. else if(i == 2)
  257. inputPipe = XBOX_INPUT_PIPE_3;
  258. else
  259. inputPipe = XBOX_INPUT_PIPE_4;
  260. bufferSize = EP_MAXPKTSIZE; // This is the maximum number of bytes we want to receive
  261. pUsb->inTransfer(bAddress, epInfo[ inputPipe ].epAddr, &bufferSize, readBuf);
  262. if(bufferSize > 0) { // The number of received bytes
  263. #ifdef EXTRADEBUG
  264. Notify(PSTR("Bytes Received: "), 0x80);
  265. D_PrintHex<uint16_t > (bufferSize, 0x80);
  266. Notify(PSTR("\r\n"), 0x80);
  267. #endif
  268. readReport(i);
  269. #ifdef PRINTREPORT
  270. printReport(i, bufferSize); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
  271. #endif
  272. }
  273. }
  274. return 0;
  275. }
  276. void XBOXRECV::readReport(uint8_t controller) {
  277. if(readBuf == NULL)
  278. return;
  279. // This report is send when a controller is connected and disconnected
  280. if(readBuf[0] == 0x08 && readBuf[1] != Xbox360Connected[controller]) {
  281. Xbox360Connected[controller] = readBuf[1];
  282. #ifdef DEBUG_USB_HOST
  283. Notify(PSTR("Controller "), 0x80);
  284. Notify(controller, 0x80);
  285. #endif
  286. if(Xbox360Connected[controller]) {
  287. #ifdef DEBUG_USB_HOST
  288. const char* str = 0;
  289. switch(readBuf[1]) {
  290. case 0x80: str = PSTR(" as controller\r\n");
  291. break;
  292. case 0x40: str = PSTR(" as headset\r\n");
  293. break;
  294. case 0xC0: str = PSTR(" as controller+headset\r\n");
  295. break;
  296. }
  297. Notify(PSTR(": connected"), 0x80);
  298. Notify(str, 0x80);
  299. #endif
  300. onInit(controller);
  301. }
  302. #ifdef DEBUG_USB_HOST
  303. else
  304. Notify(PSTR(": disconnected\r\n"), 0x80);
  305. #endif
  306. return;
  307. }
  308. // Controller status report
  309. if(readBuf[1] == 0x00 && readBuf[3] & 0x13 && readBuf[4] >= 0x22) {
  310. controllerStatus[controller] = ((uint16_t)readBuf[3] << 8) | readBuf[4];
  311. return;
  312. }
  313. if(readBuf[1] != 0x01) // Check if it's the correct report - the receiver also sends different status reports
  314. return;
  315. // A controller must be connected if it's sending data
  316. if(!Xbox360Connected[controller])
  317. Xbox360Connected[controller] |= 0x80;
  318. ButtonState[controller] = (uint32_t)(readBuf[9] | ((uint16_t)readBuf[8] << 8) | ((uint32_t)readBuf[7] << 16) | ((uint32_t)readBuf[6] << 24));
  319. hatValue[controller][LeftHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
  320. hatValue[controller][LeftHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
  321. hatValue[controller][RightHatX] = (int16_t)(((uint16_t)readBuf[15] << 8) | readBuf[14]);
  322. hatValue[controller][RightHatY] = (int16_t)(((uint16_t)readBuf[17] << 8) | readBuf[16]);
  323. //Notify(PSTR("\r\nButtonState: "), 0x80);
  324. //PrintHex<uint32_t>(ButtonState[controller], 0x80);
  325. if(ButtonState[controller] != OldButtonState[controller]) {
  326. buttonStateChanged[controller] = true;
  327. ButtonClickState[controller] = (ButtonState[controller] >> 16) & ((~OldButtonState[controller]) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2
  328. if(((uint8_t)OldButtonState[controller]) == 0 && ((uint8_t)ButtonState[controller]) != 0) // The L2 and R2 buttons are special as they are analog buttons
  329. R2Clicked[controller] = true;
  330. if((uint8_t)(OldButtonState[controller] >> 8) == 0 && (uint8_t)(ButtonState[controller] >> 8) != 0)
  331. L2Clicked[controller] = true;
  332. OldButtonState[controller] = ButtonState[controller];
  333. }
  334. }
  335. void XBOXRECV::printReport(uint8_t controller, uint8_t nBytes) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
  336. #ifdef PRINTREPORT
  337. if(readBuf == NULL)
  338. return;
  339. Notify(PSTR("Controller "), 0x80);
  340. Notify(controller, 0x80);
  341. Notify(PSTR(": "), 0x80);
  342. for(uint8_t i = 0; i < nBytes; i++) {
  343. D_PrintHex<uint8_t > (readBuf[i], 0x80);
  344. Notify(PSTR(" "), 0x80);
  345. }
  346. Notify(PSTR("\r\n"), 0x80);
  347. #endif
  348. }
  349. uint8_t XBOXRECV::getButtonPress(ButtonEnum b, uint8_t controller) {
  350. if(b == L2) // These are analog buttons
  351. return (uint8_t)(ButtonState[controller] >> 8);
  352. else if(b == R2)
  353. return (uint8_t)ButtonState[controller];
  354. return (bool)(ButtonState[controller] & ((uint32_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]) << 16));
  355. }
  356. bool XBOXRECV::getButtonClick(ButtonEnum b, uint8_t controller) {
  357. if(b == L2) {
  358. if(L2Clicked[controller]) {
  359. L2Clicked[controller] = false;
  360. return true;
  361. }
  362. return false;
  363. } else if(b == R2) {
  364. if(R2Clicked[controller]) {
  365. R2Clicked[controller] = false;
  366. return true;
  367. }
  368. return false;
  369. }
  370. uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
  371. bool click = (ButtonClickState[controller] & button);
  372. ButtonClickState[controller] &= ~button; // clear "click" event
  373. return click;
  374. }
  375. int16_t XBOXRECV::getAnalogHat(AnalogHatEnum a, uint8_t controller) {
  376. return hatValue[controller][a];
  377. }
  378. bool XBOXRECV::buttonChanged(uint8_t controller) {
  379. bool state = buttonStateChanged[controller];
  380. buttonStateChanged[controller] = false;
  381. return state;
  382. }
  383. /*
  384. ControllerStatus Breakdown
  385. ControllerStatus[controller] & 0x0001 // 0
  386. ControllerStatus[controller] & 0x0002 // normal batteries, no rechargeable battery pack
  387. ControllerStatus[controller] & 0x0004 // controller starting up / settling
  388. ControllerStatus[controller] & 0x0008 // headset adapter plugged in, but no headphones connected (mute?)
  389. ControllerStatus[controller] & 0x0010 // 0
  390. ControllerStatus[controller] & 0x0020 // 1
  391. ControllerStatus[controller] & 0x0040 // battery level (high bit)
  392. ControllerStatus[controller] & 0x0080 // battery level (low bit)
  393. ControllerStatus[controller] & 0x0100 // 1
  394. ControllerStatus[controller] & 0x0200 // 1
  395. ControllerStatus[controller] & 0x0400 // headset adapter plugged in
  396. ControllerStatus[controller] & 0x0800 // 0
  397. ControllerStatus[controller] & 0x1000 // 1
  398. ControllerStatus[controller] & 0x2000 // 0
  399. ControllerStatus[controller] & 0x4000 // 0
  400. ControllerStatus[controller] & 0x8000 // 0
  401. */
  402. uint8_t XBOXRECV::getBatteryLevel(uint8_t controller) {
  403. return ((controllerStatus[controller] & 0x00C0) >> 6);
  404. }
  405. void XBOXRECV::XboxCommand(uint8_t controller, uint8_t* data, uint16_t nbytes) {
  406. #ifdef EXTRADEBUG
  407. uint8_t rcode;
  408. #endif
  409. uint8_t outputPipe;
  410. switch(controller) {
  411. case 0: outputPipe = XBOX_OUTPUT_PIPE_1;
  412. break;
  413. case 1: outputPipe = XBOX_OUTPUT_PIPE_2;
  414. break;
  415. case 2: outputPipe = XBOX_OUTPUT_PIPE_3;
  416. break;
  417. case 3: outputPipe = XBOX_OUTPUT_PIPE_4;
  418. break;
  419. default:
  420. return;
  421. }
  422. #ifdef EXTRADEBUG
  423. rcode =
  424. #endif
  425. pUsb->outTransfer(bAddress, epInfo[ outputPipe ].epAddr, nbytes, data);
  426. #ifdef EXTRADEBUG
  427. if(rcode)
  428. Notify(PSTR("Error sending Xbox message\r\n"), 0x80);
  429. #endif
  430. }
  431. void XBOXRECV::disconnect(uint8_t controller) {
  432. writeBuf[0] = 0x00;
  433. writeBuf[1] = 0x00;
  434. writeBuf[2] = 0x08;
  435. writeBuf[3] = 0xC0;
  436. XboxCommand(controller, writeBuf, 4);
  437. }
  438. void XBOXRECV::setLedRaw(uint8_t value, uint8_t controller) {
  439. writeBuf[0] = 0x00;
  440. writeBuf[1] = 0x00;
  441. writeBuf[2] = 0x08;
  442. writeBuf[3] = value | 0x40;
  443. XboxCommand(controller, writeBuf, 4);
  444. }
  445. void XBOXRECV::setLedOn(LEDEnum led, uint8_t controller) {
  446. if(led == OFF)
  447. setLedRaw(0, controller);
  448. else if(led != ALL) // All LEDs can't be on a the same time
  449. setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]) + 4, controller);
  450. }
  451. void XBOXRECV::setLedBlink(LEDEnum led, uint8_t controller) {
  452. setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]), controller);
  453. }
  454. void XBOXRECV::setLedMode(LEDModeEnum ledMode, uint8_t controller) { // This function is used to do some speciel LED stuff the controller supports
  455. setLedRaw((uint8_t)ledMode, controller);
  456. }
  457. /* PC runs this at interval of approx 2 seconds
  458. Thanks to BusHound from Perisoft.net for the Windows USB Analysis output
  459. Found by timstamp.co.uk
  460. */
  461. void XBOXRECV::checkStatus() {
  462. if(!bPollEnable)
  463. return;
  464. // Get controller info
  465. writeBuf[0] = 0x08;
  466. writeBuf[1] = 0x00;
  467. writeBuf[2] = 0x0f;
  468. writeBuf[3] = 0xc0;
  469. for(uint8_t i = 0; i < 4; i++) {
  470. XboxCommand(i, writeBuf, 4);
  471. }
  472. // Get battery status
  473. writeBuf[0] = 0x00;
  474. writeBuf[1] = 0x00;
  475. writeBuf[2] = 0x00;
  476. writeBuf[3] = 0x40;
  477. for(uint8_t i = 0; i < 4; i++) {
  478. if(Xbox360Connected[i])
  479. XboxCommand(i, writeBuf, 4);
  480. }
  481. }
  482. void XBOXRECV::setRumbleOn(uint8_t lValue, uint8_t rValue, uint8_t controller) {
  483. writeBuf[0] = 0x00;
  484. writeBuf[1] = 0x01;
  485. writeBuf[2] = 0x0f;
  486. writeBuf[3] = 0xc0;
  487. writeBuf[4] = 0x00;
  488. writeBuf[5] = lValue; // big weight
  489. writeBuf[6] = rValue; // small weight
  490. XboxCommand(controller, writeBuf, 7);
  491. }
  492. void XBOXRECV::onInit(uint8_t controller) {
  493. if(pFuncOnInit)
  494. pFuncOnInit(); // Call the user function
  495. else {
  496. LEDEnum led;
  497. if(controller == 0)
  498. led = LED1;
  499. else if(controller == 1)
  500. led = LED2;
  501. else if(controller == 2)
  502. led = LED3;
  503. else
  504. led = LED4;
  505. setLedOn(led, controller);
  506. }
  507. }