Setting the LED, lightbar, rumble via Bluetooth is now working

This commit is contained in:
Kristian Sloth Lauszus 2021-01-19 10:57:14 +01:00
parent 28a75dea6b
commit 9a0a4940b3
7 changed files with 173 additions and 193 deletions

View file

@ -336,11 +336,11 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
Notify(PSTR(" "), 0x80); Notify(PSTR(" "), 0x80);
} }
#endif #endif
if(l2capinbuf[8] == 0xA1) { // HID_THDR_DATA_INPUT if(l2capinbuf[8] == 0xA1) { // HID BT DATA (0xA0) | Report Type (Input 0x01)
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]); ParseBTHIDData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
switch(l2capinbuf[9]) { switch(l2capinbuf[9]) { // Report ID
case 0x01: // Keyboard or Joystick events case 0x01: // Keyboard or Joystick events
if(pRptParser[KEYBOARD_PARSER_ID]) if(pRptParser[KEYBOARD_PARSER_ID])
pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance pRptParser[KEYBOARD_PARSER_ID]->Parse(reinterpret_cast<USBHID *>(this), 0, (uint8_t)(length - 2), &l2capinbuf[10]); // Use reinterpret_cast again to extract the instance
@ -357,6 +357,11 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
break; break;
#endif #endif
} }
} else {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nUnhandled L2CAP interrupt report: "), 0x80);
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
#endif
} }
} else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control } else if(l2capinbuf[6] == control_dcid[0] && l2capinbuf[7] == control_dcid[1]) { // l2cap_control
#ifdef PRINTREPORT #ifdef PRINTREPORT
@ -366,9 +371,14 @@ void BTHID::ACLData(uint8_t* l2capinbuf) {
Notify(PSTR(" "), 0x80); Notify(PSTR(" "), 0x80);
} }
#endif #endif
if(l2capinbuf[8] == 0xA3) { if(l2capinbuf[8] == 0xA3) { // HID BT DATA (0xA0) | Report Type (Feature 0x03)
uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]); uint16_t length = ((uint16_t)l2capinbuf[5] << 8 | l2capinbuf[4]);
ParseBTHIDControlData((uint8_t)(length - 1), &l2capinbuf[9]); ParseBTHIDControlData((uint8_t)(length - 1), &l2capinbuf[9]); // First byte will be the report ID
} else {
#ifdef EXTRADEBUG
Notify(PSTR("\r\nUnhandled L2CAP control report: "), 0x80);
D_PrintHex<uint8_t > (l2capinbuf[8], 0x80);
#endif
} }
} }
#ifdef EXTRADEBUG #ifdef EXTRADEBUG

133
PS5BT.h
View file

