Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions examples/PS5USB/PS5USB.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "Arduino.h"
#include <usbhub.h>
#include <PS5USB.h>

#define SerialDebug Serial1

USBHost usb;
PS5USB PS5(&usb);

bool printAngle, printTouch;
uint8_t oldL2Value, oldR2Value;


void setup()
{
delay(1000);
SerialDebug.begin(115200);
SerialDebug.println("Starting PS5 USB Test");

SerialDebug.println("Initializing USB");
if (usb.Init() == -1)
SerialDebug.println("USBhost did not start.");
SerialDebug.println("USB Started");

delay( 20 );
}

uint32_t lastUSBstate;
uint16_t lastMessageCounter = -1;

void loop()
{
usb.Task();

if (PS5.connected() && lastMessageCounter!=PS5.getMessageCounter()) {
SerialDebug.print(PS5.getMessageCounter());
SerialDebug.print(F("\tLeftHatX: "));
SerialDebug.print(PS5.getAnalogHat(LeftHatX));
SerialDebug.print(F("\tLeftHatY: "));
SerialDebug.print(PS5.getAnalogHat(LeftHatY));
SerialDebug.print(F("\tRightHatX: "));
SerialDebug.print(PS5.getAnalogHat(RightHatX));
SerialDebug.print(F("\tRightHatY: "));
SerialDebug.print(PS5.getAnalogHat(RightHatY));
SerialDebug.print(F("\tL2: "));
SerialDebug.print(PS5.getAnalogButton(L2));
SerialDebug.print(F("\tR2: "));
SerialDebug.print(PS5.getAnalogButton(R2));
SerialDebug.println();

// set the left trigger to resist at the right trigger's level
PS5.leftTrigger.setTriggerForce(0, PS5.getAnalogButton(R2), 255);

if (PS5.getButtonClick(CROSS)) {
PS5.setLed(255,0,0);
}
if (PS5.getButtonClick(SQUARE)) {
PS5.setLed(0,255,0);
}
if (PS5.getButtonClick(CIRCLE)) {
PS5.setLed(0,0,255);
}
}
}
158 changes: 158 additions & 0 deletions src/PS5Parser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. 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 Lauszus, TKJ Electronics
Web : http://www.tkjelectronics.com
e-mail : [email protected]

PS4 to PS5 port by Joseph Duchesne, based on reading Ludwig Füchsl's https://github.com/Ohjurot/DualSense-Windows PS5 port
*/
#include "PS5Parser.h"


enum DPADEnum {
DPAD_UP = 0x0,
DPAD_UP_RIGHT = 0x1,
DPAD_RIGHT = 0x2,
DPAD_RIGHT_DOWN = 0x3,
DPAD_DOWN = 0x4,
DPAD_DOWN_LEFT = 0x5,
DPAD_LEFT = 0x6,
DPAD_LEFT_UP = 0x7,
DPAD_OFF = 0x8,
};

// To enable serial debugging see "settings.h"
#define PRINTREPORT // Uncomment to print the report send by the PS5 Controller

bool PS5Parser::checkDpad(ButtonEnum b) {
switch (b) {
case UP:
return ps5Data.btn.dpad == DPAD_LEFT_UP || ps5Data.btn.dpad == DPAD_UP || ps5Data.btn.dpad == DPAD_UP_RIGHT;
case RIGHT:
return ps5Data.btn.dpad == DPAD_UP_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT_DOWN;
case DOWN:
return ps5Data.btn.dpad == DPAD_RIGHT_DOWN || ps5Data.btn.dpad == DPAD_DOWN || ps5Data.btn.dpad == DPAD_DOWN_LEFT;
case LEFT:
return ps5Data.btn.dpad == DPAD_DOWN_LEFT || ps5Data.btn.dpad == DPAD_LEFT || ps5Data.btn.dpad == DPAD_LEFT_UP;
default:
return false;
}
}

bool PS5Parser::getButtonPress(ButtonEnum b) {
if (b <= LEFT) // Dpad
return checkDpad(b);
else
return ps5Data.btn.val & (1UL << pgm_read_byte(&PS5_BUTTONS[(uint8_t)b]));
}

