Sony DualShock 4/Data Structures

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];
};

```

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;
};

```