USB Host Shield 2.0
PS4Parser.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2014 Kristian Lauszus, TKJ Electronics. 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 Lauszus, TKJ Electronics
14  Web : http://www.tkjelectronics.com
15  e-mail : kristianl@tkjelectronics.com
16  */
17 
18 #include "PS4Parser.h"
19 
20 enum DPADEnum {
21  DPAD_UP = 0x0,
23  DPAD_RIGHT = 0x2,
25  DPAD_DOWN = 0x4,
27  DPAD_LEFT = 0x6,
28  DPAD_LEFT_UP = 0x7,
29  DPAD_OFF = 0x8,
30 };
31 
32 // To enable serial debugging see "settings.h"
33 //#define PRINTREPORT // Uncomment to print the report send by the PS4 Controller
34 
35 int8_t PS4Parser::getButtonIndexPS4(ButtonEnum b) {
36  const int8_t index = ButtonIndex(b);
37  if ((uint8_t) index >= (sizeof(PS4_BUTTONS) / sizeof(PS4_BUTTONS[0]))) return -1;
38  return index;
39 }
40 
41 bool PS4Parser::checkDpad(ButtonEnum b) {
42  switch (b) {
43  case UP:
44  return ps4Data.btn.dpad == DPAD_LEFT_UP || ps4Data.btn.dpad == DPAD_UP || ps4Data.btn.dpad == DPAD_UP_RIGHT;
45  case RIGHT:
46  return ps4Data.btn.dpad == DPAD_UP_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT || ps4Data.btn.dpad == DPAD_RIGHT_DOWN;
47  case DOWN:
48  return ps4Data.btn.dpad == DPAD_RIGHT_DOWN || ps4Data.btn.dpad == DPAD_DOWN || ps4Data.btn.dpad == DPAD_DOWN_LEFT;
49  case LEFT:
50  return ps4Data.btn.dpad == DPAD_DOWN_LEFT || ps4Data.btn.dpad == DPAD_LEFT || ps4Data.btn.dpad == DPAD_LEFT_UP;
51  default:
52  return false;
53  }
54 }
55 
57  const int8_t index = getButtonIndexPS4(b); if (index < 0) return 0;
58  if (index <= LEFT) // Dpad
59  return checkDpad(b);
60  else
61  return ps4Data.btn.val & (1UL << pgm_read_byte(&PS4_BUTTONS[index]));
62 }
63 
65  const int8_t index = getButtonIndexPS4(b); if (index < 0) return 0;
66  uint32_t mask = 1UL << pgm_read_byte(&PS4_BUTTONS[index]);
67  bool click = buttonClickState.val & mask;
68  buttonClickState.val &= ~mask; // Clear "click" event
69  return click;
70 }
71 
73  const int8_t index = getButtonIndexPS4(b); if (index < 0) return 0;
74  if (index == ButtonIndex(L2)) // These are the only analog buttons on the controller
75  return ps4Data.trigger[0];
76  else if (index == ButtonIndex(R2))
77  return ps4Data.trigger[1];
78  return 0;
79 }
80 
82  return ps4Data.hatValue[(uint8_t)a];
83 }
84 
85 void PS4Parser::Parse(uint8_t len, uint8_t *buf) {
86  if (len > 1 && buf) {
87 #ifdef PRINTREPORT
88  Notify(PSTR("\r\n"), 0x80);
89  for (uint8_t i = 0; i < len; i++) {
90  D_PrintHex<uint8_t > (buf[i], 0x80);
91  Notify(PSTR(" "), 0x80);
92  }
93 #endif
94 
95  if (buf[0] == 0x01) // Check report ID
96  memcpy(&ps4Data, buf + 1, min((uint8_t)(len - 1), MFK_CASTUINT8T sizeof(ps4Data)));
97  else if (buf[0] == 0x11) { // This report is send via Bluetooth, it has an offset of 2 compared to the USB data
98  if (len < 4) {
99 #ifdef DEBUG_USB_HOST
100  Notify(PSTR("\r\nReport is too short: "), 0x80);
101  D_PrintHex<uint8_t > (len, 0x80);
102 #endif
103  return;
104  }
105  memcpy(&ps4Data, buf + 3, min((uint8_t)(len - 3), MFK_CASTUINT8T sizeof(ps4Data)));
106  } else {
107 #ifdef DEBUG_USB_HOST
108  Notify(PSTR("\r\nUnknown report id: "), 0x80);
109  D_PrintHex<uint8_t > (buf[0], 0x80);
110 #endif
111  return;
112  }
113 
114  if (ps4Data.btn.val != oldButtonState.val) { // Check if anything has changed
115  buttonClickState.val = ps4Data.btn.val & ~oldButtonState.val; // Update click state variable
116  oldButtonState.val = ps4Data.btn.val;
117 
118  // 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
119  uint8_t newDpad = 0;
120  if (checkDpad(UP))
121  newDpad |= 1 << UP;
122  if (checkDpad(RIGHT))
123  newDpad |= 1 << RIGHT;
124  if (checkDpad(DOWN))
125  newDpad |= 1 << DOWN;
126  if (checkDpad(LEFT))
127  newDpad |= 1 << LEFT;
128  if (newDpad != oldDpad) {
129  buttonClickState.dpad = newDpad & ~oldDpad; // Override values
130  oldDpad = newDpad;
131  }
132  }
133  }
134 
135  if (ps4Output.reportChanged)
136  sendOutputReport(&ps4Output); // Send output report
137 }
138 
140  uint8_t i;
141  for (i = 0; i < sizeof(ps4Data.hatValue); i++)
142  ps4Data.hatValue[i] = 127; // Center value
143  ps4Data.btn.val = 0;
144  oldButtonState.val = 0;
145  for (i = 0; i < sizeof(ps4Data.trigger); i++)
146  ps4Data.trigger[i] = 0;
147  for (i = 0; i < sizeof(ps4Data.xy)/sizeof(ps4Data.xy[0]); i++) {
148  for (uint8_t j = 0; j < sizeof(ps4Data.xy[0].finger)/sizeof(ps4Data.xy[0].finger[0]); j++)
149  ps4Data.xy[i].finger[j].touching = 1; // The bit is cleared if the finger is touching the touchpad
150  }
151 
152  ps4Data.btn.dpad = DPAD_OFF;
153  oldButtonState.dpad = DPAD_OFF;
154  buttonClickState.dpad = 0;
155  oldDpad = 0;
156 
157  ps4Output.bigRumble = ps4Output.smallRumble = 0;
158  ps4Output.r = ps4Output.g = ps4Output.b = 0;
159  ps4Output.flashOn = ps4Output.flashOff = 0;
160  ps4Output.reportChanged = false;
161 };
162 
DPADEnum
Definition: PS4Parser.cpp:20
@ DPAD_DOWN_LEFT
Definition: PS4Parser.cpp:26
@ DPAD_RIGHT_DOWN
Definition: PS4Parser.cpp:24
@ DPAD_UP
Definition: PS4Parser.cpp:21
@ DPAD_DOWN
Definition: PS4Parser.cpp:25
@ DPAD_UP_RIGHT
Definition: PS4Parser.cpp:22
@ DPAD_LEFT_UP
Definition: PS4Parser.cpp:28
@ DPAD_OFF
Definition: PS4Parser.cpp:29
@ DPAD_RIGHT
Definition: PS4Parser.cpp:23
@ DPAD_LEFT
Definition: PS4Parser.cpp:27
const uint8_t PS4_BUTTONS[]
Definition: PS4Parser.h:25
void Reset()
Definition: PS4Parser.cpp:139
void Parse(uint8_t len, uint8_t *buf)
Definition: PS4Parser.cpp:85
uint8_t getAnalogButton(ButtonEnum b)
Definition: PS4Parser.cpp:72
virtual void sendOutputReport(PS4Output *output)=0
bool getButtonClick(ButtonEnum b)
Definition: PS4Parser.cpp:64
uint8_t getAnalogHat(AnalogHatEnum a)
Definition: PS4Parser.cpp:81
bool getButtonPress(ButtonEnum b)
Definition: PS4Parser.cpp:56
constexpr int8_t ButtonIndex(ButtonEnum key)
AnalogHatEnum
ButtonEnum
@ L2
@ R2
@ DOWN
@ UP
@ LEFT
@ RIGHT
#define Notify(...)
Definition: message.h:51
#define MFK_CASTUINT8T
Definition: settings.h:200
touchpadXY xy[3]
Definition: PS4Parser.h:108
PS4Buttons btn
Definition: PS4Parser.h:95
uint8_t hatValue[4]
Definition: PS4Parser.h:94
uint8_t trigger[2]
Definition: PS4Parser.h:96
uint8_t b
Definition: PS4Parser.h:118
uint8_t flashOff
Definition: PS4Parser.h:119
uint8_t flashOn
Definition: PS4Parser.h:119
uint8_t r
Definition: PS4Parser.h:118
uint8_t smallRumble
Definition: PS4Parser.h:117
uint8_t bigRumble
Definition: PS4Parser.h:117
uint8_t g
Definition: PS4Parser.h:118
bool reportChanged
Definition: PS4Parser.h:120
struct touchpadXY::@28 finger[2]
uint8_t touching
Definition: PS4Parser.h:78
uint8_t dpad
Definition: PS4Parser.h:52
uint32_t val
Definition: PS4Parser.h:71
#define pgm_read_byte(addr)
#define PSTR(str)