Sony DualShock 4

* Pro/Slim (V2)
* Original (V1)

`0x0BA0` (Dongle)

`0x0BA1` (Dongle DFU)

## Input

* 12× Digital Buttons
	+ Face: , , ,
	+ Shoulder: L1, R1
	+ Other: "PS", SHARE, OPTIONS, touchpad click, L3, R3
* Digital Directional Pad
* Touch Pad
	+ 2× Point
	+ Capacitive
	+ Data Resolution: 1919x941
* 2× Analog Sticks
* 2× Analog Triggers
	+ L2, R2
* Motion
	+ 3 Axis Accelerometer
	+ 3 Axis Gyroscope
	+ Mono Microphone via TRRS jack

## Output

* Rumble via ERM
	+ Right: Light (1 weight)
	+ Left: Heavy (4 weights)
* RGB LED (24 bit color)
* Mono Speaker
	+ Bluetooth Mode Only
* Stereo Audio via TRRS jack

## Ports

* microUSB (Micro-B) 2.0 ⚡ 🖥️
* 3.5mm Phone TRRS 🎤 🔈
* Proprietary EXT Port
	+ data (I2C Interface)
	+ charging

# HID Interface

On USB and Dongle the full controller state is provided by Input report `ReportIn01USB` (`0x01`).

On Bluetooth the reduced controller state is provided by Input report `ReportIn01BT` (`0x01`).
On reading Feature Input report `ReportFeatureInCalibrateBT` (`0x05`) the former reduced controller state Input report is no longer emitted and instead Input reports `ReportIn11` (`0x11`) through `ReportIn19` (`0x19`) are emitted.

All controller state Input reports on Bluetooth that are not the reduced input report (`0x01`) must check the `EnableHID` bit before processing data. If this bit is not set the packet does not contain controller state data and should instead have the `EnableAudio` bit high as it contains only audio data. All relevant bits should be checked before processing data. For reports larger than `ReportIn11` (`0x11`) both state and audio data may be present. Controller state data is always placed before audio data when both are present.

Most HID reports over Bluetooth end in a CRC32 (`0xedb88320`) of the report contents. The bytes hashed includes the Bluetooth HID Report Type, Report ID, and report contents up to the CRC.

Bluetooth Report Types:

```
DATA (0xA0) + INPUT   (0x01) // HID Input
DATA (0xA0) + OUTPUT  (0x02) // HID Output
DATA (0xA0) + FEATURE (0x03) // HID Feature Input
     (0x50) + FEATURE (0x03) // HID Feature Output

```

Dongle Feature Write `e2 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00`

Bluetooth Feature Write: `53 08 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 ef a2 23`

Debug command dump:

 0x00
 0x00

 0x01
 0x01
 0x00
 0x00

 0x05
 0x00
 0x00
 0x00

 0x04
 0x00

 0x03
 0x00
 0x00

 0xFF
 0x01
 0x00

 0x20
 0x01
 0x00

 0x??
 0x??

 0x??

 0x??

## Descriptor

### USB

