diff options
author | Ryan <fauxpark@gmail.com> | 2021-08-18 18:20:25 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-18 18:20:25 +1000 |
commit | b16091659cc9a724a8800f77e631643b4ab089ad (patch) | |
tree | e44933472c6d100bd4fc5d8a693d9d21e3c32f6f /lib/usbhost/USB_Host_Shield_2.0/XBOXUSB.cpp | |
parent | cf5e40c25139ff64ff246f1c6280e983ef75551c (diff) | |
download | qmk_firmware-b16091659cc9a724a8800f77e631643b4ab089ad.tar.gz qmk_firmware-b16091659cc9a724a8800f77e631643b4ab089ad.zip |
Move USB Host Shield and Arduino core to `lib/` (#13973)
Diffstat (limited to 'lib/usbhost/USB_Host_Shield_2.0/XBOXUSB.cpp')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/XBOXUSB.cpp | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/XBOXUSB.cpp b/lib/usbhost/USB_Host_Shield_2.0/XBOXUSB.cpp new file mode 100644 index 000000000..ddece21b4 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/XBOXUSB.cpp | |||
@@ -0,0 +1,361 @@ | |||
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 | |||
23 | XBOXUSB::XBOXUSB(USB *p) : | ||
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; | ||
31 | epInfo[i].bmNakPower = (i) ? USB_NAK_NOWAIT : USB_NAK_MAX_POWER; | ||
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 | ||
57 | return USB_ERROR_CLASS_INSTANCE_ALREADY_IN_USE; | ||
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 | ||
67 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
68 | } | ||
69 | |||
70 | if(!p->epinfo) { | ||
71 | #ifdef DEBUG_USB_HOST | ||
72 | Notify(PSTR("\r\nepinfo is null"), 0x80); | ||
73 | #endif | ||
74 | return USB_ERROR_EPINFO_IS_NULL; | ||
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; | ||
103 | } else if(PID == XBOX_WIRELESS_RECEIVER_PID || PID == XBOX_WIRELESS_RECEIVER_THIRD_PARTY_PID) { | ||
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 && PID != JOYTECH_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) | ||
115 | return USB_ERROR_OUT_OF_ADDRESS_SPACE_IN_POOL; | ||
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) | ||
143 | return USB_ERROR_ADDRESS_NOT_FOUND_IN_POOL; | ||
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 | ||
158 | epInfo[ XBOX_INPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
159 | epInfo[ XBOX_INPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
160 | epInfo[ XBOX_INPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; | ||
161 | epInfo[ XBOX_INPUT_PIPE ].bmSndToggle = 0; | ||
162 | epInfo[ XBOX_INPUT_PIPE ].bmRcvToggle = 0; | ||
163 | epInfo[ XBOX_OUTPUT_PIPE ].epAddr = 0x02; // XBOX 360 output endpoint | ||
164 | epInfo[ XBOX_OUTPUT_PIPE ].epAttribs = USB_TRANSFER_TYPE_INTERRUPT; | ||
165 | epInfo[ XBOX_OUTPUT_PIPE ].bmNakPower = USB_NAK_NOWAIT; // Only poll once for interrupt endpoints | ||
166 | epInfo[ XBOX_OUTPUT_PIPE ].maxPktSize = EP_MAXPKTSIZE; | ||
167 | epInfo[ XBOX_OUTPUT_PIPE ].bmSndToggle = 0; | ||
168 | epInfo[ XBOX_OUTPUT_PIPE ].bmRcvToggle = 0; | ||
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 | ||
191 | NotifyFailGetDevDescr(); | ||
192 | goto Fail; | ||
193 | #endif | ||
194 | |||
195 | FailSetDevTblEntry: | ||
196 | #ifdef DEBUG_USB_HOST | ||
197 | NotifyFailSetDevTblEntry(); | ||
198 | goto Fail; | ||
199 | #endif | ||
200 | |||
201 | FailSetConfDescr: | ||
202 | #ifdef DEBUG_USB_HOST | ||
203 | NotifyFailSetConfDescr(); | ||
204 | #endif | ||
205 | goto Fail; | ||
206 | |||
207 | FailUnknownDevice: | ||
208 | #ifdef DEBUG_USB_HOST | ||
209 | NotifyFailUnknownDevice(VID, PID); | ||
210 | #endif | ||
211 | rcode = USB_DEV_CONFIG_ERROR_DEVICE_NOT_SUPPORTED; | ||
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; | ||
225 | pUsb->GetAddressPool().FreeAddress(bAddress); | ||
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 | |||
282 | uint8_t XBOXUSB::getButtonPress(ButtonEnum b) { | ||
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 | |||
290 | bool XBOXUSB::getButtonClick(ButtonEnum b) { | ||
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 | |||
310 | int16_t XBOXUSB::getAnalogHat(AnalogHatEnum a) { | ||
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 | |||
328 | void XBOXUSB::setLedOn(LEDEnum led) { | ||
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 | |||
335 | void XBOXUSB::setLedBlink(LEDEnum led) { | ||
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 | } | ||