1/*
2 Simple DirectMedia Layer
3 Copyright (C) 2020 Valve Corporation
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#ifndef _CONTROLLER_STRUCTS_
22#define _CONTROLLER_STRUCTS_
23
24#pragma pack(1)
25
26#define HID_FEATURE_REPORT_BYTES 64
27
28// Header for all host <==> target messages
29typedef struct
30{
31 unsigned char type;
32 unsigned char length;
33} FeatureReportHeader;
34
35// Generic controller settings structure
36typedef struct
37{
38 unsigned char settingNum;
39 unsigned short settingValue;
40} ControllerSetting;
41
42// Generic controller attribute structure
43typedef struct
44{
45 unsigned char attributeTag;
46 uint32_t attributeValue;
47} ControllerAttribute;
48
49// Generic controller settings structure
50typedef struct
51{
52 ControllerSetting settings[ ( HID_FEATURE_REPORT_BYTES - sizeof( FeatureReportHeader ) ) / sizeof( ControllerSetting ) ];
53} MsgSetSettingsValues, MsgGetSettingsValues, MsgGetSettingsDefaults, MsgGetSettingsMaxs;
54
55// Generic controller settings structure
56typedef struct
57{
58 ControllerAttribute attributes[ ( HID_FEATURE_REPORT_BYTES - sizeof( FeatureReportHeader ) ) / sizeof( ControllerAttribute ) ];
59} MsgGetAttributes;
60
61typedef struct
62{
63 unsigned char attributeTag;
64 char attributeValue[20];
65} MsgGetStringAttribute;
66
67typedef struct
68{
69 unsigned char mode;
70} MsgSetControllerMode;
71
72// Trigger a haptic pulse
73typedef struct {
74 unsigned char which_pad;
75 unsigned short pulse_duration;
76 unsigned short pulse_interval;
77 unsigned short pulse_count;
78 short dBgain;
79 unsigned char priority;
80} MsgFireHapticPulse;
81
82typedef struct {
83 uint8_t mode;
84} MsgHapticSetMode;
85
86typedef enum {
87 HAPTIC_TYPE_OFF,
88 HAPTIC_TYPE_TICK,
89 HAPTIC_TYPE_CLICK,
90 HAPTIC_TYPE_TONE,
91 HAPTIC_TYPE_RUMBLE,
92 HAPTIC_TYPE_NOISE,
93 HAPTIC_TYPE_SCRIPT,
94 HAPTIC_TYPE_LOG_SWEEP,
95} haptic_type_t;
96
97typedef enum {
98 HAPTIC_INTENSITY_SYSTEM,
99 HAPTIC_INTENSITY_SHORT,
100 HAPTIC_INTENSITY_MEDIUM,
101 HAPTIC_INTENSITY_LONG,
102 HAPTIC_INTENSITY_INSANE,
103} haptic_intensity_t;
104
105typedef struct {
106 uint8_t side; // 0x01 = L, 0x02 = R, 0x03 = Both
107 uint8_t cmd; // 0 = Off, 1 = tick, 2 = click, 3 = tone, 4 = rumble, 5 =
108 // rumble_noise, 6 = script, 7 = sweep,
109 uint8_t ui_intensity; // 0-4 (0 = default)
110 int8_t dBgain; // dB Can be positive (reasonable clipping / limiting will apply)
111 uint16_t freq; // Frequency of tone (if applicable)
112 int16_t dur_ms; // Duration of tone / rumble (if applicable) (neg = infinite)
113
114 uint16_t noise_intensity;
115 uint16_t lfo_freq; // Drives both tone and rumble geneators
116 uint8_t lfo_depth; // percentage, typically 100
117 uint8_t rand_tone_gain; // Randomize each LFO cycle's gain
118 uint8_t script_id; // Used w/ dBgain for scripted haptics
119
120 uint16_t lss_start_freq; // Used w/ Log Sine Sweep
121 uint16_t lss_end_freq; // Ditto
122} MsgTriggerHaptic;
123
124typedef struct {
125 uint8_t unRumbleType;
126 uint16_t unIntensity;
127 uint16_t unLeftMotorSpeed;
128 uint16_t unRightMotorSpeed;
129 int8_t nLeftGain;
130 int8_t nRightGain;
131} MsgSimpleRumbleCmd;
132
133// This is the only message struct that application code should use to interact with feature request messages. Any new
134// messages should be added to the union. The structures defined here should correspond to the ones defined in
135// ValveDeviceCore.cpp.
136//
137typedef struct
138{
139 FeatureReportHeader header;
140 union
141 {
142 MsgSetSettingsValues setSettingsValues;
143 MsgGetSettingsValues getSettingsValues;
144 MsgGetSettingsMaxs getSettingsMaxs;
145 MsgGetSettingsDefaults getSettingsDefaults;
146 MsgGetAttributes getAttributes;
147 MsgSetControllerMode controllerMode;
148 MsgFireHapticPulse fireHapticPulse;
149 MsgGetStringAttribute getStringAttribute;
150 MsgHapticSetMode hapticMode;
151 MsgTriggerHaptic triggerHaptic;
152 MsgSimpleRumbleCmd simpleRumble;
153 } payload;
154
155} FeatureReportMsg;
156
157// Roll this version forward anytime that you are breaking compatibility of existing
158// message types within ValveInReport_t or the header itself. Hopefully this should
159// be super rare and instead you should just add new message payloads to the union,
160// or just add fields to the end of existing payload structs which is expected to be
161// safe in all code consuming these as they should just consume/copy up to the prior size
162// they were aware of when processing.
163#define k_ValveInReportMsgVersion 0x01
164
165typedef enum
166{
167 ID_CONTROLLER_STATE = 1,
168 ID_CONTROLLER_DEBUG = 2,
169 ID_CONTROLLER_WIRELESS = 3,
170 ID_CONTROLLER_STATUS = 4,
171 ID_CONTROLLER_DEBUG2 = 5,
172 ID_CONTROLLER_SECONDARY_STATE = 6,
173 ID_CONTROLLER_BLE_STATE = 7,
174 ID_CONTROLLER_DECK_STATE = 9,
175 ID_CONTROLLER_MSG_COUNT
176} ValveInReportMessageIDs;
177
178typedef struct
179{
180 unsigned short unReportVersion;
181
182 unsigned char ucType;
183 unsigned char ucLength;
184
185} ValveInReportHeader_t;
186
187// State payload
188typedef struct
189{
190 // If packet num matches that on your prior call, then the controller state hasn't been changed since
191 // your last call and there is no need to process it
192 Uint32 unPacketNum;
193
194 // Button bitmask and trigger data.
195 union
196 {
197 Uint64 ulButtons;
198 struct
199 {
200 unsigned char _pad0[3];
201 unsigned char nLeft;
202 unsigned char nRight;
203 unsigned char _pad1[3];
204 } Triggers;
205 } ButtonTriggerData;
206
207 // Left pad coordinates
208 short sLeftPadX;
209 short sLeftPadY;
210
211 // Right pad coordinates
212 short sRightPadX;
213 short sRightPadY;
214
215 // This is redundant, packed above, but still sent over wired
216 unsigned short sTriggerL;
217 unsigned short sTriggerR;
218
219 // FIXME figure out a way to grab this stuff over wireless
220 short sAccelX;
221 short sAccelY;
222 short sAccelZ;
223
224 short sGyroX;
225 short sGyroY;
226 short sGyroZ;
227
228 short sGyroQuatW;
229 short sGyroQuatX;
230 short sGyroQuatY;
231 short sGyroQuatZ;
232
233} ValveControllerStatePacket_t;
234
235// BLE State payload this has to be re-formatted from the normal state because BLE controller shows up as
236//a HID device and we don't want to send all the optional parts of the message. Keep in sync with struct above.
237typedef struct
238{
239 // If packet num matches that on your prior call, then the controller state hasn't been changed since
240 // your last call and there is no need to process it
241 Uint32 unPacketNum;
242
243 // Button bitmask and trigger data.
244 union
245 {
246 Uint64 ulButtons;
247 struct
248 {
249 unsigned char _pad0[3];
250 unsigned char nLeft;
251 unsigned char nRight;
252 unsigned char _pad1[3];
253 } Triggers;
254 } ButtonTriggerData;
255
256 // Left pad coordinates
257 short sLeftPadX;
258 short sLeftPadY;
259
260 // Right pad coordinates
261 short sRightPadX;
262 short sRightPadY;
263
264 //This mimcs how the dongle reconstitutes HID packets, there will be 0-4 shorts depending on gyro mode
265 unsigned char ucGyroDataType; //TODO could maybe find some unused bits in the button field for this info (is only 2bits)
266 short sGyro[4];
267
268} ValveControllerBLEStatePacket_t;
269
270// Define a payload for reporting debug information
271typedef struct
272{
273 // Left pad coordinates
274 short sLeftPadX;
275 short sLeftPadY;
276
277 // Right pad coordinates
278 short sRightPadX;
279 short sRightPadY;
280
281 // Left mouse deltas
282 short sLeftPadMouseDX;
283 short sLeftPadMouseDY;
284
285 // Right mouse deltas
286 short sRightPadMouseDX;
287 short sRightPadMouseDY;
288
289 // Left mouse filtered deltas
290 short sLeftPadMouseFilteredDX;
291 short sLeftPadMouseFilteredDY;
292
293 // Right mouse filtered deltas
294 short sRightPadMouseFilteredDX;
295 short sRightPadMouseFilteredDY;
296
297 // Pad Z values
298 unsigned char ucLeftZ;
299 unsigned char ucRightZ;
300
301 // FingerPresent
302 unsigned char ucLeftFingerPresent;
303 unsigned char ucRightFingerPresent;
304
305 // Timestamps
306 unsigned char ucLeftTimestamp;
307 unsigned char ucRightTimestamp;
308
309 // Double tap state
310 unsigned char ucLeftTapState;
311 unsigned char ucRightTapState;
312
313 unsigned int unDigitalIOStates0;
314 unsigned int unDigitalIOStates1;
315
316} ValveControllerDebugPacket_t;
317
318typedef struct
319{
320 unsigned char ucPadNum;
321 unsigned char ucPad[3]; // need Data to be word aligned
322 short Data[20];
323 unsigned short unNoise;
324} ValveControllerTrackpadImage_t;
325
326typedef struct
327{
328 unsigned char ucPadNum;
329 unsigned char ucOffset;
330 unsigned char ucPad[2]; // need Data to be word aligned
331 short rgData[28];
332} ValveControllerRawTrackpadImage_t;
333
334// Payload for wireless metadata
335typedef struct
336{
337 unsigned char ucEventType;
338} SteamControllerWirelessEvent_t;
339
340typedef struct
341{
342 // Current packet number.
343 unsigned int unPacketNum;
344
345 // Event codes and state information.
346 unsigned short sEventCode;
347 unsigned short unStateFlags;
348
349 // Current battery voltage (mV).
350 unsigned short sBatteryVoltage;
351
352 // Current battery level (0-100).
353 unsigned char ucBatteryLevel;
354} SteamControllerStatusEvent_t;
355
356// Deck State payload
357typedef struct
358{
359 // If packet num matches that on your prior call, then the controller
360 // state hasn't been changed since your last call and there is no need to
361 // process it
362 Uint32 unPacketNum;
363
364 // Button bitmask and trigger data.
365 union
366 {
367 Uint64 ulButtons;
368 struct
369 {
370 Uint32 ulButtonsL;
371 Uint32 ulButtonsH;
372 };
373 };
374
375 // Left pad coordinates
376 short sLeftPadX;
377 short sLeftPadY;
378
379 // Right pad coordinates
380 short sRightPadX;
381 short sRightPadY;
382
383 // Accelerometer values
384 short sAccelX;
385 short sAccelY;
386 short sAccelZ;
387
388 // Gyroscope values
389 short sGyroX;
390 short sGyroY;
391 short sGyroZ;
392
393 // Gyro quaternions
394 short sGyroQuatW;
395 short sGyroQuatX;
396 short sGyroQuatY;
397 short sGyroQuatZ;
398
399 // Uncalibrated trigger values
400 unsigned short sTriggerRawL;
401 unsigned short sTriggerRawR;
402
403 // Left stick values
404 short sLeftStickX;
405 short sLeftStickY;
406
407 // Right stick values
408 short sRightStickX;
409 short sRightStickY;
410
411 // Touchpad pressures
412 unsigned short sPressurePadLeft;
413 unsigned short sPressurePadRight;
414} SteamDeckStatePacket_t;
415
416typedef struct
417{
418 ValveInReportHeader_t header;
419
420 union
421 {
422 ValveControllerStatePacket_t controllerState;
423 ValveControllerBLEStatePacket_t controllerBLEState;
424 ValveControllerDebugPacket_t debugState;
425 ValveControllerTrackpadImage_t padImage;
426 ValveControllerRawTrackpadImage_t rawPadImage;
427 SteamControllerWirelessEvent_t wirelessEvent;
428 SteamControllerStatusEvent_t statusEvent;
429 SteamDeckStatePacket_t deckState;
430 } payload;
431
432} ValveInReport_t;
433
434
435// Enumeration for BLE packet protocol
436enum EBLEPacketReportNums
437{
438 // Skipping past 2-3 because they are escape characters in Uart protocol
439 k_EBLEReportState = 4,
440 k_EBLEReportStatus = 5,
441};
442
443
444// Enumeration of data chunks in BLE state packets
445enum EBLEOptionDataChunksBitmask
446{
447 // First byte upper nibble
448 k_EBLEButtonChunk1 = 0x10,
449 k_EBLEButtonChunk2 = 0x20,
450 k_EBLEButtonChunk3 = 0x40,
451 k_EBLELeftJoystickChunk = 0x80,
452
453 // Second full byte
454 k_EBLELeftTrackpadChunk = 0x100,
455 k_EBLERightTrackpadChunk = 0x200,
456 k_EBLEIMUAccelChunk = 0x400,
457 k_EBLEIMUGyroChunk = 0x800,
458 k_EBLEIMUQuatChunk = 0x1000,
459};
460
461#pragma pack()
462
463#endif // _CONTROLLER_STRUCTS
464