```
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0E, // Usage Maximum (0x0E)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0E, // Report Count (14)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x7F, // Logical Maximum (127)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x21, // Usage (0x21)
0x95, 0x36, // Report Count (54)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x05, // Report ID (5)
0x09, 0x22, // Usage (0x22)
0x95, 0x1F, // Report Count (31)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x04, // Report ID (4)
0x09, 0x23, // Usage (0x23)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x02, // Report ID (2)
0x09, 0x24, // Usage (0x24)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x08, // Report ID (8)
0x09, 0x25, // Usage (0x25)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x10, // Report ID (16)
0x09, 0x26, // Usage (0x26)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x11, // Report ID (17)
0x09, 0x27, // Usage (0x27)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x12, // Report ID (18)
0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02)
0x09, 0x21, // Usage (0x21)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x13, // Report ID (19)
0x09, 0x22, // Usage (0x22)
0x95, 0x16, // Report Count (22)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x14, // Report ID (20)
0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05)
0x09, 0x20, // Usage (0x20)
0x95, 0x10, // Report Count (16)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x15, // Report ID (21)
0x09, 0x21, // Usage (0x21)
0x95, 0x2C, // Report Count (44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80)
0x85, 0x80, // Report ID (128)
0x09, 0x20, // Usage (0x20)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x81, // Report ID (129)
0x09, 0x21, // Usage (0x21)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x82, // Report ID (130)
0x09, 0x22, // Usage (0x22)
0x95, 0x05, // Report Count (5)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x83, // Report ID (131)
0x09, 0x23, // Usage (0x23)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x84, // Report ID (132)
0x09, 0x24, // Usage (0x24)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x85, // Report ID (133)
0x09, 0x25, // Usage (0x25)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x86, // Report ID (134)
0x09, 0x26, // Usage (0x26)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x87, // Report ID (135)
0x09, 0x27, // Usage (0x27)
0x95, 0x23, // Report Count (35)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x88, // Report ID (136)
0x09, 0x28, // Usage (0x28)
0x95, 0x22, // Report Count (34)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x89, // Report ID (137)
0x09, 0x29, // Usage (0x29)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x90, // Report ID (144)
0x09, 0x30, // Usage (0x30)
0x95, 0x05, // Report Count (5)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x91, // Report ID (145)
0x09, 0x31, // Usage (0x31)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x92, // Report ID (146)
0x09, 0x32, // Usage (0x32)
0x95, 0x03, // Report Count (3)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x93, // Report ID (147)
0x09, 0x33, // Usage (0x33)
0x95, 0x0C, // Report Count (12)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (160)
0x09, 0x40, // Usage (0x40)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA1, // Report ID (161)
0x09, 0x41, // Usage (0x41)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA2, // Report ID (162)
0x09, 0x42, // Usage (0x42)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA3, // Report ID (163)
0x09, 0x43, // Usage (0x43)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA4, // Report ID (164)
0x09, 0x44, // Usage (0x44)
0x95, 0x0D, // Report Count (13)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA5, // Report ID (165)
0x09, 0x45, // Usage (0x45)
0x95, 0x15, // Report Count (21)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA6, // Report ID (166)
0x09, 0x46, // Usage (0x46)
0x95, 0x15, // Report Count (21)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF0, // Report ID (240)
0x09, 0x47, // Usage (0x47)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF1, // Report ID (241)
0x09, 0x48, // Usage (0x48)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF2, // Report ID (242)
0x09, 0x49, // Usage (0x49)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA7, // Report ID (247)
0x09, 0x4A, // Usage (0x4A)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA8, // Report ID (250)
0x09, 0x4B, // Usage (0x4B)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA9, // Report ID (251)
0x09, 0x4C, // Usage (0x4C)
0x95, 0x08, // Report Count (8)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAA, // Report ID (252)
0x09, 0x4E, // Usage (0x4E)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAB, // Report ID (253)
0x09, 0x4F, // Usage (0x4F)
0x95, 0x39, // Report Count (57)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAC, // Report ID (254)
0x09, 0x50, // Usage (0x50)
0x95, 0x39, // Report Count (57)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAD, // Report ID (255)
0x09, 0x51, // Usage (0x51)
0x95, 0x0B, // Report Count (11)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAE, // Report ID (256)
0x09, 0x52, // Usage (0x52)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAF, // Report ID (175)
0x09, 0x53, // Usage (0x53)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB0, // Report ID (176)
0x09, 0x54, // Usage (0x54)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection

// 467 bytes

```

### BT

```
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x35, // Usage (Rz)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39, // Usage (Hat switch)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0E, // Usage Maximum (0x0E)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0E, // Report Count (14)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x04, 0xFF, // Usage Page (Vendor Defined 0xFF04)
0x85, 0x02, // Report ID (2)
0x09, 0x24, // Usage (0x24)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA3, // Report ID (163)
0x09, 0x25, // Usage (0x25)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x05, // Report ID (5)
0x09, 0x26, // Usage (0x26)
0x95, 0x28, // Report Count (40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x06, // Report ID (6)
0x09, 0x27, // Usage (0x27)
0x95, 0x34, // Report Count (52)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x07, // Report ID (7)
0x09, 0x28, // Usage (0x28)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x08, // Report ID (8)
0x09, 0x29, // Usage (0x29)
0x95, 0x2F, // Report Count (47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x09, // Report ID (9)
0x09, 0x2A, // Usage (0x2A)
0x95, 0x13, // Report Count (19)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x03, 0xFF, // Usage Page (Vendor Defined 0xFF03)
0x85, 0x03, // Report ID (3)
0x09, 0x21, // Usage (0x21)
0x95, 0x26, // Report Count (38)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x04, // Report ID (4)
0x09, 0x22, // Usage (0x22)
0x95, 0x2E, // Report Count (46)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF0, // Report ID (240)
0x09, 0x47, // Usage (0x47)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF1, // Report ID (241)
0x09, 0x48, // Usage (0x48)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xF2, // Report ID (242)
0x09, 0x49, // Usage (0x49)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x85, 0x11, // Report ID (17)
0x09, 0x20, // Usage (0x20)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x4D, // Report Count (77)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x21, // Usage (0x21)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x12, // Report ID (18)
0x09, 0x22, // Usage (0x22)
0x95, 0x8D, // Report Count (141)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x23, // Usage (0x23)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x13, // Report ID (19)
0x09, 0x24, // Usage (0x24)
0x95, 0xCD, // Report Count (205)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x25, // Usage (0x25)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x14, // Report ID (20)
0x09, 0x26, // Usage (0x26)
0x96, 0x0D, 0x01, // Report Count (269)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x27, // Usage (0x27)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x15, // Report ID (21)
0x09, 0x28, // Usage (0x28)
0x96, 0x4D, 0x01, // Report Count (333)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x29, // Usage (0x29)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x16, // Report ID (22)
0x09, 0x2A, // Usage (0x2A)
0x96, 0x8D, 0x01, // Report Count (397)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x2B, // Usage (0x2B)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x17, // Report ID (23)
0x09, 0x2C, // Usage (0x2C)
0x96, 0xCD, 0x01, // Report Count (461)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x2D, // Usage (0x2D)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x18, // Report ID (24)
0x09, 0x2E, // Usage (0x2E)
0x96, 0x0D, 0x02, // Report Count (525)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x2F, // Usage (0x2F)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x19, // Report ID (25)
0x09, 0x30, // Usage (0x30)
0x96, 0x22, 0x02, // Report Count (546)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x31, // Usage (0x31)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80)
0x85, 0x82, // Report ID (130)
0x09, 0x22, // Usage (0x22)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x83, // Report ID (131)
0x09, 0x23, // Usage (0x23)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x84, // Report ID (132)
0x09, 0x24, // Usage (0x24)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x90, // Report ID (144)
0x09, 0x30, // Usage (0x30)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x91, // Report ID (145)
0x09, 0x31, // Usage (0x31)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x92, // Report ID (146)
0x09, 0x32, // Usage (0x32)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x93, // Report ID (147)
0x09, 0x33, // Usage (0x33)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x94, // Report ID (148)
0x09, 0x34, // Usage (0x34)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (160)
0x09, 0x40, // Usage (0x40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA4, // Report ID (164)
0x09, 0x44, // Usage (0x44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA7, // Report ID (167)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA8, // Report ID (168)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA9, // Report ID (169)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAA, // Report ID (170)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAB, // Report ID (171)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAC, // Report ID (172)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xAD, // Report ID (173)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB3, // Report ID (179)
0x09, 0x45, // Usage (0x45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB4, // Report ID (180)
0x09, 0x46, // Usage (0x46)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB5, // Report ID (181)
0x09, 0x47, // Usage (0x47)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xD0, // Report ID (208)
0x09, 0x40, // Usage (0x40)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xD4, // Report ID (212)
0x09, 0x44, // Usage (0x44)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection

// 442 bytes

```

