switch-pico/switch2_reports.cpp
Joey Yakimowich-Payne f8de986717 Implement Switch2 reports
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-08-11 12:23:07 +09:00

89 lines
3.6 KiB
C++

#include "switch2_reports.h"
// Report layouts are pinned to:
// https://github.com/ndeadly/switch2_controller_research/blob/d1c5a7f7ba298f83017fae84952a4e6d2ef8fc92/hid_reports.md
namespace {
void pack_stick(uint8_t* destination, uint16_t x, uint16_t y) {
const uint16_t packed_x = x >> 4;
const uint16_t packed_y = y >> 4;
destination[0] = static_cast<uint8_t>(packed_x & 0xFF);
destination[1] = static_cast<uint8_t>(
((packed_x >> 8) & 0x0F) | ((packed_y & 0x0F) << 4));
destination[2] = static_cast<uint8_t>(packed_y >> 4);
}
} // namespace
Switch2InputReport switch2_build_input_report(
Switch2InputReportId id,
const SwitchInputState& state,
uint32_t counter) {
Switch2InputReport report{id, {}};
std::array<uint8_t, 63>& payload = report.payload;
switch (id) {
case Switch2InputReportId::Common:
payload[0] = static_cast<uint8_t>(counter);
payload[1] = static_cast<uint8_t>(counter >> 8);
payload[2] = static_cast<uint8_t>(counter >> 16);
payload[3] = static_cast<uint8_t>(counter >> 24);
payload[4] = static_cast<uint8_t>(
(state.button_zr ? 0x80 : 0) |
(state.button_r ? 0x40 : 0) |
(state.button_a ? 0x08 : 0) |
(state.button_b ? 0x04 : 0) |
(state.button_x ? 0x02 : 0) |
(state.button_y ? 0x01 : 0));
payload[5] = static_cast<uint8_t>(
(state.button_capture ? 0x20 : 0) |
(state.button_home ? 0x10 : 0) |
(state.button_l3 ? 0x08 : 0) |
(state.button_r3 ? 0x04 : 0) |
(state.button_plus ? 0x02 : 0) |
(state.button_minus ? 0x01 : 0));
payload[6] = static_cast<uint8_t>(
(state.button_zl ? 0x80 : 0) |
(state.button_l ? 0x40 : 0) |
(state.dpad_left ? 0x08 : 0) |
(state.dpad_right ? 0x04 : 0) |
(state.dpad_up ? 0x02 : 0) |
(state.dpad_down ? 0x01 : 0));
pack_stick(&payload[10], state.lx, state.ly);
pack_stick(&payload[13], state.rx, state.ry);
payload[0x29] = 0x01;
break;
case Switch2InputReportId::Pro:
payload[0] = static_cast<uint8_t>(counter);
// USB external power is known; charging and battery bits stay zero.
payload[1] = 0x01;
payload[2] = static_cast<uint8_t>(
(state.button_r3 ? 0x80 : 0) |
(state.button_plus ? 0x40 : 0) |
(state.button_zr ? 0x20 : 0) |
(state.button_r ? 0x10 : 0) |
(state.button_x ? 0x08 : 0) |
(state.button_y ? 0x04 : 0) |
(state.button_a ? 0x02 : 0) |
(state.button_b ? 0x01 : 0));
payload[3] = static_cast<uint8_t>(
(state.button_l3 ? 0x80 : 0) |
(state.button_minus ? 0x40 : 0) |
(state.button_zl ? 0x20 : 0) |
(state.button_l ? 0x10 : 0) |
(state.dpad_up ? 0x08 : 0) |
(state.dpad_left ? 0x04 : 0) |
(state.dpad_right ? 0x02 : 0) |
(state.dpad_down ? 0x01 : 0));
payload[4] = static_cast<uint8_t>(
(state.button_capture ? 0x02 : 0) |
(state.button_home ? 0x01 : 0));
pack_stick(&payload[5], state.lx, state.ly);
pack_stick(&payload[8], state.rx, state.ry);
payload[11] = 0x30;
break;
}
return report;
}