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 bool PS5Parser::checkDpad(ButtonEnum b) {
40  switch (b) {
41  case UP:
42  return ps5Data.btn.dpad == DPAD_LEFT_UP || ps5Data.btn.dpad == DPAD_UP || ps5Data.btn.dpad == DPAD_UP_RIGHT;
43  case RIGHT:
44  return ps5Data.btn.dpad == DPAD_UP_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT || ps5Data.btn.dpad == DPAD_RIGHT_DOWN;
45  case DOWN:
46  return ps5Data.btn.dpad == DPAD_RIGHT_DOWN || ps5Data.btn.dpad == DPAD_DOWN || ps5Data.btn.dpad == DPAD_DOWN_LEFT;
47  case LEFT:
48  return ps5Data.btn.dpad == DPAD_DOWN_LEFT || ps5Data.btn.dpad == DPAD_LEFT || ps5Data.btn.dpad == DPAD_LEFT_UP;
49  default:
50  return false;
51  }
52 }
53 
55  if (b <= LEFT) // Dpad
56  return checkDpad(b);
57  else
58  return ps5Data.btn.val & (1UL << pgm_read_byte(&PS5_BUTTONS[(uint8_t)b]));
59 }
60 
62  uint32_t mask = 1UL << pgm_read_byte(&PS5_BUTTONS[(uint8_t)b]);
63  bool click = buttonClickState.val & mask;
64  buttonClickState.val &= ~mask; // Clear "click" event
65  return click;
66 }
67 
69  if (b == L2) // These are the only analog buttons on the controller
70  return ps5Data.trigger[0];
71  else if (b == R2)
72  return ps5Data.trigger[1];
73  return 0;
74 }
75 
77  return ps5Data.hatValue[(uint8_t)a];
78 }
79 
80 void PS5Parser::Parse(uint8_t len, uint8_t *buf) {
81  if (len > 1 && buf) {
82 #ifdef PRINTREPORT
83  Notify(PSTR("\r\nLen: "), 0x80); Notify(len, 0x80);
84  Notify(PSTR(", data: "), 0x80);
85  for (uint8_t i = 0; i < len; i++) {
86  D_PrintHex<uint8_t > (buf[i], 0x80);
87  Notify(PSTR(" "), 0x80);
88  }
89 #endif
90 
91  if (buf[0] == 0x01) // Check report ID
92  memcpy(&ps5Data, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(ps5Data)));
93  else if (buf[0] == 0x31) { // This report is send via Bluetooth, it has an offset of 1 compared to the USB data
94  if (len < 3) {
95 #ifdef DEBUG_USB_HOST
96  Notify(PSTR("\r\nReport is too short: "), 0x80);
97  D_PrintHex<uint8_t > (len, 0x80);
98 #endif
99  return;
100  }
101  memcpy(&ps5Data, buf + 2, min((uint8_t)(len - 2), MFK_CASTUINT8T sizeof(ps5Data)));
102  } else {
103 #ifdef DEBUG_USB_HOST
104  Notify(PSTR("\r\nUnknown report id: "), 0x80);
105  D_PrintHex<uint8_t > (buf[0], 0x80);
106  Notify(PSTR(", len: "), 0x80);
107  D_PrintHex<uint8_t > (len, 0x80);
108 #endif
109  return;
110  }
111 
112  if (ps5Data.btn.val != oldButtonState.val) { // Check if anything has changed
113  buttonClickState.val = ps5Data.btn.val & ~oldButtonState.val; // Update click state variable
114  oldButtonState.val = ps5Data.btn.val;
115 
116  // 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
117  uint8_t newDpad = 0;
118  if (checkDpad(UP))
119  newDpad |= 1 << UP;
120  if (checkDpad(RIGHT))
121  newDpad |= 1 << RIGHT;
122  if (checkDpad(DOWN))
123  newDpad |= 1 << DOWN;
124  if (checkDpad(LEFT))
125  newDpad |= 1 << LEFT;
126  if (newDpad != oldDpad) {
127  buttonClickState.dpad = newDpad & ~oldDpad; // Override values
128  oldDpad = newDpad;
129  }
130  }
131 
132  message_counter++;
133  }
134 
136  sendOutputReport(&ps5Output); // Send output report
137 }
138 
139 
141  uint8_t i;
142  for (i = 0; i < sizeof(ps5Data.hatValue); i++)
143  ps5Data.hatValue[i] = 127; // Center value
144  ps5Data.btn.val = 0;
145  oldButtonState.val = 0;
146  for (i = 0; i < sizeof(ps5Data.trigger); i++)
147  ps5Data.trigger[i] = 0;
148  for (i = 0; i < sizeof(ps5Data.xy.finger)/sizeof(ps5Data.xy.finger[0]); i++)
149  ps5Data.xy.finger[i].touching = 1; // The bit is cleared if the finger is touching the touchpad
150 
151  ps5Data.btn.dpad = DPAD_OFF;
152  oldButtonState.dpad = DPAD_OFF;
153  buttonClickState.dpad = 0;
154  oldDpad = 0;
155 
156  leftTrigger.Reset();
158 
159  ps5Output.bigRumble = ps5Output.smallRumble = 0;
160  ps5Output.microphoneLed = 0;
161  ps5Output.disableLeds = 0;
162  ps5Output.playerLeds = 0;
163  ps5Output.r = ps5Output.g = ps5Output.b = 0;
164  ps5Output.reportChanged = false;
165 };
bool reportChanged
Definition: PS5Parser.h:145
uint8_t disableLeds
Definition: PS5Parser.h:142
uint8_t playerLeds
Definition: PS5Parser.h:143
AnalogHatEnum
uint8_t hatValue[4]
Definition: PS5Parser.h:107
DPADEnum
Definition: PS4Parser.cpp:20
#define pgm_read_byte(addr)
uint32_t val
Definition: PS5Parser.h:78
uint8_t r
Definition: PS5Parser.h:144
uint8_t touching
Definition: PS5Parser.h:84
uint8_t trigger[2]
Definition: PS5Parser.h:108
struct ps5TouchpadXY::@31 finger[2]
#define Notify(...)
Definition: message.h:51
virtual void sendOutputReport(PS5Output *output)=0
void Parse(uint8_t len, uint8_t *buf)
Definition: PS5Parser.cpp:80
PS5Buttons btn
Definition: PS5Parser.h:112
const uint8_t PS5_BUTTONS[]
Definition: PS5Parser.h:30
bool getButtonPress(ButtonEnum b)
Definition: PS5Parser.cpp:54
PS5Trigger leftTrigger
Definition: PS5Parser.h:154
uint8_t getAnalogButton(ButtonEnum b)
Definition: PS5Parser.cpp:68
ButtonEnum
PS5Trigger rightTrigger
Definition: PS5Parser.h:154
uint8_t dpad
Definition: PS5Parser.h:58
bool reportChanged
Definition: PS5Trigger.h:88
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS5Parser.cpp:76
#define PSTR(str)
#define MFK_CASTUINT8T
Definition: settings.h:194
uint8_t microphoneLed
Definition: PS5Parser.h:141
uint8_t bigRumble
Definition: PS5Parser.h:140
ps5TouchpadXY xy
Definition: PS5Parser.h:125
uint8_t b
Definition: PS5Parser.h:144
bool getButtonClick(ButtonEnum b)
Definition: PS5Parser.cpp:61
uint8_t smallRumble
Definition: PS5Parser.h:140
uint8_t g
Definition: PS5Parser.h:144
void Reset()
Definition: PS5Trigger.h:100
void Reset()
Definition: PS5Parser.cpp:140