@ -21,7 +21,12 @@
#include "BTHID.h" #include "BTHID.h"
#include "PS5Parser.h" #include "PS5Parser.h"
/*const uint32_t crc32_table[] PROGMEM = { /**
* Generated from the standard Ethernet CRC-32 polynomial:
* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
* Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/libkern/crc32.c
*/
const uint32_t crc32_table[] PROGMEM = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
@ -67,76 +72,35 @@
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
}; };
uint32_t crc32(uint8_t *buffer, size_t length) { // Inspired by: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/libkern/crc32.c and http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=28214
uint32_t crc = ~0L; // Initial value
for (size_t i = 0; i < length; i++)
crc = (crc >> 8) ^ pgm_read_dword(&crc32_table[*buffer++ ^ (crc & 0xFF)]);
return ~crc;
};*/
/* /*
* There are multiple 16-bit CRC polynomials in common use, but this is * There are multiple 16-bit CRC polynomials in common use, but this is
* *the* standard CRC-32 polynomial, first popularized by Ethernet. * *the* standard CRC-32 polynomial, first popularized by Ethernet.
* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
*/ */
#if 0
#define CRC32_POLY_LE 0xedb88320 #define CRC32_POLY_LE 0xedb88320
#define CRC32_POLY_BE 0x04c11db7
#define CRC_LE_BITS 1 static inline uint32_t crc32_le_generic(uint32_t crc, uint8_t const *p, size_t len, uint32_t polynomial) {
// Source: https://github.com/torvalds/linux/blob/c4cf498dc0241fa2d758dba177634268446afb06/lib/crc32.c
typedef uint32_t u32;
static inline u32 crc32_le_generic(u32 crc, unsigned char const *p, size_t len, const u32 (*tab)[256], u32 polynomial)
{
#if CRC_LE_BITS == 1
int i; int i;
while (len--) { while (len--) {
crc ^= *p++; crc ^= *p++;
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
} }
# elif CRC_LE_BITS == 2
while (len--) {
crc ^= *p++;
crc = (crc >> 2) ^ tab[0][crc & 3];
crc = (crc >> 2) ^ tab[0][crc & 3];
crc = (crc >> 2) ^ tab[0][crc & 3];
crc = (crc >> 2) ^ tab[0][crc & 3];
}
# elif CRC_LE_BITS == 4
while (len--) {
crc ^= *p++;
crc = (crc >> 4) ^ tab[0][crc & 15];
crc = (crc >> 4) ^ tab[0][crc & 15];
}
# elif CRC_LE_BITS == 8
/* aka Sarwate algorithm */
while (len--) {
crc ^= *p++;
crc = (crc >> 8) ^ tab[0][crc & 255];
}
# else
crc = (__force u32) __cpu_to_le32(crc);
crc = crc32_body(crc, p, len, tab);
crc = __le32_to_cpu((__force __le32)crc);
#endif
return crc; return crc;
} }
#if CRC_LE_BITS == 1 static inline uint32_t crc32(uint32_t crc, const void *buf, size_t size) {
static u32 crc32_le(u32 crc, unsigned char const *p, size_t len) #if 1 // Use a table, as it's faster, but takes up more space
{ // Inspired by: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/libkern/crc32.c
return crc32_le_generic(crc, p, len, NULL, CRC32_POLY_LE); const uint8_t *p = (const uint8_t*)buf;
} while (size--)
#else crc = pgm_read_dword(&crc32_table[*p++ ^ (crc & 0xFF)]) ^ (crc >> 8);
static u32 crc32_le(u32 crc, unsigned char const *p, size_t len) return crc;
{ #else // Can be used to save flash, but is slower
return crc32_le_generic(crc, p, len, (const u32 (*)[256])crc32table_le, CRC32_POLY_LE); return crc32_le_generic(crc, (uint8_t const*)buf, size, CRC32_POLY_LE);
}
#endif
#endif #endif
};
/** /**
* This class implements support for the PS5 controller via Bluetooth. * This class implements support for the PS5 controller via Bluetooth.
@ -151,7 +115,7 @@ public:
* @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used. * @param pin Write the pin to BTD#btdPin. If argument is omitted, then "0000" will be used.
*/ */
PS5BT(BTD *p, bool pair = false, const char *pin = "0000") : PS5BT(BTD *p, bool pair = false, const char *pin = "0000") :
BTHID(p, pair, pin) { BTHID(p, pair, pin), output_sequence_counter(0) {
PS5Parser::Reset(); PS5Parser::Reset();
}; };
@ -182,10 +146,10 @@ protected:
virtual void OnInitBTHID() { virtual void OnInitBTHID() {
PS5Parser::Reset(); PS5Parser::Reset();
enable_sixaxis(); // Make the controller send out the entire output report enable_sixaxis(); // Make the controller send out the entire output report
if (pFuncOnInit)
pFuncOnInit(); // Call the user function // Only call this is a user function has not been set
else if (!pFuncOnInit)
setLed(Blue); setLed(Red); // Set the LED to red, as the PS5 controller turns Bluetooth when searching for a device
}; };
/** Used to reset the different buffers to there default values */ /** Used to reset the different buffers to there default values */
@ -196,20 +160,17 @@ protected:
/** @name PS5Parser implementation */ /** @name PS5Parser implementation */
virtual void sendOutputReport(PS5Output *output) { virtual void sendOutputReport(PS5Output *output) {
#if 1 // See the series of patches here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
return; // TODO: Fix this uint8_t buf[1 /* BT DATA Output Report */ + 1 /* report id */ + 1 /* seq_tag */ + 1 /* tag */ + 47 /* common */ + 24 /* reserved */ + 4 /* crc32 */];
#else
// See the series of patches here: https://patchwork.kernel.org/project/linux-input/patch/20201219062336.72568-14-roderick@gaikai.com/
uint8_t buf[1 /* BT Set Output Report */ + 1 /* report id */ + 1 /* seq_tag */ + 1 /* tag */ + 47 /* common */ + 24 /* reserved */ + 4 /* crc32 */];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
buf[0] = 0x52; // HID BT Set_report (0x50) | Report Type (Output 0x02) // Send as a Bluetooth HID DATA output report on the interrupt channel
buf[0] = 0xA2; // HID BT DATA (0xA0) | Report Type (Output 0x02)
buf[0x01] = 0x31; // Report ID buf[0x01] = 0x31; // Report ID
buf[0x02] = (output_sequence << 4) | 0x0; // Highest 4-bit is a sequence number, which needs to be increased every report. Lowest 4-bit is tag and can be zero for now. buf[0x02] = (output_sequence_counter << 4) | 0x0; // Highest 4-bit is a sequence number, which needs to be increased every report. Lowest 4-bit is tag and can be zero for now.
if(++output_sequence == 15) if(++output_sequence_counter == 15)
output_sequence = 0; output_sequence_counter = 0;
buf[0x03] = 0x10; // Magic number must be set to 0x10 buf[0x03] = 0x10; // Magic number must be set to 0x10
buf[0x01 + 3] = 0xFF; // feature flags 1 buf[0x01 + 3] = 0xFF; // feature flags 1
@ -243,40 +204,30 @@ protected:
buf[0x2E + 3] = output->g; // Green buf[0x2E + 3] = output->g; // Green
buf[0x2F + 3] = output->b; // Blue buf[0x2F + 3] = output->b; // Blue
//uint32_t crc = crc32(&buf[1], 79 - 1 /* do not include the BT Set Output Report */ - 4 /* crc */); uint32_t crc = ~crc32(0xFFFFFFFF, buf, sizeof(buf) - 4 /* Do not include the crc32 */); // Note how the report type is also included in the output report
buf[75] = crc & 0xFF;
uint8_t seed = 0xA2; buf[76] = (crc >> 8) & 0xFF;
uint32_t crc = crc32_le(0xFFFFFFFF, &seed, 1); buf[77] = (crc >> 16);
crc = ~crc32_le(crc, &buf[1], 79 - 1 /* do not include the BT Set Output Report */ - 4 /* crc */); buf[78] = (crc >> 24);
buf[75] = crc;
buf[76] = crc >> 8;
buf[77] = crc >> 16;
buf[78] = crc >> 24;
output->reportChanged = false; output->reportChanged = false;
// The PS5 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed // Send the Bluetooth DATA output report on the interrupt channel
pBtd->L2CAP_Command(hci_handle, buf, sizeof(buf), interrupt_scid[0], interrupt_scid[1]);
HID_Command(buf, sizeof(buf));
#endif
}; };
/**@}*/ /**@}*/
private: private:
uint8_t output_sequence = 0;
void enable_sixaxis() { // Command used to make the PS5 controller send out the entire output report void enable_sixaxis() { // Command used to make the PS5 controller send out the entire output report
// Request the paring info. This makes the controller send out the full report - see: https://patchwork.kernel.org/project/linux-input/patch/20201219062336.72568-14-roderick@gaikai.com/ // Request the paring info. This makes the controller send out the full report - see: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
uint8_t buf[2]; uint8_t buf[2];
buf[0] = 0x43; // HID BT Get_report (0x40) | Report Type (Feature 0x03) buf[0] = 0x43; // HID BT Get_report (0x40) | Report Type (Feature 0x03)
buf[1] = 9; // Report ID for paring info buf[1] = 0x09; // Report ID for paring info
HID_Command(buf, 2); // Send the Bluetooth Get_report Feature report on the control channel
pBtd->L2CAP_Command(hci_handle, buf, 2, control_scid[0], control_scid[1]);
}; };
void HID_Command(uint8_t *data, uint8_t nbytes) { uint8_t output_sequence_counter;
pBtd->L2CAP_Command(hci_handle, data, nbytes, control_scid[0], control_scid[1]);
};
}; };
#endif #endif

