bluetooth-mitm: add support for 8bitdo sn30 pro (xbox cloud gaming edition), support both report formats for 8bitdo zero

This commit is contained in:
ndeadly 2021-02-07 18:22:34 +01:00
parent 7b6b0ce893
commit 5ac15a48a2
2 changed files with 180 additions and 54 deletions

View file

@ -18,52 +18,115 @@
namespace ams::controller {
namespace {
constexpr float stick_scale_factor = float(UINT12_MAX) / UINT16_MAX;
}
void EightBitDoController::UpdateControllerState(const bluetooth::HidReport *report) {
auto eightbitdo_report = reinterpret_cast<const EightBitDoReportData *>(&report->data);
switch(eightbitdo_report->id) {
case 0x01:
this->HandleInputReport0x01(eightbitdo_report);
this->HandleInputReport0x01(eightbitdo_report, report->size == 9 ? EightBitDoReportFormat_ZeroV1 : EightBitDoReportFormat_Other);
break;
case 0x03:
this->HandleInputReport0x03(eightbitdo_report);
this->HandleInputReport0x03(eightbitdo_report, report->size == 11 ? EightBitDoReportFormat_ZeroV1 : EightBitDoReportFormat_ZeroV2);
break;
default:
break;
}
}
void EightBitDoController::HandleInputReport0x01(const EightBitDoReportData *src) {
m_buttons.dpad_down = (src->input0x01.dpad == EightBitDoDPad_S) ||
(src->input0x01.dpad == EightBitDoDPad_SE) ||
(src->input0x01.dpad == EightBitDoDPad_SW);
m_buttons.dpad_up = (src->input0x01.dpad == EightBitDoDPad_N) ||
(src->input0x01.dpad == EightBitDoDPad_NE) ||
(src->input0x01.dpad == EightBitDoDPad_NW);
m_buttons.dpad_right = (src->input0x01.dpad == EightBitDoDPad_E) ||
(src->input0x01.dpad == EightBitDoDPad_NE) ||
(src->input0x01.dpad == EightBitDoDPad_SE);
m_buttons.dpad_left = (src->input0x01.dpad == EightBitDoDPad_W) ||
(src->input0x01.dpad == EightBitDoDPad_NW) ||
(src->input0x01.dpad == EightBitDoDPad_SW);
void EightBitDoController::HandleInputReport0x01(const EightBitDoReportData *src, EightBitDoReportFormat fmt) {
if (fmt == EightBitDoReportFormat_ZeroV1) {
m_buttons.dpad_down = (src->input0x01_v1.dpad == EightBitDoDPadV1_S) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_SE) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_SW);
m_buttons.dpad_up = (src->input0x01_v1.dpad == EightBitDoDPadV1_N) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_NE) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_NW);
m_buttons.dpad_right = (src->input0x01_v1.dpad == EightBitDoDPadV1_E) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_NE) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_SE);
m_buttons.dpad_left = (src->input0x01_v1.dpad == EightBitDoDPadV1_W) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_NW) ||
(src->input0x01_v1.dpad == EightBitDoDPadV1_SW);
}
else {
m_left_stick = this->PackStickData(
static_cast<uint16_t>(stick_scale_factor * src->input0x01_v2.left_stick.x) & 0xfff,
static_cast<uint16_t>(stick_scale_factor * (UINT16_MAX - src->input0x01_v2.left_stick.y)) & 0xfff
);
m_right_stick = this->PackStickData(
static_cast<uint16_t>(stick_scale_factor * src->input0x01_v2.right_stick.x) & 0xfff,
static_cast<uint16_t>(stick_scale_factor * (UINT16_MAX - src->input0x01_v2.right_stick.y)) & 0xfff
);
m_buttons.dpad_down = (src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_S) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_SE) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_SW);
m_buttons.dpad_up = (src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_N) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_NE) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_NW);
m_buttons.dpad_right = (src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_E) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_NE) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_SE);
m_buttons.dpad_left = (src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_W) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_NW) ||
(src->input0x01_v2.buttons.dpad == EightBitDoDPadV2_SW);
m_buttons.A = src->input0x01_v2.buttons.B;
m_buttons.B = src->input0x01_v2.buttons.A;
m_buttons.X = src->input0x01_v2.buttons.Y;
m_buttons.Y = src->input0x01_v2.buttons.X;
m_buttons.R = src->input0x01_v2.buttons.R1;
m_buttons.ZR = src->input0x01_v2.right_trigger > 0x7f;
m_buttons.L = src->input0x01_v2.buttons.L1;
m_buttons.ZL = src->input0x01_v2.left_trigger > 0x7f;
m_buttons.minus = src->input0x01_v2.buttons.select;
m_buttons.plus = src->input0x01_v2.buttons.start;
m_buttons.lstick_press = src->input0x01_v2.buttons.L3;
m_buttons.rstick_press = src->input0x01_v2.buttons.R3;
m_buttons.home = src->input0x01_v2.buttons.home;
}
}
void EightBitDoController::HandleInputReport0x03(const EightBitDoReportData *src) {
m_buttons.dpad_down = src->input0x03.left_stick.y == 0xff;
m_buttons.dpad_up = src->input0x03.left_stick.y == 0x00;
m_buttons.dpad_right = src->input0x03.left_stick.x == 0xff;
m_buttons.dpad_left = src->input0x03.left_stick.x == 0x00;
void EightBitDoController::HandleInputReport0x03(const EightBitDoReportData *src, EightBitDoReportFormat fmt) {
if (fmt == EightBitDoReportFormat_ZeroV1) {
m_buttons.A = src->input0x03_v1.buttons.B;
m_buttons.B = src->input0x03_v1.buttons.A;
m_buttons.X = src->input0x03_v1.buttons.Y;
m_buttons.Y = src->input0x03_v1.buttons.X;
m_buttons.A = src->input0x03.buttons.B;
m_buttons.B = src->input0x03.buttons.A;
m_buttons.X = src->input0x03.buttons.Y;
m_buttons.Y = src->input0x03.buttons.X;
m_buttons.R = src->input0x03_v1.buttons.R1;
m_buttons.L = src->input0x03_v1.buttons.L1;
m_buttons.R = src->input0x03.buttons.R;
m_buttons.L = src->input0x03.buttons.L;
m_buttons.minus = src->input0x03_v1.buttons.select;
m_buttons.plus = src->input0x03_v1.buttons.start;
}
else if (fmt == EightBitDoReportFormat_ZeroV2) {
m_buttons.dpad_down = src->input0x03_v2.left_stick.y == 0xff;
m_buttons.dpad_up = src->input0x03_v2.left_stick.y == 0x00;
m_buttons.dpad_right = src->input0x03_v2.left_stick.x == 0xff;
m_buttons.dpad_left = src->input0x03_v2.left_stick.x == 0x00;
m_buttons.minus = src->input0x03.buttons.select;
m_buttons.plus = src->input0x03.buttons.start;
m_buttons.A = src->input0x03_v2.buttons.B;
m_buttons.B = src->input0x03_v2.buttons.A;
m_buttons.X = src->input0x03_v2.buttons.Y;
m_buttons.Y = src->input0x03_v2.buttons.X;
m_buttons.R = src->input0x03_v2.buttons.R1;
m_buttons.L = src->input0x03_v2.buttons.L1;
m_buttons.minus = src->input0x03_v2.buttons.select;
m_buttons.plus = src->input0x03_v2.buttons.start;
}
}
}

