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/PS4Parser.h | |
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/PS4Parser.h')
-rw-r--r-- | lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h | 407 |
1 files changed, 407 insertions, 0 deletions
diff --git a/lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h b/lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h new file mode 100644 index 000000000..51f080636 --- /dev/null +++ b/lib/usbhost/USB_Host_Shield_2.0/PS4Parser.h | |||
@@ -0,0 +1,407 @@ | |||
1 | /* Copyright (C) 2014 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 | #ifndef _ps4parser_h_ | ||
19 | #define _ps4parser_h_ | ||
20 | |||
21 | #include "Usb.h" | ||
22 | #include "controllerEnums.h" | ||
23 | |||
24 | /** Buttons on the controller */ | ||
25 | const uint8_t PS4_BUTTONS[] PROGMEM = { | ||
26 | UP, // UP | ||
27 | RIGHT, // RIGHT | ||
28 | DOWN, // DOWN | ||
29 | LEFT, // LEFT | ||
30 | |||
31 | 0x0C, // SHARE | ||
32 | 0x0D, // OPTIONS | ||
33 | 0x0E, // L3 | ||
34 | 0x0F, // R3 | ||
35 | |||
36 | 0x0A, // L2 | ||
37 | 0x0B, // R2 | ||
38 | 0x08, // L1 | ||
39 | 0x09, // R1 | ||
40 | |||
41 | 0x07, // TRIANGLE | ||
42 | 0x06, // CIRCLE | ||
43 | 0x05, // CROSS | ||
44 | 0x04, // SQUARE | ||
45 | |||
46 | 0x10, // PS | ||
47 | 0x11, // TOUCHPAD | ||
48 | }; | ||
49 | |||
50 | union PS4Buttons { | ||
51 | struct { | ||
52 | uint8_t dpad : 4; | ||
53 | uint8_t square : 1; | ||
54 | uint8_t cross : 1; | ||
55 | uint8_t circle : 1; | ||
56 | uint8_t triangle : 1; | ||
57 | |||
58 | uint8_t l1 : 1; | ||
59 | uint8_t r1 : 1; | ||
60 | uint8_t l2 : 1; | ||
61 | uint8_t r2 : 1; | ||
62 | uint8_t share : 1; | ||
63 | uint8_t options : 1; | ||
64 | uint8_t l3 : 1; | ||
65 | uint8_t r3 : 1; | ||
66 | |||
67 | uint8_t ps : 1; | ||
68 | uint8_t touchpad : 1; | ||
69 | uint8_t reportCounter : 6; | ||
70 | } __attribute__((packed)); | ||
71 | uint32_t val : 24; | ||
72 | } __attribute__((packed)); | ||
73 | |||
74 | struct touchpadXY { | ||
75 | uint8_t dummy; // I can not figure out what this data is for, it seems to change randomly, maybe a timestamp? | ||
76 | struct { | ||
77 | uint8_t counter : 7; // Increments every time a finger is touching the touchpad | ||
78 | uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad | ||
79 | uint16_t x : 12; | ||
80 | uint16_t y : 12; | ||
81 | } __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger | ||
82 | } __attribute__((packed)); | ||
83 | |||
84 | struct PS4Status { | ||
85 | uint8_t battery : 4; | ||
86 | uint8_t usb : 1; | ||
87 | uint8_t audio : 1; | ||
88 | uint8_t mic : 1; | ||
89 | uint8_t unknown : 1; // Extension port? | ||
90 | } __attribute__((packed)); | ||
91 | |||
92 | struct PS4Data { | ||
93 | /* Button and joystick values */ | ||
94 | uint8_t hatValue[4]; | ||
95 | PS4Buttons btn; | ||
96 | uint8_t trigger[2]; | ||
97 | |||
98 | /* Gyro and accelerometer values */ | ||
99 | uint8_t dummy[3]; // First two looks random, while the third one might be some kind of status - it increments once in a while | ||
100 | int16_t gyroY, gyroZ, gyroX; | ||
101 | int16_t accX, accZ, accY; | ||
102 | |||
103 | uint8_t dummy2[5]; | ||
104 | PS4Status status; | ||
105 | uint8_t dummy3[3]; | ||
106 | |||
107 | /* The rest is data for the touchpad */ | ||
108 | touchpadXY xy[3]; // It looks like it sends out three coordinates each time, this might be because the microcontroller inside the PS4 controller is much faster than the Bluetooth connection. | ||
109 | // The last data is read from the last position in the array while the oldest measurement is from the first position. | ||
110 | // The first position will also keep it's value after the finger is released, while the other two will set them to zero. | ||
111 | // Note that if you read fast enough from the device, then only the first one will contain any data. | ||
112 | |||
113 | // The last three bytes are always: 0x00, 0x80, 0x00 | ||
114 | } __attribute__((packed)); | ||
115 | |||
116 | struct PS4Output { | ||
117 | uint8_t bigRumble, smallRumble; // Rumble | ||
118 | uint8_t r, g, b; // RGB | ||
119 | uint8_t flashOn, flashOff; // Time to flash bright/dark (255 = 2.5 seconds) | ||
120 | bool reportChanged; // The data is send when data is received from the controller | ||
121 | } __attribute__((packed)); | ||
122 | |||
123 | enum DPADEnum { | ||
124 | DPAD_UP = 0x0, | ||
125 | DPAD_UP_RIGHT = 0x1, | ||
126 | DPAD_RIGHT = 0x2, | ||
127 | DPAD_RIGHT_DOWN = 0x3, | ||
128 | DPAD_DOWN = 0x4, | ||
129 | DPAD_DOWN_LEFT = 0x5, | ||
130 | DPAD_LEFT = 0x6, | ||
131 | DPAD_LEFT_UP = 0x7, | ||
132 | DPAD_OFF = 0x8, | ||
133 | }; | ||
134 | |||
135 | /** This class parses all the data sent by the PS4 controller */ | ||
136 | class PS4Parser { | ||
137 | public: | ||
138 | /** Constructor for the PS4Parser class. */ | ||
139 | PS4Parser() { | ||
140 | Reset(); | ||
141 | }; | ||
142 | |||
143 | /** @name PS4 Controller functions */ | ||
144 | /** | ||
145 | * getButtonPress(ButtonEnum b) will return true as long as the button is held down. | ||
146 | * | ||
147 | * While getButtonClick(ButtonEnum b) will only return it once. | ||
148 | * | ||
149 | * So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b), | ||
150 | * but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b). | ||
151 | * @param b ::ButtonEnum to read. | ||
152 | * @return getButtonPress(ButtonEnum b) will return a true as long as a button is held down, while getButtonClick(ButtonEnum b) will return true once for each button press. | ||
153 | */ | ||
154 | bool getButtonPress(ButtonEnum b); | ||
155 | bool getButtonClick(ButtonEnum b); | ||
156 | /**@}*/ | ||
157 | /** @name PS4 Controller functions */ | ||
158 | /** | ||
159 | * Used to get the analog value from button presses. | ||
160 | * @param b The ::ButtonEnum to read. | ||
161 | * The supported buttons are: | ||
162 | * ::UP, ::RIGHT, ::DOWN, ::LEFT, ::L1, ::L2, ::R1, ::R2, | ||
163 | * ::TRIANGLE, ::CIRCLE, ::CROSS, ::SQUARE, and ::T. | ||
164 | * @return Analog value in the range of 0-255. | ||
165 | */ | ||
166 | uint8_t getAnalogButton(ButtonEnum b); | ||
167 | |||
168 | /** | ||
169 | * Used to read the analog joystick. | ||
170 | * @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY. | ||
171 | * @return Return the analog value in the range of 0-255. | ||
172 | */ | ||
173 | uint8_t getAnalogHat(AnalogHatEnum a); | ||
174 | |||
175 | /** | ||
176 | * Get the x-coordinate of the touchpad. Position 0 is in the top left. | ||
177 | * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. | ||
178 | * @param xyId The controller sends out three packets with the same structure. | ||
179 | * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. | ||
180 | * For that reason it will be set to 0 if the argument is omitted. | ||
181 | * @return Returns the x-coordinate of the finger. | ||
182 | */ | ||
183 | uint16_t getX(uint8_t finger = 0, uint8_t xyId = 0) { | ||
184 | return ps4Data.xy[xyId].finger[finger].x; | ||
185 | }; | ||
186 | |||
187 | /** | ||
188 | * Get the y-coordinate of the touchpad. Position 0 is in the top left. | ||
189 | * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. | ||
190 | * @param xyId The controller sends out three packets with the same structure. | ||
191 | * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. | ||
192 | * For that reason it will be set to 0 if the argument is omitted. | ||
193 | * @return Returns the y-coordinate of the finger. | ||
194 | */ | ||
195 | uint16_t getY(uint8_t finger = 0, uint8_t xyId = 0) { | ||
196 | return ps4Data.xy[xyId].finger[finger].y; | ||
197 | }; | ||
198 | |||
199 | /** | ||
200 | * Returns whenever the user is toucing the touchpad. | ||
201 | * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. | ||
202 | * @param xyId The controller sends out three packets with the same structure. | ||
203 | * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. | ||
204 | * For that reason it will be set to 0 if the argument is omitted. | ||
205 | * @return Returns true if the specific finger is touching the touchpad. | ||
206 | */ | ||
207 | bool isTouching(uint8_t finger = 0, uint8_t xyId = 0) { | ||
208 | return !(ps4Data.xy[xyId].finger[finger].touching); // The bit is cleared when a finger is touching the touchpad | ||
209 | }; | ||
210 | |||
211 | /** | ||
212 | * This counter increments every time a finger touches the touchpad. | ||
213 | * @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used. | ||
214 | * @param xyId The controller sends out three packets with the same structure. | ||
215 | * The third one will contain the last measure, but if you read from the controller then there is only be data in the first one. | ||
216 | * For that reason it will be set to 0 if the argument is omitted. | ||
217 | * @return Return the value of the counter, note that it is only a 7-bit value. | ||
218 | */ | ||
219 | uint8_t getTouchCounter(uint8_t finger = 0, uint8_t xyId = 0) { | ||
220 | return ps4Data.xy[xyId].finger[finger].counter; | ||
221 | }; | ||
222 | |||
223 | /** | ||
224 | * Get the angle of the controller calculated using the accelerometer. | ||
225 | * @param a Either ::Pitch or ::Roll. | ||
226 | * @return Return the angle in the range of 0-360. | ||
227 | */ | ||
228 | double getAngle(AngleEnum a) { | ||
229 | if (a == Pitch) | ||
230 | return (atan2(ps4Data.accY, ps4Data.accZ) + PI) * RAD_TO_DEG; | ||
231 | else | ||
232 | return (atan2(ps4Data.accX, ps4Data.accZ) + PI) * RAD_TO_DEG; | ||
233 | }; | ||
234 | |||
235 | /** | ||
236 | * Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS4 controller. | ||
237 | * @param s The sensor to read. | ||
238 | * @return Returns the raw sensor reading. | ||
239 | */ | ||
240 | int16_t getSensor(SensorEnum s) { | ||
241 | switch(s) { | ||
242 | case gX: | ||
243 | return ps4Data.gyroX; | ||
244 | case gY: | ||
245 | return ps4Data.gyroY; | ||
246 | case gZ: | ||
247 | return ps4Data.gyroZ; | ||
248 | case aX: | ||
249 | return ps4Data.accX; | ||
250 | case aY: | ||
251 | return ps4Data.accY; | ||
252 | case aZ: | ||
253 | return ps4Data.accZ; | ||
254 | default: | ||
255 | return 0; | ||
256 | } | ||
257 | }; | ||
258 | |||
259 | /** | ||
260 | * Return the battery level of the PS4 controller. | ||
261 | * @return The battery level in the range 0-15. | ||
262 | */ | ||
263 | uint8_t getBatteryLevel() { | ||
264 | return ps4Data.status.battery; | ||
265 | }; | ||
266 | |||
267 | /** | ||
268 | * Use this to check if an USB cable is connected to the PS4 controller. | ||
269 | * @return Returns true if an USB cable is connected. | ||
270 | */ | ||
271 | bool getUsbStatus() { | ||
272 | return ps4Data.status.usb; | ||
273 | }; | ||
274 | |||
275 | /** | ||
276 | * Use this to check if an audio jack cable is connected to the PS4 controller. | ||
277 | * @return Returns true if an audio jack cable is connected. | ||
278 | */ | ||
279 | bool getAudioStatus() { | ||
280 | return ps4Data.status.audio; | ||
281 | }; | ||
282 | |||
283 | /** | ||
284 | * Use this to check if a microphone is connected to the PS4 controller. | ||
285 | * @return Returns true if a microphone is connected. | ||
286 | */ | ||
287 | bool getMicStatus() { | ||
288 | return ps4Data.status.mic; | ||
289 | }; | ||
290 | |||
291 | /** Turn both rumble and the LEDs off. */ | ||
292 | void setAllOff() { | ||
293 | setRumbleOff(); | ||
294 | setLedOff(); | ||
295 | }; | ||
296 | |||
297 | /** Set rumble off. */ | ||
298 | void setRumbleOff() { | ||
299 | setRumbleOn(0, 0); | ||
300 | }; | ||
301 | |||
302 | /** | ||
303 | * Turn on rumble. | ||
304 | * @param mode Either ::RumbleHigh or ::RumbleLow. | ||
305 | */ | ||
306 | void setRumbleOn(RumbleEnum mode) { | ||
307 | if (mode == RumbleLow) | ||
308 | setRumbleOn(0x00, 0xFF); | ||
309 | else | ||
310 | setRumbleOn(0xFF, 0x00); | ||
311 | }; | ||
312 | |||
313 | /** | ||
314 | * Turn on rumble. | ||
315 | * @param bigRumble Value for big motor. | ||
316 | * @param smallRumble Value for small motor. | ||
317 | */ | ||
318 | void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) { | ||
319 | ps4Output.bigRumble = bigRumble; | ||
320 | ps4Output.smallRumble = smallRumble; | ||
321 | ps4Output.reportChanged = true; | ||
322 | }; | ||
323 | |||
324 | /** Turn all LEDs off. */ | ||
325 | void setLedOff() { | ||
326 | setLed(0, 0, 0); | ||
327 | }; | ||
328 | |||
329 | /** | ||
330 | * Use this to set the color using RGB values. | ||
331 | * @param r,g,b RGB value. | ||
332 | */ | ||
333 | void setLed(uint8_t r, uint8_t g, uint8_t b) { | ||
334 | ps4Output.r = r; | ||
335 | ps4Output.g = g; | ||
336 | ps4Output.b = b; | ||
337 | ps4Output.reportChanged = true; | ||
338 | }; | ||
339 | |||
340 | /** | ||
341 | * Use this to set the color using the predefined colors in ::ColorsEnum. | ||
342 | * @param color The desired color. | ||
343 | */ | ||
344 | void setLed(ColorsEnum color) { | ||
345 | setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color)); | ||
346 | }; | ||
347 | |||
348 | /** | ||
349 | * Set the LEDs flash time. | ||
350 | * @param flashOn Time to flash bright (255 = 2.5 seconds). | ||
351 | * @param flashOff Time to flash dark (255 = 2.5 seconds). | ||
352 | */ | ||
353 | void setLedFlash(uint8_t flashOn, uint8_t flashOff) { | ||
354 | ps4Output.flashOn = flashOn; | ||
355 | ps4Output.flashOff = flashOff; | ||
356 | ps4Output.reportChanged = true; | ||
357 | }; | ||
358 | /**@}*/ | ||
359 | |||
360 | protected: | ||
361 | /** | ||
362 | * Used to parse data sent from the PS4 controller. | ||
363 | * @param len Length of the data. | ||
364 | * @param buf Pointer to the data buffer. | ||
365 | */ | ||
366 | void Parse(uint8_t len, uint8_t *buf); | ||
367 | |||
368 | /** Used to reset the different buffers to their default values */ | ||
369 | void Reset() { | ||
370 | uint8_t i; | ||
371 | for (i = 0; i < sizeof(ps4Data.hatValue); i++) | ||
372 | ps4Data.hatValue[i] = 127; // Center value | ||
373 | ps4Data.btn.val = 0; | ||
374 | oldButtonState.val = 0; | ||
375 | for (i = 0; i < sizeof(ps4Data.trigger); i++) | ||
376 | ps4Data.trigger[i] = 0; | ||
377 | for (i = 0; i < sizeof(ps4Data.xy)/sizeof(ps4Data.xy[0]); i++) { | ||
378 | for (uint8_t j = 0; j < sizeof(ps4Data.xy[0].finger)/sizeof(ps4Data.xy[0].finger[0]); j++) | ||
379 | ps4Data.xy[i].finger[j].touching = 1; // The bit is cleared if the finger is touching the touchpad | ||
380 | } | ||
381 | |||
382 | ps4Data.btn.dpad = DPAD_OFF; | ||
383 | oldButtonState.dpad = DPAD_OFF; | ||
384 | buttonClickState.dpad = 0; | ||
385 | oldDpad = 0; | ||
386 | |||
387 | ps4Output.bigRumble = ps4Output.smallRumble = 0; | ||
388 | ps4Output.r = ps4Output.g = ps4Output.b = 0; | ||
389 | ps4Output.flashOn = ps4Output.flashOff = 0; | ||
390 | ps4Output.reportChanged = false; | ||
391 | }; | ||
392 | |||
393 | /** | ||
394 | * Send the output to the PS4 controller. This is implemented in PS4BT.h and PS4USB.h. | ||
395 | * @param output Pointer to PS4Output buffer; | ||
396 | */ | ||
397 | virtual void sendOutputReport(PS4Output *output) = 0; | ||
398 | |||
399 | private: | ||
400 | bool checkDpad(ButtonEnum b); // Used to check PS4 DPAD buttons | ||
401 | |||
402 | PS4Data ps4Data; | ||
403 | PS4Buttons oldButtonState, buttonClickState; | ||
404 | PS4Output ps4Output; | ||
405 | uint8_t oldDpad; | ||
406 | }; | ||
407 | #endif | ||