View file

@ -16,7 +16,7 @@
Thanks to Joseph Duchesne for the initial code. Thanks to Joseph Duchesne for the initial code.
Based on Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port 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/patch/20201219062336.72568-14-roderick@gaikai.com/ and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
*/ */
#include "PS5Parser.h" #include "PS5Parser.h"
@ -80,7 +80,8 @@ uint8_t PS5Parser::getAnalogHat(AnalogHatEnum a) {
void PS5Parser::Parse(uint8_t len, uint8_t *buf) { void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
if (len > 1 && buf) { if (len > 1 && buf) {
#ifdef PRINTREPORT #ifdef PRINTREPORT
Notify(PSTR("\r\n"), 0x80); Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
Notify(PSTR(", data: "), 0x80);
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80); D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR(" "), 0x80); Notify(PSTR(" "), 0x80);
@ -89,7 +90,7 @@ void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
if (buf[0] == 0x01) // Check report ID if (buf[0] == 0x01) // Check report ID
memcpy(&ps5Data, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(ps5Data))); memcpy(&ps5Data, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(ps5Data)));
else if (buf[0] == 0x31) { // This report is send via Bluetooth, it has an offset of 2 compared to the USB data else if (buf[0] == 0x31) { // This report is send via Bluetooth, it has an offset of 1 compared to the USB data
if (len < 3) { if (len < 3) {
#ifdef DEBUG_USB_HOST #ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReport is too short: "), 0x80); Notify(PSTR("\r\nReport is too short: "), 0x80);
@ -127,8 +128,9 @@ void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
oldDpad = newDpad; oldDpad = newDpad;
} }
} }
message_counter++;
} }
message_counter++;
if (ps5Output.reportChanged || leftTrigger.reportChanged || rightTrigger.reportChanged) if (ps5Output.reportChanged || leftTrigger.reportChanged || rightTrigger.reportChanged)
sendOutputReport(&ps5Output); // Send output report sendOutputReport(&ps5Output); // Send output report

