Skip to content

Commit d9b1aec

Browse files
authored
feat(hid): Add PS5 DualSense BT/LE HID Report Descriptors and Input Report Structures (#520)
* feat(hid): Add PS5 DualSense BT/LE HID Report Descriptors and Input Report Structures * fix spelling of message * fix sa * revert update to hid-rp which included a breaking api change to the unit::code enum * define storage type for enum calss * fix sa
1 parent d1d5a8b commit d9b1aec

File tree

14 files changed

+1966
-89
lines changed

14 files changed

+1966
-89
lines changed

components/hid-rp/example/main/hid_rp_example.cpp

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "logger.hpp"
55

66
#include "hid-rp-gamepad.hpp"
7+
#include "hid-rp-playstation.hpp"
78
#include "hid-rp-switch-pro.hpp"
89
#include "hid-rp-xbox.hpp"
910
#include "hid-rp.hpp"
@@ -60,7 +61,6 @@ extern "C" void app_main(void) {
6061

6162
using SwitchProInput = espp::SwitchProGamepadInputReport<>;
6263
SwitchProInput switch_pro_input_report;
63-
switch_pro_input_report.reset();
6464
logger.info("{}", switch_pro_input_report);
6565
logger.info("Switch Pro Input Report Size: {}", switch_pro_input_report.get_report().size());
6666
logger.info("Switch Pro Input Report Data: {::#04X}", switch_pro_input_report.get_report());
@@ -76,12 +76,39 @@ extern "C" void app_main(void) {
7676
}
7777
logger.info(" Data: [{}]", str);
7878

79+
using PlaystationDualsenseBleSimpleInput = espp::PlaystationDualsenseBLESimpleInputReport<>;
80+
PlaystationDualsenseBleSimpleInput dualsense_simple_input_report;
81+
using PlaystationDualsenseBleComplexInput = espp::PlaystationDualsenseBLEComplexInputReport<>;
82+
PlaystationDualsenseBleComplexInput dualsense_complex_input_report;
83+
logger.info("Playstation Dualsense BLE Report Descriptor:");
84+
auto ps_raw_descriptor = espp::playstation_dualsense_ble_descriptor();
85+
auto ps_descriptor = std::vector<uint8_t>(ps_raw_descriptor.begin(), ps_raw_descriptor.end());
86+
logger.info(" Size: {}", ps_descriptor.size());
87+
str = "";
88+
for (auto &byte : ps_descriptor) {
89+
str += fmt::format("0x{:02X}, ", byte);
90+
}
91+
logger.info(" Data: [{}]", str);
92+
7993
GamepadInput::Hat hat = GamepadInput::Hat::UP_RIGHT;
8094
int button_index = 5;
8195
float angle = 2.0f * M_PI * button_index / num_buttons;
8296

83-
// update the gamepad input report
97+
// reset all reports
8498
gamepad_input_report.reset();
99+
xbox_input_report.reset();
100+
switch_pro_input_report.reset();
101+
dualsense_simple_input_report.reset();
102+
dualsense_complex_input_report.reset();
103+
104+
// print out the reports in their default states
105+
logger.info("{}", gamepad_input_report);
106+
logger.info("{}", xbox_input_report);
107+
logger.info("{}", switch_pro_input_report);
108+
logger.info("{}", dualsense_simple_input_report);
109+
logger.info("{}", dualsense_complex_input_report);
110+
111+
// update the gamepad input report
85112
logger.info("{}", gamepad_input_report);
86113
gamepad_input_report.set_hat(hat);
87114
gamepad_input_report.set_button(button_index, true);
@@ -92,11 +119,51 @@ extern "C" void app_main(void) {
92119
gamepad_input_report.set_accelerator(std::abs(sin(angle)));
93120
gamepad_input_report.set_brake(std::abs(cos(angle)));
94121

122+
switch_pro_input_report.set_button(button_index, true);
123+
switch_pro_input_report.set_dpad(false, true, false, true); // down-right
124+
switch_pro_input_report.set_left_joystick(sin(angle), cos(angle));
125+
switch_pro_input_report.set_right_joystick(cos(angle), sin(angle));
126+
switch_pro_input_report.set_left_trigger((float)std::abs(cos(angle)));
127+
switch_pro_input_report.set_right_trigger((float)std::abs(sin(angle)));
128+
129+
dualsense_simple_input_report.set_button(button_index, true);
130+
dualsense_simple_input_report.set_hat(hat);
131+
dualsense_simple_input_report.set_left_joystick(sin(angle), cos(angle));
132+
dualsense_simple_input_report.set_right_joystick(cos(angle), sin(angle));
133+
dualsense_simple_input_report.set_left_trigger(std::abs(cos(angle)));
134+
dualsense_simple_input_report.set_right_trigger(std::abs(sin(angle)));
135+
136+
dualsense_complex_input_report.set_button(button_index, true);
137+
dualsense_complex_input_report.set_hat(hat);
138+
dualsense_complex_input_report.set_left_joystick(sin(angle), cos(angle));
139+
dualsense_complex_input_report.set_right_joystick(cos(angle), sin(angle));
140+
dualsense_complex_input_report.set_left_trigger(std::abs(cos(angle)));
141+
dualsense_complex_input_report.set_right_trigger(std::abs(sin(angle)));
142+
95143
button_index = (button_index % num_buttons) + 1;
96144

97145
// send an input report
98146
auto report = gamepad_input_report.get_report();
99-
logger.info("Input report:");
147+
logger.info("{}", gamepad_input_report);
148+
logger.info("Gamepad Input report:");
149+
logger.info(" Size: {}", report.size());
150+
logger.info(" Data: {::#02X}", report);
151+
152+
report = switch_pro_input_report.get_report();
153+
logger.info("{}", switch_pro_input_report);
154+
logger.info("Switch Pro Input report:");
155+
logger.info(" Size: {}", report.size());
156+
logger.info(" Data: {::#02X}", report);
157+
158+
report = dualsense_simple_input_report.get_report();
159+
logger.info("{}", dualsense_simple_input_report);
160+
logger.info("Playstation Dualsense BLE Simple Input report:");
161+
logger.info(" Size: {}", report.size());
162+
logger.info(" Data: {::#02X}", report);
163+
164+
report = dualsense_complex_input_report.get_report();
165+
logger.info("{}", dualsense_complex_input_report);
166+
logger.info("Playstation Dualsense BLE Complex Input report:");
100167
logger.info(" Size: {}", report.size());
101168
logger.info(" Data: {::#02X}", report);
102169

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
namespace espp {
6+
namespace gamepad {
7+
/// Possible Hat switch directions
8+
enum class Hat : std::uint8_t {
9+
CENTERED = 0x0f, ///< Centered, no direction pressed.
10+
UP = 1,
11+
UP_RIGHT,
12+
RIGHT,
13+
DOWN_RIGHT,
14+
DOWN,
15+
DOWN_LEFT,
16+
LEFT,
17+
UP_LEFT
18+
};
19+
} // namespace gamepad
20+
} // namespace espp
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
namespace espp {
6+
namespace gamepad {
7+
/// Accelerometer data
8+
struct Accelerometer {
9+
union {
10+
struct {
11+
std::int16_t X;
12+
std::int16_t Y;
13+
std::int16_t Z;
14+
} __attribute__((packed));
15+
std::int16_t raw[3];
16+
} __attribute__((packed));
17+
} __attribute__((packed));
18+
19+
/// Gyroscope data
20+
struct Gyroscope {
21+
union {
22+
struct {
23+
std::int16_t X;
24+
std::int16_t Y;
25+
std::int16_t Z;
26+
} __attribute__((packed));
27+
struct {
28+
std::int16_t Pitch;
29+
std::int16_t Yaw;
30+
std::int16_t Roll;
31+
} __attribute__((packed));
32+
std::int16_t raw[3];
33+
} __attribute__((packed));
34+
} __attribute__((packed));
35+
} // namespace gamepad
36+
} // namespace espp

components/hid-rp/include/hid-rp-gamepad.hpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include "format.hpp"
66
#include "hid-rp.hpp"
77

8+
#include "gamepad_hat.hpp"
9+
810
namespace espp {
911

1012
/// HID Gamepad Input Report
@@ -54,18 +56,7 @@ class GamepadInputReport : public hid::report::base<hid::report::type::INPUT, RE
5456
};
5557

5658
public:
57-
/// Possible Hat switch directions
58-
enum class Hat {
59-
CENTERED = 0x0f, ///< Centered, no direction pressed.
60-
UP = 1,
61-
UP_RIGHT,
62-
RIGHT,
63-
DOWN_RIGHT,
64-
DOWN,
65-
DOWN_LEFT,
66-
LEFT,
67-
UP_LEFT
68-
};
59+
using Hat = espp::gamepad::Hat;
6960

7061
/// Construct a new Gamepad Input Report object
7162
constexpr GamepadInputReport() = default;
@@ -136,13 +127,17 @@ class GamepadInputReport : public hid::report::base<hid::report::type::INPUT, RE
136127
/// @return brake trigger value
137128
constexpr void get_brake(TRIGGER_TYPE &value) const { value = trigger_axes[0]; }
138129

130+
/// Get the left trigger value
131+
/// @param value left trigger value, in the range [0, 1]
132+
constexpr void get_left_trigger(float &value) const { get_brake(value); }
133+
139134
/// Set the brake trigger value
140135
/// @param value brake trigger value, in the range [0, 1]
141136
constexpr void set_brake(float value) { set_trigger_axis(0, value); }
142137

143-
/// Set the accelerator trigger value
144-
/// @param value accelerator trigger value, in the range [0, 1]
145-
constexpr void set_accelerator(float value) { set_trigger_axis(1, value); }
138+
/// Set the left trigger value
139+
/// @param value left trigger value, in the range [0, 1]
140+
constexpr void set_left_trigger(float value) { set_trigger_axis(0, value); }
146141

147142
/// Get the accelerator trigger value
148143
/// @param value accelerator trigger value, in the range [0, 1]
@@ -154,6 +149,18 @@ class GamepadInputReport : public hid::report::base<hid::report::type::INPUT, RE
154149
/// @return accelerator trigger value
155150
constexpr void get_accelerator(TRIGGER_TYPE &value) const { value = trigger_axes[1]; }
156151

152+
/// Get the right trigger value
153+
/// @param value right trigger value, in the range [0, 1]
154+
constexpr void get_right_trigger(float &value) const { get_accelerator(value); }
155+
156+
/// Set the accelerator trigger value
157+
/// @param value accelerator trigger value, in the range [0, 1]
158+
constexpr void set_accelerator(float value) { set_trigger_axis(1, value); }
159+
160+
/// Set the right trigger value
161+
/// @param value right trigger value, in the range [0, 1]
162+
constexpr void set_right_trigger(float value) { set_trigger_axis(1, value); }
163+
157164
/// Set the hat switch (d-pad) value
158165
/// @param hat Hat enum / direction to set
159166
constexpr void set_hat(Hat hat) { set_hat_switch(uint8_t(hat)); }
@@ -270,7 +277,9 @@ class GamepadInputReport : public hid::report::base<hid::report::type::INPUT, RE
270277

271278
/// Set the hat switch value
272279
/// \param hat The hat switch value to set.
273-
constexpr void set_hat_switch(Hat hat) { hat_switch = static_cast<std::uint8_t>(hat); }
280+
constexpr void set_hat_switch(Hat hat) { // cppcheck-suppress passedByValue
281+
hat_switch = static_cast<std::uint8_t>(hat);
282+
}
274283
/// Set the hat switch value
275284
/// \param value The hat switch value to set.
276285
/// \note The value should match the values within the Hat enum.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#pragma once
2+
3+
#include "format.hpp"
4+
5+
template <uint8_t REPORT_ID>
6+
struct fmt::formatter<espp::PlaystationDualsenseBLESimpleInputReport<REPORT_ID>> {
7+
template <typename ParseContext> constexpr auto parse(ParseContext &ctx) const {
8+
return ctx.begin();
9+
}
10+
11+
template <typename FormatContext>
12+
auto format(const espp::PlaystationDualsenseBLESimpleInputReport<REPORT_ID> &report,
13+
FormatContext &ctx) const {
14+
auto out = ctx.out();
15+
fmt::format_to(out, "PlaystationDualsenseBLESimpleInputReport<{}> {{", report.button_count);
16+
fmt::format_to(out, "joystick_axes: [");
17+
for (size_t i = 0; i < 4; i++) {
18+
fmt::format_to(out, "{}", report.joystick_axes[i]);
19+
if (i < 3) {
20+
fmt::format_to(out, ", ");
21+
}
22+
}
23+
fmt::format_to(out, "], trigger_axes: [");
24+
for (size_t i = 0; i < 2; i++) {
25+
fmt::format_to(out, "{}", report.trigger_axes[i]);
26+
if (i < 1) {
27+
fmt::format_to(out, ", ");
28+
}
29+
}
30+
fmt::format_to(out, "], hat_switch: {}, buttons: [", report.buttons.hat_switch);
31+
std::bitset<report.button_count> buttons;
32+
for (size_t i = 1; i <= report.button_count; i++) {
33+
buttons.set(i - 1, report.get_button(i));
34+
}
35+
fmt::format_to(out, "{}]", buttons);
36+
return fmt::format_to(out, "}}");
37+
}
38+
};
39+
40+
template <uint8_t REPORT_ID>
41+
struct fmt::formatter<espp::PlaystationDualsenseBLEComplexInputReport<REPORT_ID>> {
42+
template <typename ParseContext> constexpr auto parse(ParseContext &ctx) const {
43+
return ctx.begin();
44+
}
45+
46+
template <typename FormatContext>
47+
auto format(const espp::PlaystationDualsenseBLEComplexInputReport<REPORT_ID> &report,
48+
FormatContext &ctx) const {
49+
auto out = ctx.out();
50+
fmt::format_to(out, "PlaystationDualsenseBLEComplexInputReport<{}> {{", report.button_count);
51+
fmt::format_to(out, "joystick_axes: [");
52+
for (size_t i = 0; i < 4; i++) {
53+
fmt::format_to(out, "{}", report.joystick_axes[i]);
54+
if (i < 3) {
55+
fmt::format_to(out, ", ");
56+
}
57+
}
58+
fmt::format_to(out, "], trigger_axes: [");
59+
for (size_t i = 0; i < 2; i++) {
60+
fmt::format_to(out, "{}", report.trigger_axes[i]);
61+
if (i < 1) {
62+
fmt::format_to(out, ", ");
63+
}
64+
}
65+
fmt::format_to(out, "], hat_switch: {}, buttons: [", report.buttons.hat_switch);
66+
std::bitset<report.button_count> buttons;
67+
for (size_t i = 1; i <= report.button_count; i++) {
68+
buttons.set(i - 1, report.get_button(i));
69+
}
70+
fmt::format_to(out, "{}]", buttons);
71+
return fmt::format_to(out, "}}");
72+
}
73+
};

0 commit comments

Comments
 (0)