OpenSteamController icon indicating copy to clipboard operation
OpenSteamController copied to clipboard

Document HID Controller Interface protocol

Open roblabla opened this issue 4 years ago • 6 comments

This is an issue to gather information about the HID Controller Interface protocol, as described here.

Look at #25 for my current progress.

Old information The HID Controller Interface is interfaced either via Firmware USB EP3 , Bootloader USB EP1, or via some currently unknown wireless mechanism. It works by transferring buffers of 0x40 bytes. The first byte is a packet id, while the second byte is the length of the additional data. Here is a packetid table containing both bootloader and firmware packets as of 57bf5c10.

Host->Controller:

Packet ID Name Controller Bootloader Controller Firmware Dongle Description
0x80 ⛔️
0x81 ExitLizardMode ⛔️ Exits the "lizard mode" - Tells the steam controller to acting like a dumb keyboard/mouse combo. Might need to be sent periodically?
0x82 ⛔️
0x83 ControllerInfoRequest Asks the controller to send its ControllerInfo.
0x85 ⛔️
0x87 SetSettings ⛔️ Sets the controller settings
0x89 ⛔️
0x8d ⛔️
0x8e ⛔️
0x8f TriggerHapticPulse ⛔️
0x90 ReinvokeISP Reinvokes the LPC ISP Firmware (ISP being what happens when you boot while holding the right trigger). Seems to also work on the dongle?
0x91 EraseLPCFirmware ⛔️ Erases the LPC firmware.
0x92 FlashLPCFirmware ⛔️ Flashes a chunk of LPC firmware.
0x93 VerifyLPCFirmware ⛔️ Finishes flashing the LPC firmware, and validates it against a checksum.
0x95 ResetSOC Restarts both LPC and NRF CPUs.
0x96 SetPrngEntropy ⛔️ ⛔️ Sends a block of 0x10 random bytes to the device.
0x97 EraseNRFFirmware (Supposedly, no RE) Erases the NRF Firmware
0x98 FlashNRFFirmware (Supposedly, no RE) Flashes a chunk of NRF Firmware
0x99 VerifyNRFFirmware (Supposedly, no RE) Finishes flashing the NRF firmware, and validates it against a checksum.
0x9a ⛔️ Sends data to the nRF chip, wrapped in a packet ']'.
0x9f TurnOffController ⛔️
0xa7 CalibrateTrackpads ⛔️
0xa9 ⛔️
0xa0 SetHardwareVersion ⛔️ THIS COMMAND IS EXTREMELY DANGEROUS
0xaa ⛔️
0xab ⛔️
0xac ⛔️
0xad SetDonglePairingMode ⛔️ ⛔️ 2 byte args
0xae ControllerInfoRequest ⛔️
0xb1 SetControllerKeyboardMouseInputState ⛔️ ⛔️
0xb2 PairingFailed ⛔️ ⛔️
0xb3 PairingSuccess ⛔️ ⛔️
0xb4 GetControllerInfo ⛔️ ⛔️
0xb5 CalibrateIMU ⛔️
0xb6 PlayAudio ⛔️ Plays the selected jingle
0xb7 StartFlashJingle ⛔️ Does something weird with the jingle_data_ptr :eyes:
0xb8 FlashJingle ⛔️ Writes data to the jingle flash buffer
0xb9 EndFlashJingle ⛔️ Finishes flashing a jingle, writing it to eeprom after making sure it looks somewhat valid.
0xba GetChipID ⛔️
0xbb ReadUID ⛔️ Returns the result of ISP ReadUID.
0xbf CalibrateJoystick ⛔️ Sets eeprom field 0x34 with some computed data
0xc1 SetAudioMapping ⛔️ Sets the jingle to play for various events
0xc5 SetUserLedColor ⛔️ ⛔️
0xc6 SendIRCode ⛔️ ⛔️
0xc7 StopIR ⛔️ ⛔️

ControllerInfoRequest/ControllerInfoResponse

When sent from Host to Controller, takes no data and asks the controller to send its ControllerInfo.

When sent from Controller to Host: The additional data is an array of HardwareInfo, where HardwareInfo is a structure of one byte (Type) and 4 byte (Data). Here are the different types byte observed:

Type ID Name Bootloader Description
1 USB PID The same as the USB PID. Likely more useful for wireless transmission.
2 Unknown ⛔️ Firmware always returns 3
4 Firmware Version Version/timestamp of the firmware running on the LPC side (e.g. 57bf5c10).
5 NRF Firmware Version ⛔️ Version/timestamp of the firmware running on the NRF side
9 Hardware Version Version of the controller hardware (as stored in EEPROM)
10 Unknown ⛔️ Firmware returns the data stored at DAT_10000078

