diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 0708ed1218..926e7ded1f 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -104,6 +104,7 @@ bool Joycons::IsPayloadCorrect(int status, std::span 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 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, }; diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index 30893e0f3b..3130378c5b 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -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 { diff --git a/src/input_common/helpers/joycon_protocol.cpp b/src/input_common/helpers/joycon_protocol.cpp index 6131058d8f..24e814974d 100644 --- a/src/input_common/helpers/joycon_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol.cpp @@ -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 buffer(Joycon::max_resp_size); buffer[0] = static_cast(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(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 buffer{static_cast(gsen), static_cast(asen), static_cast(gfrec), static_cast(afrec)}; + std::vector 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 buffer{leds}; + std::vector 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 buffer{static_cast(report_mode)}; + std::vector 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 buffer; SDL_hid_set_nonblocking(joycon_handle.handle, 0); - buffer = ReadSPI(joycon_handle, Joycon::CalAddr::COLOR_DATA, 12); - joycon_color.body = static_cast((buffer[2] << 16) | (buffer[1] << 8) | buffer[0]); - joycon_color.buttons = static_cast((buffer[5] << 16) | (buffer[4] << 8) | buffer[3]); - joycon_color.left_grip = static_cast((buffer[8] << 16) | (buffer[7] << 8) | buffer[6]); - joycon_color.right_grip = static_cast((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((buffer[2] << 16) | (buffer[1] << 8) | buffer[0]); + color.buttons = static_cast((buffer[5] << 16) | (buffer[4] << 8) | buffer[3]); + color.left_grip = static_cast((buffer[8] << 16) | (buffer[7] << 8) | buffer[6]); + color.right_grip = static_cast((buffer[11] << 16) | (buffer[10] << 8) | buffer[9]); + return ErrorCode::Success; } -std::array GetMacAddress(JoyconHandle& joycon_handle) { - std::array 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(std::stoi(value, 0, 16)); } - return mac_address; + return ErrorCode::Success; } -std::array GetSerialNumber(JoyconHandle& joycon_handle) { - std::array serial_number; +ErrorCode GetSerialNumber(JoyconHandle& joycon_handle, SerialNumber& serial_number) { + std::vector buffer; SDL_hid_set_nonblocking(joycon_handle.handle, 0); - const std::vector 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 buffer = ReadSPI(joycon_handle, Joycon::CalAddr::DEVICE_TYPE, 1); - SDL_hid_set_nonblocking(joycon_handle.handle, 1); - return static_cast(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 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(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 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(((buffer[1] & 0x0F) << 8) | buffer[0]); - joystick.y.max = static_cast((buffer[2] << 4) | (buffer[1] >> 4)); - joystick.x.center = static_cast(((buffer[4] & 0x0F) << 8) | buffer[3]); - joystick.y.center = static_cast((buffer[5] << 4) | (buffer[4] >> 4)); - joystick.x.min = static_cast(((buffer[7] & 0x0F) << 8) | buffer[6]); - joystick.y.min = static_cast((buffer[8] << 4) | (buffer[7] >> 4)); + if (result != ErrorCode::Success) { + return result; + } + + calibration.x.max = static_cast(((buffer[1] & 0x0F) << 8) | buffer[0]); + calibration.y.max = static_cast((buffer[2] << 4) | (buffer[1] >> 4)); + calibration.x.center = static_cast(((buffer[4] & 0x0F) << 8) | buffer[3]); + calibration.y.center = static_cast((buffer[5] << 4) | (buffer[4] >> 4)); + calibration.x.min = static_cast(((buffer[7] & 0x0F) << 8) | buffer[6]); + calibration.y.min = static_cast((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 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(((buffer[1] & 0x0F) << 8) | buffer[0]); - joystick.y.center = static_cast((buffer[2] << 4) | (buffer[1] >> 4)); - joystick.x.min = static_cast(((buffer[4] & 0x0F) << 8) | buffer[3]); - joystick.y.min = static_cast((buffer[5] << 4) | (buffer[4] >> 4)); - joystick.x.max = static_cast(((buffer[7] & 0x0F) << 8) | buffer[6]); - joystick.y.max = static_cast((buffer[8] << 4) | (buffer[7] >> 4)); + if (result != ErrorCode::Success) { + return result; + } + + calibration.x.center = static_cast(((buffer[1] & 0x0F) << 8) | buffer[0]); + calibration.y.center = static_cast((buffer[2] << 4) | (buffer[1] >> 4)); + calibration.x.min = static_cast(((buffer[4] & 0x0F) << 8) | buffer[3]); + calibration.y.min = static_cast((buffer[5] << 4) | (buffer[4] >> 4)); + calibration.x.max = static_cast(((buffer[7] & 0x0F) << 8) | buffer[6]); + calibration.y.max = static_cast((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 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(buffer[index] | (buffer[index + 1] << 8)); - imu.accelerometer[i].scale = static_cast(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(buffer[index + 12] | (buffer[index + 13] << 8)); - imu.gyro[i].scale = static_cast(buffer[index + 18] | (buffer[index + 19] << 8)); + calibration.accelerometer[i].offset = + static_cast(buffer[index] | (buffer[index + 1] << 8)); + calibration.accelerometer[i].scale = + static_cast(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(buffer[index + 12] | (buffer[index + 13] << 8)); + calibration.gyro[i].scale = + static_cast(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 buffer{static_cast(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 output; SDL_hid_set_nonblocking(joycon_handle.handle, 0); - const std::vector buffer{static_cast(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 buffer, std::size_t size) { - SDL_hid_write(joycon_handle.handle, buffer.data(), size); +ErrorCode EnableRumble(JoyconHandle& joycon_handle, bool enable) { + const std::vector buffer{static_cast(enable ? 1 : 0)}; + std::vector 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 GetResponse(JoyconHandle& joycon_handle, SubCommand sc) { +ErrorCode SendData(JoyconHandle& joycon_handle, std::span 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& output) { constexpr int timeout_mili = 100; + constexpr int max_tries = 10; int tries = 0; std::vector 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(sc)); - return buffer; + } while (tries < max_tries && buffer[0] != 0x21 && buffer[14] != static_cast(sc)); + + if (tries >= max_tries) { + return ErrorCode::Timeout; + } + if (buffer[0] != 0x21 && buffer[14] != static_cast(sc)) { + return ErrorCode::WrongReply; + } + + output = buffer; + return ErrorCode::Success; } -std::vector SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, - std::span buffer, std::size_t size) { +ErrorCode SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, std::span buffer, + std::size_t size, std::vector& output) { std::vector local_buffer(size + 11); local_buffer[0] = static_cast(OutputReport::RUMBLE_AND_SUBCMD); @@ -337,26 +440,40 @@ std::vector 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 ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, u8 size) { +ErrorCode ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, std::vector& output, u8 size) { constexpr std::size_t max_tries = 10; + std::size_t tries = 0; std::vector buffer = {0x00, 0x00, 0x00, 0x00, size}; std::vector local_buffer(size + 20); buffer[0] = static_cast(static_cast(addr) & 0x00FF); buffer[1] = static_cast((static_cast(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(local_buffer.begin() + 20, local_buffer.end()); + + output = std::vector(local_buffer.begin() + 20, local_buffer.end()); + return ErrorCode::Success; } } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol.h b/src/input_common/helpers/joycon_protocol.h index 063fbe3ac4..06c3d550e7 100644 --- a/src/input_common/helpers/joycon_protocol.h +++ b/src/input_common/helpers/joycon_protocol.h @@ -18,6 +18,9 @@ namespace InputCommon::Joycon { constexpr u32 max_resp_size = 49; constexpr std::array default_buffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; +using MacAddress = std::array; +using SerialNumber = std::array; + 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 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 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 buffer, std::size_t size); +ErrorCode SendData(JoyconHandle& joycon_handle, std::span 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 buffer, std::size * @param sub_command type of data to be returned * @returns a buffer containing the responce */ -std::vector GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command); +ErrorCode GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command, std::vector& output); /** * Sends data to the joycon device @@ -391,8 +411,8 @@ std::vector GetResponse(JoyconHandle& joycon_handle, SubCommand sub_command) * @param buffer data to be send * @param size size in bytes of the buffer */ -std::vector SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, - std::span buffer, std::size_t size); +ErrorCode SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, std::span buffer, + std::size_t size, std::vector& output); /** * Sends data to the joycon device @@ -400,6 +420,6 @@ std::vector SendSubCommand(JoyconHandle& joycon_handle, SubCommand sc, * @param buffer data to be send * @param size size in bytes of the buffer */ -std::vector ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, u8 size); +ErrorCode ReadSPI(JoyconHandle& joycon_handle, CalAddr addr, std::vector& output, u8 size); } // namespace InputCommon::Joycon