diff options
Diffstat (limited to 'src/input_common/helpers/joycon_driver.cpp')
-rw-r--r-- | src/input_common/helpers/joycon_driver.cpp | 245 |
1 files changed, 180 insertions, 65 deletions
diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 95106f16d..cf51f3481 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -1,7 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "common/input.h" #include "common/logging/log.h" +#include "common/scope_exit.h" #include "common/swap.h" #include "common/thread.h" #include "input_common/helpers/joycon_driver.h" @@ -27,13 +29,13 @@ void JoyconDriver::Stop() { input_thread = {}; } -DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { +Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) { std::scoped_lock lock{mutex}; handle_device_type = ControllerType::None; GetDeviceType(device_info, handle_device_type); if (handle_device_type == ControllerType::None) { - return DriverResult::UnsupportedControllerType; + return Common::Input::DriverResult::UnsupportedControllerType; } hidapi_handle->handle = @@ -42,15 +44,15 @@ DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_info* device_info) if (!hidapi_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 DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } SDL_hid_set_nonblocking(hidapi_handle->handle, 1); - return DriverResult::Success; + return Common::Input::DriverResult::Success; } -DriverResult JoyconDriver::InitializeDevice() { +Common::Input::DriverResult JoyconDriver::InitializeDevice() { if (!hidapi_handle->handle) { - return DriverResult::InvalidHandle; + return Common::Input::DriverResult::InvalidHandle; } std::scoped_lock lock{mutex}; disable_input_thread = true; @@ -71,6 +73,7 @@ DriverResult JoyconDriver::InitializeDevice() { nfc_enabled = false; passive_enabled = false; irs_enabled = false; + input_only_device = false; gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; gyro_performance = Joycon::GyroPerformance::HZ833; accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; @@ -85,16 +88,23 @@ DriverResult JoyconDriver::InitializeDevice() { rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); // Get fixed joycon info - generic_protocol->GetVersionNumber(version); - generic_protocol->SetLowPowerMode(false); - generic_protocol->GetColor(color); - if (handle_device_type == ControllerType::Pro) { - // Some 3rd party controllers aren't pro controllers - generic_protocol->GetControllerType(device_type); - } else { - device_type = handle_device_type; + if (generic_protocol->GetVersionNumber(version) != Common::Input::DriverResult::Success) { + // If this command fails the device doesn't accept configuration commands + input_only_device = true; + } + + if (!input_only_device) { + generic_protocol->SetLowPowerMode(false); + generic_protocol->GetColor(color); + if (handle_device_type == ControllerType::Pro) { + // Some 3rd party controllers aren't pro controllers + generic_protocol->GetControllerType(device_type); + } else { + device_type = handle_device_type; + } + generic_protocol->GetSerialNumber(serial_number); } - generic_protocol->GetSerialNumber(serial_number); + supported_features = GetSupportedFeatures(); // Get Calibration data @@ -112,7 +122,7 @@ DriverResult JoyconDriver::InitializeDevice() { joycon_poller = std::make_unique<JoyconPoller>(device_type, left_stick_calibration, right_stick_calibration, motion_calibration); - // Start pooling for data + // Start polling for data is_connected = true; if (!input_thread_running) { input_thread = @@ -120,7 +130,7 @@ DriverResult JoyconDriver::InitializeDevice() { } disable_input_thread = false; - return DriverResult::Success; + return Common::Input::DriverResult::Success; } void JoyconDriver::InputThread(std::stop_token stop_token) { @@ -208,7 +218,7 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); } - if (nfc_protocol->IsEnabled()) { + if (nfc_protocol->IsPolling()) { if (amiibo_detected) { if (!nfc_protocol->HasAmiibo()) { joycon_poller->UpdateAmiibo({}); @@ -218,10 +228,10 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { } if (!amiibo_detected) { - std::vector<u8> data(0x21C); - const auto result = nfc_protocol->ScanAmiibo(data); - if (result == DriverResult::Success) { - joycon_poller->UpdateAmiibo(data); + Joycon::TagInfo tag_info; + const auto result = nfc_protocol->GetTagInfo(tag_info); + if (result == Common::Input::DriverResult::Success) { + joycon_poller->UpdateAmiibo(tag_info); amiibo_detected = true; } } @@ -246,7 +256,8 @@ void JoyconDriver::OnNewData(std::span<u8> buffer) { } } -DriverResult JoyconDriver::SetPollingMode() { +Common::Input::DriverResult JoyconDriver::SetPollingMode() { + SCOPE_EXIT({ disable_input_thread = false; }); disable_input_thread = true; rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); @@ -259,6 +270,10 @@ DriverResult JoyconDriver::SetPollingMode() { generic_protocol->EnableImu(false); } + if (input_only_device) { + return Common::Input::DriverResult::NotSupported; + } + if (irs_protocol->IsEnabled()) { irs_protocol->DisableIrs(); } @@ -275,46 +290,42 @@ DriverResult JoyconDriver::SetPollingMode() { if (irs_enabled && supported_features.irs) { auto result = irs_protocol->EnableIrs(); - if (result == DriverResult::Success) { - disable_input_thread = false; + if (result == Common::Input::DriverResult::Success) { return result; } irs_protocol->DisableIrs(); LOG_ERROR(Input, "Error enabling IRS"); + return result; } if (nfc_enabled && supported_features.nfc) { auto result = nfc_protocol->EnableNfc(); - if (result == DriverResult::Success) { - result = nfc_protocol->StartNFCPollingMode(); - } - if (result == DriverResult::Success) { - disable_input_thread = false; + if (result == Common::Input::DriverResult::Success) { return result; } nfc_protocol->DisableNfc(); LOG_ERROR(Input, "Error enabling NFC"); + return result; } if (hidbus_enabled && supported_features.hidbus) { auto result = ring_protocol->EnableRingCon(); - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { result = ring_protocol->StartRingconPolling(); } - if (result == DriverResult::Success) { + if (result == Common::Input::DriverResult::Success) { ring_connected = true; - disable_input_thread = false; return result; } ring_connected = false; ring_protocol->DisableRingCon(); LOG_ERROR(Input, "Error enabling Ringcon"); + return result; } if (passive_enabled && supported_features.passive) { const auto result = generic_protocol->EnablePassiveMode(); - if (result == DriverResult::Success) { - disable_input_thread = false; + if (result == Common::Input::DriverResult::Success) { return result; } LOG_ERROR(Input, "Error enabling passive mode"); @@ -322,13 +333,12 @@ DriverResult JoyconDriver::SetPollingMode() { // Default Mode const auto result = generic_protocol->EnableActiveMode(); - if (result != DriverResult::Success) { + if (result != Common::Input::DriverResult::Success) { LOG_ERROR(Input, "Error enabling active mode"); } // Switch calls this function after enabling active mode generic_protocol->TriggersElapsed(); - disable_input_thread = false; return result; } @@ -339,6 +349,10 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { .vibration = true, }; + if (input_only_device) { + return features; + } + if (device_type == ControllerType::Right) { features.nfc = true; features.irs = true; @@ -383,26 +397,26 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span<const u8> buffer) { return true; } -DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { +Common::Input::DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { std::scoped_lock lock{mutex}; if (disable_input_thread) { - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } return rumble_protocol->SendVibration(vibration); } -DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { +Common::Input::DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { std::scoped_lock lock{mutex}; if (disable_input_thread) { - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } return generic_protocol->SetLedPattern(led_pattern); } -DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { +Common::Input::DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { std::scoped_lock lock{mutex}; if (disable_input_thread) { - return DriverResult::HandleInUse; + return Common::Input::DriverResult::HandleInUse; } disable_input_thread = true; const auto result = irs_protocol->SetIrsConfig(mode_, format_); @@ -410,7 +424,7 @@ DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { return result; } -DriverResult JoyconDriver::SetPassiveMode() { +Common::Input::DriverResult JoyconDriver::SetPassiveMode() { std::scoped_lock lock{mutex}; motion_enabled = false; hidbus_enabled = false; @@ -420,7 +434,7 @@ DriverResult JoyconDriver::SetPassiveMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetActiveMode() { +Common::Input::DriverResult JoyconDriver::SetActiveMode() { if (is_ring_disabled_by_irs) { is_ring_disabled_by_irs = false; SetActiveMode(); @@ -436,11 +450,11 @@ DriverResult JoyconDriver::SetActiveMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetIrMode() { +Common::Input::DriverResult JoyconDriver::SetIrMode() { std::scoped_lock lock{mutex}; if (!supported_features.irs) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (ring_connected) { @@ -455,11 +469,11 @@ DriverResult JoyconDriver::SetIrMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetNfcMode() { +Common::Input::DriverResult JoyconDriver::SetNfcMode() { std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } motion_enabled = true; @@ -470,11 +484,11 @@ DriverResult JoyconDriver::SetNfcMode() { return SetPollingMode(); } -DriverResult JoyconDriver::SetRingConMode() { +Common::Input::DriverResult JoyconDriver::SetRingConMode() { std::scoped_lock lock{mutex}; if (!supported_features.hidbus) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } motion_enabled = true; @@ -486,29 +500,130 @@ DriverResult JoyconDriver::SetRingConMode() { const auto result = SetPollingMode(); if (!ring_connected) { - return DriverResult::NoDeviceDetected; + return Common::Input::DriverResult::NoDeviceDetected; + } + + return result; +} + +Common::Input::DriverResult JoyconDriver::StartNfcPolling() { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return Common::Input::DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return Common::Input::DriverResult::Disabled; } + disable_input_thread = true; + const auto result = nfc_protocol->StartNFCPollingMode(); + disable_input_thread = false; + return result; } -DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { +Common::Input::DriverResult JoyconDriver::StopNfcPolling() { std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return Common::Input::DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return Common::Input::DriverResult::Disabled; + } + disable_input_thread = true; + const auto result = nfc_protocol->StopNFCPollingMode(); + disable_input_thread = false; + + if (amiibo_detected) { + amiibo_detected = false; + joycon_poller->UpdateAmiibo({}); + } + + return result; +} + +Common::Input::DriverResult JoyconDriver::ReadAmiiboData(std::vector<u8>& out_data) { + std::scoped_lock lock{mutex}; if (!supported_features.nfc) { - return DriverResult::NotSupported; + return Common::Input::DriverResult::NotSupported; } if (!nfc_protocol->IsEnabled()) { - return DriverResult::Disabled; + return Common::Input::DriverResult::Disabled; } if (!amiibo_detected) { - return DriverResult::ErrorWritingData; + return Common::Input::DriverResult::ErrorWritingData; } + out_data.resize(0x21C); + disable_input_thread = true; + const auto result = nfc_protocol->ReadAmiibo(out_data); + disable_input_thread = false; + + return result; +} + +Common::Input::DriverResult JoyconDriver::WriteNfcData(std::span<const u8> data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return Common::Input::DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return Common::Input::DriverResult::Disabled; + } + if (!amiibo_detected) { + return Common::Input::DriverResult::ErrorWritingData; + } + + disable_input_thread = true; const auto result = nfc_protocol->WriteAmiibo(data); + disable_input_thread = false; + + return result; +} +Common::Input::DriverResult JoyconDriver::ReadMifareData(std::span<const MifareReadChunk> data, + std::span<MifareReadData> out_data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return Common::Input::DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return Common::Input::DriverResult::Disabled; + } + if (!amiibo_detected) { + return Common::Input::DriverResult::ErrorWritingData; + } + + disable_input_thread = true; + const auto result = nfc_protocol->ReadMifare(data, out_data); disable_input_thread = false; + + return result; +} + +Common::Input::DriverResult JoyconDriver::WriteMifareData(std::span<const MifareWriteChunk> data) { + std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return Common::Input::DriverResult::NotSupported; + } + if (!nfc_protocol->IsEnabled()) { + return Common::Input::DriverResult::Disabled; + } + if (!amiibo_detected) { + return Common::Input::DriverResult::ErrorWritingData; + } + + disable_input_thread = true; + const auto result = nfc_protocol->WriteMifare(data); + disable_input_thread = false; + return result; } @@ -561,8 +676,8 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { joycon_poller->SetCallbacks(callbacks); } -DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, - ControllerType& controller_type) { +Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, + ControllerType& controller_type) { static constexpr std::array<std::pair<u32, ControllerType>, 6> supported_devices{ std::pair<u32, ControllerType>{0x2006, ControllerType::Left}, {0x2007, ControllerType::Right}, @@ -572,25 +687,25 @@ DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, controller_type = ControllerType::None; if (device_info->vendor_id != nintendo_vendor_id) { - return DriverResult::UnsupportedControllerType; + return Common::Input::DriverResult::UnsupportedControllerType; } for (const auto& [product_id, type] : supported_devices) { if (device_info->product_id == static_cast<u16>(product_id)) { controller_type = type; - return Joycon::DriverResult::Success; + return Common::Input::DriverResult::Success; } } - return Joycon::DriverResult::UnsupportedControllerType; + return Common::Input::DriverResult::UnsupportedControllerType; } -DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, - SerialNumber& serial_number) { +Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, + SerialNumber& serial_number) { if (device_info->serial_number == nullptr) { - return DriverResult::Unknown; + return Common::Input::DriverResult::Unknown; } std::memcpy(&serial_number, device_info->serial_number, 15); - return Joycon::DriverResult::Success; + return Common::Input::DriverResult::Success; } } // namespace InputCommon::Joycon |