Add error handling

This commit is contained in:
german77
2022-03-05 13:12:36 -06:00
parent a1ed499ce8
commit c3589d89cc
4 changed files with 348 additions and 206 deletions
+33 -28
View File
@@ -104,6 +104,7 @@ bool Joycons::IsPayloadCorrect(int status, std::span<const u8> buffer) {
input_error_counter = 0; input_error_counter = 0;
return true; return true;
} }
void Joycons::Setup() { void Joycons::Setup() {
// Initialize all controllers as unplugged // Initialize all controllers as unplugged
for (std::size_t port = 0; port < joycon_data.size(); ++port) { for (std::size_t port = 0; port < joycon_data.size(); ++port) {
@@ -123,35 +124,39 @@ void Joycons::ScanThread(std::stop_token stop_token) {
Common::SetCurrentThreadName("yuzu:input:JoyconScanThread"); Common::SetCurrentThreadName("yuzu:input:JoyconScanThread");
scan_thread_running = true; scan_thread_running = true;
std::size_t port = 0; std::size_t port = 0;
while (!stop_token.stop_requested()) { // while (!stop_token.stop_requested()) {
LOG_INFO(Input, "Scanning for devices"); LOG_INFO(Input, "Scanning for devices");
SDL_hid_device_info* devs = SDL_hid_enumerate(0x057e, 0x0); SDL_hid_device_info* devs = SDL_hid_enumerate(0x057e, 0x0);
SDL_hid_device_info* cur_dev = devs; SDL_hid_device_info* cur_dev = devs;
while (cur_dev) { while (cur_dev) {
LOG_WARNING(Input, "Device Found"); LOG_WARNING(Input, "Device Found");
LOG_WARNING(Input, "type : {:04X} {:04X}", cur_dev->vendor_id, cur_dev->product_id); LOG_WARNING(Input, "type : {:04X} {:04X}", cur_dev->vendor_id, cur_dev->product_id);
bool skip_device = false; bool skip_device = false;
for (std::size_t i = 0; i < joycon_data.size(); ++i) { for (std::size_t i = 0; i < joycon_data.size(); ++i) {
if (Joycon::GetDeviceType(cur_dev) == joycon_data[i].type) { Joycon::ControllerType type{};
LOG_WARNING(Input, "Device already exist"); const auto result = Joycon::GetDeviceType(cur_dev, type);
skip_device = true;
break; if (result != Joycon::ErrorCode::Success || type == joycon_data[i].type) {
} LOG_WARNING(Input, "Device already exist, result = {}, type = {}", result, type);
skip_device = true;
break;
} }
if (!skip_device) {
if (Joycon::CheckDeviceAccess(joycon_data[port].joycon_handle, cur_dev)) {
LOG_WARNING(Input, "Device verified and accessible");
++port;
}
}
cur_dev = cur_dev->next;
} }
GetJCEndpoint(); if (!skip_device) {
const auto result = Joycon::CheckDeviceAccess(joycon_data[port].joycon_handle, cur_dev);
std::this_thread::sleep_for(std::chrono::seconds(2)); if (result == Joycon::ErrorCode::Success) {
LOG_WARNING(Input, "Device verified and accessible");
++port;
}
}
cur_dev = cur_dev->next;
} }
GetJCEndpoint();
// std::this_thread::sleep_for(std::chrono::seconds(2));
//}
scan_thread_running = false; scan_thread_running = false;
} }
@@ -181,12 +186,12 @@ void Joycons::GetJCEndpoint() {
} }
LOG_INFO(Input, "Initializing device {}", port); LOG_INFO(Input, "Initializing device {}", port);
joycon.type = Joycon::GetDeviceType(handle); Joycon::GetDeviceType(handle, joycon.type);
// joycon_data[port].mac= Joycon::GetMac(); // joycon_data[port].mac= Joycon::GetMac();
// SetSerialNumber(joycon_data[port]); // SetSerialNumber(joycon_data[port]);
// SetVersionNumber(joycon_data[port]); // SetVersionNumber(joycon_data[port]);
// SetDeviceType(joycon_data[port]); // SetDeviceType(joycon_data[port]);
joycon.calibration = Joycon::GetFactoryCalibrationData(handle, joycon.type); Joycon::GetFactoryCalibrationData(handle, joycon.calibration, joycon.type);
// GetColor(joycon_data[port]); // GetColor(joycon_data[port]);
joycon.rumble_enabled = true; joycon.rumble_enabled = true;
@@ -401,7 +406,7 @@ BasicMotion Joycons::GetMotionInput(std::span<const u8> buffer, Joycon::ImuCalib
} }
Common::Input::VibrationError Joycons::SetRumble(const PadIdentifier& identifier, Common::Input::VibrationError Joycons::SetRumble(const PadIdentifier& identifier,
const Common::Input::VibrationStatus vibration) { const Common::Input::VibrationStatus& vibration) {
const Joycon::VibrationValue native_vibration{ const Joycon::VibrationValue native_vibration{
.low_amplitude = vibration.low_amplitude, .low_amplitude = vibration.low_amplitude,
.low_frequency = vibration.low_frequency, .low_frequency = vibration.low_frequency,
@@ -418,7 +423,7 @@ Joycon::JoyconHandle& Joycons::GetHandle(PadIdentifier identifier) {
PadIdentifier Joycons::GetIdentifier(std::size_t port) const { PadIdentifier Joycons::GetIdentifier(std::size_t port) const {
return { return {
.guid = Common::UUID{Common::INVALID_UUID}, .guid = Common::UUID{Common::InvalidUUID},
.port = port, .port = port,
.pad = 0, .pad = 0,
}; };
+1 -1
View File
@@ -26,7 +26,7 @@ public:
Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
Common::Input::VibrationError SetRumble( Common::Input::VibrationError SetRumble(
const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
private: private:
enum class PadAxes { enum class PadAxes {
+257 -140
View File
@@ -14,9 +14,11 @@ u8 GetCounter(JoyconHandle& joycon_handle) {
return joycon_handle.packet_counter; return joycon_handle.packet_counter;
} }
bool CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device_info) { ErrorCode CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device_info) {
if (GetDeviceType(device_info) == ControllerType::None) { ControllerType controller_type{ControllerType::None};
return false; const auto result = GetDeviceType(device_info, controller_type);
if (result != ErrorCode::Success || controller_type == ControllerType::None) {
return ErrorCode::UnsupportedControllerType;
} }
joycon_handle.handle = joycon_handle.handle =
@@ -24,10 +26,10 @@ bool CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device_
if (!joycon_handle.handle) { if (!joycon_handle.handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id); device_info->vendor_id, device_info->product_id);
return false; return ErrorCode::HandleInUse;
} }
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return true; return ErrorCode::Success;
} }
f32 EncodeRumbleAmplification(f32 amplification) { f32 EncodeRumbleAmplification(f32 amplification) {
@@ -41,7 +43,7 @@ f32 EncodeRumbleAmplification(f32 amplification) {
return roundf((log2f(amplification) * 64) + 200); return roundf((log2f(amplification) * 64) + 200);
} }
void SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration) { ErrorCode SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration) {
std::vector<u8> buffer(Joycon::max_resp_size); std::vector<u8> buffer(Joycon::max_resp_size);
buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY); buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY);
@@ -51,8 +53,7 @@ void SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration) {
for (std::size_t i = 0; i < Joycon::default_buffer.size(); ++i) { for (std::size_t i = 0; i < Joycon::default_buffer.size(); ++i) {
buffer[2 + i] = Joycon::default_buffer[i]; buffer[2 + i] = Joycon::default_buffer[i];
} }
SendData(joycon_handle, buffer, max_resp_size); return SendData(joycon_handle, buffer, max_resp_size);
return;
} }
const u16 encoded_hf = const u16 encoded_hf =
@@ -79,252 +80,354 @@ void SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration) {
buffer[5 + offset] = static_cast<u8>(encoded_amp); buffer[5 + offset] = static_cast<u8>(encoded_amp);
} }
SendData(joycon_handle, buffer, max_resp_size); return SendData(joycon_handle, buffer, max_resp_size);
} }
void SetImuConfig(JoyconHandle& joycon_handle, GyroSensitivity gsen, GyroPerformance gfrec, ErrorCode SetImuConfig(JoyconHandle& joycon_handle, GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec) { AccelerometerSensitivity asen, AccelerometerPerformance afrec) {
const std::vector<u8> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), const std::vector<u8> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
static_cast<u8>(gfrec), static_cast<u8>(afrec)}; static_cast<u8>(gfrec), static_cast<u8>(afrec)};
std::vector<u8> output;
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
SendSubCommand(joycon_handle, SubCommand::SET_IMU_SENSITIVITY, buffer, buffer.size()); const auto result = SendSubCommand(joycon_handle, SubCommand::SET_IMU_SENSITIVITY, buffer,
buffer.size(), output);
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return result;
} }
void SetLedConfig(JoyconHandle& joycon_handle, u8 leds) { ErrorCode SetLedConfig(JoyconHandle& joycon_handle, u8 leds) {
const std::vector<u8> buffer{leds}; const std::vector<u8> buffer{leds};
std::vector<u8> output;
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
SendSubCommand(joycon_handle, SubCommand::SET_PLAYER_LIGHTS, buffer, buffer.size()); const auto result =
SendSubCommand(joycon_handle, SubCommand::SET_PLAYER_LIGHTS, buffer, buffer.size(), output);
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return result;
} }
void SetReportMode(JoyconHandle& joycon_handle, ReportMode report_mode) { ErrorCode SetReportMode(JoyconHandle& joycon_handle, ReportMode report_mode) {
const std::vector<u8> buffer{static_cast<u8>(report_mode)}; const std::vector<u8> buffer{static_cast<u8>(report_mode)};
std::vector<u8> output;
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
SendSubCommand(joycon_handle, SubCommand::SET_REPORT_MODE, buffer, buffer.size()); const auto result =
SendSubCommand(joycon_handle, SubCommand::SET_REPORT_MODE, buffer, buffer.size(), output);
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return result;
} }
Color GetColor(JoyconHandle& joycon_handle) { ErrorCode GetColor(JoyconHandle& joycon_handle, Color& color) {
Color joycon_color;
std::vector<u8> buffer; std::vector<u8> buffer;
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
buffer = ReadSPI(joycon_handle, Joycon::CalAddr::COLOR_DATA, 12); const auto result = ReadSPI(joycon_handle, Joycon::CalAddr::COLOR_DATA, buffer, 12);
joycon_color.body = static_cast<u32>((buffer[2] << 16) | (buffer[1] << 8) | buffer[0]);
joycon_color.buttons = static_cast<u32>((buffer[5] << 16) | (buffer[4] << 8) | buffer[3]);
joycon_color.left_grip = static_cast<u32>((buffer[8] << 16) | (buffer[7] << 8) | buffer[6]);
joycon_color.right_grip = static_cast<u32>((buffer[11] << 16) | (buffer[10] << 8) | buffer[9]);
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return joycon_color; if (result != ErrorCode::Success) {
return result;
}
color.body = static_cast<u32>((buffer[2] << 16) | (buffer[1] << 8) | buffer[0]);
color.buttons = static_cast<u32>((buffer[5] << 16) | (buffer[4] << 8) | buffer[3]);
color.left_grip = static_cast<u32>((buffer[8] << 16) | (buffer[7] << 8) | buffer[6]);
color.right_grip = static_cast<u32>((buffer[11] << 16) | (buffer[10] << 8) | buffer[9]);
return ErrorCode::Success;
} }
std::array<u8, 6> GetMacAddress(JoyconHandle& joycon_handle) { ErrorCode GetMacAddress(JoyconHandle& joycon_handle, MacAddress& mac_address) {
std::array<u8, 6> mac_address{};
wchar_t buffer[255]; wchar_t buffer[255];
const auto result = const auto result =
SDL_hid_get_serial_number_string(joycon_handle.handle, buffer, std::size(buffer)); SDL_hid_get_serial_number_string(joycon_handle.handle, buffer, std::size(buffer));
if (result == -1) { if (result == -1) {
LOG_ERROR(Input, "Unable to get mac address"); LOG_ERROR(Input, "Unable to get mac address {}", result);
return mac_address; return ErrorCode::ErrorReadingData;
} }
for (std::size_t i = 0; i < mac_address.size(); ++i) { for (std::size_t i = 0; i < mac_address.size(); ++i) {
wchar_t value[3] = {buffer[i * 2], buffer[(i * 2) + 1]}; wchar_t value[3] = {buffer[i * 2], buffer[(i * 2) + 1]};
mac_address[i] = static_cast<u8>(std::stoi(value, 0, 16)); mac_address[i] = static_cast<u8>(std::stoi(value, 0, 16));
} }
return mac_address; return ErrorCode::Success;
} }
std::array<u8, 15> GetSerialNumber(JoyconHandle& joycon_handle) { ErrorCode GetSerialNumber(JoyconHandle& joycon_handle, SerialNumber& serial_number) {
std::array<u8, 15> serial_number; std::vector<u8> buffer;
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const std::vector<u8> buffer = ReadSPI(joycon_handle, Joycon::CalAddr::SERIAL_NUMBER, 16); const auto result = ReadSPI(joycon_handle, Joycon::CalAddr::SERIAL_NUMBER, buffer, 16);
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
if (result != ErrorCode::Success) {
return result;
}
for (std::size_t i = 0; i < serial_number.size(); ++i) { for (std::size_t i = 0; i < serial_number.size(); ++i) {
serial_number[i] = buffer[i + 1]; serial_number[i] = buffer[i + 1];
} }
return serial_number; return ErrorCode::Success;
} }
ControllerType GetDeviceType(SDL_hid_device_info* device_info) { ErrorCode GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) {
if (device_info->vendor_id != 0x057e) { constexpr u16 nintendo_vendor_id = 0x057e;
return ControllerType::None; constexpr u16 left_joycon_id = 0x2006;
constexpr u16 right_joycon_id = 0x2007;
constexpr u16 pro_controller_id = 0x2009;
if (device_info->vendor_id != nintendo_vendor_id) {
return ErrorCode::UnsupportedControllerType;
} }
switch (device_info->product_id) { switch (device_info->product_id) {
case 0x2006: case left_joycon_id:
return ControllerType::Left; controller_type = ControllerType::Left;
case 0x2007: break;
return ControllerType::Right; case right_joycon_id:
case 0x2009: controller_type = ControllerType::Right;
return ControllerType::Pro; break;
case pro_controller_id:
controller_type = ControllerType::Pro;
break;
default: default:
return ControllerType::None; controller_type = ControllerType::None;
break;
} }
return ErrorCode::Success;
} }
ControllerType GetDeviceType(JoyconHandle& joycon_handle) { ErrorCode GetDeviceType(JoyconHandle& joycon_handle, ControllerType& controller_type) {
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const std::vector<u8> buffer = ReadSPI(joycon_handle, Joycon::CalAddr::DEVICE_TYPE, 1);
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return static_cast<Joycon::ControllerType>(buffer[0]);
}
u16 GetVersionNumber([[maybe_unused]] JoyconHandle& joycon_handle) {
// Not implemented
return 0;
}
JoyStickCalibration GetLeftJoyStickCalibration(JoyconHandle& joycon_handle,
bool is_factory_calibration) {
JoyStickCalibration joystick{};
std::vector<u8> buffer; std::vector<u8> buffer;
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const auto result = ReadSPI(joycon_handle, Joycon::CalAddr::DEVICE_TYPE, buffer, 1);
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
if (result != ErrorCode::Success) {
return result;
}
controller_type = static_cast<Joycon::ControllerType>(buffer[0]);
return ErrorCode::Success;
}
ErrorCode GetVersionNumber([[maybe_unused]] JoyconHandle& joycon_handle, FirmwareVersion& version) {
// Not implemented
version = FirmwareVersion::Rev_0;
return ErrorCode::Success;
}
ErrorCode GetLeftJoyStickCalibration(JoyconHandle& joycon_handle, JoyStickCalibration& calibration,
bool is_factory_calibration) {
std::vector<u8> buffer;
ErrorCode result{ErrorCode::Unknown};
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
if (is_factory_calibration) { if (is_factory_calibration) {
buffer = ReadSPI(joycon_handle, CalAddr::FACT_LEFT_DATA, 9); result = ReadSPI(joycon_handle, CalAddr::FACT_LEFT_DATA, buffer, 9);
} else { } else {
buffer = ReadSPI(joycon_handle, CalAddr::USER_LEFT_DATA, 9); result = ReadSPI(joycon_handle, CalAddr::USER_LEFT_DATA, buffer, 9);
} }
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
joystick.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]); if (result != ErrorCode::Success) {
joystick.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4)); return result;
joystick.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]); }
joystick.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
joystick.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]); calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
joystick.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4)); calibration.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
calibration.x.center = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
calibration.y.center = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
calibration.x.min = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
calibration.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
// Nintendo fix for drifting stick // Nintendo fix for drifting stick
// buffer = ReadSPI(0x60, 0x86 , 16); // result = ReadSPI(0x60, 0x86 ,buffer, 16);
// joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]); // calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
return joystick; return ErrorCode::Success;
} }
JoyStickCalibration GetRightJoyStickCalibration(JoyconHandle& joycon_handle, ErrorCode GetRightJoyStickCalibration(JoyconHandle& joycon_handle, JoyStickCalibration& calibration,
bool is_factory_calibration) { bool is_factory_calibration) {
JoyStickCalibration joystick{};
std::vector<u8> buffer; std::vector<u8> buffer;
ErrorCode result{ErrorCode::Unknown};
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
if (is_factory_calibration) { if (is_factory_calibration) {
buffer = ReadSPI(joycon_handle, CalAddr::FACT_RIGHT_DATA, 9); result = ReadSPI(joycon_handle, CalAddr::FACT_RIGHT_DATA, buffer, 9);
} else { } else {
buffer = ReadSPI(joycon_handle, CalAddr::USER_RIGHT_DATA, 9); result = ReadSPI(joycon_handle, CalAddr::USER_RIGHT_DATA, buffer, 9);
} }
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
joystick.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]); if (result != ErrorCode::Success) {
joystick.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4)); return result;
joystick.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]); }
joystick.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
joystick.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]); calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
joystick.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4)); calibration.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
calibration.x.min = static_cast<u16>(((buffer[4] & 0x0F) << 8) | buffer[3]);
calibration.y.min = static_cast<u16>((buffer[5] << 4) | (buffer[4] >> 4));
calibration.x.max = static_cast<u16>(((buffer[7] & 0x0F) << 8) | buffer[6]);
calibration.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
// Nintendo fix for drifting stick // Nintendo fix for drifting stick
// buffer = ReadSPI(0x60, 0x98 , 16); // buffer = ReadSPI(0x60, 0x98 , 16);
// joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]); // joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
return joystick; return ErrorCode::Success;
} }
ImuCalibration GetImuCalibration(JoyconHandle& joycon_handle, bool is_factory_calibration) { ErrorCode GetImuCalibration(JoyconHandle& joycon_handle, ImuCalibration& calibration,
ImuCalibration imu{}; bool is_factory_calibration) {
std::vector<u8> buffer; std::vector<u8> buffer;
ErrorCode result{ErrorCode::Unknown};
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
if (is_factory_calibration) { if (is_factory_calibration) {
buffer = ReadSPI(joycon_handle, CalAddr::FACT_IMU_DATA, 24); result = ReadSPI(joycon_handle, CalAddr::FACT_IMU_DATA, buffer, 24);
} else { } else {
buffer = ReadSPI(joycon_handle, CalAddr::USER_IMU_DATA, 24); result = ReadSPI(joycon_handle, CalAddr::USER_IMU_DATA, buffer, 24);
} }
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
for (std::size_t i = 0; i < imu.accelerometer.size(); ++i) {
const std::size_t index = i * 2; if (result != ErrorCode::Success) {
imu.accelerometer[i].offset = static_cast<s16>(buffer[index] | (buffer[index + 1] << 8)); return result;
imu.accelerometer[i].scale = static_cast<s16>(buffer[index + 6] | (buffer[index + 7] << 8));
} }
for (std::size_t i = 0; i < imu.gyro.size(); ++i) {
for (std::size_t i = 0; i < calibration.accelerometer.size(); ++i) {
const std::size_t index = i * 2; const std::size_t index = i * 2;
imu.gyro[i].offset = static_cast<s16>(buffer[index + 12] | (buffer[index + 13] << 8)); calibration.accelerometer[i].offset =
imu.gyro[i].scale = static_cast<s16>(buffer[index + 18] | (buffer[index + 19] << 8)); static_cast<s16>(buffer[index] | (buffer[index + 1] << 8));
calibration.accelerometer[i].scale =
static_cast<s16>(buffer[index + 6] | (buffer[index + 7] << 8));
} }
return imu; for (std::size_t i = 0; i < calibration.gyro.size(); ++i) {
const std::size_t index = i * 2;
calibration.gyro[i].offset =
static_cast<s16>(buffer[index + 12] | (buffer[index + 13] << 8));
calibration.gyro[i].scale =
static_cast<s16>(buffer[index + 18] | (buffer[index + 19] << 8));
}
return ErrorCode::Success;
} }
CalibrationData GetUserCalibrationData(JoyconHandle& joycon_handle, ErrorCode GetUserCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type) { ControllerType controller_type) {
CalibrationData calibration{}; ErrorCode result{ErrorCode::Unknown};
switch (controller_type) { switch (controller_type) {
case ControllerType::Left: case ControllerType::Left:
calibration.left_stick = GetLeftJoyStickCalibration(joycon_handle, false); result = GetLeftJoyStickCalibration(joycon_handle, calibration_data.left_stick, false);
if (result != ErrorCode::Success) {
return result;
}
break; break;
case ControllerType::Right: case ControllerType::Right:
calibration.right_stick = GetRightJoyStickCalibration(joycon_handle, false); result = GetRightJoyStickCalibration(joycon_handle, calibration_data.right_stick, false);
if (result != ErrorCode::Success) {
return result;
}
break; break;
case Joycon::ControllerType::Pro: case Joycon::ControllerType::Pro:
calibration.left_stick = GetLeftJoyStickCalibration(joycon_handle, false); result = GetLeftJoyStickCalibration(joycon_handle, calibration_data.left_stick, false);
calibration.right_stick = GetRightJoyStickCalibration(joycon_handle, false); if (result != ErrorCode::Success) {
return result;
}
result = GetRightJoyStickCalibration(joycon_handle, calibration_data.right_stick, false);
if (result != ErrorCode::Success) {
return result;
}
break; break;
default: default:
break; return ErrorCode::UnsupportedControllerType;
} }
calibration.imu = GetImuCalibration(joycon_handle, false); result = GetImuCalibration(joycon_handle, calibration_data.imu, false);
return calibration;
if (result != ErrorCode::Success) {
return result;
}
return ErrorCode::Success;
} }
CalibrationData GetFactoryCalibrationData(JoyconHandle& joycon_handle, ErrorCode GetFactoryCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type) { ControllerType controller_type) {
CalibrationData calibration{}; ErrorCode result{ErrorCode::Unknown};
switch (controller_type) { switch (controller_type) {
case ControllerType::Left: case ControllerType::Left:
calibration.left_stick = GetLeftJoyStickCalibration(joycon_handle, true); result = GetLeftJoyStickCalibration(joycon_handle, calibration_data.left_stick, true);
if (result != ErrorCode::Success) {
return result;
}
break; break;
case ControllerType::Right: case ControllerType::Right:
calibration.right_stick = GetRightJoyStickCalibration(joycon_handle, true); result = GetRightJoyStickCalibration(joycon_handle, calibration_data.right_stick, true);
if (result != ErrorCode::Success) {
return result;
}
break; break;
case Joycon::ControllerType::Pro: case Joycon::ControllerType::Pro:
calibration.left_stick = GetLeftJoyStickCalibration(joycon_handle, true); result = GetLeftJoyStickCalibration(joycon_handle, calibration_data.left_stick, true);
calibration.right_stick = GetRightJoyStickCalibration(joycon_handle, true); if (result != ErrorCode::Success) {
return result;
}
result = GetRightJoyStickCalibration(joycon_handle, calibration_data.right_stick, true);
if (result != ErrorCode::Success) {
return result;
}
break; break;
default: default:
break; return ErrorCode::UnsupportedControllerType;
} }
calibration.imu = GetImuCalibration(joycon_handle, true); result = GetImuCalibration(joycon_handle, calibration_data.imu, true);
return calibration;
if (result != ErrorCode::Success) {
return result;
}
return ErrorCode::Success;
} }
void EnableImu(JoyconHandle& joycon_handle, bool enable) { ErrorCode EnableImu(JoyconHandle& joycon_handle, bool enable) {
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)}; const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)};
SendSubCommand(joycon_handle, SubCommand::ENABLE_IMU, buffer, buffer.size()); std::vector<u8> output;
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
}
void EnableRumble(JoyconHandle& joycon_handle, bool enable) {
SDL_hid_set_nonblocking(joycon_handle.handle, 0); SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)}; const auto result =
SendSubCommand(joycon_handle, SubCommand::ENABLE_VIBRATION, buffer, buffer.size()); SendSubCommand(joycon_handle, SubCommand::ENABLE_IMU, buffer, buffer.size(), output);
SDL_hid_set_nonblocking(joycon_handle.handle, 1); SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return result;
} }
void SendData(JoyconHandle& joycon_handle, std::span<const u8> buffer, std::size_t size) { ErrorCode EnableRumble(JoyconHandle& joycon_handle, bool enable) {
SDL_hid_write(joycon_handle.handle, buffer.data(), size); const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)};
std::vector<u8> output;
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const auto result =
SendSubCommand(joycon_handle, SubCommand::ENABLE_VIBRATION, buffer, buffer.size(), output);
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return result;
} }
std::vector<u8> GetResponse(JoyconHandle& joycon_handle, SubCommand sc) { ErrorCode SendData(JoyconHandle& joycon_handle, std::span<const u8> buffer, std::size_t size) {
const auto result = SDL_hid_write(joycon_handle.handle, buffer.data(), size);
if (result == -1) {
return ErrorCode::ErrorWritingData;
}
return ErrorCode::Success;
}
ErrorCode GetResponse(JoyconHandle& joycon_handle, SubCommand sc, std::vector<u8>& output) {
constexpr int timeout_mili = 100; constexpr int timeout_mili = 100;
constexpr int max_tries = 10;
int tries = 0; int tries = 0;
std::vector<u8> buffer(max_resp_size); std::vector<u8> buffer(max_resp_size);
do { do {
int result = int result =
SDL_hid_read_timeout(joycon_handle.handle, buffer.data(), max_resp_size, timeout_time); SDL_hid_read_timeout(joycon_handle.handle, buffer.data(), max_resp_size, timeout_mili);
if (result < 1) { if (result < 1) {
LOG_ERROR(Input, "No response from joycon"); LOG_ERROR(Input, "No response from joycon");
} }
tries++; tries++;
} while (tries < 10 && buffer[0] != 0x21 && buffer[14] != static_cast<u8>(sc)); } while (tries < max_tries && buffer[0] != 0x21 && buffer[14] != static_cast<u8>(sc));
return buffer;
if (tries >= max_tries) {
return ErrorCode::Timeout;
}
if (buffer[0] != 0x21 && buffer[14] != static_cast<u8>(sc)) {
return ErrorCode::WrongReply;
}
output = buffer;
return ErrorCode::Success;
} }
std::vector<u8> SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, ErrorCode SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, std::span<const u8> buffer,
std::span<const u8> buffer, std::size_t size) { std::size_t size, std::vector<u8>& output) {
std::vector<u8> local_buffer(size + 11); std::vector<u8> local_buffer(size + 11);
local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD); local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD);
@@ -337,26 +440,40 @@ std::vector<u8> SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc,
local_buffer[11 + i] = buffer[i]; local_buffer[11 + i] = buffer[i];
} }
SendData(joycon_handle, local_buffer, size + 11); auto result = SendData(joycon_handle, local_buffer, size + 11);
return GetResponse(joycon_handle, sc);
if (result != ErrorCode::Success) {
return result;
}
result = GetResponse(joycon_handle, sc, output);
return ErrorCode::Success;
} }
std::vector<u8> ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, u8 size) { ErrorCode ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, std::vector<u8>& output, u8 size) {
constexpr std::size_t max_tries = 10; constexpr std::size_t max_tries = 10;
std::size_t tries = 0;
std::vector<u8> buffer = {0x00, 0x00, 0x00, 0x00, size}; std::vector<u8> buffer = {0x00, 0x00, 0x00, 0x00, size};
std::vector<u8> local_buffer(size + 20); std::vector<u8> local_buffer(size + 20);
buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF);
buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8); buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8);
for (std::size_t i = 0; i < max_tries; ++i) { do {
local_buffer = const auto result = SendSubCommand(joycon_handle, SubCommand::SPI_FLASH_READ, buffer,
SendSubCommand(joycon_handle, SubCommand::SPI_FLASH_READ, buffer, buffer.size()); buffer.size(), local_buffer);
// Recieved packed has to match with the requested address if (result != ErrorCode::Success) {
if (local_buffer[15] == buffer[0] && local_buffer[16] == buffer[1]) { return result;
break;
} }
tries++;
} while (tries < max_tries && (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]));
if (tries >= max_tries) {
return ErrorCode::Timeout;
} }
return std::vector<u8>(local_buffer.begin() + 20, local_buffer.end());
output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.end());
return ErrorCode::Success;
} }
} // namespace InputCommon::Joycon } // namespace InputCommon::Joycon
+57 -37
View File
@@ -18,6 +18,9 @@ namespace InputCommon::Joycon {
constexpr u32 max_resp_size = 49; constexpr u32 max_resp_size = 49;
constexpr std::array<u8, 8> default_buffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; constexpr std::array<u8, 8> default_buffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40};
using MacAddress = std::array<u8, 6>;
using SerialNumber = std::array<u8, 15>;
enum class ControllerType { enum class ControllerType {
None, None,
Left, Left,
@@ -170,6 +173,21 @@ enum class AccelerometerPerformance {
HZ100, // Default HZ100, // Default
}; };
enum class FirmwareVersion {
Rev_0,
};
enum class ErrorCode {
Success,
WrongReply,
Timeout,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
ErrorWritingData,
Unknown,
};
struct ImuSensorCalibration { struct ImuSensorCalibration {
s16 offset; s16 offset;
s16 scale; s16 scale;
@@ -226,21 +244,10 @@ u8 GetCounter(JoyconHandle& joycon_handle);
/** /**
* Verifies and sets the joycon_handle if device is valid * Verifies and sets the joycon_handle if device is valid
* @param joycon_handle device to send the data * @param joycon_handle device to send the data
* @param device device info from the driver * @param device info from the driver
* @returns true if the device is valid * @returns true if the device is valid
*/ */
bool CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device); ErrorCode CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device);
/**
* Sends a request to set the configuration of the motion sensor
* @param joycon_handle device to send the data
* @param gsen gyro sensitivity
* @param gfrec gyro update frequency
* @param asen accelerometer sensitivity
* @param afrec accelerometer update frequency
*/
void SetImuConfig(JoyconHandle& joycon_handle, GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec);
/** /**
* Encondes the amplitude to be sended on a packet * Encondes the amplitude to be sended on a packet
@@ -254,63 +261,74 @@ f32 EncodeRumbleAmplification(f32 amplification);
* @param joycon_handle device to send the data * @param joycon_handle device to send the data
* @param vibration amplitude and frequency of the vibration * @param vibration amplitude and frequency of the vibration
*/ */
void SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration); ErrorCode SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration);
/**
* Sends a request to set the configuration of the motion sensor
* @param joycon_handle device to send the data
* @param gsen gyro sensitivity
* @param gfrec gyro update frequency
* @param asen accelerometer sensitivity
* @param afrec accelerometer update frequency
*/
ErrorCode SetImuConfig(JoyconHandle& joycon_handle, GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec);
/** /**
* Sends a request to set the polling mode of the joycon * Sends a request to set the polling mode of the joycon
* @param joycon_handle device to send the data * @param joycon_handle device to send the data
* @param report_mode polling mode to be set * @param report_mode polling mode to be set
*/ */
void SetReportMode(JoyconHandle& joycon_handle, Joycon::ReportMode report_mode); ErrorCode SetReportMode(JoyconHandle& joycon_handle, Joycon::ReportMode report_mode);
/** /**
* Sends a request to set a specific led pattern * Sends a request to set a specific led pattern
* @param joycon_handle device to send the data * @param joycon_handle device to send the data
* @param leds led pattern to be set * @param leds led pattern to be set
*/ */
void SetLedConfig(JoyconHandle& joycon_handle, u8 leds); ErrorCode SetLedConfig(JoyconHandle& joycon_handle, u8 leds);
/** /**
* Sends a request to obtain the joycon colors from memory * Sends a request to obtain the joycon colors from memory
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @returns color object with the colors of the joycon * @returns color object with the colors of the joycon
*/ */
Color GetColor(JoyconHandle& joycon_handle); ErrorCode GetColor(JoyconHandle& joycon_handle, Color& color);
/** /**
* Sends a request to obtain the joycon mac address from handle * Sends a request to obtain the joycon mac address from handle
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @returns array containing the mac address * @returns array containing the mac address
*/ */
std::array<u8, 6> GetMacAddress(JoyconHandle& joycon_handle); ErrorCode GetMacAddress(JoyconHandle& joycon_handle, MacAddress& mac_address);
/** /**
* Sends a request to obtain the joycon serial number from memory * Sends a request to obtain the joycon serial number from memory
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @returns array containing the serial number * @returns array containing the serial number
*/ */
std::array<u8, 15> GetSerialNumber(JoyconHandle& joycon_handle); ErrorCode GetSerialNumber(JoyconHandle& joycon_handle, SerialNumber& serial_number);
/** /**
* Sends a request to obtain the joycon type from handle * Sends a request to obtain the joycon type from handle
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @returns controller type of the joycon * @returns controller type of the joycon
*/ */
ControllerType GetDeviceType(JoyconHandle& joycon_handle); ErrorCode GetDeviceType(JoyconHandle& joycon_handle, ControllerType& controller_type);
/** /**
* Sends a request to obtain the joycon tyoe from memory * Sends a request to obtain the joycon tyoe from memory
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @returns controller type of the joycon * @returns controller type of the joycon
*/ */
ControllerType GetDeviceType(SDL_hid_device_info* device_info); ErrorCode GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type);
/** /**
* Sends a request to obtain the joycon firmware version * Sends a request to obtain the joycon firmware version
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @returns u16 with the version number * @returns u16 with the version number
*/ */
u16 GetVersionNumber(JoyconHandle& joycon_handle); ErrorCode GetVersionNumber(JoyconHandle& joycon_handle, FirmwareVersion& version);
/** /**
* Sends a request to obtain the left stick calibration from memory * Sends a request to obtain the left stick calibration from memory
@@ -318,8 +336,8 @@ u16 GetVersionNumber(JoyconHandle& joycon_handle);
* @param is_factory_calibration if true factory values will be returned * @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the left joystick * @returns JoyStickCalibration of the left joystick
*/ */
JoyStickCalibration GetLeftJoyStickCalibration(JoyconHandle& joycon_handle, ErrorCode GetLeftJoyStickCalibration(JoyconHandle& joycon_handle, JoyStickCalibration& calibration,
bool is_factory_calibration); bool is_factory_calibration);
/** /**
* Sends a request to obtain the right stick calibration from memory * Sends a request to obtain the right stick calibration from memory
@@ -327,8 +345,8 @@ JoyStickCalibration GetLeftJoyStickCalibration(JoyconHandle& joycon_handle,
* @param is_factory_calibration if true factory values will be returned * @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the left joystick * @returns JoyStickCalibration of the left joystick
*/ */
JoyStickCalibration GetRightJoyStickCalibration(JoyconHandle& joycon_handle, ErrorCode GetRightJoyStickCalibration(JoyconHandle& joycon_handle, JoyStickCalibration& calibration,
bool is_factory_calibration); bool is_factory_calibration);
/** /**
* Sends a request to obtain the motion calibration from memory * Sends a request to obtain the motion calibration from memory
@@ -336,7 +354,8 @@ JoyStickCalibration GetRightJoyStickCalibration(JoyconHandle& joycon_handle,
* @param is_factory_calibration if true factory values will be returned * @param is_factory_calibration if true factory values will be returned
* @returns ImuCalibration of the joystick motion * @returns ImuCalibration of the joystick motion
*/ */
ImuCalibration GetImuCalibration(JoyconHandle& joycon_handle, bool is_factory_calibration); ErrorCode GetImuCalibration(JoyconHandle& joycon_handle, ImuCalibration& calibration,
bool is_factory_calibration);
/** /**
* Requests user calibration from the joystick * Requests user calibration from the joystick
@@ -344,7 +363,8 @@ ImuCalibration GetImuCalibration(JoyconHandle& joycon_handle, bool is_factory_ca
* @param controller_type type of calibration to be requested * @param controller_type type of calibration to be requested
* @returns User CalibrationData of the joystick * @returns User CalibrationData of the joystick
*/ */
CalibrationData GetUserCalibrationData(JoyconHandle& joycon_handle, ControllerType controller_type); ErrorCode GetUserCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type);
/** /**
* Requests factory calibration from the joystick * Requests factory calibration from the joystick
@@ -352,22 +372,22 @@ CalibrationData GetUserCalibrationData(JoyconHandle& joycon_handle, ControllerTy
* @param controller_type type of calibration to be requested * @param controller_type type of calibration to be requested
* @returns Factory CalibrationData of the joystick * @returns Factory CalibrationData of the joystick
*/ */
CalibrationData GetFactoryCalibrationData(JoyconHandle& joycon_handle, ErrorCode GetFactoryCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type); ControllerType controller_type);
/** /**
* Sends a request to enable motion * Sends a request to enable motion
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @param is_factory_calibration if true motion data will be enabled * @param is_factory_calibration if true motion data will be enabled
*/ */
void EnableImu(JoyconHandle& joycon_handle, bool enable); ErrorCode EnableImu(JoyconHandle& joycon_handle, bool enable);
/** /**
* Sends a request to enable vibrations * Sends a request to enable vibrations
* @param joycon_handle device to read the data * @param joycon_handle device to read the data
* @param is_factory_calibration if true rumble will be enabled * @param is_factory_calibration if true rumble will be enabled
*/ */
void EnableRumble(JoyconHandle& joycon_handle, bool enable); ErrorCode EnableRumble(JoyconHandle& joycon_handle, bool enable);
/** /**
* Sends data to the joycon device * Sends data to the joycon device
@@ -375,7 +395,7 @@ void EnableRumble(JoyconHandle& joycon_handle, bool enable);
* @param buffer data to be send * @param buffer data to be send
* @param size size in bytes of the buffer * @param size size in bytes of the buffer
*/ */
void SendData(JoyconHandle& joycon_handle, std::span<const u8> buffer, std::size_t size); ErrorCode SendData(JoyconHandle& joycon_handle, std::span<const u8> buffer, std::size_t size);
/** /**
* Waits for incoming data of the joycon device that matchs the subcommand * Waits for incoming data of the joycon device that matchs the subcommand
@@ -383,7 +403,7 @@ void SendData(JoyconHandle& joycon_handle, std::span<const u8> buffer, std::size
* @param sub_command type of data to be returned * @param sub_command type of data to be returned
* @returns a buffer containing the responce * @returns a buffer containing the responce
*/ */
std::vector<u8> GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command); ErrorCode GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command, std::vector<u8>& output);
/** /**
* Sends data to the joycon device * Sends data to the joycon device
@@ -391,8 +411,8 @@ std::vector<u8> GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command)
* @param buffer data to be send * @param buffer data to be send
* @param size size in bytes of the buffer * @param size size in bytes of the buffer
*/ */
std::vector<u8> SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, ErrorCode SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, std::span<const u8> buffer,
std::span<const u8> buffer, std::size_t size); std::size_t size, std::vector<u8>& output);
/** /**
* Sends data to the joycon device * Sends data to the joycon device
@@ -400,6 +420,6 @@ std::vector<u8> SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc,
* @param buffer data to be send * @param buffer data to be send
* @param size size in bytes of the buffer * @param size size in bytes of the buffer
*/ */
std::vector<u8> ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, u8 size); ErrorCode ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, std::vector<u8>& output, u8 size);
} // namespace InputCommon::Joycon } // namespace InputCommon::Joycon