mirror of
https://github.com/ndeadly/MissionControl
synced 2024-11-22 20:33:07 +00:00
379 lines
11 KiB
C++
379 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2020-2023 ndeadly
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#pragma once
|
|
#include "switch_analog_stick.hpp"
|
|
#include "../bluetooth_mitm/bluetooth/bluetooth_types.hpp"
|
|
#include "../bluetooth_mitm/bluetooth/bluetooth_hid_report.hpp"
|
|
#include "../async/future_response.hpp"
|
|
#include <queue>
|
|
|
|
namespace ams::controller {
|
|
|
|
using HidResponse = FutureResponse<bluetooth::HidEventType, bluetooth::HidReportEventInfo, u8>;
|
|
|
|
constexpr auto BATTERY_MAX = 8;
|
|
|
|
enum SwitchPlayerNumber : u8 {
|
|
SwitchPlayerNumber_One,
|
|
SwitchPlayerNumber_Two,
|
|
SwitchPlayerNumber_Three,
|
|
SwitchPlayerNumber_Four,
|
|
SwitchPlayerNumber_Five,
|
|
SwitchPlayerNumber_Six,
|
|
SwitchPlayerNumber_Seven,
|
|
SwitchPlayerNumber_Eight,
|
|
SwitchPlayerNumber_Unknown = 0xf
|
|
};
|
|
|
|
struct HardwareID {
|
|
u16 vid;
|
|
u16 pid;
|
|
};
|
|
|
|
struct RGBColour {
|
|
u8 r;
|
|
u8 g;
|
|
u8 b;
|
|
} PACKED;
|
|
|
|
struct ProControllerColours {
|
|
RGBColour body;
|
|
RGBColour buttons;
|
|
RGBColour left_grip;
|
|
RGBColour right_grip;
|
|
} PACKED;
|
|
|
|
struct SwitchButtonData {
|
|
u8 Y : 1;
|
|
u8 X : 1;
|
|
u8 B : 1;
|
|
u8 A : 1;
|
|
u8 : 2; // SR, SL (Right Joy)
|
|
u8 R : 1;
|
|
u8 ZR : 1;
|
|
|
|
u8 minus : 1;
|
|
u8 plus : 1;
|
|
u8 rstick_press : 1;
|
|
u8 lstick_press : 1;
|
|
u8 home : 1;
|
|
u8 capture : 1;
|
|
u8 : 0;
|
|
|
|
u8 dpad_down : 1;
|
|
u8 dpad_up : 1;
|
|
u8 dpad_right : 1;
|
|
u8 dpad_left : 1;
|
|
u8 : 2; // SR, SL (Left Joy)
|
|
u8 L : 1;
|
|
u8 ZL : 1;
|
|
} PACKED;
|
|
|
|
struct Switch6AxisData {
|
|
s16 accel_x;
|
|
s16 accel_y;
|
|
s16 accel_z;
|
|
s16 gyro_1;
|
|
s16 gyro_2;
|
|
s16 gyro_3;
|
|
} PACKED;
|
|
|
|
struct Switch6AxisCalibrationData {
|
|
struct {
|
|
s16 x;
|
|
s16 y;
|
|
s16 z;
|
|
} acc_bias;
|
|
|
|
struct {
|
|
s16 x;
|
|
s16 y;
|
|
s16 z;
|
|
} acc_sensitivity;
|
|
|
|
struct {
|
|
s16 roll;
|
|
s16 pitch;
|
|
s16 yaw;
|
|
} gyro_bias;
|
|
|
|
struct {
|
|
s16 roll;
|
|
s16 pitch;
|
|
s16 yaw;
|
|
} gyro_sensitivity;
|
|
} PACKED;
|
|
|
|
struct Switch6AxisHorizontalOffset {
|
|
s16 x;
|
|
s16 y;
|
|
s16 z;
|
|
} PACKED;
|
|
|
|
struct SwitchRumbleDataEncoded {
|
|
u8 left_motor[4];
|
|
u8 right_motor[4];
|
|
} PACKED;
|
|
|
|
struct SwitchRumbleData {
|
|
float high_band_freq;
|
|
float high_band_amp;
|
|
float low_band_freq;
|
|
float low_band_amp;
|
|
} PACKED;
|
|
|
|
enum HidCommandType : u8 {
|
|
HidCommand_PairingOut = 0x01,
|
|
HidCommand_GetDeviceInfo = 0x02,
|
|
HidCommand_SetDataFormat = 0x03,
|
|
HidCommand_LRButtonDetection = 0x04,
|
|
HidCommand_Page = 0x05,
|
|
HidCommand_Reset = 0x06,
|
|
HidCommand_ClearPairingInfo = 0x07,
|
|
HidCommand_Shipment = 0x08,
|
|
HidCommand_SerialFlashRead = 0x10,
|
|
HidCommand_SerialFlashWrite = 0x11,
|
|
HidCommand_SerialFlashSectorErase = 0x12,
|
|
HidCommand_McuReset = 0x20,
|
|
HidCommand_McuWrite = 0x21,
|
|
HidCommand_McuResume = 0x22,
|
|
HidCommand_McuPollingEnable = 0x24,
|
|
HidCommand_McuPollingDisable = 0x25,
|
|
HidCommand_AttachmentWrite = 0x28,
|
|
HidCommand_AttachmentRead = 0x29,
|
|
HidCommand_AttachmentEnable = 0x2a,
|
|
HidCommand_SetIndicatorLed = 0x30,
|
|
HidCommand_GetIndicatorLed = 0x31,
|
|
HidCommand_SetNotificationLed = 0x38,
|
|
HidCommand_SensorSleep = 0x40,
|
|
HidCommand_SensorConfig = 0x41,
|
|
HidCommand_SensorWrite = 0x42,
|
|
HidCommand_SensorRead = 0x43,
|
|
HidCommand_MotorEnable = 0x48,
|
|
HidCommand_GetBatteryVoltage = 0x50,
|
|
HidCommand_WriteChargeSetting = 0x51,
|
|
HidCommand_ReadChargeSetting = 0x52,
|
|
};
|
|
|
|
struct SwitchHidCommand {
|
|
u8 id;
|
|
union {
|
|
u8 data[0x26];
|
|
|
|
struct {
|
|
u8 id;
|
|
} set_data_format;
|
|
|
|
struct {
|
|
u32 address;
|
|
u8 size;
|
|
} serial_flash_read;
|
|
|
|
struct {
|
|
u32 address;
|
|
u8 size;
|
|
u8 data[];
|
|
} serial_flash_write;
|
|
|
|
struct {
|
|
u32 address;
|
|
} serial_flash_sector_erase;
|
|
|
|
struct {
|
|
union {
|
|
u8 leds;
|
|
|
|
struct {
|
|
u8 leds_flash : 4;
|
|
u8 leds_on : 4;
|
|
};
|
|
};
|
|
} set_indicator_led;
|
|
|
|
struct {
|
|
bool disabled;
|
|
} sensor_sleep;
|
|
|
|
struct {
|
|
u8 gyro_sensitivity;
|
|
u8 acc_sensitivity;
|
|
u8 gyro_perf_rate;
|
|
u8 acc_aa_bandwidth;
|
|
} sensor_config;
|
|
|
|
struct {
|
|
bool enabled;
|
|
} motor_enable;
|
|
};
|
|
} PACKED;
|
|
|
|
struct SwitchHidCommandResponse {
|
|
u8 ack;
|
|
u8 id;
|
|
union {
|
|
u8 raw[0x23];
|
|
|
|
struct {
|
|
struct {
|
|
u8 major;
|
|
u8 minor;
|
|
} fw_ver;
|
|
u8 type;
|
|
u8 _unk0; // Always 0x02
|
|
bluetooth::Address address;
|
|
u8 _unk1; // Always 0x01
|
|
u8 _unk2; // If 01, colors in SPI are used. Otherwise default ones
|
|
} __attribute__ ((__packed__)) get_device_info;
|
|
|
|
struct {
|
|
bool enabled;
|
|
} shipment;
|
|
|
|
struct {
|
|
u32 address;
|
|
u8 size;
|
|
u8 data[];
|
|
} serial_flash_read;
|
|
|
|
struct {
|
|
u8 status;
|
|
} serial_flash_write;
|
|
|
|
struct {
|
|
u8 status;
|
|
} serial_flash_sector_erase;
|
|
|
|
struct {
|
|
union {
|
|
u8 leds;
|
|
|
|
struct {
|
|
u8 leds_flash : 4;
|
|
u8 leds_on : 4;
|
|
};
|
|
};
|
|
} get_indicator_led;
|
|
} data;
|
|
} PACKED;
|
|
|
|
struct SwitchNfcIrResponse {
|
|
u8 data[0x138];
|
|
} PACKED;
|
|
|
|
struct SwitchInputReport {
|
|
u8 id;
|
|
u8 timer;
|
|
u8 conn_info : 4;
|
|
u8 battery : 4;
|
|
SwitchButtonData buttons;
|
|
SwitchAnalogStick left_stick;
|
|
SwitchAnalogStick right_stick;
|
|
u8 vibrator;
|
|
|
|
union {
|
|
struct {
|
|
SwitchHidCommandResponse hid_command_response;
|
|
} type0x21;
|
|
|
|
struct {
|
|
u8 mcu_fw_data[37];
|
|
} type0x23;
|
|
|
|
struct {
|
|
Switch6AxisData motion_data[3]; // IMU samples at 0, 5 and 10ms
|
|
} type0x30;
|
|
|
|
struct {
|
|
Switch6AxisData motion_data[3]; // IMU samples at 0, 5 and 10ms
|
|
SwitchNfcIrResponse nfc_ir_response;
|
|
u8 crc;
|
|
} type0x31;
|
|
};
|
|
} PACKED;
|
|
|
|
struct SwitchOutputReport {
|
|
u8 id;
|
|
u8 counter;
|
|
SwitchRumbleDataEncoded rumble_data;
|
|
|
|
union {
|
|
struct{
|
|
SwitchHidCommand hid_command;
|
|
} type0x01;
|
|
|
|
struct {
|
|
u8 nfc_ir_data[0x16];
|
|
} type0x11;
|
|
};
|
|
} PACKED;
|
|
|
|
Result LedsMaskToPlayerNumber(u8 led_mask, u8 *player_number);
|
|
|
|
std::string GetControllerDirectory(const bluetooth::Address *address);
|
|
|
|
class SwitchController {
|
|
|
|
public:
|
|
static constexpr const HardwareID hardware_ids[] = {
|
|
{0x057e, 0x2006}, // Official Joycon(L) Controller
|
|
{0x057e, 0x2007}, // Official Joycon(R) Controller/NES Online Controller
|
|
{0x057e, 0x2009}, // Official Switch Pro Controller
|
|
{0x057e, 0x2017}, // Official SNES Online Controller
|
|
{0x057e, 0x2019}, // Official N64 Online Controller
|
|
{0x057e, 0x201a} // Official Genesis/Megadrive Online Controller
|
|
};
|
|
|
|
SwitchController(const bluetooth::Address *address, HardwareID id)
|
|
: m_address(*address)
|
|
, m_id(id)
|
|
, m_input_mutex(false)
|
|
, m_output_mutex(false) { }
|
|
|
|
virtual ~SwitchController() { };
|
|
|
|
const bluetooth::Address& Address() const { return m_address; }
|
|
|
|
virtual bool IsOfficialController() { return true; }
|
|
|
|
virtual Result Initialize();
|
|
|
|
virtual Result HandleDataReportEvent(const bluetooth::HidReportEventInfo *event_info);
|
|
virtual Result HandleSetReportEvent(const bluetooth::HidReportEventInfo *event_info);
|
|
virtual Result HandleGetReportEvent(const bluetooth::HidReportEventInfo *event_info);
|
|
virtual Result HandleOutputDataReport(const bluetooth::HidReport *report);
|
|
|
|
protected:
|
|
Result WriteDataReport(const bluetooth::HidReport *report);
|
|
Result WriteDataReport(const bluetooth::HidReport *report, u8 response_id, bluetooth::HidReport *out_report);
|
|
Result SetReport(BtdrvBluetoothHhReportType type, const bluetooth::HidReport *report);
|
|
Result GetReport(u8 id, BtdrvBluetoothHhReportType type, bluetooth::HidReport *out_report);
|
|
|
|
virtual void UpdateControllerState(const bluetooth::HidReport *report);
|
|
virtual void ApplyButtonCombos(SwitchButtonData *buttons);
|
|
|
|
bluetooth::Address m_address;
|
|
HardwareID m_id;
|
|
|
|
os::Mutex m_input_mutex;
|
|
bluetooth::HidReport m_input_report;
|
|
|
|
os::Mutex m_output_mutex;
|
|
bluetooth::HidReport m_output_report;
|
|
|
|
std::queue<std::shared_ptr<HidResponse>> m_future_responses;
|
|
};
|
|
|
|
}
|