2021-01-17 20:17:32 +01:00
|
|
|
/* 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 : lauszus@gmail.com
|
|
|
|
|
|
|
|
Thanks to Joseph Duchesne for the initial code.
|
2021-01-17 23:34:31 +01:00
|
|
|
Based on Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port
|
2021-01-19 10:57:14 +01:00
|
|
|
and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
|
2021-01-17 20:17:32 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2021-01-17 23:34:31 +01:00
|
|
|
0x0C, // CREATE
|
2021-01-17 20:17:32 +01:00
|
|
|
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;
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t create : 1;
|
2021-01-17 20:17:32 +01:00
|
|
|
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;
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t dummy3 : 3;
|
2021-01-17 20:17:32 +01:00
|
|
|
} __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
|
|
|
|
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t sequence_number; // 6
|
2021-01-17 20:17:32 +01:00
|
|
|
|
|
|
|
PS5Buttons btn; // 7-9
|
|
|
|
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t reserved[5]; // 0xA-0xD
|
2021-01-17 20:17:32 +01:00
|
|
|
|
|
|
|
/* Gyro and accelerometer values */
|
|
|
|
int16_t gyroX, gyroZ, gyroY; // 0x0F - 0x14
|
|
|
|
int16_t accX, accZ, accY; // 0x15-0x1A
|
2021-01-17 23:34:31 +01:00
|
|
|
int32_t sensor_timestamp;
|
2021-01-17 20:17:32 +01:00
|
|
|
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t reserved2;
|
2021-01-17 20:17:32 +01:00
|
|
|
|
|
|
|
// 0x20 - 0x23 touchpad point 1
|
|
|
|
// 0x24 - 0x27 touchpad point 2
|
|
|
|
ps5TouchpadXY xy;
|
|
|
|
|
2021-01-19 20:29:04 +01:00
|
|
|
#if 0 // The status byte depends on if it's sent via USB or Bluetooth, so is not parsed for now
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t reserved3; // 0x28
|
2021-01-17 20:17:32 +01:00
|
|
|
|
|
|
|
uint8_t rightTriggerFeedback; // 0x29
|
|
|
|
uint8_t leftTriggerFeedback; // 0x2A
|
2021-01-17 23:34:31 +01:00
|
|
|
uint8_t reserved4[10]; // 0x2B - 0x34
|
2021-01-17 20:17:32 +01:00
|
|
|
|
|
|
|
// status bytes 0x35-0x36
|
|
|
|
PS5Status status;
|
2021-01-19 20:29:04 +01:00
|
|
|
#endif
|
2021-01-17 20:17:32 +01:00
|
|
|
} __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();
|
|
|
|
};
|
|
|
|
|
2021-01-19 10:57:14 +01:00
|
|
|
/** Used these to manipulate the haptic triggers */
|
|
|
|
PS5Trigger leftTrigger, rightTrigger;
|
|
|
|
|
2021-01-17 20:17:32 +01:00
|
|
|
/** @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.
|
|
|
|
*/
|
2021-01-24 14:40:25 +01:00
|
|
|
uint8_t getTouchCounter(uint8_t finger = 0) {
|
2021-01-17 20:17:32 +01:00
|
|
|
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)
|
2021-01-19 10:57:14 +01:00
|
|
|
return (atan2f(-ps5Data.accY, -ps5Data.accZ) + PI) * RAD_TO_DEG;
|
2021-01-17 20:17:32 +01:00
|
|
|
else
|
2021-01-19 10:57:14 +01:00
|
|
|
return (atan2f(ps5Data.accX, -ps5Data.accZ) + PI) * RAD_TO_DEG;
|
2021-01-17 20:17:32 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-01-19 20:29:04 +01:00
|
|
|
#if 0 // Seems to only be available via Bluetooth, so have been disabled for now
|
2021-01-17 20:17:32 +01:00
|
|
|
/**
|
|
|
|
* Return the battery level of the PS5 controller.
|
|
|
|
* @return The battery level in the range 0-15.
|
|
|
|
*/
|
2021-01-19 20:29:04 +01:00
|
|
|
uint8_t getBatteryLevel() {
|
|
|
|
return ps5Data.status.battery;
|
|
|
|
};
|
|
|
|
#endif
|
2021-01-17 20:17:32 +01:00
|
|
|
|
2021-01-19 20:29:04 +01:00
|
|
|
#if 0 // These are only valid via USB, so have been commented out for now
|
2021-01-17 20:17:32 +01:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
};
|
2021-01-19 20:29:04 +01:00
|
|
|
#endif
|
2021-01-17 20:17:32 +01:00
|
|
|
|
|
|
|
/** 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;
|
2021-01-19 10:57:14 +01:00
|
|
|
ps5Output.reportChanged = true;
|
2021-01-17 20:17:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** 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;
|
2021-01-19 10:57:14 +01:00
|
|
|
ps5Output.reportChanged = true;
|
2021-01-17 20:17:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** 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:
|
2021-03-25 21:18:36 +01:00
|
|
|
static int8_t getButtonIndex(ButtonEnum b);
|
2021-01-17 20:17:32 +01:00
|
|
|
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
|