Steam controller handling

Rust library to work with the Steam controller.

Request

All requests are done with a 64 bytes HID feature send, the 1st byte contains the ID, the 2nd byte the size of the packet, then the payload and the rest is padded with 0x00.

Some requests have responses, some do not, responses have the same layout as requests. In the listed responses only the payload is shown.

Check connection

When using the dongle the controller status can be checked.

Response

Build details

Information about the device can be fetched, it's a list of key/value pairs where the key is 1 byte, and the value is 4 bytes.

Keys

Serial number

Serial numbers can be requested.

Response

Receiver information

If the controller is in wireless mode information about the receiver can be fetched.

Response

Control

All controls are done with a 64 bytes HID feature send, the 1st byte contains the ID, the 2nd byte the size of the packet, then the payload and the rest is padded with 0x00.

Disable lizard mode

The so called lizard mode can be disabled.

Enable lizard mode

The so called lizard mode can be enabled.

Feedback

Feedbacks can be sent to either pad.

Sensors and timeout

The gyroscope and accellerometer can be enabled or disabled and the idle timeout can be changed.

Led intensity

The led intensity can be controlled.

Notification sound test

Each notification sound can be tested.

Notification sound change

The notification sound for turn on and turn off can be changed.

Protocol

There's a script in support/ to help out with reversing the protocol, the following is what I know so far.

Header

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 0x0100 | Type | Size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Type

It's a 1 byte flag.

Size

Tells the size of the packet.

Power

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Event | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Event

It's an unsigned char.

Idle

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Something? | 0x64 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Sequence

It's a little endian unsigned int, it's increased by one with every read.

Something?

Seems to get reset every time it goes from input to idle and increments in some kind of exponential curve.

Input

0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Sequence | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Buttons | Left Trigger | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Right Trigger | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Left Pad X | Left Pad Y | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Right Pad X | Right Pad Y | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | Acceleration Pitch | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acceleration Yaw | Acceleration Roll | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Orientation Pitch | Orientation Yaw | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Orientation Roll | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Sequence

It's a little endian unsigned int, it's increased by one with every read.

Buttons

It's a 24 bit set, the values below are in big endian.

Left trigger

It's an unsigned byte for the pressure applied to the trigger.

Right trigger

It's an unsigned byte for the pressure applied to the trigger.

Left Pad X

It's a little endian signed short.

Left Pad Y

It's a little endian signed short.

Right Pad X

It's a little endian signed short.

Right Pad Y

It's a little endian signed short.

Orientation Roll

It's a little endian signed short.

Orientation Yawl

It's a little endian signed short.

Orientation Pitch

It's a little endian signed short.

Acceleration Roll

It's a little endian signed short.

Acceleration Yaw

It's a little endian signed short.

Acceleration Pitch

It's a little endian signed short.

Something?

There's something, I don't know what it is tho.