Monado OpenXR Runtime
Loading...
Searching...
No Matches
pssense_protocol.h
Go to the documentation of this file.
1// Copyright 2023, Collabora, Ltd.
2// Copyright 2023, Jarett Millard
3// Copyright 2026, Beyley Cardellio
4// SPDX-License-Identifier: BSL-1.0
5/*!
6 * @file
7 * @brief PlayStation Sense controller prober and driver code.
8 * @author Jarett Millard <jarett.millard@gmail.com>
9 * @author Beyley Cardellio <ep1cm1n10n123@gmail.com>
10 * @ingroup drv_pssense
11 */
12
13#pragma once
14
15#include "xrt/xrt_byte_order.h"
16
17#include "math/m_api.h"
18
19
20#pragma pack(push, 1)
21
22// @todo Remove when clang-format is updated in CI
23// clang-format off
24// IMU ticks are in thirds of a microsecond, so 1 tick = 333.333... nanoseconds
25#define NS_TO_IMU_TICKS(ns) (((uint64_t)(ns) * 3) / 1000)
26#define IMU_TICKS_TO_NS(ticks) (((uint64_t)(ticks) * 1000) / 3)
27
28#define PERIOD_ID_TO_DURATION_NS(period_id) (time_duration_ns)(IMU_TICKS_TO_NS(150LLU * (uint64_t)period_id))
29// @note: the +1 is to ensure things round correctly when dealing with converting to and back
30#define DURATION_NS_TO_PERIOD_ID(duration_ns) (uint8_t)(((NS_TO_IMU_TICKS(duration_ns + 1)) / 150LLU) & 0xFF)
31// clang-format on
32
33#define STABLE_MIN_PERIOD_ID 20
34
35#define MIN_PERIOD_ID 1
36#define MAX_PERIOD_ID 42
37
38#define PCM_SAMPLE_RATE 3000
39#define PCM_HAPTIC_BUF_SIZE 32
40
41#define INPUT_REPORT_ID_USB 0x01
42#define INPUT_REPORT_ID_BLUETOOTH 0x31
43
44#define OUTPUT_REPORT_ID_BLUETOOTH 0x31
45#define OUTPUT_REPORT_TAG 0x10
46
47#define CALIBRATION_DATA_FEATURE_REPORT_ID 0x05
48#define SET_POLLING_RATE_FEATURE_REPORT_ID 0x08
49
50#define CALIBRATION_DATA_PART_ID_1 0
51#define CALIBRATION_DATA_PART_ID_2 0x81
52
53const uint8_t INPUT_REPORT_CRC32_SEED = 0xa1;
54const uint8_t OUTPUT_REPORT_CRC32_SEED = 0xa2;
55const uint8_t FEATURE_REPORT_CRC32_SEED = 0xa3;
56const uint8_t SET_FEATURE_REPORT_CRC32_SEED = 0x53;
57
58const uint8_t CHARGE_STATE_DISCHARGING = 0x00;
59const uint8_t CHARGE_STATE_CHARGING = 0x01;
60const uint8_t CHARGE_STATE_FULL = 0x02;
61const uint8_t CHARGE_STATE_ABNORMAL_VOLTAGE = 0x0A;
62const uint8_t CHARGE_STATE_ABNORMAL_TEMP = 0x0B;
63const uint8_t CHARGE_STATE_CHARGING_ERROR = 0x0F;
64
65#define INPUT_REPORT_BLUETOOTH_LENGTH 78
66#define INPUT_REPORT_USB_LENGTH 64
67
69{
70 uint8_t thumbstick_x;
71 uint8_t thumbstick_y;
72 uint8_t trigger_value;
73 uint8_t trigger_proximity;
74 uint8_t squeeze_proximity;
75 uint8_t unknown1[2]; // Always 0x0001
76 uint8_t buttons[3];
77 uint8_t unknown2; // Always 0x00
78 __le32 seq_no;
79 __le16 gyro[3];
80 __le16 accel[3];
81 __le32 imu_ticks;
82 uint8_t temperature;
83 uint8_t unknown3[7];
84 uint8_t trigger_feedback_state;
85 uint8_t trigger_feedback_mode;
86 uint8_t battery_state; // Low nibble charge level 0x00-0x0a, high nibble battery state
87 uint8_t plug_state; // Flags for USB data and/or power connected
88 __le32 host_timestamp;
89 __le32 device_timestamp_ticks;
90 uint8_t unknown4[4];
91 uint8_t aes_cmac[8];
92};
93
95{
96 uint8_t report_id;
97 struct pssense_input_report_common common;
98};
99static_assert(sizeof(struct pssense_usb_input_report) == INPUT_REPORT_USB_LENGTH,
100 "Incorrect input report struct length");
101
102/*!
103 * HID input report data packet.
104 */
106{
107 uint8_t report_id;
108 uint8_t bt_header;
109 struct pssense_input_report_common common;
110 uint8_t unknown5;
111 uint8_t crc_failure_count;
112 uint8_t padding[7];
113 __le32 crc;
114};
115static_assert(sizeof(struct pssense_bluetooth_input_report) == INPUT_REPORT_BLUETOOTH_LENGTH,
116 "Incorrect input report struct length");
117
118enum pssense_output_settings_flag1
119{
120 PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK0 = 1 << 0,
121 PSSENSE_OUTPUT_SETTINGS_FLAG1_RUMBLE_EMULATION = 1 << 1,
122 PSSENSE_OUTPUT_SETTINGS_FLAG1_ADAPTIVE_TRIGGER_ENABLE = 1 << 2,
123 PSSENSE_OUTPUT_SETTINGS_FLAG1_INTENSITY_INCREASE_SET_ENABLE = 1 << 3,
124 PSSENSE_OUTPUT_SETTINGS_FLAG1_INTENSITY_REDUCTION_SET_ENABLE = 1 << 4,
125 PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK5 = 1 << 5,
126 PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK6 = 1 << 6,
127 PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK7 = 1 << 7,
128};
129
130#define OUTPUT_SETTINGS_ENABLE_VIBRATION_BITS \
131 (PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK0 | PSSENSE_OUTPUT_SETTINGS_FLAG1_RUMBLE_EMULATION)
132
133#define OUTPUT_SETTINGS_VIBRATE_MODE_HIGH_120HZ 0x00
134// 0x20
135#define OUTPUT_SETTINGS_VIBRATE_MODE_LOW_60HZ (PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK5)
136// 0x40
137#define OUTPUT_SETTINGS_VIBRATE_MODE_CLASSIC_RUMBLE (PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK6)
138// 0x60
139#define OUTPUT_SETTINGS_VIBRATE_MODE_DIET_RUMBLE \
140 (PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK5 | PSSENSE_OUTPUT_SETTINGS_FLAG1_UNK6)
141
143{
144 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK0 = 1 << 0,
145 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK1 = 1 << 1,
146 //! Used to mark whether to read the status LED enable bool or not.
148 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK3 = 1 << 3,
149 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK4 = 1 << 4,
150 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK5 = 1 << 5,
151 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK6 = 1 << 6,
152 PSSENSE_OUTPUT_SETTINGS_FLAG2_UNK7 = 1 << 7,
153};
154
155enum pssense_adaptive_trigger_mode
156{
157 TRIGGER_FEEDBACK_MODE_OFF = 0x05,
158
159 // simple versions of other effects, shouldn't be used
160 TRIGGER_FEEDBACK_MODE_SIMPLE_FEEDBACK = 0x01,
161 TRIGGER_FEEDBACK_MODE_SIMPLE_WEAPON = 0x02,
162 TRIGGER_FEEDBACK_MODE_SIMPLE_VIBRATION = 0x06,
163
164 // limited versions of official
165 TRIGGER_FEEDBACK_MODE_LIMITED_FEEDBACK = 0x11,
166 TRIGGER_FEEDBACK_MODE_LIMITED_WEAPON = 0x12,
167
168 // official ones found through reverse engineering
169 TRIGGER_FEEDBACK_MODE_FEEDBACK = 0x21,
170 TRIGGER_FEEDBACK_MODE_SLOPE_FEEDBACK = 0x22, // aka Bow
171 TRIGGER_FEEDBACK_MODE_WEAPON = 0x25,
172 TRIGGER_FEEDBACK_MODE_VIBRATION = 0x26,
173
174 // unofficial ones found through fuzzing firmware
175 TRIGGER_FEEDBACK_MODE_GALLOPING = 0x23,
176 TRIGGER_FEEDBACK_MODE_MACHINE = 0x27,
177};
178
180{
181 uint8_t mode; // See enum pssense_adaptive_trigger_mode
182 union {
183 uint8_t raw_parameters[10];
184 };
185};
186
187enum pssense_led_sync_phase
188{
189 // initializing
190 LED_SYNC_PHASE_INIT = 0,
191 // ???
192 LED_SYNC_PHASE_PRESCAN = 1,
193 // ???
194 LED_SYNC_PHASE_BROAD = 2,
195 // ???
196 LED_SYNC_PHASE_BG = 3,
197 // ???
198 LED_SYNC_PHASE_STABLE = 4,
199 // used during passthrough to prevent LEDs from bleeding into it
200 LED_SYNC_PHASE_LED_ALL_OFF = 5,
201 // probably 100% duty cycle?
202 LED_SYNC_PHASE_LED_ALL_ON = 6,
203 // probably also 100% duty cycle?
204 LED_SYNC_PHASE_DEBUG = 7,
205};
206
208{
209 uint8_t phase;
210 uint8_t sequence_number;
211 uint8_t period_id;
212 //! The position, in IMU ticks, @ref NS_PER_IMU_TICK
214 //! The length, in thirds of a nanosecond.
216 uint8_t led_blink[4];
217};
218
220{
221 //! See enum pssense_output_settings_flag1
222 uint8_t flag1;
223 //! See enum pssense_output_settings_flag2
224 uint8_t flag2;
225 //! Vibration amplitude from 0x00-0xff. Sending 0 turns vibration off.
227 //! Sony driver sometimes sets to 0x82.
228 uint8_t unk0;
229 //! Settings for the adaptive trigger
231 //! Time of packet send, in host time, in microseconds
233 //! Settings of the tracking LEDs.
235 //! Lower 4 bits for haptics reduction, upper 4 bits for trigger reduction. Decreases in 12.5% increments.
237 //! Whether to enable the status LED or not.
239 uint8_t unk1[2];
240};
241static_assert(sizeof(struct pssense_output_settings) == 38, "Incorrect output settings struct length");
242
243#define OUTPUT_REPORT_LENGTH_PS5 78
244#define OUTPUT_REPORT_LENGTH_USB 39
245
246/**
247 * HID output report data packet matching the PS5 layout, with PCM haptics.
248 *
249 * Reference:
250 * https://github.com/BnuuySolutions/PSVR2Toolkit/blob/b6ffe9f03cb2456d9d07aea74e839d9c5fd188f5/projects/psvr2_openvr_driver_ex/sense_controller.h#L44
251 */
253{
254 uint8_t report_id;
255 uint8_t seq_no_mode; // High bits only; low bits are always 0
256 uint8_t tag; // Needs to be 0x10 for this report
257 struct pssense_output_settings settings;
258 uint8_t counter;
259 uint8_t haptics[PCM_HAPTIC_BUF_SIZE];
260 __le32 crc;
261};
262static_assert(sizeof(struct pssense_ps5_output_report) == OUTPUT_REPORT_LENGTH_PS5,
263 "Incorrect output report struct length");
264
266{
267 // @note: There appears to be no dedicated report ID field here. Setting this report ID to
268 // any non-zero number seems to work, though. Zero doesn't work.
269 // I believe this controller just expects strange report IDs over USB.
270 // If USB breaks when using hidapi, this is the first place to check.
271 uint8_t seq_no_mode;
272 struct pssense_output_settings settings;
273};
274static_assert(sizeof(struct pssense_usb_output_report) == OUTPUT_REPORT_LENGTH_USB,
275 "Incorrect output report struct length");
276
277#define FEATURE_REPORT_LENGTH 64
278#define CALIBRATION_DATA_LENGTH 116
279
280/**
281 * HID output report data packet.
282 */
284{
285 uint8_t report_id;
286 uint8_t part_id;
287 uint8_t data[CALIBRATION_DATA_LENGTH / 2];
288 __le32 crc;
289};
290static_assert(sizeof(struct pssense_feature_report) == FEATURE_REPORT_LENGTH, "Incorrect feature report struct length");
291
293{
294 int16_t accel_plus_x; // 0x00
295 uint8_t _pad0[4]; // 0x02-0x05
296 int16_t accel_minus_x; // 0x06
297 uint8_t _pad1[6]; // 0x08-0x0D
298 int16_t accel_plus_y; // 0x0E
299 uint8_t _pad2[4]; // 0x10-0x13
300 int16_t accel_minus_y; // 0x14
301 uint8_t _pad3[6]; // 0x16-0x1B
302 int16_t accel_plus_z; // 0x1C
303 uint8_t _pad4[4]; // 0x1E-0x21
304 int16_t accel_minus_z; // 0x22
305 uint8_t _pad5[6]; // 0x24-0x29
306 int16_t gyro_plus_y; // 0x2A
307 uint8_t _pad6[4]; // 0x2C-0x2F
308 int16_t gyro_minus_y; // 0x30
309 uint8_t _pad7[6]; // 0x32-0x37
310 int16_t gyro_plus_z; // 0x38
311
312 uint8_t _pad8[4]; // 0x3A-0x3D
313 int16_t gyro_minus_z; // 0x3E
314 int16_t gyro_bias_x; // 0x40
315 int16_t gyro_bias_y; // 0x42
316 int16_t gyro_bias_z; // 0x44
317 int16_t gyro_plus_x; // 0x46
318 uint8_t _pad9[4]; // 0x48-0x4B
319 int16_t gyro_minus_x; // 0x4C
320 int16_t gyro_speed_ref1; // 0x4E
321 int16_t gyro_speed_ref2; // 0x50
322 uint8_t _pad_end[34]; // 0x52-0x73
323};
324static_assert(sizeof(struct pssense_calibration_data) == CALIBRATION_DATA_LENGTH,
325 "Incorrect calibration data struct length");
326
327#define SET_POLLING_RATE_FEATURE_REPORT_LENGTH 48
329{
330 uint8_t report_id;
331 uint8_t unk;
332 __le16 rate_1;
333 __le16 rate_2;
334 uint8_t padding[38];
335 __le32 crc;
336};
337static_assert(sizeof(struct pssense_set_polling_rate_feature_report) == SET_POLLING_RATE_FEATURE_REPORT_LENGTH,
338 "Incorrect feature report struct length");
339
340#pragma pack(pop)
C interface to math library.
pssense_output_settings_flag2
Definition pssense_protocol.h:143
@ PSSENSE_OUTPUT_SETTINGS_FLAG2_STATUS_LED_SET_ENABLE
Used to mark whether to read the status LED enable bool or not.
Definition pssense_protocol.h:147
HID input report data packet.
Definition pssense_protocol.h:106
Definition pssense_protocol.h:293
HID output report data packet.
Definition pssense_protocol.h:284
Definition pssense_protocol.h:69
Definition pssense_protocol.h:208
__le32 cycle_position
The position, in IMU ticks, NS_PER_IMU_TICK.
Definition pssense_protocol.h:213
__le32 cycle_length
The length, in thirds of a nanosecond.
Definition pssense_protocol.h:215
Definition pssense_protocol.h:180
Definition pssense_protocol.h:220
uint8_t flag2
See enum pssense_output_settings_flag2.
Definition pssense_protocol.h:224
struct pssense_led_settings led_settings
Settings of the tracking LEDs.
Definition pssense_protocol.h:234
__le32 host_timestamp_send_time_us
Time of packet send, in host time, in microseconds.
Definition pssense_protocol.h:232
uint8_t status_led_enable
Whether to enable the status LED or not.
Definition pssense_protocol.h:238
uint8_t vibration_amplitude
Vibration amplitude from 0x00-0xff. Sending 0 turns vibration off.
Definition pssense_protocol.h:226
uint8_t flag1
See enum pssense_output_settings_flag1.
Definition pssense_protocol.h:222
struct pssense_output_adaptive_trigger_settings trigger_settings
Settings for the adaptive trigger.
Definition pssense_protocol.h:230
uint8_t trigger_haptics_reduction
Lower 4 bits for haptics reduction, upper 4 bits for trigger reduction. Decreases in 12....
Definition pssense_protocol.h:236
uint8_t unk0
Sony driver sometimes sets to 0x82.
Definition pssense_protocol.h:228
HID output report data packet matching the PS5 layout, with PCM haptics.
Definition pssense_protocol.h:253
Definition pssense_protocol.h:329
Definition pssense_protocol.h:95
Definition pssense_protocol.h:266
Endian-specific byte order defines.