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;
return true;
}
void Joycons::Setup() {
// Initialize all controllers as unplugged
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");
scan_thread_running = true;
std::size_t port = 0;
while (!stop_token.stop_requested()) {
LOG_INFO(Input, "Scanning for devices");
SDL_hid_device_info* devs = SDL_hid_enumerate(0x057e, 0x0);
SDL_hid_device_info* cur_dev = devs;
// while (!stop_token.stop_requested()) {
LOG_INFO(Input, "Scanning for devices");
SDL_hid_device_info* devs = SDL_hid_enumerate(0x057e, 0x0);
SDL_hid_device_info* cur_dev = devs;
while (cur_dev) {
LOG_WARNING(Input, "Device Found");
LOG_WARNING(Input, "type : {:04X} {:04X}", cur_dev->vendor_id, cur_dev->product_id);
bool skip_device = false;
while (cur_dev) {
LOG_WARNING(Input, "Device Found");
LOG_WARNING(Input, "type : {:04X} {:04X}", cur_dev->vendor_id, cur_dev->product_id);
bool skip_device = false;
for (std::size_t i = 0; i < joycon_data.size(); ++i) {
if (Joycon::GetDeviceType(cur_dev) == joycon_data[i].type) {
LOG_WARNING(Input, "Device already exist");
skip_device = true;
break;
}
for (std::size_t i = 0; i < joycon_data.size(); ++i) {
Joycon::ControllerType type{};
const auto result = Joycon::GetDeviceType(cur_dev, type);
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();
std::this_thread::sleep_for(std::chrono::seconds(2));
if (!skip_device) {
const auto result = Joycon::CheckDeviceAccess(joycon_data[port].joycon_handle, cur_dev);
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;
}
@@ -181,12 +186,12 @@ void Joycons::GetJCEndpoint() {
}
LOG_INFO(Input, "Initializing device {}", port);
joycon.type = Joycon::GetDeviceType(handle);
Joycon::GetDeviceType(handle, joycon.type);
// joycon_data[port].mac= Joycon::GetMac();
// SetSerialNumber(joycon_data[port]);
// SetVersionNumber(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]);
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,
const Common::Input::VibrationStatus vibration) {
const Common::Input::VibrationStatus& vibration) {
const Joycon::VibrationValue native_vibration{
.low_amplitude = vibration.low_amplitude,
.low_frequency = vibration.low_frequency,
@@ -418,7 +423,7 @@ Joycon::JoyconHandle& Joycons::GetHandle(PadIdentifier identifier) {
PadIdentifier Joycons::GetIdentifier(std::size_t port) const {
return {
.guid = Common::UUID{Common::INVALID_UUID},
.guid = Common::UUID{Common::InvalidUUID},
.port = port,
.pad = 0,
};
+1 -1
View File
@@ -26,7 +26,7 @@ public:
Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;
Common::Input::VibrationError SetRumble(
const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override;
const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;
private:
enum class PadAxes {
+257 -140
View File
@@ -14,9 +14,11 @@ u8 GetCounter(JoyconHandle& joycon_handle) {
return joycon_handle.packet_counter;
}
bool CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device_info) {
if (GetDeviceType(device_info) == ControllerType::None) {
return false;
ErrorCode CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device_info) {
ControllerType controller_type{ControllerType::None};
const auto result = GetDeviceType(device_info, controller_type);
if (result != ErrorCode::Success || controller_type == ControllerType::None) {
return ErrorCode::UnsupportedControllerType;
}
joycon_handle.handle =
@@ -24,10 +26,10 @@ bool CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device_
if (!joycon_handle.handle) {
LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.",
device_info->vendor_id, device_info->product_id);
return false;
return ErrorCode::HandleInUse;
}
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return true;
return ErrorCode::Success;
}
f32 EncodeRumbleAmplification(f32 amplification) {
@@ -41,7 +43,7 @@ f32 EncodeRumbleAmplification(f32 amplification) {
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);
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) {
buffer[2 + i] = Joycon::default_buffer[i];
}
SendData(joycon_handle, buffer, max_resp_size);
return;
return SendData(joycon_handle, buffer, max_resp_size);
}
const u16 encoded_hf =
@@ -79,252 +80,354 @@ void SetVibration(JoyconHandle& joycon_handle, VibrationValue vibration) {
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,
AccelerometerSensitivity asen, AccelerometerPerformance afrec) {
ErrorCode SetImuConfig(JoyconHandle& joycon_handle, GyroSensitivity gsen, GyroPerformance gfrec,
AccelerometerSensitivity asen, AccelerometerPerformance afrec) {
const std::vector<u8> buffer{static_cast<u8>(gsen), static_cast<u8>(asen),
static_cast<u8>(gfrec), static_cast<u8>(afrec)};
std::vector<u8> output;
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);
return result;
}
void SetLedConfig(JoyconHandle& joycon_handle, u8 leds) {
ErrorCode SetLedConfig(JoyconHandle& joycon_handle, u8 leds) {
const std::vector<u8> buffer{leds};
std::vector<u8> output;
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);
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)};
std::vector<u8> output;
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);
return result;
}
Color GetColor(JoyconHandle& joycon_handle) {
Color joycon_color;
ErrorCode GetColor(JoyconHandle& joycon_handle, Color& color) {
std::vector<u8> buffer;
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
buffer = ReadSPI(joycon_handle, Joycon::CalAddr::COLOR_DATA, 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]);
const auto result = ReadSPI(joycon_handle, Joycon::CalAddr::COLOR_DATA, buffer, 12);
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) {
std::array<u8, 6> mac_address{};
ErrorCode GetMacAddress(JoyconHandle& joycon_handle, MacAddress& mac_address) {
wchar_t buffer[255];
const auto result =
SDL_hid_get_serial_number_string(joycon_handle.handle, buffer, std::size(buffer));
if (result == -1) {
LOG_ERROR(Input, "Unable to get mac address");
return mac_address;
LOG_ERROR(Input, "Unable to get mac address {}", result);
return ErrorCode::ErrorReadingData;
}
for (std::size_t i = 0; i < mac_address.size(); ++i) {
wchar_t value[3] = {buffer[i * 2], buffer[(i * 2) + 1]};
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) {
std::array<u8, 15> serial_number;
ErrorCode GetSerialNumber(JoyconHandle& joycon_handle, SerialNumber& serial_number) {
std::vector<u8> buffer;
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);
if (result != ErrorCode::Success) {
return result;
}
for (std::size_t i = 0; i < serial_number.size(); ++i) {
serial_number[i] = buffer[i + 1];
}
return serial_number;
return ErrorCode::Success;
}
ControllerType GetDeviceType(SDL_hid_device_info* device_info) {
if (device_info->vendor_id != 0x057e) {
return ControllerType::None;
ErrorCode GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) {
constexpr u16 nintendo_vendor_id = 0x057e;
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) {
case 0x2006:
return ControllerType::Left;
case 0x2007:
return ControllerType::Right;
case 0x2009:
return ControllerType::Pro;
case left_joycon_id:
controller_type = ControllerType::Left;
break;
case right_joycon_id:
controller_type = ControllerType::Right;
break;
case pro_controller_id:
controller_type = ControllerType::Pro;
break;
default:
return ControllerType::None;
controller_type = ControllerType::None;
break;
}
return ErrorCode::Success;
}
ControllerType GetDeviceType(JoyconHandle& joycon_handle) {
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{};
ErrorCode GetDeviceType(JoyconHandle& joycon_handle, ControllerType& controller_type) {
std::vector<u8> buffer;
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) {
buffer = ReadSPI(joycon_handle, CalAddr::FACT_LEFT_DATA, 9);
result = ReadSPI(joycon_handle, CalAddr::FACT_LEFT_DATA, buffer, 9);
} 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);
joystick.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
joystick.y.max = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
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]);
joystick.y.min = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
if (result != ErrorCode::Success) {
return result;
}
calibration.x.max = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
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
// buffer = ReadSPI(0x60, 0x86 , 16);
// joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
return joystick;
// result = ReadSPI(0x60, 0x86 ,buffer, 16);
// calibration.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
return ErrorCode::Success;
}
JoyStickCalibration GetRightJoyStickCalibration(JoyconHandle& joycon_handle,
bool is_factory_calibration) {
JoyStickCalibration joystick{};
ErrorCode GetRightJoyStickCalibration(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) {
buffer = ReadSPI(joycon_handle, CalAddr::FACT_RIGHT_DATA, 9);
result = ReadSPI(joycon_handle, CalAddr::FACT_RIGHT_DATA, buffer, 9);
} 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);
joystick.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
joystick.y.center = static_cast<u16>((buffer[2] << 4) | (buffer[1] >> 4));
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]);
joystick.y.max = static_cast<u16>((buffer[8] << 4) | (buffer[7] >> 4));
if (result != ErrorCode::Success) {
return result;
}
calibration.x.center = static_cast<u16>(((buffer[1] & 0x0F) << 8) | buffer[0]);
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
// buffer = ReadSPI(0x60, 0x98 , 16);
// joystick.deadzone = (u16)((buffer[4] << 8) & 0xF00 | buffer[3]);
return joystick;
return ErrorCode::Success;
}
ImuCalibration GetImuCalibration(JoyconHandle& joycon_handle, bool is_factory_calibration) {
ImuCalibration imu{};
ErrorCode GetImuCalibration(JoyconHandle& joycon_handle, ImuCalibration& 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) {
buffer = ReadSPI(joycon_handle, CalAddr::FACT_IMU_DATA, 24);
result = ReadSPI(joycon_handle, CalAddr::FACT_IMU_DATA, buffer, 24);
} 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);
for (std::size_t i = 0; i < imu.accelerometer.size(); ++i) {
const std::size_t index = i * 2;
imu.accelerometer[i].offset = static_cast<s16>(buffer[index] | (buffer[index + 1] << 8));
imu.accelerometer[i].scale = static_cast<s16>(buffer[index + 6] | (buffer[index + 7] << 8));
if (result != ErrorCode::Success) {
return result;
}
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;
imu.gyro[i].offset = static_cast<s16>(buffer[index + 12] | (buffer[index + 13] << 8));
imu.gyro[i].scale = static_cast<s16>(buffer[index + 18] | (buffer[index + 19] << 8));
calibration.accelerometer[i].offset =
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,
ControllerType controller_type) {
CalibrationData calibration{};
ErrorCode GetUserCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type) {
ErrorCode result{ErrorCode::Unknown};
switch (controller_type) {
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;
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;
case Joycon::ControllerType::Pro:
calibration.left_stick = GetLeftJoyStickCalibration(joycon_handle, false);
calibration.right_stick = GetRightJoyStickCalibration(joycon_handle, false);
result = GetLeftJoyStickCalibration(joycon_handle, calibration_data.left_stick, false);
if (result != ErrorCode::Success) {
return result;
}
result = GetRightJoyStickCalibration(joycon_handle, calibration_data.right_stick, false);
if (result != ErrorCode::Success) {
return result;
}
break;
default:
break;
return ErrorCode::UnsupportedControllerType;
}
calibration.imu = GetImuCalibration(joycon_handle, false);
return calibration;
result = GetImuCalibration(joycon_handle, calibration_data.imu, false);
if (result != ErrorCode::Success) {
return result;
}
return ErrorCode::Success;
}
CalibrationData GetFactoryCalibrationData(JoyconHandle& joycon_handle,
ControllerType controller_type) {
CalibrationData calibration{};
ErrorCode GetFactoryCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type) {
ErrorCode result{ErrorCode::Unknown};
switch (controller_type) {
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;
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;
case Joycon::ControllerType::Pro:
calibration.left_stick = GetLeftJoyStickCalibration(joycon_handle, true);
calibration.right_stick = GetRightJoyStickCalibration(joycon_handle, true);
result = GetLeftJoyStickCalibration(joycon_handle, calibration_data.left_stick, true);
if (result != ErrorCode::Success) {
return result;
}
result = GetRightJoyStickCalibration(joycon_handle, calibration_data.right_stick, true);
if (result != ErrorCode::Success) {
return result;
}
break;
default:
break;
return ErrorCode::UnsupportedControllerType;
}
calibration.imu = GetImuCalibration(joycon_handle, true);
return calibration;
result = GetImuCalibration(joycon_handle, calibration_data.imu, true);
if (result != ErrorCode::Success) {
return result;
}
return ErrorCode::Success;
}
void EnableImu(JoyconHandle& joycon_handle, bool enable) {
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
ErrorCode EnableImu(JoyconHandle& joycon_handle, bool enable) {
const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)};
SendSubCommand(joycon_handle, SubCommand::ENABLE_IMU, buffer, buffer.size());
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
}
void EnableRumble(JoyconHandle& joycon_handle, bool enable) {
std::vector<u8> output;
SDL_hid_set_nonblocking(joycon_handle.handle, 0);
const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)};
SendSubCommand(joycon_handle, SubCommand::ENABLE_VIBRATION, buffer, buffer.size());
const auto result =
SendSubCommand(joycon_handle, SubCommand::ENABLE_IMU, buffer, buffer.size(), output);
SDL_hid_set_nonblocking(joycon_handle.handle, 1);
return result;
}
void SendData(JoyconHandle& joycon_handle, std::span<const u8> buffer, std::size_t size) {
SDL_hid_write(joycon_handle.handle, buffer.data(), size);
ErrorCode EnableRumble(JoyconHandle& joycon_handle, bool enable) {
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 max_tries = 10;
int tries = 0;
std::vector<u8> buffer(max_resp_size);
do {
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) {
LOG_ERROR(Input, "No response from joycon");
}
tries++;
} while (tries < 10 && buffer[0] != 0x21 && buffer[14] != static_cast<u8>(sc));
return buffer;
} while (tries < max_tries && buffer[0] != 0x21 && buffer[14] != static_cast<u8>(sc));
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,
std::span<const u8> buffer, std::size_t size) {
ErrorCode SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, std::span<const u8> buffer,
std::size_t size, std::vector<u8>& output) {
std::vector<u8> local_buffer(size + 11);
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];
}
SendData(joycon_handle, local_buffer, size + 11);
return GetResponse(joycon_handle, sc);
auto result = SendData(joycon_handle, local_buffer, size + 11);
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;
std::size_t tries = 0;
std::vector<u8> buffer = {0x00, 0x00, 0x00, 0x00, size};
std::vector<u8> local_buffer(size + 20);
buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF);
buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8);
for (std::size_t i = 0; i < max_tries; ++i) {
local_buffer =
SendSubCommand(joycon_handle, SubCommand::SPI_FLASH_READ, buffer, buffer.size());
// Recieved packed has to match with the requested address
if (local_buffer[15] == buffer[0] && local_buffer[16] == buffer[1]) {
break;
do {
const auto result = SendSubCommand(joycon_handle, SubCommand::SPI_FLASH_READ, buffer,
buffer.size(), local_buffer);
if (result != ErrorCode::Success) {
return result;
}
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
+57 -37
View File
@@ -18,6 +18,9 @@ namespace InputCommon::Joycon {
constexpr u32 max_resp_size = 49;
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 {
None,
Left,
@@ -170,6 +173,21 @@ enum class AccelerometerPerformance {
HZ100, // Default
};
enum class FirmwareVersion {
Rev_0,
};
enum class ErrorCode {
Success,
WrongReply,
Timeout,
UnsupportedControllerType,
HandleInUse,
ErrorReadingData,
ErrorWritingData,
Unknown,
};
struct ImuSensorCalibration {
s16 offset;
s16 scale;
@@ -226,21 +244,10 @@ u8 GetCounter(JoyconHandle& joycon_handle);
/**
* Verifies and sets the joycon_handle if device is valid
* @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
*/
bool 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);
ErrorCode CheckDeviceAccess(JoyconHandle& joycon_handle, SDL_hid_device_info* device);
/**
* 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 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
* @param joycon_handle device to send the data
* @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
* @param joycon_handle device to send the data
* @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
* @param joycon_handle device to read the data
* @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
* @param joycon_handle device to read the data
* @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
* @param joycon_handle device to read the data
* @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
* @param joycon_handle device to read the data
* @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
* @param joycon_handle device to read the data
* @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
* @param joycon_handle device to read the data
* @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
@@ -318,8 +336,8 @@ u16 GetVersionNumber(JoyconHandle& joycon_handle);
* @param is_factory_calibration if true factory values will be returned
* @returns JoyStickCalibration of the left joystick
*/
JoyStickCalibration GetLeftJoyStickCalibration(JoyconHandle& joycon_handle,
bool is_factory_calibration);
ErrorCode GetLeftJoyStickCalibration(JoyconHandle& joycon_handle, JoyStickCalibration& calibration,
bool is_factory_calibration);
/**
* 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
* @returns JoyStickCalibration of the left joystick
*/
JoyStickCalibration GetRightJoyStickCalibration(JoyconHandle& joycon_handle,
bool is_factory_calibration);
ErrorCode GetRightJoyStickCalibration(JoyconHandle& joycon_handle, JoyStickCalibration& calibration,
bool is_factory_calibration);
/**
* 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
* @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
@@ -344,7 +363,8 @@ ImuCalibration GetImuCalibration(JoyconHandle& joycon_handle, bool is_factory_ca
* @param controller_type type of calibration to be requested
* @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
@@ -352,22 +372,22 @@ CalibrationData GetUserCalibrationData(JoyconHandle& joycon_handle, ControllerTy
* @param controller_type type of calibration to be requested
* @returns Factory CalibrationData of the joystick
*/
CalibrationData GetFactoryCalibrationData(JoyconHandle& joycon_handle,
ControllerType controller_type);
ErrorCode GetFactoryCalibrationData(JoyconHandle& joycon_handle, CalibrationData& calibration_data,
ControllerType controller_type);
/**
* Sends a request to enable motion
* @param joycon_handle device to read the data
* @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
* @param joycon_handle device to read the data
* @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
@@ -375,7 +395,7 @@ void EnableRumble(JoyconHandle& joycon_handle, bool enable);
* @param buffer data to be send
* @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
@@ -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
* @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
@@ -391,8 +411,8 @@ std::vector<u8> GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command)
* @param buffer data to be send
* @param size size in bytes of the buffer
*/
std::vector<u8> SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc,
std::span<const u8> buffer, std::size_t size);
ErrorCode SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, std::span<const u8> buffer,
std::size_t size, std::vector<u8>& output);
/**
* 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 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