USB Host Shield 2.0
PS5Parser.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2021 Kristian Sloth Lauszus. 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 Sloth Lauszus
14  Web : https://lauszus.com
15  e-mail : lauszus@gmail.com
16 
17  Thanks to Joseph Duchesne for the initial code.
18  Based on Ludwig F├╝chsl's https://github.com/Ohjurot/DualSense-Windows PS5 port
19  and the series of patches found here: https://patchwork.kernel.org/project/linux-input/cover/20201219062336.72568-1-roderick@gaikai.com/
20  */
21 
22 #include "PS5Parser.h"
23 
24 enum DPADEnum {
25  DPAD_UP = 0x0,
27  DPAD_RIGHT = 0x2,
29  DPAD_DOWN = 0x4,
31  DPAD_LEFT = 0x6,
32  DPAD_LEFT_UP = 0x7,
33  DPAD_OFF = 0x8,
34 };
35 
36 // To enable serial debugging see "settings.h"
37 //#define PRINTREPORT // Uncomment to print the report send by the PS5 Controller
38 
39 int8_t PS5Parser::getButtonIndexPS5(ButtonEnum b) {
40  const int8_t index = ButtonIndex(b);
41  if ((uint8_t) index >= (sizeof(PS5_BUTTONS) / sizeof(PS5_BUTTONS[0]))) return -1;
42  return index;
43 }
44 
45 bool PS5Parser::checkDpad(ButtonEnum b) {
46  switch (b) {
47  case UP:
48  return ps5Data.btn.dpad == DPAD_LEFT_UP || ps5Data.btn.dpad == DPAD_UP || ps5Data.btn.dpad == DPAD_UP_RIGHT;
49  case RIGHT:
50  return ps5Data.btn.dpad == DPAD_UP_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT_DOWN;
51  case DOWN:
52  return ps5Data.btn.dpad == DPAD_RIGHT_DOWN || ps5Data.btn.dpad == DPAD_DOWN || ps5Data.btn.dpad == DPAD_DOWN_LEFT;
53  case LEFT:
54  return ps5Data.btn.dpad == DPAD_DOWN_LEFT || ps5Data.btn.dpad == DPAD_LEFT || ps5Data.btn.dpad == DPAD_LEFT_UP;
55  default:
56  return false;
57  }
58 }
59 
61  const int8_t index = getButtonIndexPS5(b); if (index < 0) return 0;
62  if (index <= LEFT) // Dpad
63  return checkDpad(b);
64  else
65  return ps5Data.btn.val & (1UL << pgm_read_byte(&PS5_BUTTONS[index]));
66 }
67 
69  const int8_t index = getButtonIndexPS5(b); if (index < 0) return 0;
70  uint32_t mask = 1UL << pgm_read_byte(&PS5_BUTTONS[index]);
71  bool click = buttonClickState.val & mask;
72  buttonClickState.val &= ~mask; // Clear "click" event
73  return click;
74 }
75 
77  const int8_t index = getButtonIndexPS5(b); if (index < 0) return 0;
78  if (index == ButtonIndex(L2)) // These are the only analog buttons on the controller
79  return ps5Data.trigger[0];
80  else if (index == ButtonIndex(R2))
81  return ps5Data.trigger[1];
82  return 0;
83 }
84 
86  return ps5Data.hatValue[(uint8_t)a];
87 }
88 
89 void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
90  if (len > 1 && buf) {
91 #ifdef PRINTREPORT
92  Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
93  Notify(PSTR(", data: "), 0x80);
94  for (uint8_t i = 0; i < len; i++) {
95  D_PrintHex<uint8_t > (buf[i], 0x80);
96  Notify(PSTR(" "), 0x80);
97  }
98 #endif
99 
100  if (buf[0] == 0x01) // Check report ID
101  memcpy(&ps5Data, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(ps5Data)));
102  else if (buf[0] == 0x31) { // This report is send via Bluetooth, it has an offset of 1 compared to the USB data
103  if (len < 3) {
104 #ifdef DEBUG_USB_HOST
105  Notify(PSTR("\r\nReport is too short: "), 0x80);
106  D_PrintHex<uint8_t > (len, 0x80);
107 #endif
108  return;
109  }
110  memcpy(&ps5Data, buf + 2, min((uint8_t)(len - 2), MFK_CASTUINT8T sizeof(ps5Data)));
111  } else {
112 #ifdef DEBUG_USB_HOST
113  Notify(PSTR("\r\nUnknown report id: "), 0x80);
114  D_PrintHex<uint8_t > (buf[0], 0x80);
115  Notify(PSTR(", len: "), 0x80);
116  D_PrintHex<uint8_t > (len, 0x80);
117 #endif
118  return;
119  }
120 
121  if (ps5Data.btn.val != oldButtonState.val) { // Check if anything has changed
122  buttonClickState.val = ps5Data.btn.val & ~oldButtonState.val; // Update click state variable
123  oldButtonState.val = ps5Data.btn.val;
124 
125  // 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
126  uint8_t newDpad = 0;
127  if (checkDpad(UP))
128  newDpad |= 1 << UP;
129  if (checkDpad(RIGHT))
130  newDpad |= 1 << RIGHT;
131  if (checkDpad(DOWN))
132  newDpad |= 1 << DOWN;
133  if (checkDpad(LEFT))
134  newDpad |= 1 << LEFT;
135  if (newDpad != oldDpad) {
136  buttonClickState.dpad = newDpad & ~oldDpad; // Override values
137  oldDpad = newDpad;
138  }
139  }
140 
141  message_counter++;
142  }
143 
145  sendOutputReport(&ps5Output); // Send output report
146 }
147 
148 
150  uint8_t i;
151  for (i = 0; i < sizeof(ps5Data.hatValue); i++)
152  ps5Data.hatValue[i] = 127; // Center value
153  ps5Data.btn.val = 0;
154  oldButtonState.val = 0;
155  for (i = 0; i < sizeof(ps5Data.trigger); i++)
156  ps5Data.trigger[i] = 0;
157  for (i = 0; i < sizeof(ps5Data.xy.finger)/sizeof(ps5Data.xy.finger[0]); i++)
158  ps5Data.xy.finger[i].touching = 1; // The bit is cleared if the finger is touching the touchpad
159 
160  ps5Data.btn.dpad = DPAD_OFF;
161  oldButtonState.dpad = DPAD_OFF;
162  buttonClickState.dpad = 0;
163  oldDpad = 0;
164 
165  leftTrigger.Reset();
167 
168  ps5Output.bigRumble = ps5Output.smallRumble = 0;
169  ps5Output.microphoneLed = 0;
170  ps5Output.disableLeds = 0;
171  ps5Output.playerLeds = 0;
172  ps5Output.r = ps5Output.g = ps5Output.b = 0;
173  ps5Output.reportChanged = false;
174 };
DPAD_UP
@ DPAD_UP
Definition: PS5Parser.cpp:25
PS5Trigger::Reset
void Reset()
Definition: PS5Trigger.h:100
MFK_CASTUINT8T
#define MFK_CASTUINT8T
Definition: settings.h:200
PS5Parser::rightTrigger
PS5Trigger rightTrigger
Definition: PS5Parser.h:157
DPAD_LEFT_UP
@ DPAD_LEFT_UP
Definition: PS5Parser.cpp:32
PS5Buttons::val
uint32_t val
Definition: PS5Parser.h:78
PS5Output::microphoneLed
uint8_t microphoneLed
Definition: PS5Parser.h:141
DPAD_LEFT
@ DPAD_LEFT
Definition: PS5Parser.cpp:31
DPAD_DOWN_LEFT
@ DPAD_DOWN_LEFT
Definition: PS5Parser.cpp:30
ButtonIndex
constexpr int8_t ButtonIndex(ButtonEnum key)
Definition: controllerEnums.h:191
PS5Trigger::reportChanged
bool reportChanged
Definition: PS5Trigger.h:88
PS5Output::playerLeds
uint8_t playerLeds
Definition: PS5Parser.h:143
PS5Data::btn
PS5Buttons btn
Definition: PS5Parser.h:112
Notify
#define Notify(...)
Definition: message.h:51
PS5Data::trigger
uint8_t trigger[2]
Definition: PS5Parser.h:108
PS5Parser::Parse
void Parse(uint8_t len, uint8_t *buf)
Definition: PS5Parser.cpp:89
UP
@ UP
Definition: controllerEnums.h:81
PS5Parser::getAnalogButton
uint8_t getAnalogButton(ButtonEnum b)
Definition: PS5Parser.cpp:76
DPADEnum
DPADEnum
Definition: PS4Parser.cpp:20
PS5Buttons::dpad
uint8_t dpad
Definition: PS5Parser.h:58
PS5Data::hatValue
uint8_t hatValue[4]
Definition: PS5Parser.h:107
RIGHT
@ RIGHT
Definition: controllerEnums.h:82
PS5Parser::getButtonClick
bool getButtonClick(ButtonEnum b)
Definition: PS5Parser.cpp:68
DOWN
@ DOWN
Definition: controllerEnums.h:83
ps5TouchpadXY::touching
uint8_t touching
Definition: PS5Parser.h:84
PS5Output::reportChanged
bool reportChanged
Definition: PS5Parser.h:145
PS5Output::bigRumble
uint8_t bigRumble
Definition: PS5Parser.h:140
L2
@ L2
Definition: controllerEnums.h:102
PS5Output::b
uint8_t b
Definition: PS5Parser.h:144
DPAD_RIGHT_DOWN
@ DPAD_RIGHT_DOWN
Definition: PS5Parser.cpp:28
PS5Parser::sendOutputReport
virtual void sendOutputReport(PS5Output *output)=0
DPAD_DOWN
@ DPAD_DOWN
Definition: PS5Parser.cpp:29
PS5Parser::Reset
void Reset()
Definition: PS5Parser.cpp:149
pgm_read_byte
#define pgm_read_byte(addr)
Definition: version_helper.h:161
PS5_BUTTONS
const uint8_t PS5_BUTTONS[]
Definition: PS5Parser.h:30
DPAD_UP_RIGHT
@ DPAD_UP_RIGHT
Definition: PS5Parser.cpp:26
PS5Parser::getButtonPress
bool getButtonPress(ButtonEnum b)
Definition: PS5Parser.cpp:60
PS5Data::xy
ps5TouchpadXY xy
Definition: PS5Parser.h:125
PS5Output::smallRumble
uint8_t smallRumble
Definition: PS5Parser.h:140
PSTR
#define PSTR(str)
Definition: version_helper.h:54
PS5Parser::getAnalogHat
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS5Parser.cpp:85
DPAD_RIGHT
@ DPAD_RIGHT
Definition: PS5Parser.cpp:27
DPAD_OFF
@ DPAD_OFF
Definition: PS5Parser.cpp:33
PS5Output::disableLeds
uint8_t disableLeds
Definition: PS5Parser.h:142
PS5Output::r
uint8_t r
Definition: PS5Parser.h:144
R2
@ R2
Definition: controllerEnums.h:103
ps5TouchpadXY::finger
struct ps5TouchpadXY::@31 finger[2]
ButtonEnum
ButtonEnum
Definition: controllerEnums.h:78
LEFT
@ LEFT
Definition: controllerEnums.h:84
PS5Parser.h
AnalogHatEnum
AnalogHatEnum
Definition: controllerEnums.h:218
PS5Parser::leftTrigger
PS5Trigger leftTrigger
Definition: PS5Parser.h:154
PS5Output::g
uint8_t g
Definition: PS5Parser.h:144