View file

@ -16,7 +16,7 @@
Thanks to Joseph Duchesne for the initial code. Thanks to Joseph Duchesne for the initial code.
Based on Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port 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/patch/20201219062336.72568-14-roderick@gaikai.com/ and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
*/ */
#ifndef _ps5parser_h_ #ifndef _ps5parser_h_
@ -146,14 +146,14 @@ struct PS5Output {
/** This class parses all the data sent by the PS5 controller */ /** This class parses all the data sent by the PS5 controller */
class PS5Parser { class PS5Parser {
public: public:
PS5Trigger leftTrigger;
PS5Trigger rightTrigger;
/** Constructor for the PS5Parser class. */ /** Constructor for the PS5Parser class. */
PS5Parser() : leftTrigger(), rightTrigger() { PS5Parser() : leftTrigger(), rightTrigger() {
Reset(); Reset();
}; };
/** Used these to manipulate the haptic triggers */
PS5Trigger leftTrigger, rightTrigger;
/** @name PS5 Controller functions */ /** @name PS5 Controller functions */
/** /**
* getButtonPress(ButtonEnum b) will return true as long as the button is held down. * getButtonPress(ButtonEnum b) will return true as long as the button is held down.
@ -227,9 +227,9 @@ public:
*/ */
float getAngle(AngleEnum a) { float getAngle(AngleEnum a) {
if (a == Pitch) if (a == Pitch)
return (atan2f(ps5Data.accY, ps5Data.accZ) + PI) * RAD_TO_DEG; return (atan2f(-ps5Data.accY, -ps5Data.accZ) + PI) * RAD_TO_DEG;
else else
return (atan2f(ps5Data.accX, ps5Data.accZ) + PI) * RAD_TO_DEG; return (atan2f(ps5Data.accX, -ps5Data.accZ) + PI) * RAD_TO_DEG;
}; };
/** /**
@ -356,6 +356,7 @@ public:
*/ */
void setPlayerLed(uint8_t mask) { void setPlayerLed(uint8_t mask) {
ps5Output.playerLeds = mask; ps5Output.playerLeds = mask;
ps5Output.reportChanged = true;
} }
/** Use to turn the microphone LED off. */ /** Use to turn the microphone LED off. */
@ -369,6 +370,7 @@ public:
*/ */
void setMicLed(bool on) { void setMicLed(bool on) {
ps5Output.microphoneLed = on ? 1 : 0; ps5Output.microphoneLed = on ? 1 : 0;
ps5Output.reportChanged = true;
} }
/** Get the incoming message count. */ /** Get the incoming message count. */

View file

@ -83,7 +83,7 @@ protected:
if (pFuncOnInit) if (pFuncOnInit)
pFuncOnInit(); // Call the user function pFuncOnInit(); // Call the user function
else else
setLed(Blue); setLed(Red); // Set the LED to red, so it is consistent with the PS5BT driver
}; };
return 0; return 0;
}; };
@ -92,9 +92,9 @@ protected:
/** @name PS5Parser implementation */ /** @name PS5Parser implementation */
virtual void sendOutputReport(PS5Output *output) { // Source: https://github.com/chrippa/ds4drv virtual void sendOutputReport(PS5Output *output) { // Source: https://github.com/chrippa/ds4drv
// PS4 Source: https://github.com/chrippa/ds4drv // PS4 Source: https://github.com/chrippa/ds4drv
// PS5 values from https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/ // PS5 values from https://www.reddit.com/r/gamedev/comments/jumvi5/dualsense_haptics_leds_and_more_hid_output_report/,
// , Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows // Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows and
// and the series of patches found here: https://patchwork.kernel.org/project/linux-input/patch/20201219062336.72568-14-roderick@gaikai.com/ // the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
uint8_t buf[1 /* report id */ + 47 /* common */]; uint8_t buf[1 /* report id */ + 47 /* common */];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
@ -133,7 +133,7 @@ protected:
output->reportChanged = false; output->reportChanged = false;
// The PS5 console actually set the four last bytes to a CRC32 checksum, but it seems like it is actually not needed // There is no need to calculate a crc32 when the controller is connected via USB
pUsb->outTransfer(bAddress, epInfo[ hidInterfaces[0].epIndex[epInterruptOutIndex] ].epAddr, sizeof(buf), buf); pUsb->outTransfer(bAddress, epInfo[ hidInterfaces[0].epIndex[epInterruptOutIndex] ].epAddr, sizeof(buf), buf);
}; };