### Dongle

```
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x09, 0x30, // Usage (0x30)
0x09, 0x31, // Usage (0x31)
0x09, 0x32, // Usage (0x32)
0x09, 0x35, // Usage (0x35)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x39, // Usage (0x39)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x07, // Logical Maximum (7)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x65, 0x00, // Unit (None)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0E, // Usage Maximum (0x0E)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0E, // Report Count (14)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x7F, // Logical Maximum (127)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x21, // Usage (0x21)
0x95, 0x36, // Report Count (54)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x05, // Report ID (5)
0x09, 0x22, // Usage (0x22)
0x95, 0x1F, // Report Count (31)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x02, // Report ID (2)
0x09, 0x24, // Usage (0x24)
0x95, 0x24, // Report Count (36)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02)
0x85, 0x12, // Report ID (18)
0x09, 0x21, // Usage (0x21)
0x95, 0x0F, // Report Count (15)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05)
0x85, 0x15, // Report ID (21)
0x09, 0x21, // Usage (0x21)
0x95, 0x2D, // Report Count (45)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80)
0x85, 0x80, // Report ID (128)
0x09, 0x20, // Usage (0x20)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x81, // Report ID (129)
0x09, 0x21, // Usage (0x21)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x85, // Report ID (133)
0x09, 0x25, // Usage (0x25)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x86, // Report ID (134)
0x09, 0x26, // Usage (0x26)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x8A, // Report ID (138)
0x09, 0x27, // Usage (0x27)
0x95, 0x16, // Report Count (22)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA0, // Report ID (160)
0x09, 0x40, // Usage (0x40)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA1, // Report ID (161)
0x09, 0x41, // Usage (0x41)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA2, // Report ID (162)
0x09, 0x42, // Usage (0x42)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA3, // Report ID (163)
0x09, 0x43, // Usage (0x43)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA4, // Report ID (164)
0x09, 0x44, // Usage (0x44)
0x95, 0x0D, // Report Count (13)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA5, // Report ID (165)
0x09, 0x45, // Usage (0x45)
0x95, 0x15, // Report Count (21)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xA6, // Report ID (166)
0x09, 0x46, // Usage (0x46)
0x95, 0x15, // Report Count (21)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xB0, // Report ID (176)
0x09, 0x54, // Usage (0x54)
0x95, 0x3F, // Report Count (63)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE0, // Report ID (224)
0x09, 0x56, // Usage (0x56)
0x95, 0x02, // Report Count (2)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE1, // Report ID (225)
0x09, 0x57, // Usage (0x57)
0x95, 0x30, // Report Count (48)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE2, // Report ID (226)
0x09, 0x57, // Usage (0x57)
0x95, 0x10, // Report Count (16)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE3, // Report ID (227)
0x09, 0x57, // Usage (0x57)
0x95, 0x04, // Report Count (4)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE4, // Report ID (228)
0x09, 0x57, // Usage (0x57)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0xE5, // Report ID (229)
0x09, 0x57, // Usage (0x57)
0x95, 0x06, // Report Count (6)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection

// 295 bytes

```