SetSettings

When sent from Host to Controller: Sets the controller settings. The additional data is an array of ControllerSetting, where ControllerSetting is a structure of one byte (type) and 2 bytes (value). Here are some observed type bytes:

Type ID Name Description
0x3 ?
0x8 ? Lizard mode related? Data is 7 when sent to dongle.
0x2d ? Sent periodically

SetDonglePairingMode

Arguments:

  • Don't pair: 0x00 0x00
  • Start pairing: 0x2 0x3c

roblabla avatar Mar 12 '20 23:03 roblabla

Alright small update: I managed to identify the code in the steam client that interacts with the Steam Controller. And fortunately, a lot of symbols and assert messages are left over, allowing me to find the official name for more or less every single packet, along with a whole host of packets that seem to be used for other valve hardware - The valve index and steam controller share a lot of code.

I'll update the table above with this newfound information as I go.

roblabla avatar Mar 23 '20 13:03 roblabla

Hello, I am trying to analyze the protocol of Steam Controller BLE HID, I updated it here, hope it can help you. There are some data that I haven’t had time to update, because English is not my native language, I write very slowly😂. Your document is very helpful to me, looking forward to your update😄

tiehichi avatar Apr 03 '20 14:04 tiehichi

Hey @tiehichi thanks for this, it's pretty useful! I've been focusing on this weird proprietary protocol and haven't looked at the actual input reports at all so far :). The HID layer is identical both for BLE, USB and Enhanced ShockBurst (the protocol used to talk to the dongle), so a lot of your findings should apply everywhere.

I'll make a PR later today with my latest findings, in a couple of proper markdowns :). I've figured out a couple of interesting things - it seems there's still some hidden features in the Steam Controller firmware that are going to be fun to play around with ^^.

roblabla avatar Apr 03 '20 16:04 roblabla

@tiehichi I have previously categorized some of the meaning behind the bytes in valve mode.

I think that the second byte is a mode indicator. I haven't dug into what the meaning of the bytes are when the byte is 0x05 but I have the meaning of the bytes when the mode is 0x04.

The steam controller seems to have 5 distinct modes; The modes are on the second byte of the packet.

Mode Byte Value Description
Idle 0x05 The controller is in an idle state
Active 0x04 The controller is in an active state (Or waiting for input before switching back to idle)
Buttons 0x14 A button is being pressed/released
Triggers 0x24 A trigger is being depressed
Joysticks 0x84 The joystick is being used

When using more than one mode (aka, buttons and joysticks) these modes are or'ed together.

The touch pads modes are on the third byte of the packet. When the touch pads are in use the second byte is set to active and the following mode conditions are set.

Touchpad-Mode Byte Value Description
Left pad 0x01 Left touch pad
Right pad 0x02 Right touch pad

Similarly when both pads are in use the bytes are or'ed together for a value of 0x03.

Then the inputs always start on the forth byte. When all controls are being touched the controls are on the packet in the order: buttons->triggers->joystick->touchpads. All the input cannot fit on one packet so the right touch pad seems to be left off.

When buttons are active they take up 3 bytes of space:

Button Byte Value
A 4 0x80
B 4 0x20
X 4 0x40
Y 4 0x10
Left Shoulder 4 0x08
Right Shoulder 4 0x04
Left Trigger Press 4 0x02
Right Trigger Press 4 0x01
Home 5 0x20
Select 5 0x10
Play 5 0x40
Back Left 5 0x80
Back Right 6 0x01
Joystick Press 6 0x40
Left Touch pad press 6 0x02
Right Touch Press 6 0x04

When the trigger is depressed it takes up 2 bytes of space.

Trigger Byte
Left 4
Right 5

When the joystick is active it takes up 4 bytes of space. this can be converted into a short and then divided by 32767 for a float between -1 to +1.

Joystick Byte Description
4 & 5 The Y value
6 & 7 The X value

Finally the touch pads can appear in the packet independently. Each touch pad takes up 4 bytes of space and when both are used the bytes the right touch pad uses are shifted so they appear as left touch pad->right touch pad, in the packet.

touch pad Byte Description
Left (4, 5) & (6, 7) The X/Y value
Right (4, 5) & (6, 7) The X/Y value

nrc4867 avatar Apr 03 '20 20:04 nrc4867

Hey @roblabla , looking forward to your update, these features must be very cool! Hello @nrc4867 , thank you very much for these information! I am trying to connect SteamController to nintendo switch using ESP32, these data are very useful for me! And if I have any new discoveries, I will share them in time😁

tiehichi avatar Apr 04 '20 03:04 tiehichi