bluetooth-mitm: extended report, battery, and player LEDs for DualSense (#180)

This commit is contained in:
Sean Maas 2021-01-27 14:51:22 -05:00 committed by GitHub
parent 3d635cc468
commit d1ec785a08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 135 additions and 6 deletions

View file

@ -22,6 +22,51 @@ namespace ams::controller {
const constexpr float stick_scale_factor = float(UINT12_MAX) / UINT8_MAX;
const uint8_t player_led_flags[] = {
// Mimic the Switch's player LEDs
0x01,
0x03,
0x0B,
0x1B,
0x11,
0x09,
0x19,
0x0A
};
const RGBColour player_led_colours[] = {
// Same colours used by PS4
{0x00, 0x00, 0x40}, // blue
{0x40, 0x00, 0x00}, // red
{0x00, 0x40, 0x00}, // green
{0x20, 0x00, 0x20}, // pink
// New colours for controllers 5-8
{0x00, 0x20, 0x20}, // cyan
{0x30, 0x10, 0x00}, // orange
{0x20, 0x20, 0x00}, // yellow
{0x10, 0x00, 0x30} // purple
};
}
Result DualsenseController::Initialize(void) {
R_TRY(EmulatedSwitchController::Initialize());
R_TRY(this->PushRumbleLedState());
return ams::ResultSuccess();
}
Result DualsenseController::SetPlayerLed(uint8_t led_mask) {
uint8_t player_number;
R_TRY(LedsMaskToPlayerNumber(led_mask, &player_number));
m_led_flags = player_led_flags[player_number];
RGBColour colour = player_led_colours[player_number];
return this->SetLightbarColour(colour);
}
Result DualsenseController::SetLightbarColour(RGBColour colour) {
m_led_colour = colour;
return this->PushRumbleLedState();
}
void DualsenseController::UpdateControllerState(const bluetooth::HidReport *report) {
@ -31,12 +76,15 @@ namespace ams::controller {
case 0x01:
this->HandleInputReport0x01(dualsense_report);
break;
case 0x31:
this->HandleInputReport0x31(dualsense_report);
break;
default:
break;
}
}
void DualsenseController::HandleInputReport0x01(const DualsenseReportData *src) {
void DualsenseController::HandleInputReport0x01(const DualsenseReportData *src) {
m_left_stick = this->PackStickData(
static_cast<uint16_t>(stick_scale_factor * src->input0x01.left_stick.x) & 0xfff,
static_cast<uint16_t>(stick_scale_factor * (UINT8_MAX - src->input0x01.left_stick.y)) & 0xfff
@ -49,6 +97,32 @@ namespace ams::controller {
this->MapButtons(&src->input0x01.buttons);
}
void DualsenseController::HandleInputReport0x31(const DualsenseReportData *src) {
if (!src->input0x31.usb || src->input0x31.full)
m_charging = false;
else
m_charging = true;
uint8_t battery_level = src->input0x31.battery_level;
if (!src->input0x31.usb)
battery_level++;
if (battery_level > 10)
battery_level = 10;
m_battery = static_cast<uint8_t>(8 * (battery_level + 1) / 10) & 0x0e;
m_left_stick = this->PackStickData(
static_cast<uint16_t>(stick_scale_factor * src->input0x31.left_stick.x) & 0xfff,
static_cast<uint16_t>(stick_scale_factor * (UINT8_MAX - src->input0x31.left_stick.y)) & 0xfff
);
m_right_stick = this->PackStickData(
static_cast<uint16_t>(stick_scale_factor * src->input0x31.right_stick.x) & 0xfff,
static_cast<uint16_t>(stick_scale_factor * (UINT8_MAX - src->input0x31.right_stick.y)) & 0xfff
);
this->MapButtons(&src->input0x31.buttons);
}
void DualsenseController::MapButtons(const DualsenseButtonData *buttons) {
m_buttons.dpad_down = (buttons->dpad == DualsenseDPad_S) ||
(buttons->dpad == DualsenseDPad_SE) ||
@ -83,4 +157,20 @@ namespace ams::controller {
m_buttons.home = buttons->ps;
}
Result DualsenseController::PushRumbleLedState(void) {
DualsenseOutputReport0x31 report = {0xa2, 0x31, 0x02, 0x00, 0x14};
report.data[41] = 0x02;
report.data[44] = 0x02;
report.data[46] = m_led_flags;
report.data[47] = m_led_colour.r;
report.data[48] = m_led_colour.g;
report.data[49] = m_led_colour.b;
report.crc = crc32Calculate(report.data, sizeof(report.data));
s_output_report.size = sizeof(report) - 1;
std::memcpy(s_output_report.data, &report.data[1], s_output_report.size);
return bluetooth::hid::report::SendHidReport(&m_address, &s_output_report);
}
}

View file

@ -56,18 +56,49 @@ namespace ams::controller {
uint8_t counter : 6;
} __attribute__((packed));
struct DualsenseOutputReport0x31 {
struct {
uint8_t data[75];
};
uint32_t crc;
} __attribute__((packed));
struct DualsenseInputReport0x01 {
DualsenseStickData left_stick;
DualsenseStickData right_stick;
DualsenseButtonData buttons;
DualsenseStickData left_stick;
DualsenseStickData right_stick;
DualsenseButtonData buttons;
uint8_t left_trigger;
uint8_t right_trigger;
} __attribute__((packed));
struct DualsenseInputReport0x31 {
uint8_t _unk0;
DualsenseStickData left_stick;
DualsenseStickData right_stick;
uint8_t left_trigger;
uint8_t right_trigger;
uint8_t counter;
DualsenseButtonData buttons;
uint8_t _unk1[5];
uint16_t vel_x;
uint16_t vel_y;
uint16_t vel_z;
uint16_t acc_x;
uint16_t acc_y;
uint16_t acc_z;
uint8_t _unk2[25];
uint8_t battery_level : 4;
uint8_t usb : 1;
uint8_t full : 1;
uint8_t : 0;
} __attribute__((packed));
struct DualsenseReportData {
uint8_t id;
union {
DualsenseInputReport0x01 input0x01;
DualsenseInputReport0x31 input0x31;
};
} __attribute__((packed));
@ -79,15 +110,23 @@ namespace ams::controller {
};
DualsenseController(const bluetooth::Address *address)
: EmulatedSwitchController(address) { };
: EmulatedSwitchController(address), m_led_flags(0), m_led_colour({0, 0, 0}) { };
//Result Initialize(void);
Result Initialize(void);
Result SetPlayerLed(uint8_t led_mask);
Result SetLightbarColour(RGBColour colour);
void UpdateControllerState(const bluetooth::HidReport *report);
private:
void HandleInputReport0x01(const DualsenseReportData *src);
void HandleInputReport0x31(const DualsenseReportData *src);
void MapButtons(const DualsenseButtonData *buttons);
Result PushRumbleLedState(void);
uint8_t m_led_flags;
RGBColour m_led_colour;
};
}