### Dongle (DFU Mode)

```
0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)
0x06, 0x01, 0xFF, // Usage Page (Vendor Defined 0xFF01)
0x09, 0x22, // Usage (0x22)
0x75, 0x08, // Report Size (8)
0x95, 0x3F, // Report Count (63)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0xF0, // Report ID (240)
0x09, 0x23, // Usage (0x23)
0x95, 0x3E, // Report Count (62)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection

// 24 bytes

```

## Data Structures

### Common Structures

```
enum Direction : uint8\_t {
 North = 0,
 NorthEast,
 East,
 SouthEast,
 South,
 SouthWest,
 West,
 NorthWest,
 None = 8
};

template<int N> struct BTCRC {
 uint8\_t Buff[N-4];
 uint32\_t CRC;
};

template<int N> struct BTAudio {
 uint16\_t FrameNumber;
 uint8\_t AudioTarget; // 0x02 speaker?, 0x24 headset?, 0x03 mic?
 uint8\_t SBCData[N-3];
};

```

### Input Reports

```
template<int N> struct BTGetStateDataAndAudio {
 BTGetStateData State;
 BTAudio<N-75> Audio;
};

struct TouchFingerData {
 uint8\_t Index : 7;
 uint8\_t NotTouching : 1;
 uint16\_t FingerX : 12;
 uint16\_t FingerY : 12;
};

struct TouchData {
 uint8\_t Timestamp;
 TouchFingerData Finger[2];
};

struct BasicGetStateData {
/\*0 \*/ uint8\_t LeftStickX;
/\*1 \*/ uint8\_t LeftStickY;
/\*2 \*/ uint8\_t RightStickX;
/\*3 \*/ uint8\_t RightStickY;
/\*4.0\*/ Direction DPad : 4;
/\*4.4\*/ uint8\_t ButtonSquare : 1;
/\*4.5\*/ uint8\_t ButtonCross : 1;
/\*4.6\*/ uint8\_t ButtonCircle : 1;
/\*4.7\*/ uint8\_t ButtonTriangle : 1;
/\*5.0\*/ uint8\_t ButtonL1 : 1;
/\*5.1\*/ uint8\_t ButtonR1 : 1;
/\*5.2\*/ uint8\_t ButtonL2 : 1;
/\*5.3\*/ uint8\_t ButtonR2 : 1;
/\*5.4\*/ uint8\_t ButtonShare : 1;
/\*5.5\*/ uint8\_t ButtonOptions : 1;
/\*5.6\*/ uint8\_t ButtonL3 : 1;
/\*5.7\*/ uint8\_t ButtonR3 : 1;
/\*6.0\*/ uint8\_t ButtonHome : 1;
/\*6.1\*/ uint8\_t ButtonPad : 1;
/\*6.2\*/ uint8\_t Counter : 6; // always 0 on USB, counts up with some skips on BT
/\*7 \*/ uint8\_t TriggerLeft;
/\*8 \*/ uint8\_t TriggerRight;
};

struct GetStateData : BasicGetStateData {
/\* 9 \*/ uint16\_t Timestamp; // in 5.33us units?
/\*11 \*/ uint8\_t Temperture;
/\*12 \*/ int16\_t AngularVelocityX;
/\*14 \*/ int16\_t AngularVelocityZ;
/\*16 \*/ int16\_t AngularVelocityY;
/\*18 \*/ int16\_t AccelerometerX;
/\*20 \*/ int16\_t AccelerometerY;
/\*22 \*/ int16\_t AccelerometerZ;
/\*24 \*/ uint8\_t[5] ExtData; // range can be set by EXT device
/\*29 \*/ uint8\_t PowerPercent : 4; // 0x00-0x0A or 0x01-0x0B if plugged int
/\*29.4\*/ uint8\_t PluggedPowerCable : 1;
/\*29.5\*/ uint8\_t PluggedHeadphones : 1;
/\*29.6\*/ uint8\_t PluggedMic : 1;
/\*29,7\*/ uint8\_t PluggedExt : 1;
/\*30.0\*/ uint8\_t UnkExt1 : 1; // ExtCapableOfExtraData?
/\*30.1\*/ uint8\_t UnkExt2 : 1; // ExtHasExtraData?
/\*30.2\*/ uint8\_t NotConnected : 1; // Used by dongle to indicate no controller
/\*30.3\*/ uint8\_t Unk1 : 5;
/\*31 \*/ uint8\_t Unk2; // unused?
/\*32 \*/ uint8\_t TouchCount;
};

struct USBGetStateData : GetStateData {
 TouchData TouchData[3];
 uint8\_t Pad[3];
};

struct BTGetStateData : GetStateData {
 TouchData TouchData[4];
 uint8\_t Pad[6];
};

```

