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