View file

@ -18,58 +18,121 @@
namespace ams::controller {
enum EightBitDoDPadDirection : uint16_t {
EightBitDoDPad_Released = 0x0000,
EightBitDoDPad_N = 0x0052,
EightBitDoDPad_NE = 0x524f,
EightBitDoDPad_E = 0x004f,
EightBitDoDPad_SE = 0x4f51,
EightBitDoDPad_S = 0x0051,
EightBitDoDPad_SW = 0x5150,
EightBitDoDPad_W = 0x0050,
EightBitDoDPad_NW = 0x5250,
enum EightBitDoReportFormat {
EightBitDoReportFormat_ZeroV1,
EightBitDoReportFormat_ZeroV2,
EightBitDoReportFormat_Other
};
struct EightBitDoStickData {
enum EightBitDoDPadDirectionV1 : uint16_t {
EightBitDoDPadV1_Released = 0x0000,
EightBitDoDPadV1_N = 0x0052,
EightBitDoDPadV1_NE = 0x524f,
EightBitDoDPadV1_E = 0x004f,
EightBitDoDPadV1_SE = 0x4f51,
EightBitDoDPadV1_S = 0x0051,
EightBitDoDPadV1_SW = 0x5150,
EightBitDoDPadV1_W = 0x0050,
EightBitDoDPadV1_NW = 0x5250,
};
enum EightBitDoDPadDirectionV2 {
EightBitDoDPadV2_N,
EightBitDoDPadV2_NE,
EightBitDoDPadV2_E,
EightBitDoDPadV2_SE,
EightBitDoDPadV2_S,
EightBitDoDPadV2_SW,
EightBitDoDPadV2_W,
EightBitDoDPadV2_NW,
EightBitDoDPadV2_Released
};
struct EightBitDoStickData8 {
uint8_t x;
uint8_t y;
} __attribute__((packed));
struct EightBitDoButtonData {
struct EightBitDoStickData16 {
uint16_t x;
uint16_t y;
} __attribute__((packed));
struct EightBitDoButtonDataV1 {
uint8_t A : 1;
uint8_t B : 1;
uint8_t : 1;
uint8_t X : 1;
uint8_t Y : 1;
uint8_t : 1;
uint8_t L : 1;
uint8_t R : 1;
uint8_t L1 : 1;
uint8_t R1 : 1;
uint8_t : 2;
uint8_t select : 1;
uint8_t start : 1;
uint8_t : 0;
uint8_t : 0;
}__attribute__((packed));
struct EightBitDoInputReport0x01 {
struct EightBitDoButtonDataV2 {
uint8_t A : 1;
uint8_t B : 1;
uint8_t : 1;
uint8_t X : 1;
uint8_t Y : 1;
uint8_t : 1;
uint8_t L1 : 1;
uint8_t R1 : 1;
uint8_t select : 1;
uint8_t : 2;
uint8_t start : 1;
uint8_t home : 1;
uint8_t L3 : 1;
uint8_t R3 : 1;
uint8_t : 1;
uint8_t dpad;
}__attribute__((packed));
struct EightBitDoInputReport0x01V1 {
uint8_t _unk0[2];
uint16_t dpad;
uint8_t _unk1[4];
} __attribute__((packed));
struct EightBitDoInputReport0x03 {
struct EightBitDoInputReport0x01V2 {
EightBitDoButtonDataV2 buttons;
EightBitDoStickData16 left_stick;
EightBitDoStickData16 right_stick;
uint8_t left_trigger;
uint8_t right_trigger;
uint8_t _unk0;
} __attribute__((packed));
struct EightBitDoInputReport0x03V1 {
uint8_t dpad;
EightBitDoStickData left_stick;
EightBitDoStickData right_stick;
EightBitDoStickData8 left_stick;
EightBitDoStickData8 right_stick;
uint8_t _unk[3];
EightBitDoButtonDataV1 buttons;
} __attribute__((packed));
struct EightBitDoInputReport0x03V2 {
uint8_t dpad;
EightBitDoStickData8 left_stick;
EightBitDoStickData8 right_stick;
uint8_t _unk[2];
EightBitDoButtonData buttons;
EightBitDoButtonDataV1 buttons;
} __attribute__((packed));
struct EightBitDoReportData{
uint8_t id;
union {
EightBitDoInputReport0x01 input0x01;
EightBitDoInputReport0x03 input0x03;
EightBitDoInputReport0x01V1 input0x01_v1;
EightBitDoInputReport0x01V2 input0x01_v2;
EightBitDoInputReport0x03V1 input0x03_v1;
EightBitDoInputReport0x03V2 input0x03_v2;
};
} __attribute__((packed));
@ -77,7 +140,8 @@ namespace ams::controller {
public:
static constexpr const HardwareID hardware_ids[] = {
{0x05a0, 0x3232} // 8BitDo Zero
{0x05a0, 0x3232}, // 8BitDo Zero
{0x2dc8, 0x2100} // 8BitDo SN30 Pro for Xbox Cloud Gaming
};
EightBitDoController(const bluetooth::Address *address)
@ -86,10 +150,9 @@ namespace ams::controller {
void UpdateControllerState(const bluetooth::HidReport *report);
private:
void HandleInputReport0x01(const EightBitDoReportData *src);
void HandleInputReport0x03(const EightBitDoReportData *src);
void HandleInputReport0x01(const EightBitDoReportData *src, EightBitDoReportFormat fmt);
void HandleInputReport0x03(const EightBitDoReportData *src, EightBitDoReportFormat);
};
}