#### HID Report 0x01 Input USB/Dongle

```
struct ReportIn01USB {
 uint8\_t ReportID; // 0x01
 USBGetStateData State;
};

```

#### HID Report 0x01 Input BT

```
struct ReportIn01BT {
 uint8\_t ReportID; // 0x01
 BasicGetStateData State;
};

```

#### HID Report 0x11 Input BT

```
struct ReportIn11 {
 union {
 BTCRC<78> CRC;
 struct {
 uint8\_t ReportID; // 0x11
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateData State;
 BTAudio<75> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x12 Input BT

```
struct ReportIn12 {
 union {
 BTCRC<142> CRC;
 struct {
 uint8\_t ReportID; // 0x12
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<139> State;
 BTAudio<139> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x13 Input BT

```
struct ReportIn13 {
 union {
 BTCRC<206> CRC;
 struct {
 uint8\_t ReportID; // 0x13
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<203> State;
 BTAudio<203> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x14 Input BT

```
struct ReportIn14 {
 union {
 BTCRC<270> CRC;
 struct {
 uint8\_t ReportID; // 0x14
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<267> State;
 BTAudio<267> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x15 Input BT

```
struct ReportIn15 {
 union {
 BTCRC<334> CRC;
 struct {
 uint8\_t ReportID; // 0x15
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<331> State;
 BTAudio<331> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x16 Input BT

```
struct ReportIn16 {
 union {
 BTCRC<398> CRC;
 struct {
 uint8\_t ReportID; // 0x16
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<395> State;
 BTAudio<395> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x17 Input BT

```
struct ReportIn17 {
 union {
 BTCRC<462> CRC;
 struct {
 uint8\_t ReportID; // 0x17
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<459> State;
 BTAudio<459> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x18 Input BT

```
struct ReportIn18 {
 union {
 BTCRC<526> CRC;
 struct {
 uint8\_t ReportID; // 0x18
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<523> State;
 BTAudio<523> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x19 Input BT

```
struct ReportIn19 {
 union {
 BTCRC<547> CRC;
 struct {
 uint8\_t ReportID; // 0x19
 uint8\_t Unk1 : 6;
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t Unk2 : 7;
 uint8\_t EnableAudio : 1;
 union {
 BTGetStateDataAndAudio<544> State;
 BTAudio<544> Audio;
 };
 } Data;
 };
};

```

### Output Reports

```
template<int N> struct BTSetStateDataAndAudio {
 BTSetStateData State;
 BTAudio<N-75> Audio;
};

struct USBSetStateData {
 uint8\_t EnableRumbleUpdate : 1;
 uint8\_t EnableLedUpdate : 1;
 uint8\_t EnableLedBlink : 1;
 uint8\_t EnableExtWrite : 1;
 uint8\_t EnableVolumeLeftUpdate : 1;
 uint8\_t EnableVolumeRightUpdate : 1;
 uint8\_t EnableVolumeMicUpdate : 1;
 uint8\_t EnableVolumeSpeakerUpdate : 1;
 uint8\_t UNK\_RESET1: 1; // unknown reset, both set high by Remote Play
 uint8\_t UNK\_RESET2: 1; // unknown reset, both set high by Remote Play
 uint8\_t UNK1: 1;
 uint8\_t UNK2: 1;
 uint8\_t UNK3: 1;
 uint8\_t UNKPad: 3;
 uint8\_t Empty1;
 uint8\_t RumbleRight; // weak
 uint8\_t RumbleLeft; // strong
 uint8\_t LedRed;
 uint8\_t LedGreen;
 uint8\_t LedBlue;
 uint8\_t LedFlashOnPeriod;
 uint8\_t LedFlashOffPeriod;
 uint8\_t ExtDataSend[8]; // sent to I2C EXT port, stored in 8x8 byte block
 uint8\_t VolumeLeft; // 0x00 - 0x4F inclusive
 uint8\_t VolumeRight; // 0x00 - 0x4F inclusive
 uint8\_t VolumeMic; // 0x00, 0x01 - 0x40 inclusive (0x00 is special behavior)
 uint8\_t VolumeSpeaker; // 0x00 - 0x4F
 uint8\_t UNK\_AUDIO1 : 7; // clamped to 1-64 inclusive, appears to be set to 5 for audio
 uint8\_t UNK\_AUDIO2: 1; // unknown, appears to be set to 1 for audio
 uint8\_t Pad[8];
};

struct BTSetStateData {
 uint8\_t EnableRumbleUpdate : 1;
 uint8\_t EnableLedUpdate : 1;
 uint8\_t EnableLedBlink : 1;
 uint8\_t EnableExtWrite : 1;
 uint8\_t EnableVolumeLeftUpdate : 1;
 uint8\_t EnableVolumeRightUpdate : 1;
 uint8\_t EnableVolumeMicUpdate : 1;
 uint8\_t EnableVolumeSpeakerUpdate : 1;
 uint8\_t UNK\_RESET1: 1; // unknown reset, both set high by Remote Play
 uint8\_t UNK\_RESET2: 1; // unknown reset, both set high by Remote Play
 uint8\_t UNK1: 1;
 uint8\_t UNK2: 1;
 uint8\_t UNK3: 1;
 uint8\_t UNKPad: 3;
 uint8\_t Empty1;
 uint8\_t RumbleRight; // weak
 uint8\_t RumbleLeft; // strong
 uint8\_t LedRed;
 uint8\_t LedGreen
 uint8\_t LedBlue;
 uint8\_t LedFlashOnPeriod;
 uint8\_t LedFlashOffPeriod;
 uint8\_t ExtDataSend[8]; // sent to I2C EXT port, stored in 8x8 byte block
 uint8\_t VolumeLeft; // 0x00 - 0x4F inclusive
 uint8\_t VolumeRight; // 0x00 - 0x4F inclusive
 uint8\_t VolumeMic; // 0x00, 0x01 - 0x40 inclusive (0x00 is special behavior)
 uint8\_t VolumeSpeaker; // 0x00 - 0x4F
 uint8\_t UNK\_AUDIO1 : 7; // clamped to 1-64 inclusive, appears to be set to 5 for audio
 uint8\_t UNK\_AUDIO2: 1; // unknown, appears to be set to 1 for audio
 uint8\_t Pad[52];
};

```

#### HID Report 0x05 Output USB/Dongle

```
struct ReportIn05 {
 uint8\_t ReportID; // 0x05
 USBSetStateData State;
};

```

#### HID Report 0x11 Output BT

```
struct ReportOut11 {
 union {
 BTCRC<78> CRC;
 struct {
 uint8\_t ReportID; // 0x11
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateData State;
 BTAudio<75> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x12 Output BT

```
struct ReportOut12 {
 union {
 BTCRC<142> CRC;
 struct {
 uint8\_t ReportID; // 0x12
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<139> State;
 BTAudio<139> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x13 Output BT

```
struct ReportOut13 {
 union {
 BTCRC<206> CRC;
 struct {
 uint8\_t ReportID; // 0x13
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<203> State;
 BTAudio<203> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x14 Output BT

```
struct ReportOut14 {
 union {
 BTCRC<270> CRC;
 struct {
 uint8\_t ReportID; // 0x14
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<267> State;
 BTAudio<267> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x15 Output BT

```
struct ReportOut15 {
 union {
 BTCRC<334> CRC;
 struct {
 uint8\_t ReportID; // 0x15
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<331> State;
 BTAudio<331> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x16 Output BT

```
struct ReportOut16 {
 union {
 BTCRC<398> CRC;
 struct {
 uint8\_t ReportID; // 0x16
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<395> State;
 BTAudio<395> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x17 Output BT

```
struct ReportOut17 {
 union {
 BTCRC<462> CRC;
 struct {
 uint8\_t ReportID; // 0x17
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<459> State;
 BTAudio<459> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x18 Output BT

```
struct ReportOut18 {
 union {
 BTCRC<526> CRC;
 struct {
 uint8\_t ReportID; // 0x18
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<523> State;
 BTAudio<523> Audio;
 };
 } Data;
 };
};

```

#### HID Report 0x19 Output BT

```
struct ReportOut19 {
 union {
 BTCRC<547> CRC;
 struct {
 uint8\_t ReportID; // 0x19
 uint8\_t PollingRate: 6; // note 0 appears to be clamped to 1
 uint8\_t EnableCRC : 1;
 uint8\_t EnableHID : 1;
 uint8\_t EnableMic : 3; // somehow enables mic, appears to be 3 bit flags
 uint8\_t UnkA4 : 1;
 uint8\_t UnkB1 : 1;
 uint8\_t UnkB2 : 1; // seems to always be 1
 uint8\_t UnkB3 : 1;
 uint8\_t EnableAudio : 1;
 union {
 BTSetStateDataAndAudio<544> State;
 BTAudio<544> Audio;
 };
 } Data;
 };
};

```

### Feature Reports

#### Calibration

Reading calibration is required to switch input reports from the truncated 0x01 report to the expanded 0x11-0x19 reports.

Linux hid-sony.c

```
/\* Set gyroscope calibration and normalization parameters.
 \* Data values will be normalized to 1/DS4\_GYRO\_RES\_PER\_DEG\_S degree/s.
 \*/
speed\_2x = (gyro\_speed\_plus + gyro\_speed\_minus);
sc->ds4\_calib\_data[0].abs\_code = ABS\_RX;
sc->ds4\_calib\_data[0].bias = gyro\_pitch\_bias;
sc->ds4\_calib\_data[0].sens\_numer = speed\_2x\*DS4\_GYRO\_RES\_PER\_DEG\_S;
sc->ds4\_calib\_data[0].sens\_denom = gyro\_pitch\_plus - gyro\_pitch\_minus;

sc->ds4\_calib\_data[1].abs\_code = ABS\_RY;
sc->ds4\_calib\_data[1].bias = gyro\_yaw\_bias;
sc->ds4\_calib\_data[1].sens\_numer = speed\_2x\*DS4\_GYRO\_RES\_PER\_DEG\_S;
sc->ds4\_calib\_data[1].sens\_denom = gyro\_yaw\_plus - gyro\_yaw\_minus;

sc->ds4\_calib\_data[2].abs\_code = ABS\_RZ;
sc->ds4\_calib\_data[2].bias = gyro\_roll\_bias;
sc->ds4\_calib\_data[2].sens\_numer = speed\_2x\*DS4\_GYRO\_RES\_PER\_DEG\_S;
sc->ds4\_calib\_data[2].sens\_denom = gyro\_roll\_plus - gyro\_roll\_minus;

/\* Set accelerometer calibration and normalization parameters.
 \* Data values will be normalized to 1/DS4\_ACC\_RES\_PER\_G G.
 \*/
range\_2g = acc\_x\_plus - acc\_x\_minus;
sc->ds4\_calib\_data[3].abs\_code = ABS\_X;
sc->ds4\_calib\_data[3].bias = acc\_x\_plus - range\_2g / 2;
sc->ds4\_calib\_data[3].sens\_numer = 2\*DS4\_ACC\_RES\_PER\_G;
sc->ds4\_calib\_data[3].sens\_denom = range\_2g;

range\_2g = acc\_y\_plus - acc\_y\_minus;
sc->ds4\_calib\_data[4].abs\_code = ABS\_Y;
sc->ds4\_calib\_data[4].bias = acc\_y\_plus - range\_2g / 2;
sc->ds4\_calib\_data[4].sens\_numer = 2\*DS4\_ACC\_RES\_PER\_G;
sc->ds4\_calib\_data[4].sens\_denom = range\_2g;

range\_2g = acc\_z\_plus - acc\_z\_minus;
sc->ds4\_calib\_data[5].abs\_code = ABS\_Z;
sc->ds4\_calib\_data[5].bias = acc\_z\_plus - range\_2g / 2;
sc->ds4\_calib\_data[5].sens\_numer = 2\*DS4\_ACC\_RES\_PER\_G;
sc->ds4\_calib\_data[5].sens\_denom = range\_2g;

```

In Remote Play, version 17 controllers lock GyroSpeedPlus and GyroSpeedMinus to 540

In Remote Play, a version of 18 or lower sets MotionDataTimestampUnits to 7.0999999

In Remote Play, a version over 18 sets MotionDataTimestampUnits to 5.3299999

What this value is used for is unclear.

Version comes from the device's revision number and is bashed from hex to decimal. (0x1F93 -> 1993)

##### USB 0x02

```
struct ReportFeatureInCalibrateUSB {
 uint8\_t ReportID; // 0x02
 int16\_t GyroPitchBias;
 int16\_t GyroYawBias;
 int16\_t GyroRollBias;
 int16\_t GyroPitchPlus;
 int16\_t GyroPitchMinus;
 int16\_t GyroYawPlus;
 int16\_t GyroYawMinus;
 int16\_t GyroRollPlus;
 int16\_t GyroRollMinus;
 int16\_t GyroSpeedPlus;
 int16\_t GyroSpeedMinus;
 int16\_t AccelXPlus;
 int16\_t AccelXMinus;
 int16\_t AccelYPlus;
 int16\_t AccelYMinus;
 int16\_t AccelZPlus;
 int16\_t AccelZMinus;
 int16\_t Unknown;
};

```

##### Bluetooth 0x05

```
struct ReportFeatureInCalibrateBT {
 union {
 BTCRC<41> CRC;
 struct {
 uint8\_t ReportID; // 0x05
 int16\_t GyroPitchBias;
 int16\_t GyroYawBias;
 int16\_t GyroRollBias;
 int16\_t GyroPitchPlus;
 int16\_t GyroYawPlus;
 int16\_t GyroRollPlus;
 int16\_t GyroPitchMinus;
 int16\_t GyroYawMinus;
 int16\_t GyroRollMinus;
 int16\_t GyroSpeedPlus;
 int16\_t GyroSpeedMinus;
 int16\_t AccelXPlus;
 int16\_t AccelXMinus;
 int16\_t AccelYPlus;
 int16\_t AccelYMinus;
 int16\_t AccelZPlus;
 int16\_t AccelZMinus;
 int16\_t Unknown;
 } Data;
 }
};

```

##### Dongle 0x02

```
struct ReportFeatureInCalibrateDongle {
 uint8\_t ReportID; // 0x02
 int16\_t GyroPitchBias;
 int16\_t GyroYawBias;
 int16\_t GyroRollBias;
 int16\_t GyroPitchPlus;
 int16\_t GyroYawPlus;
 int16\_t GyroRollPlus;
 int16\_t GyroPitchMinus;
 int16\_t GyroYawMinus;
 int16\_t GyroRollMinus;
 int16\_t GyroSpeedPlus;
 int16\_t GyroSpeedMinus;
 int16\_t AccelXPlus;
 int16\_t AccelXMinus;
 int16\_t AccelYPlus;
 int16\_t AccelYMinus;
 int16\_t AccelZPlus;
 int16\_t AccelZMinus;
 int16\_t Unknown;
};

```

##### Get All MAC USB/Dongle 0x12

```
struct ReportFeatureInMacAll {
 uint8\_t ReportID; // 0x12 (0x09 for BT)
 uint8\_t[6] ClientMac; // Right to Left
 uint8\_t Hard08;
 uint8\_t Hard25;
 uint8\_t Hard00;
 uint8\_t[6] HostMac; // Right to Left
};

```

##### Get All MAC BT 0x09

```
struct ReportFeatureInMacAllBT {
 union {
 BTCRC<53> CRC;
 ReportFeatureInControllerVersion Data; // with ReportID 0x09
 }
};

```

##### Get Client MAC USB/Dongle 0x81

```
struct ReportFeatureInMacClient {
 uint8\_t ReportID; // 0x81
 uint8\_t[6] ClientMac; // Right to Left
};

```

##### Get Host Dongle 0xE5

```
struct ReportFeatureInMacHost {
 uint8\_t ReportID; // 0xE5
 uint8\_t[6] HostMac; // Right to Left
};

```

##### Set Host MAC and Linkkey USB 0x13

```
struct ReportFeatureOutMacHost {
 uint8\_t ReportID; // 0x13
 uint8\_t[6] ClientMac; // Right to Left
 uint8\_t[16] Linkkey;
};

```

##### Set Client MAC USB 0x80

```
struct ReportFeatureOutMacClient {
 uint8\_t ReportID; // 0x80
 uint8\_t[6] ClientMac; // Right to Left
};

```

#### Date and Version

##### Controller Date/Version Dongle/USB 0xA3

```
struct ReportFeatureInControllerVersion {
 uint8\_t ReportID; // 0xA3 (0x06 for BT)
 char[16] Date; // string
 char[16] Time; // string
 uint16\_t HardwareVersionMajor; // %04x.%04x AKA DevRel
 uint16\_t HardwareVersionMinor; // Must be >= 0x3100u for Remote Play
 // might be bitwise anded with 0xFFC0
 uint32\_t SoftwareVersionMajor; // firmware ignores this for debug terminal output a hardcode of 3
 uint16\_t SoftwareVersionMinor; // written %08x.%04x, 3, sw\_ver\_minor
 uint16\_t SoftwareSeries; // %04x
 uint32\_t CodeSize;
};

```

##### Controller Date/Version Bluetooth 0x06

```
struct ReportFeatureInControllerVersionBT {
 union {
 BTCRC<53> CRC;
 ReportFeatureInControllerVersion Data; // with ReportID 0x06
 }
};

```

##### Dongle Date/Version Dongle 0xE1

```
struct ReportFeatureInDongleVersion {
 uint8\_t ReportID; // 0xE1
 char[16] Date; // string
 char[16] Time; // string
 uint16\_t HardwareVersionMajor;
 uint16\_t HardwareVersionMinor;
 uint32\_t SoftwareVersionMajor;
 uint16\_t SoftwareVersionMinor;
 uint16\_t SoftwareSeries;
 uint32\_t CodeSize;
};

```

#### Other

##### Controller VID/PID Dongle 0xE3

Access controller's VID/PID to determine what controller is connected to dongle. Note: Dongle's revision number is used.

```
struct ReportFeatureInControllerVidPidDongle {
 uint8\_t ReportID; // 0xE3
 uint16\_t VID; // Ex: 0x054C
 uint16\_t PID; // Ex: 0x09CC
};

```

##### Get Audio Chip Ident 0xAF

Confirm if this is USB only

```
struct ReportFeatureInMacClient {
 uint8\_t ReportID; // 0xAF
 uint16\_t Ident; // 0x1801 for WM1801
};

```

##### Get AC\_ON\_STATE 0xAE

Confirm if this is USB only, this is of unknown purpose

```
struct ReportFeatureInMacClient {
 uint8\_t ReportID; // 0xAE
 uint8\_t Value; // 0x00 - L, 0x01 - H
};

```

##### Dongle Set Audio Output Dongle 0xE0

```
// Note that the headset output does not downmix, so mono only comes from the left
enum AudioOutput : uint8\_t {
 HeadsetStereo = 0, // Left and Right to headphones
 HeadsetMono, // Left to headphones
 HeadsetMonoSpeaker, // Left to headphones, Right to speaker
 Speaker, // Right to speaker
 Disabled = 4
};
struct ReportFeatureInDongleSetAudio {
 uint8\_t ReportID; // 0xE0
 uint8\_t Unknown; // 0x00
 AudioOutput Output;
};

```