bool PS5Parser::getButtonClick(ButtonEnum b) {
uint32_t mask = 1UL << pgm_read_byte(&PS5_BUTTONS[(uint8_t)b]);
bool click = buttonClickState.val & mask;
buttonClickState.val &= ~mask; // Clear "click" event
return click;
}

uint8_t PS5Parser::getAnalogButton(ButtonEnum b) {
if (b == L2) // These are the only analog buttons on the controller
return ps5Data.trigger[0];
else if (b == R2)
return ps5Data.trigger[1];
return 0;
}

uint8_t PS5Parser::getAnalogHat(AnalogHatEnum a) {
return ps5Data.hatValue[(uint8_t)a];
}

void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
if (len > 1 && buf) {
#ifdef PRINTREPORT
Notify(PSTR("\r\n"), 0x80);
for (uint8_t i = 0; i < len; i++) {
D_PrintHex<uint8_t > (buf[i], 0x80);
Notify(PSTR(" "), 0x80);
}
#endif

if (buf[0] == 0x01) // Check report ID
memcpy(&ps5Data, buf + 1, min((uint8_t)(len - 1), sizeof(ps5Data)));
else if (buf[0] == 0x11) { // This report is send via Bluetooth, it has an offset of 2 compared to the USB data
if (len < 4) {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nReport is too short: "), 0x80);
D_PrintHex<uint8_t > (len, 0x80);
#endif
return;
}
memcpy(&ps5Data, buf + 3, min((uint8_t)(len - 3), sizeof(ps5Data)));
} else {
#ifdef DEBUG_USB_HOST
Notify(PSTR("\r\nUnknown report id: "), 0x80);
D_PrintHex<uint8_t > (buf[0], 0x80);
#endif
return;
}

if (ps5Data.btn.val != oldButtonState.val) { // Check if anything has changed
buttonClickState.val = ps5Data.btn.val & ~oldButtonState.val; // Update click state variable
oldButtonState.val = ps5Data.btn.val;

// The DPAD buttons does not set the different bits, but set a value corresponding to the buttons pressed, we will simply set the bits ourself
uint8_t newDpad = 0;
if (checkDpad(UP))
newDpad |= 1 << UP;
if (checkDpad(RIGHT))
newDpad |= 1 << RIGHT;
if (checkDpad(DOWN))
newDpad |= 1 << DOWN;
if (checkDpad(LEFT))
newDpad |= 1 << LEFT;
if (newDpad != oldDpad) {
buttonClickState.dpad = newDpad & ~oldDpad; // Override values
oldDpad = newDpad;
}
}
}
message_counter++;

if (ps5Output.reportChanged || leftTrigger.reportChanged || rightTrigger.reportChanged)
sendOutputReport(&ps5Output); // Send output report
}


void PS5Parser::Reset() {
uint8_t i;
for (i = 0; i < sizeof(ps5Data.hatValue); i++)
ps5Data.hatValue[i] = 127; // Center value
ps5Data.btn.val = 0;
oldButtonState.val = 0;
for (i = 0; i < sizeof(ps5Data.trigger); i++)
ps5Data.trigger[i] = 0;
for (i = 0; i < sizeof(ps5Data.xy)/sizeof(ps5Data.xy[0]); i++) {
for (uint8_t j = 0; j < sizeof(ps5Data.xy[0].finger)/sizeof(ps5Data.xy[0].finger[0]); j++)
ps5Data.xy[i].finger[j].touching = 1; // The bit is cleared if the finger is touching the touchpad
}

ps5Data.btn.dpad = DPAD_OFF;
oldButtonState.dpad = DPAD_OFF;
buttonClickState.dpad = 0;
oldDpad = 0;

leftTrigger.Reset();
rightTrigger.Reset();

ps5Output.bigRumble = ps5Output.smallRumble = 0;
ps5Output.r = ps5Output.g = ps5Output.b = 0;
ps5Output.reportChanged = false;
};
Loading