View file

@ -1,7 +1,7 @@
/* /*
Example sketch for the PS5 Bluetooth library - developed by Kristian Sloth Lauszus Example sketch for the PS5 Bluetooth library - developed by Kristian Sloth Lauszus
For more information visit the Github repository: github.com/felis/USB_Host_Shield_2.0 or For more information visit the Github repository: github.com/felis/USB_Host_Shield_2.0 or
send me an e-mail: lauszus@gmail.com send me an e-mail: lauszus@gmail.com
*/ */
#include <PS5BT.h> #include <PS5BT.h>
@ -25,10 +25,11 @@ PS5BT PS5(&Btd, PAIR);
// After that you can simply create the instance like so and then press the PS button on the device // After that you can simply create the instance like so and then press the PS button on the device
//PS5BT PS5(&Btd); //PS5BT PS5(&Btd);
bool printAngle, printTouch; bool printAngle = false, printTouch = false;
uint16_t lastMessageCounter = -1; uint16_t lastMessageCounter = -1;
uint8_t player_led_mask = 0; uint8_t player_led_mask = 0;
bool microphone_led = false; bool microphone_led = false;
uint32_t ps_timer;
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -67,91 +68,101 @@ void loop() {
} }
// Set the left trigger to resist at the right trigger's level // Set the left trigger to resist at the right trigger's level
PS5.leftTrigger.setTriggerForce(PS5.getAnalogButton(R2), 255); static uint8_t oldR2Value = 0xFF;
if (PS5.getAnalogButton(R2) != oldR2Value) {
oldR2Value = PS5.getAnalogButton(R2);
PS5.leftTrigger.setTriggerForce(oldR2Value, 255);
}
if (PS5.getButtonClick(PS)) { // Hold the PS button for 1 second to disconnect the controller
// This prevents the controller from disconnecting when it is reconnected,
// as the PS button is sent when it reconnects
if (PS5.getButtonPress(PS)) {
if (millis() - ps_timer > 1000)
PS5.disconnect();
} else
ps_timer = millis();
if (PS5.getButtonClick(PS))
Serial.print(F("\r\nPS")); Serial.print(F("\r\nPS"));
PS5.disconnect(); if (PS5.getButtonClick(TRIANGLE)) {
} else { Serial.print(F("\r\nTriangle"));
if (PS5.getButtonClick(TRIANGLE)) { PS5.setRumbleOn(RumbleLow);
Serial.print(F("\r\nTriangle")); }
PS5.setRumbleOn(RumbleLow); if (PS5.getButtonClick(CIRCLE)) {
} Serial.print(F("\r\nCircle"));
if (PS5.getButtonClick(CIRCLE)) { PS5.setRumbleOn(RumbleHigh);
Serial.print(F("\r\nCircle")); }
PS5.setRumbleOn(RumbleHigh); if (PS5.getButtonClick(CROSS)) {
} Serial.print(F("\r\nCross"));
if (PS5.getButtonClick(CROSS)) {
Serial.print(F("\r\nCross"));
// Set the player LEDs // Set the player LEDs
player_led_mask = (player_led_mask << 1) | 1; player_led_mask = (player_led_mask << 1) | 1;
if (player_led_mask > 0x1F) if (player_led_mask > 0x1F)
player_led_mask = 0; player_led_mask = 0;
PS5.setPlayerLed(player_led_mask); // The bottom 5 bits set player LEDs PS5.setPlayerLed(player_led_mask); // The bottom 5 bits set player LEDs
} }
if (PS5.getButtonClick(SQUARE)) { if (PS5.getButtonClick(SQUARE)) {
Serial.print(F("\r\nSquare")); Serial.print(F("\r\nSquare"));
PS5.setRumbleOff(); PS5.setRumbleOff();
} }
if (PS5.getButtonClick(UP)) { if (PS5.getButtonClick(UP)) {
Serial.print(F("\r\nUp")); Serial.print(F("\r\nUp"));
PS5.setLed(Red); PS5.setLed(Red);
} if (PS5.getButtonClick(RIGHT)) { } if (PS5.getButtonClick(RIGHT)) {
Serial.print(F("\r\nRight")); Serial.print(F("\r\nRight"));
PS5.setLed(Blue); PS5.setLed(Blue);
} if (PS5.getButtonClick(DOWN)) { } if (PS5.getButtonClick(DOWN)) {
Serial.print(F("\r\nDown")); Serial.print(F("\r\nDown"));
PS5.setLed(Yellow); PS5.setLed(Yellow);
} if (PS5.getButtonClick(LEFT)) { } if (PS5.getButtonClick(LEFT)) {
Serial.print(F("\r\nLeft")); Serial.print(F("\r\nLeft"));
PS5.setLed(Green); PS5.setLed(Green);
} }
if (PS5.getButtonClick(L1)) if (PS5.getButtonClick(L1))
Serial.print(F("\r\nL1")); Serial.print(F("\r\nL1"));
if (PS5.getButtonClick(L3)) if (PS5.getButtonClick(L3))
Serial.print(F("\r\nL3")); Serial.print(F("\r\nL3"));
if (PS5.getButtonClick(R1)) if (PS5.getButtonClick(R1))
Serial.print(F("\r\nR1")); Serial.print(F("\r\nR1"));
if (PS5.getButtonClick(R3)) if (PS5.getButtonClick(R3))
Serial.print(F("\r\nR3")); Serial.print(F("\r\nR3"));
if (PS5.getButtonClick(CREATE)) if (PS5.getButtonClick(CREATE))
Serial.print(F("\r\nCreate")); Serial.print(F("\r\nCreate"));
if (PS5.getButtonClick(OPTIONS)) { if (PS5.getButtonClick(OPTIONS)) {
Serial.print(F("\r\nOptions")); Serial.print(F("\r\nOptions"));
printAngle = !printAngle; printAngle = !printAngle;
} }
if (PS5.getButtonClick(TOUCHPAD)) { if (PS5.getButtonClick(TOUCHPAD)) {
Serial.print(F("\r\nTouchpad")); Serial.print(F("\r\nTouchpad"));
printTouch = !printTouch; printTouch = !printTouch;
} }
if (PS5.getButtonClick(MICROPHONE)) { if (PS5.getButtonClick(MICROPHONE)) {
Serial.print(F("\r\nMicrophone")); Serial.print(F("\r\nMicrophone"));
microphone_led = !microphone_led; microphone_led = !microphone_led;
PS5.setMicLed(microphone_led); PS5.setMicLed(microphone_led);
} }
if (printAngle) { // Print angle calculated using the accelerometer only if (printAngle) { // Print angle calculated using the accelerometer only
Serial.print(F("\r\nPitch: ")); Serial.print(F("\r\nPitch: "));
Serial.print(PS5.getAngle(Pitch)); Serial.print(PS5.getAngle(Pitch));
Serial.print(F("\tRoll: ")); Serial.print(F("\tRoll: "));
Serial.print(PS5.getAngle(Roll)); Serial.print(PS5.getAngle(Roll));
} }
if (printTouch) { // Print the x, y coordinates of the touchpad if (printTouch) { // Print the x, y coordinates of the touchpad
if (PS5.isTouching(0) || PS5.isTouching(1)) // Print newline and carriage return if any of the fingers are touching the touchpad if (PS5.isTouching(0) || PS5.isTouching(1)) // Print newline and carriage return if any of the fingers are touching the touchpad
Serial.print(F("\r\n")); Serial.print(F("\r\n"));
for (uint8_t i = 0; i < 2; i++) { // The touchpad track two fingers for (uint8_t i = 0; i < 2; i++) { // The touchpad track two fingers
if (PS5.isTouching(i)) { // Print the position of the finger if it is touching the touchpad if (PS5.isTouching(i)) { // Print the position of the finger if it is touching the touchpad
Serial.print(F("X")); Serial.print(i + 1); Serial.print(F(": ")); Serial.print(F("X")); Serial.print(i + 1); Serial.print(F(": "));
Serial.print(PS5.getX(i)); Serial.print(PS5.getX(i));
Serial.print(F("\tY")); Serial.print(i + 1); Serial.print(F(": ")); Serial.print(F("\tY")); Serial.print(i + 1); Serial.print(F(": "));
Serial.print(PS5.getY(i)); Serial.print(PS5.getY(i));
Serial.print(F("\t")); Serial.print(F("\t"));
}
} }
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
Example sketch for the PS5 USB library - developed by Kristian Sloth Lauszus Example sketch for the PS5 USB library - developed by Kristian Sloth Lauszus
For more information visit the Github repository: github.com/felis/USB_Host_Shield_2.0 or For more information visit the Github repository: github.com/felis/USB_Host_Shield_2.0 or
send me an e-mail: lauszus@gmail.com send me an e-mail: lauszus@gmail.com
*/ */
#include <PS5USB.h> #include <PS5USB.h>
@ -15,7 +15,7 @@
USB Usb; USB Usb;
PS5USB PS5(&Usb); PS5USB PS5(&Usb);
bool printAngle, printTouch; bool printAngle = false, printTouch = false;
uint16_t lastMessageCounter = -1; uint16_t lastMessageCounter = -1;
uint8_t player_led_mask = 0; uint8_t player_led_mask = 0;
bool microphone_led = false; bool microphone_led = false;
@ -57,7 +57,11 @@ void loop() {
} }
// Set the left trigger to resist at the right trigger's level // Set the left trigger to resist at the right trigger's level
PS5.leftTrigger.setTriggerForce(PS5.getAnalogButton(R2), 255); static uint8_t oldR2Value = 0xFF;
if (PS5.getAnalogButton(R2) != oldR2Value) {
oldR2Value = PS5.getAnalogButton(R2);
PS5.leftTrigger.setTriggerForce(oldR2Value, 255);
}
if (PS5.getButtonClick(PS)) if (PS5.getButtonClick(PS))
Serial.print(F("\r\nPS")); Serial.print(F("\r\nPS"));