-
Notifications
You must be signed in to change notification settings - Fork 786
/
PS5Parser.h
415 lines (355 loc) · 13.5 KB
/
PS5Parser.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
/* Copyright (C) 2021 Kristian Sloth Lauszus. All rights reserved.
This software may be distributed and modified under the terms of the GNU
General Public License version 2 (GPL2) as published by the Free Software
Foundation and appearing in the file GPL2.TXT included in the packaging of
this file. Please note that GPL2 Section 2[b] requires that all works based
on this software must also be made publicly available under the terms of
the GPL2 ("Copyleft").
Contact information
-------------------
Kristian Sloth Lauszus
Web : https://lauszus.com
e-mail : [email protected]
Thanks to Joseph Duchesne for the initial code.
Based on Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port
and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/[email protected]/
*/
#ifndef _ps5parser_h_
#define _ps5parser_h_
#include "Usb.h"
#include "controllerEnums.h"
#include "PS5Trigger.h"
/** Buttons on the controller */
const uint8_t PS5_BUTTONS[] PROGMEM = {
UP, // UP
RIGHT, // RIGHT
DOWN, // DOWN
LEFT, // LEFT
0x0C, // CREATE
0x0D, // OPTIONS
0x0E, // L3
0x0F, // R3
0x0A, // L2
0x0B, // R2
0x08, // L1
0x09, // R1
0x07, // TRIANGLE
0x06, // CIRCLE
0x05, // CROSS
0x04, // SQUARE
0x10, // PS
0x11, // TOUCHPAD
0x12, // MICROPHONE
};
union PS5Buttons {
struct {
uint8_t dpad : 4;
uint8_t square : 1;
uint8_t cross : 1;
uint8_t circle : 1;
uint8_t triangle : 1;
uint8_t l1 : 1;
uint8_t r1 : 1;
uint8_t l2 : 1;
uint8_t r2 : 1;
uint8_t create : 1;
uint8_t menu : 1;
uint8_t l3 : 1;
uint8_t r3 : 1;
uint8_t ps : 1;
uint8_t touchpad : 1;
uint8_t mic : 1;
uint8_t dummy : 5;
} __attribute__((packed));
uint32_t val : 24;
} __attribute__((packed));
struct ps5TouchpadXY {
struct {
uint8_t counter : 7; // Increments every time a finger is touching the touchpad
uint8_t touching : 1; // The top bit is cleared if the finger is touching the touchpad
uint16_t x : 12;
uint16_t y : 12;
} __attribute__((packed)) finger[2]; // 0 = first finger, 1 = second finger
} __attribute__((packed));
union PS5Status {
struct {
// first byte
uint8_t headphone : 1;
uint8_t dummy : 2; // Seems to change when a jack is plugged in. First bit stays on when a mic is plugged in.
uint8_t usb : 1; // charging
uint8_t dummy2: 4;
// second byte
uint8_t mic : 1;
uint8_t dummy3 : 3;
} __attribute__((packed));
uint16_t val;
} __attribute__((packed));
struct PS5Data {
/* Button and joystick values */
uint8_t hatValue[4]; // 0-3 bytes
uint8_t trigger[2]; // 4-5
uint8_t sequence_number; // 6
PS5Buttons btn; // 7-9
uint8_t reserved[5]; // 0xA-0xD
/* Gyro and accelerometer values */
int16_t gyroX, gyroZ, gyroY; // 0x0F - 0x14
int16_t accX, accZ, accY; // 0x15-0x1A
int32_t sensor_timestamp;
uint8_t reserved2;
// 0x20 - 0x23 touchpad point 1
// 0x24 - 0x27 touchpad point 2
ps5TouchpadXY xy;
#if 0 // The status byte depends on if it's sent via USB or Bluetooth, so is not parsed for now
uint8_t reserved3; // 0x28
uint8_t rightTriggerFeedback; // 0x29
uint8_t leftTriggerFeedback; // 0x2A
uint8_t reserved4[10]; // 0x2B - 0x34
// status bytes 0x35-0x36
PS5Status status;
#endif
} __attribute__((packed));
struct PS5Output {
uint8_t bigRumble, smallRumble; // Rumble
uint8_t microphoneLed;
uint8_t disableLeds;
uint8_t playerLeds;
uint8_t r, g, b; // RGB for lightbar
bool reportChanged; // The data is send when data is received from the controller
} __attribute__((packed));
/** This class parses all the data sent by the PS5 controller */
class PS5Parser {
public:
/** Constructor for the PS5Parser class. */
PS5Parser() : leftTrigger(), rightTrigger() {
Reset();
};
/** Used these to manipulate the haptic triggers */
PS5Trigger leftTrigger, rightTrigger;
/** @name PS5 Controller functions */
/**
* getButtonPress(ButtonEnum b) will return true as long as the button is held down.
*
* While getButtonClick(ButtonEnum b) will only return it once.
*
* So you instance if you need to increase a variable once you would use getButtonClick(ButtonEnum b),
* but if you need to drive a robot forward you would use getButtonPress(ButtonEnum b).
* @param b ::ButtonEnum to read.
* @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.
*/
bool getButtonPress(ButtonEnum b);
bool getButtonClick(ButtonEnum b);
/**@}*/
/** @name PS5 Controller functions */
/**
* Used to get the analog value from button presses.
* @param b The ::ButtonEnum to read.
* The supported buttons are:
* ::L2 and ::R2.
* @return Analog value in the range of 0-255.
*/
uint8_t getAnalogButton(ButtonEnum b);
/**
* Used to read the analog joystick.
* @param a ::LeftHatX, ::LeftHatY, ::RightHatX, and ::RightHatY.
* @return Return the analog value in the range of 0-255.
*/
uint8_t getAnalogHat(AnalogHatEnum a);
/**
* Get the x-coordinate of the touchpad. Position 0 is in the top left.
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
*/
uint16_t getX(uint8_t finger = 0) {
return ps5Data.xy.finger[finger].x;
};
/**
* Get the y-coordinate of the touchpad. Position 0 is in the top left.
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
* @return Returns the y-coordinate of the finger.
*/
uint16_t getY(uint8_t finger = 0) {
return ps5Data.xy.finger[finger].y;
};
/**
* Returns whenever the user is toucing the touchpad.
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
* @return Returns true if the specific finger is touching the touchpad.
*/
bool isTouching(uint8_t finger = 0) {
return !(ps5Data.xy.finger[finger].touching); // The bit is cleared when a finger is touching the touchpad
};
/**
* This counter increments every time a finger touches the touchpad.
* @param finger 0 = first finger, 1 = second finger. If omitted, then 0 will be used.
* @return Return the value of the counter, note that it is only a 7-bit value.
*/
uint8_t getTouchCounter(uint8_t finger = 0) {
return ps5Data.xy.finger[finger].counter;
};
/**
* Get the angle of the controller calculated using the accelerometer.
* @param a Either ::Pitch or ::Roll.
* @return Return the angle in the range of 0-360.
*/
float getAngle(AngleEnum a) {
if (a == Pitch)
return (atan2f(-ps5Data.accY, -ps5Data.accZ) + PI) * RAD_TO_DEG;
else
return (atan2f(ps5Data.accX, -ps5Data.accZ) + PI) * RAD_TO_DEG;
};
/**
* Used to get the raw values from the 3-axis gyroscope and 3-axis accelerometer inside the PS5 controller.
* @param s The sensor to read.
* @return Returns the raw sensor reading.
*/
int16_t getSensor(SensorEnum s) {
switch(s) {
case gX:
return ps5Data.gyroX;
case gY:
return ps5Data.gyroY;
case gZ:
return ps5Data.gyroZ;
case aX:
return ps5Data.accX;
case aY:
return ps5Data.accY;
case aZ:
return ps5Data.accZ;
default:
return 0;
}
};
#if 0 // Seems to only be available via Bluetooth, so have been disabled for now
/**
* Return the battery level of the PS5 controller.
* @return The battery level in the range 0-15.
*/
uint8_t getBatteryLevel() {
return ps5Data.status.battery;
};
#endif
#if 0 // These are only valid via USB, so have been commented out for now
/**
* Use this to check if an USB cable is connected to the PS5 controller.
* @return Returns true if an USB cable is connected.
*/
bool getUsbStatus() {
return ps5Data.status.usb;
};
/**
* Use this to check if an audio jack cable is connected to the PS5 controller.
* @return Returns true if an audio jack cable is connected.
*/
bool getAudioStatus() {
return ps5Data.status.headphone;
};
/**
* Use this to check if a microphone is connected to the PS5 controller.
* @return Returns true if a microphone is connected.
*/
bool getMicStatus() {
return ps5Data.status.mic;
};
#endif
/** Turn both rumble and the LEDs off. */
void setAllOff() {
setRumbleOff();
setLedOff();
};
/** Set rumble off. */
void setRumbleOff() {
setRumbleOn(0, 0);
};
/**
* Turn on rumble.
* @param mode Either ::RumbleHigh or ::RumbleLow.
*/
void setRumbleOn(RumbleEnum mode) {
if (mode == RumbleLow)
setRumbleOn(0x00, 0xFF);
else
setRumbleOn(0xFF, 0x00);
};
/**
* Turn on rumble.
* @param bigRumble Value for big motor.
* @param smallRumble Value for small motor.
*/
void setRumbleOn(uint8_t bigRumble, uint8_t smallRumble) {
ps5Output.bigRumble = bigRumble;
ps5Output.smallRumble = smallRumble;
ps5Output.reportChanged = true;
};
/** Turn all LEDs off. */
void setLedOff() {
setLed(0, 0, 0);
};
/**
* Use this to set the color using RGB values.
* @param r,g,b RGB value.
*/
void setLed(uint8_t r, uint8_t g, uint8_t b) {
ps5Output.r = r;
ps5Output.g = g;
ps5Output.b = b;
ps5Output.reportChanged = true;
};
/**
* Use this to set the color using the predefined colors in ::ColorsEnum.
* @param color The desired color.
*/
void setLed(ColorsEnum color) {
setLed((uint8_t)(color >> 16), (uint8_t)(color >> 8), (uint8_t)(color));
};
/** Turn all player LEDs off. */
void setPlayerLedOff() {
setPlayerLed(0);
}
/**
* Use this to set five player LEDs.
* @param mask Bit mask to set the five player LEDs. The first 5 bits represent a LED each.
*/
void setPlayerLed(uint8_t mask) {
ps5Output.playerLeds = mask;
ps5Output.reportChanged = true;
}
/** Use to turn the microphone LED off. */
void setMicLedOff() {
setMicLed(0);
}
/**
* Use this to turn the microphone LED on/off.
* @param on Turn the microphone LED on/off.
*/
void setMicLed(bool on) {
ps5Output.microphoneLed = on ? 1 : 0;
ps5Output.reportChanged = true;
}
/** Get the incoming message count. */
uint16_t getMessageCounter(){
return message_counter;
}
protected:
/**
* Used to parse data sent from the PS5 controller.
* @param len Length of the data.
* @param buf Pointer to the data buffer.
*/
void Parse(uint8_t len, uint8_t *buf);
/** Used to reset the different buffers to their default values */
void Reset();
/**
* Send the output to the PS5 controller. This is implemented in PS5BT.h and PS5USB.h.
* @param output Pointer to PS5Output buffer;
*/
virtual void sendOutputReport(PS5Output *output) = 0;
private:
static int8_t getButtonIndexPS5(ButtonEnum b);
bool checkDpad(ButtonEnum b); // Used to check PS5 DPAD buttons
PS5Data ps5Data;
PS5Buttons oldButtonState, buttonClickState;
PS5Output ps5Output;
uint8_t oldDpad;
uint16_t message_counter = 0;
};
#endif