USB Host Shield 2.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
XBOXOLD.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2013 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 "XBOXOLD.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 controller
22 
24 const uint8_t XBOXOLDBUTTONS[] PROGMEM = {
25  0x01, // UP
26  0x08, // RIGHT
27  0x02, // DOWN
28  0x04, // LEFT
29 
30  0x20, // BACK
31  0x10, // START
32  0x40, // L3
33  0x80, // R3
34 
35  // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
36  4, // BLACK
37  5, // WHTIE
38  6, // L1
39  7, // R1
40 
41  1, // B
42  0, // A
43  2, // X
44  3, // Y
45 };
46 
48 pUsb(p), // pointer to USB class instance - mandatory
49 bAddress(0), // device address - mandatory
50 bPollEnable(false) { // don't start polling before dongle is connected
51  for (uint8_t i = 0; i < XBOX_MAX_ENDPOINTS; i++) {
52  epInfo[i].epAddr = 0;
53  epInfo[i].maxPktSize = (i) ? 0 : 8;
54  epInfo[i].epAttribs = 0;
56  }
57 
58  if (pUsb) // register in USB subsystem
59  pUsb->RegisterDeviceClass(this); //set devConfig[] entry
60 }
61 
62 uint8_t XBOXOLD::Init(uint8_t parent, uint8_t port, bool lowspeed) {
63  uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
64  uint8_t rcode;
65  UsbDevice *p = NULL;
66  EpInfo *oldep_ptr = NULL;
67  uint16_t PID;
68  uint16_t VID;
69 
70  // get memory address of USB device address pool
71  AddressPool &addrPool = pUsb->GetAddressPool();
72 #ifdef EXTRADEBUG
73  Notify(PSTR("\r\nXBOXUSB Init"), 0x80);
74 #endif
75  // check if address has already been assigned to an instance
76  if (bAddress) {
77 #ifdef DEBUG_USB_HOST
78  Notify(PSTR("\r\nAddress in use"), 0x80);
79 #endif
81  }
82 
83  // Get pointer to pseudo device with address 0 assigned
84  p = addrPool.GetUsbDevicePtr(0);
85 
86  if (!p) {
87 #ifdef DEBUG_USB_HOST
88  Notify(PSTR("\r\nAddress not found"), 0x80);
89 #endif
91  }
92 
93  if (!p->epinfo) {
94 #ifdef DEBUG_USB_HOST
95  Notify(PSTR("\r\nepinfo is null"), 0x80);
96 #endif
98  }
99 
100  // Save old pointer to EP_RECORD of address 0
101  oldep_ptr = p->epinfo;
102 
103  // Temporary assign new pointer to epInfo to p->epinfo in order to avoid toggle inconsistence
104  p->epinfo = epInfo;
105 
106  p->lowspeed = lowspeed;
107 
108  // Get device descriptor
109  rcode = pUsb->getDevDescr(0, 0, sizeof (USB_DEVICE_DESCRIPTOR), (uint8_t*)buf); // Get device descriptor - addr, ep, nbytes, data
110  // Restore p->epinfo
111  p->epinfo = oldep_ptr;
112 
113  if (rcode)
114  goto FailGetDevDescr;
115 
116  VID = ((USB_DEVICE_DESCRIPTOR*)buf)->idVendor;
117  PID = ((USB_DEVICE_DESCRIPTOR*)buf)->idProduct;
118 
119  if ((VID != XBOX_VID && VID != MADCATZ_VID && VID != JOYTECH_VID) || (PID != XBOX_OLD_PID1 && PID != XBOX_OLD_PID2 && PID != XBOX_OLD_PID3 && PID != XBOX_OLD_PID4)) // Check if VID and PID match
120  goto FailUnknownDevice;
121 
122  // Allocate new address according to device class
123  bAddress = addrPool.AllocAddress(parent, false, port);
124 
125  if (!bAddress)
127 
128  // Extract Max Packet Size from device descriptor
129  epInfo[0].maxPktSize = (uint8_t)((USB_DEVICE_DESCRIPTOR*)buf)->bMaxPacketSize0;
130 
131  // Assign new address to the device
132  rcode = pUsb->setAddr(0, 0, bAddress);
133  if (rcode) {
134  p->lowspeed = false;
135  addrPool.FreeAddress(bAddress);
136  bAddress = 0;
137 #ifdef DEBUG_USB_HOST
138  Notify(PSTR("\r\nsetAddr: "), 0x80);
139  D_PrintHex<uint8_t > (rcode, 0x80);
140 #endif
141  return rcode;
142  }
143 #ifdef EXTRADEBUG
144  Notify(PSTR("\r\nAddr: "), 0x80);
145  D_PrintHex<uint8_t > (bAddress, 0x80);
146 #endif
147  delay(300); // Spec says you should wait at least 200ms
148 
149  p->lowspeed = false;
150 
151  //get pointer to assigned address record
152  p = addrPool.GetUsbDevicePtr(bAddress);
153  if (!p)
155 
156  p->lowspeed = lowspeed;
157 
158  // Assign epInfo to epinfo pointer - only EP0 is known
159  rcode = pUsb->setEpInfoEntry(bAddress, 1, epInfo);
160  if (rcode)
161  goto FailSetDevTblEntry;
162 
163  /* The application will work in reduced host mode, so we can save program and data
164  memory space. After verifying the VID we will use known values for the
165  configuration values for device, interface, endpoints and HID for the XBOX controllers */
166 
167  /* Initialize data structures for endpoints of device */
168  epInfo[ XBOX_INPUT_PIPE ].epAddr = 0x01; // XBOX report endpoint
170  epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
174  epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX output endpoint
176  epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints
180 
181  rcode = pUsb->setEpInfoEntry(bAddress, 3, epInfo);
182  if (rcode)
183  goto FailSetDevTblEntry;
184 
185  delay(200); // Give time for address change
186 
187  rcode = pUsb->setConf(bAddress, epInfo[ XBOX_CONTROL_PIPE ].epAddr, 1);
188  if (rcode)
189  goto FailSetConfDescr;
190 
191 #ifdef DEBUG_USB_HOST
192  Notify(PSTR("\r\nXbox Controller Connected\r\n"), 0x80);
193 #endif
194  if (pFuncOnInit)
195  pFuncOnInit(); // Call the user function
196  XboxConnected = true;
197  bPollEnable = true;
198  return 0; // Successful configuration
199 
200  /* Diagnostic messages */
201 FailGetDevDescr:
202 #ifdef DEBUG_USB_HOST
204  goto Fail;
205 #endif
206 
207 FailSetDevTblEntry:
208 #ifdef DEBUG_USB_HOST
210  goto Fail;
211 #endif
212 
213 FailSetConfDescr:
214 #ifdef DEBUG_USB_HOST
216  goto Fail;
217 #endif
218 FailUnknownDevice:
219 #ifdef DEBUG_USB_HOST
220  NotifyFailUnknownDevice(VID, PID);
221 #endif
223 
224 Fail:
225 #ifdef DEBUG_USB_HOST
226  Notify(PSTR("\r\nXbox Init Failed, error code: "), 0x80);
227  NotifyFail(rcode);
228 #endif
229  Release();
230  return rcode;
231 }
232 
233 /* Performs a cleanup after failed Init() attempt */
234 uint8_t XBOXOLD::Release() {
235  XboxConnected = false;
237  bAddress = 0;
238  bPollEnable = false;
239  return 0;
240 }
241 
242 uint8_t XBOXOLD::Poll() {
243  if (!bPollEnable)
244  return 0;
245  uint16_t BUFFER_SIZE = EP_MAXPKTSIZE;
246  pUsb->inTransfer(bAddress, epInfo[ XBOX_INPUT_PIPE ].epAddr, &BUFFER_SIZE, readBuf); // input on endpoint 1
247  readReport();
248 #ifdef PRINTREPORT
249  printReport(BUFFER_SIZE); // Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
250 #endif
251  return 0;
252 }
253 
254 void XBOXOLD::readReport() {
255  ButtonState = readBuf[2];
256 
257  for (uint8_t i = 0; i < sizeof(buttonValues); i++)
258  buttonValues[i] = readBuf[i + 4]; // A, B, X, Y, BLACK, WHITE, L1, and R1
259 
260  hatValue[LeftHatX] = (int16_t)(((uint16_t)readBuf[12] << 8) | readBuf[13]);
261  hatValue[LeftHatY] = (int16_t)(((uint16_t)readBuf[14] << 8) | readBuf[15]);
262  hatValue[RightHatX] = (int16_t)(((uint16_t)readBuf[16] << 8) | readBuf[17]);
263  hatValue[RightHatY] = (int16_t)(((uint16_t)readBuf[18] << 8) | readBuf[19]);
264 
265  //Notify(PSTR("\r\nButtonState"), 0x80);
266  //PrintHex<uint8_t>(ButtonState, 0x80);
267 
268  if (ButtonState != OldButtonState || memcmp(buttonValues, oldButtonValues, sizeof(buttonValues)) != 0) {
269  ButtonClickState = ButtonState & ~OldButtonState; // Update click state variable
270  OldButtonState = ButtonState;
271 
272  for (uint8_t i = 0; i < sizeof(buttonValues); i++) {
273  if (oldButtonValues[i] == 0 && buttonValues[i] != 0)
274  buttonClicked[i] = true; // Update A, B, X, Y, BLACK, WHITE, L1, and R1 click state
275  oldButtonValues[i] = buttonValues[i];
276  }
277  }
278 }
279 
280 void XBOXOLD::printReport(uint16_t length) { //Uncomment "#define PRINTREPORT" to print the report send by the Xbox controller
281 #ifdef PRINTREPORT
282  if (readBuf == NULL)
283  return;
284  for (uint8_t i = 0; i < length; i++) {
285  D_PrintHex<uint8_t > (readBuf[i], 0x80);
286  Notify(PSTR(" "), 0x80);
287  }
288  Notify(PSTR("\r\n"), 0x80);
289 #endif
290 }
291 
293  uint8_t button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]);
294  if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
295  return buttonValues[button]; // Analog buttons
296  return (ButtonState & button); // Digital buttons
297 }
298 
300  uint8_t button = pgm_read_byte(&XBOXOLDBUTTONS[(uint8_t)b]);
301  if (b == A || b == B || b == X || b == Y || b == BLACK || b == WHITE || b == L1 || b == R1) { // A, B, X, Y, BLACK, WHITE, L1, and R1 are analog buttons
302  if (buttonClicked[button]) {
303  buttonClicked[button] = false;
304  return true;
305  }
306  return false;
307  }
308 
309  bool click = (ButtonClickState & button);
310  ButtonClickState &= ~button; // clear "click" event
311  return click;
312 }
313 
315  return hatValue[a];
316 }
317 
318 /* Xbox Controller commands */
319 void XBOXOLD::XboxCommand(uint8_t* data, uint16_t nbytes) {
320  //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)
321  pUsb->ctrlReq(bAddress, epInfo[XBOX_CONTROL_PIPE].epAddr, bmREQ_HID_OUT, HID_REQUEST_SET_REPORT, 0x00, 0x02, 0x00, nbytes, nbytes, data, NULL);
322 }
323 
324 void XBOXOLD::setRumbleOn(uint8_t lValue, uint8_t rValue) {
325  uint8_t writeBuf[6];
326 
327  writeBuf[0] = 0x00;
328  writeBuf[1] = 0x06;
329  writeBuf[2] = 0x00;
330  writeBuf[3] = rValue; // small weight
331  writeBuf[4] = 0x00;
332  writeBuf[5] = lValue; // big weight
333 
334  XboxCommand(writeBuf, 6);
335 }
uint8_t bmRcvToggle
Definition: address.h:41
EpInfo * epinfo
Definition: address.h:76
bool lowspeed
Definition: address.h:79
#define USB_ERROR_EPINFO_IS_NULL
Definition: UsbCore.h:67
uint8_t bmNakPower
Definition: address.h:42
virtual uint8_t Release()
Definition: XBOXOLD.cpp:234
#define NotifyFail(...)
Definition: message.h:55
const uint8_t XBOXOLDBUTTONS[]
Definition: XBOXOLD.cpp:24
uint8_t setConf(uint8_t addr, uint8_t ep, uint8_t conf_value)
Definition: Usb.cpp:798
void setRumbleOn(uint8_t lValue, uint8_t rValue)
Definition: XBOXOLD.cpp:324
#define NotifyFailGetDevDescr(...)
Definition: message.h:50
uint8_t setEpInfoEntry(uint8_t addr, uint8_t epcount, EpInfo *eprecord_ptr)
Definition: Usb.cpp:64
#define XBOX_OLD_PID4
Definition: XBOXOLD.h:43
EpInfo epInfo[XBOX_MAX_ENDPOINTS]
Definition: XBOXOLD.h:160
#define EP_MAXPKTSIZE
Definition: PS3USB.h:25
virtual void FreeAddress(uint8_t addr)=0
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:793
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
XBOXOLD(USB *pUsb)
Definition: XBOXOLD.cpp:47
#define EP_INTERRUPT
Definition: PS3USB.h:28
#define XBOX_OLD_PID1
Definition: XBOXOLD.h:40
Definition: address.h:32
#define HID_REQUEST_SET_REPORT
Definition: BTD.h:39
#define JOYTECH_VID
Definition: XBOXOLD.h:38
uint8_t getButtonPress(Button b)
Definition: XBOXOLD.cpp:292
USB * pUsb
Definition: XBOXOLD.h:156
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:69
int16_t getAnalogHat(AnalogHat a)
Definition: XBOXOLD.cpp:314
virtual uint8_t Poll()
Definition: XBOXOLD.cpp:242
#define XBOX_OLD_PID2
Definition: XBOXOLD.h:41
#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:66
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:61
virtual uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed)
Definition: XBOXOLD.cpp:62
#define XBOX_MAX_ENDPOINTS
Definition: XBOXOLD.h:49
#define bmRCVTOG0
Definition: max3421e.h:185
bool getButtonClick(Button b)
Definition: XBOXOLD.cpp:299
#define XBOX_OLD_PID3
Definition: XBOXOLD.h:42
#define bmREQ_HID_OUT
Definition: BTD.h:38
#define USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL
Definition: UsbCore.h:64
Button
bool XboxConnected
Definition: XBOXOLD.h:148
#define bmSNDTOG0
Definition: max3421e.h:187
uint8_t maxPktSize
Definition: address.h:34
AddressPool & GetAddressPool()
Definition: UsbCore.h:168
Definition: UsbCore.h:152
#define XBOX_CONTROL_PIPE
Definition: XBOXOLD.h:31
uint8_t bAddress
Definition: XBOXOLD.h:158
uint8_t RegisterDeviceClass(USBDeviceConfig *pdev)
Definition: UsbCore.h:172
#define NotifyFailSetConfDescr(...)
Definition: message.h:53
AnalogHat
uint8_t getDevDescr(uint8_t addr, uint8_t ep, uint16_t nbytes, uint8_t *dataptr)
defined(USB_METHODS_INLINE)
Definition: Usb.cpp:759
#define NotifyFailSetDevTblEntry(...)
Definition: message.h:51