USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
XBOXUSB.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
2 
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 
10  Contact information
11  -------------------
12 
13  Kristian Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "XBOXUSB.h"
19 // To enable serial debugging see "settings.h"
20 //#define EXTRADEBUG // Uncomment to get even more debugging data
21 //#define PRINTREPORT // Uncomment to print the report send by the Xbox 360 Controller
22 
24 pUsb(p), // pointer to USB class instance - mandatory
25 bAddress(0), // device address - mandatory
26 bPollEnable(false) { // don't start polling before dongle is connected
27  for(uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
28  epInfo[i].epAddr = 0;
29  epInfo[i].maxPktSize = (i) ? 0 : 8;
30  epInfo[i].epAttribs = 0;
32  }
33 
34  if(pUsb) // register in USB subsystem
35  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
36 }
37 
38 uint8_t XBOXUSB::Init(uint8_t parent, uint8_t port, bool lowspeed) {
39  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
40  USB_DEVICE_DESCRIPTOR * udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
41  uint8_t rcode;
42  UsbDevice *p = NULL;
43  EpInfo *oldep_ptr = NULL;
44  uint16_t PID;
45  uint16_t VID;
46 
47  // get memory address of USB device address pool
48  AddressPool &addrPool = pUsb->GetAddressPool();
49 #ifdef EXTRADEBUG
50  Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
51 #endif
52  // check if address has already been assigned to an instance
53  if(bAddress) {
54 #ifdef DEBUG_USB_HOST
55  Notify(PSTR("\r\nAddress in use"), 0x80);
56 #endif
58  }
59 
60  // Get pointer to pseudo device with address 0 assigned
61  p = addrPool.GetUsbDevicePtr(0);
62 
63  if(!p) {
64 #ifdef DEBUG_USB_HOST
65  Notify(PSTR("\r\nAddress not found"), 0x80);
66 #endif
68  }
69 
70  if(!p->epinfo) {
71 #ifdef DEBUG_USB_HOST
72  Notify(PSTR("\r\nepinfo is null"), 0x80);
73 #endif
75  }
76 
77  // Save old pointer to EP_RECORD of address 0
78  oldep_ptr = p->epinfo;
79 
80  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
81  p->epinfo = epInfo;
82 
83  p->lowspeed = lowspeed;
84 
85  // Get device descriptor
86  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
87  // Restore p->epinfo
88  p->epinfo = oldep_ptr;
89 
90  if(rcode)
91  goto FailGetDevDescr;
92 
93  VID = udd->idVendor;
94  PID = udd->idProduct;
95 
96  if(VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID && VID != GAMESTOP_VID) // Check VID
97  goto FailUnknownDevice;
98  if(PID == XBOX_WIRELESS_PID) {
99 #ifdef DEBUG_USB_HOST
100  Notify(PSTR("\r\nYou have plugged in a wireless Xbox 360 controller - it doesn't support USB communication"), 0x80);
101 #endif
102  goto FailUnknownDevice;
104 #ifdef DEBUG_USB_HOST
105  Notify(PSTR("\r\nThis library only supports Xbox 360 controllers via USB"), 0x80);
106 #endif
107  goto FailUnknownDevice;
108  } else if(PID != XBOX_WIRED_PID && PID != MADCATZ_WIRED_PID && PID != GAMESTOP_WIRED_PID && PID != AFTERGLOW_WIRED_PID) // Check PID
109  goto FailUnknownDevice;
110 
111  // Allocate new address according to device class
112  bAddress = addrPool.AllocAddress(parent, false, port);
113 
114  if(!bAddress)
116 
117  // Extract Max Packet Size from device descriptor
118  epInfo[0].maxPktSize = udd->bMaxPacketSize0;
119 
120  // Assign new address to the device
121  rcode = pUsb->setAddr(0, 0, bAddress);
122  if(rcode) {
123  p->lowspeed = false;
124  addrPool.FreeAddress(bAddress);
125  bAddress = 0;
126 #ifdef DEBUG_USB_HOST
127  Notify(PSTR("\r\nsetAddr: "), 0x80);
128  D_PrintHex<uint8_t > (rcode, 0x80);
129 #endif
130  return rcode;
131  }
132 #ifdef EXTRADEBUG
133  Notify(PSTR("\r\nAddr: "), 0x80);
134  D_PrintHex<uint8_t > (bAddress, 0x80);
135 #endif
136  //delay(300); // Spec says you should wait at least 200ms
137 
138  p->lowspeed = false;
139 
140  //get pointer to assigned address record
141  p = addrPool.GetUsbDevicePtr(bAddress);
142  if(!p)
144 
145  p->lowspeed = lowspeed;
146 
147  // Assign epInfo to epinfo pointer - only EP0 is known
148  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
149  if(rcode)
150  goto FailSetDevTblEntry;
151 
152  /* The application will work in reduced host mode, so we can save program and data
153  memory space. After verifying the VID we will use known values for the
154  configuration values for device, interface, endpoints and HID for the XBOX360 Controllers */
155 
156  /* Initialize data structures for endpoints of device */
157  epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX 360 report endpoint
159  epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
163  epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint
165  epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
169 
170  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
171  if(rcode)
172  goto FailSetDevTblEntry;
173 
174  delay(200); // Give time for address change
175 
176  rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
177  if(rcode)
178  goto FailSetConfDescr;
179 
180 #ifdef DEBUG_USB_HOST
181  Notify(PSTR("\r\nXbox 360 Controller Connected\r\n"), 0x80);
182 #endif
183  onInit();
184  Xbox360Connected = true;
185  bPollEnable = true;
186  return 0; // Successful configuration
187 
188  /* Diagnostic messages */
189 FailGetDevDescr:
190 #ifdef DEBUG_USB_HOST
192  goto Fail;
193 #endif
194 
195 FailSetDevTblEntry:
196 #ifdef DEBUG_USB_HOST
198  goto Fail;
199 #endif
200 
201 FailSetConfDescr:
202 #ifdef DEBUG_USB_HOST
204 #endif
205  goto Fail;
206 
207 FailUnknownDevice:
208 #ifdef DEBUG_USB_HOST
209  NotifyFailUnknownDevice(VID, PID);
210 #endif
212 
213 Fail:
214 #ifdef DEBUG_USB_HOST
215  Notify(PSTR("\r\nXbox 360 Init Failed, error code: "), 0x80);
216  NotifyFail(rcode);
217 #endif
218  Release();
219  return rcode;
220 }
221 
222 /* Performs a cleanup after failed Init() attempt */
223 uint8_t XBOXUSB::Release() {
224  Xbox360Connected = false;
226  bAddress = 0;
227  bPollEnable = false;
228  return 0;
229 }
230 
231 uint8_t XBOXUSB::Poll() {
232  if(!bPollEnable)
233  return 0;
234  uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
235  pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
236  readReport();
237 #ifdef PRINTREPORT
238  printReport(); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
239 #endif
240  return 0;
241 }
242 
243 void XBOXUSB::readReport() {
244  if(readBuf == NULL)
245  return;
246  if(readBuf[0] != 0x00 || readBuf[1] != 0x14) { // Check if it's the correct report - the controller also sends different status reports
247  return;
248  }
249 
250  ButtonState = (uint32_t)(readBuf[5] | ((uint16_t)readBuf[4] << 8) | ((uint32_t)readBuf[3] << 16) | ((uint32_t)readBuf[2] << 24));
251 
252  hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[7] << 8) | readBuf[6]);
253  hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[9] << 8) | readBuf[8]);
254  hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[11] << 8) | readBuf[10]);
255  hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[13] << 8) | readBuf[12]);
256 
257  //Notify(PSTR("\r\nButtonState"), 0x80);
258  //PrintHex<uint32_t>(ButtonState, 0x80);
259 
260  if(ButtonState != OldButtonState) {
261  ButtonClickState = (ButtonState >> 16) & ((~OldButtonState) >> 16); // Update click state variable, but don't include the two trigger buttons L2 and R2
262  if(((uint8_t)OldButtonState) == 0 && ((uint8_t)ButtonState) != 0) // The L2 and R2 buttons are special as they are analog buttons
263  R2Clicked = true;
264  if((uint8_t)(OldButtonState >> 8) == 0 && (uint8_t)(ButtonState >> 8) != 0)
265  L2Clicked = true;
266  OldButtonState = ButtonState;
267  }
268 }
269 
270 void XBOXUSB::printReport() { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox 360 Controller
271 #ifdef PRINTREPORT
272  if(readBuf == NULL)
273  return;
274  for(uint8_t i = 0; i < XBOX_REPORT_BUFFER_SIZE; i++) {
275  D_PrintHex<uint8_t > (readBuf[i], 0x80);
276  Notify(PSTR(" "), 0x80);
277  }
278  Notify(PSTR("\r\n"), 0x80);
279 #endif
280 }
281 
283  if(b == L2) // These are analog buttons
284  return (uint8_t)(ButtonState >> 8);
285  else if(b == R2)
286  return (uint8_t)ButtonState;
287  return (bool)(ButtonState & ((uint32_t)pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]) << 16));
288 }
289 
291  if(b == L2) {
292  if(L2Clicked) {
293  L2Clicked = false;
294  return true;
295  }
296  return false;
297  } else if(b == R2) {
298  if(R2Clicked) {
299  R2Clicked = false;
300  return true;
301  }
302  return false;
303  }
304  uint16_t button = pgm_read_word(&XBOX_BUTTONS[(uint8_t)b]);
305  bool click = (ButtonClickState & button);
306  ButtonClickState &= ~button; // clear "click" event
307  return click;
308 }
309 
311  return hatValue[a];
312 }
313 
314 /* Xbox Controller commands */
315 void XBOXUSB::XboxCommand(uint8_t* data, uint16_t nbytes) {
316  //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)
317  pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
318 }
319 
320 void XBOXUSB::setLedRaw(uint8_t value) {
321  writeBuf[0] = 0x01;
322  writeBuf[1] = 0x03;
323  writeBuf[2] = value;
324 
325  XboxCommand(writeBuf, 3);
326 }
327 
329  if(led == OFF)
330  setLedRaw(0);
331  else if(led != ALL) // All LEDs can't be on a the same time
332  setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]) + 4);
333 }
334 
336  setLedRaw(pgm_read_byte(&XBOX_LEDS[(uint8_t)led]));
337 }
338 
339 void XBOXUSB::setLedMode(LEDModeEnum ledMode) { // This function is used to do some special LED stuff the controller supports
340  setLedRaw((uint8_t)ledMode);
341 }
342 
343 void XBOXUSB::setRumbleOn(uint8_t lValue, uint8_t rValue) {
344  writeBuf[0] = 0x00;
345  writeBuf[1] = 0x08;
346  writeBuf[2] = 0x00;
347  writeBuf[3] = lValue; // big weight
348  writeBuf[4] = rValue; // small weight
349  writeBuf[5] = 0x00;
350  writeBuf[6] = 0x00;
351  writeBuf[7] = 0x00;
352 
353  XboxCommand(writeBuf, 8);
354 }
355 
356 void XBOXUSB::onInit() {
357  if(pFuncOnInit)
358  pFuncOnInit(); // Call the user function
359  else
360  setLedOn(LED1);
361 }
#define XBOX_WIRED_PID
Definition: XBOXUSB.h:41
uint8_t bmRcvToggle
Definition: address.h:41
#define XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID
Definition: XBOXRECV.h:49
LEDModeEnum
Definition: xboxEnums.h:24
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:81
uint8_t bmNakPower
Definition: address.h:42
#define XBOX_WIRELESS_RECEIVER_PID
Definition: XBOXRECV.h:48
void setLedOn(LEDEnum l)
Definition: XBOXUSB.cpp:328
#define NotifyFail(...)
Definition: message.h:55
AnalogHatEnum
USB * pUsb
Definition: XBOXUSB.h:194
#define XBOX_REPORT_BUFFER_SIZE
Definition: XBOXUSB.h:49
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:805
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: XBOXUSB.cpp:38
int16_t getAnalogHat(AnalogHatEnum a)
Definition: XBOXUSB.cpp:310
void setLedBlink(LEDEnum l)
Definition: XBOXUSB.cpp:335
#define NotifyFailGetDevDescr(...)
Definition: message.h:50
#define AFTERGLOW_WIRED_PID
Definition: XBOXUSB.h:47
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
#define EP_MAXPKTSIZE
Definition: PS3USB.h:25
virtual void FreeAddress(uint8_t addr)=0
LEDEnum
uint8_t epAttribs
Definition: address.h:37
uint8_t ctrlReq(uint8_t addr, uint8_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint16_t total, uint16_t nbytes, uint8_t *dataptr, USBReadParser *p)
Definition: Usb.cpp:126
virtual UsbDevice * GetUsbDevicePtr(uint8_t addr)=0
#define Notify(...)
Definition: message.h:44
uint8_t setAddr(uint8_t oldaddr, uint8_t ep, uint8_t newaddr)
Definition: Usb.cpp:796
uint8_t epAddr
Definition: address.h:33
#define NotifyFailUnknownDevice(...)
Definition: message.h:54
#define USB_NAK_MAX_POWER
Definition: address.h:27
#define XBOX_VID
Definition: XBOXOLD.h:36
#define XBOX_INPUT_PIPE
Definition: XBOXOLD.h:32
uint8_t bAddress
Definition: XBOXUSB.h:196
uint8_t getButtonPress(ButtonEnum b)
Definition: XBOXUSB.cpp:282
#define EP_INTERRUPT
Definition: PS3USB.h:28
Definition: address.h:32
#define XBOX_WIRELESS_PID
Definition: XBOXUSB.h:42
ButtonEnum
bool Xbox360Connected
Definition: XBOXUSB.h:186
#define HID_REQUEST_SET_REPORT
Definition: BTD.h:39
#define JOYTECH_VID
Definition: XBOXOLD.h:38
virtual uint8_t AllocAddress(uint8_t parent, bool is_hub=false, uint8_t port=0)=0
uint8_t bmSndToggle
Definition: address.h:40
#define USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE
Definition: UsbCore.h:83
void setRumbleOn(uint8_t lValue, uint8_t rValue)
Definition: XBOXUSB.cpp:343
XBOXUSB(USB *pUsb)
Definition: XBOXUSB.cpp:23
#define MADCATZ_VID
Definition: XBOXOLD.h:37
#define XBOX_OUTPUT_PIPE
Definition: XBOXOLD.h:33
#define USB_NAK_NOWAIT
Definition: address.h:29
#define USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL
Definition: UsbCore.h:80
uint8_t inTransfer(uint8_t addr, uint8_t ep, uint16_t *nbytesptr, uint8_t *data)
Definition: Usb.cpp:206
#define USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED
Definition: UsbCore.h:75
#define GAMESTOP_VID
Definition: XBOXUSB.h:39
const uint8_t XBOX_LEDS[]
Definition: xboxEnums.h:32
bool getButtonClick(ButtonEnum b)
Definition: XBOXUSB.cpp:290
#define XBOX_MAX_ENDPOINTS
Definition: XBOXOLD.h:49
#define bmREQ_HID_OUT
Definition: BTD.h:38
void setLedRaw(uint8_t value)
Definition: XBOXUSB.cpp:320
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:78
void setLedMode(LEDModeEnum lm)
Definition: XBOXUSB.cpp:339
#define MADCATZ_WIRED_PID
Definition: XBOXUSB.h:45
uint8_t maxPktSize
Definition: address.h:34
AddressPool & GetAddressPool()
Definition: UsbCore.h:206
Definition: UsbCore.h:190
#define XBOX_CONTROL_PIPE
Definition: XBOXOLD.h:31
virtual uint8_t Release()
Definition: XBOXUSB.cpp:223
const uint16_t XBOX_BUTTONS[]
Definition: xboxEnums.h:41
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:210
#define NotifyFailSetConfDescr(...)
Definition: message.h:53
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:761
virtual uint8_t Poll()
Definition: XBOXUSB.cpp:231
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51
EpInfo epInfo[XBOX_MAX_ENDPOINTS]
Definition: XBOXUSB.h:198
#define GAMESTOP_WIRED_PID
Definition: XBOXUSB.h:46