From d80e6c399bf8196646cca5ac1265d122638bb96b Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 20 Dec 2022 11:34:33 -0600 Subject: input_common: Initial skeleton for custom joycon driver --- src/input_common/helpers/joycon_driver.cpp | 382 +++++++++++++++++++++++++++++ 1 file changed, 382 insertions(+) create mode 100644 src/input_common/helpers/joycon_driver.cpp (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp new file mode 100644 index 000000000..a0a2a180b --- /dev/null +++ b/src/input_common/helpers/joycon_driver.cpp @@ -0,0 +1,382 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "common/swap.h" +#include "common/thread.h" +#include "input_common/helpers/joycon_driver.h" + +namespace InputCommon::Joycon { +JoyconDriver::JoyconDriver(std::size_t port_) : port{port_} { + hidapi_handle = std::make_shared(); +} + +JoyconDriver::~JoyconDriver() { + Stop(); +} + +void JoyconDriver::Stop() { + is_connected = false; + input_thread = {}; +} + +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; + } + + hidapi_handle->handle = + SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); + std::memcpy(&handle_serial_number, device_info->serial_number, 15); + 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; + } + SDL_hid_set_nonblocking(hidapi_handle->handle, 1); + return DriverResult::Success; +} + +DriverResult JoyconDriver::InitializeDevice() { + if (!hidapi_handle->handle) { + return DriverResult::InvalidHandle; + } + std::scoped_lock lock{mutex}; + disable_input_thread = true; + + // Reset Counters + error_counter = 0; + hidapi_handle->packet_counter = 0; + + // Set HW default configuration + vibration_enabled = true; + motion_enabled = true; + hidbus_enabled = false; + nfc_enabled = false; + passive_enabled = false; + gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; + gyro_performance = Joycon::GyroPerformance::HZ833; + accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; + accelerometer_performance = Joycon::AccelerometerPerformance::HZ100; + + // Initialize HW Protocols + + // Get fixed joycon info + supported_features = GetSupportedFeatures(); + + // Get Calibration data + + // Set led status + + // Apply HW configuration + SetPollingMode(); + + // Start pooling for data + is_connected = true; + if (!input_thread_running) { + input_thread = + std::jthread([this](std::stop_token stop_token) { InputThread(stop_token); }); + } + + disable_input_thread = false; + return DriverResult::Success; +} + +void JoyconDriver::InputThread(std::stop_token stop_token) { + LOG_INFO(Input, "JC Adapter input thread started"); + Common::SetCurrentThreadName("JoyconInput"); + input_thread_running = true; + + // Max update rate is 5ms, ensure we are always able to read a bit faster + constexpr int ThreadDelay = 2; + std::vector buffer(MaxBufferSize); + + while (!stop_token.stop_requested()) { + int status = 0; + + if (!IsInputThreadValid()) { + input_thread.request_stop(); + continue; + } + + // By disabling the input thread we can ensure custom commands will succeed as no package is + // skipped + if (!disable_input_thread) { + status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), + ThreadDelay); + } else { + std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay)); + } + + if (IsPayloadCorrect(status, buffer)) { + OnNewData(buffer); + } + + std::this_thread::yield(); + } + + is_connected = false; + input_thread_running = false; + LOG_INFO(Input, "JC Adapter input thread stopped"); +} + +void JoyconDriver::OnNewData(std::span buffer) { + const auto report_mode = static_cast(buffer[0]); + + switch (report_mode) { + case InputReport::STANDARD_FULL_60HZ: + ReadActiveMode(buffer); + break; + case InputReport::NFC_IR_MODE_60HZ: + ReadNfcIRMode(buffer); + break; + case InputReport::SIMPLE_HID_MODE: + ReadPassiveMode(buffer); + break; + default: + LOG_ERROR(Input, "Report mode not Implemented {}", report_mode); + break; + } +} + +void JoyconDriver::SetPollingMode() { + disable_input_thread = true; + disable_input_thread = false; +} + +JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { + SupportedFeatures features{ + .passive = true, + .motion = true, + .vibration = true, + }; + + if (device_type == ControllerType::Right) { + features.nfc = true; + features.irs = true; + features.hidbus = true; + } + + if (device_type == ControllerType::Pro) { + features.nfc = true; + } + return features; +} + +void JoyconDriver::ReadActiveMode(std::span buffer) { + InputReportActive data{}; + memcpy(&data, buffer.data(), sizeof(InputReportActive)); + + // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion + // experience + const auto now = std::chrono::steady_clock::now(); + const auto new_delta_time = + std::chrono::duration_cast(now - last_update).count(); + delta_time = static_cast((delta_time * 0.8f) + (new_delta_time * 0.2)); + last_update = now; + + switch (device_type) { + case Joycon::ControllerType::Left: + break; + case Joycon::ControllerType::Right: + break; + case Joycon::ControllerType::Pro: + break; + case Joycon::ControllerType::Grip: + case Joycon::ControllerType::Dual: + case Joycon::ControllerType::None: + break; + } + + on_battery_data(data.battery_status); + on_color_data(color); +} + +void JoyconDriver::ReadPassiveMode(std::span buffer) { + InputReportPassive data{}; + memcpy(&data, buffer.data(), sizeof(InputReportPassive)); + + switch (device_type) { + case Joycon::ControllerType::Left: + break; + case Joycon::ControllerType::Right: + break; + case Joycon::ControllerType::Pro: + break; + case Joycon::ControllerType::Grip: + case Joycon::ControllerType::Dual: + case Joycon::ControllerType::None: + break; + } +} + +void JoyconDriver::ReadNfcIRMode(std::span buffer) { + // This mode is compatible with the active mode + ReadActiveMode(buffer); + + if (!nfc_enabled) { + return; + } +} + +bool JoyconDriver::IsInputThreadValid() const { + if (!is_connected) { + return false; + } + if (hidapi_handle->handle == nullptr) { + return false; + } + // Controller is not responding. Terminate connection + if (error_counter > MaxErrorCount) { + return false; + } + return true; +} + +bool JoyconDriver::IsPayloadCorrect(int status, std::span buffer) { + if (status <= -1) { + error_counter++; + return false; + } + // There's no new data + if (status == 0) { + return false; + } + // No reply ever starts with zero + if (buffer[0] == 0x00) { + error_counter++; + return false; + } + error_counter = 0; + return true; +} + +DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { + std::scoped_lock lock{mutex}; + return DriverResult::NotSupported; +} + +DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { + std::scoped_lock lock{mutex}; + return DriverResult::NotSupported; +} + +DriverResult JoyconDriver::SetPasiveMode() { + motion_enabled = false; + hidbus_enabled = false; + nfc_enabled = false; + passive_enabled = true; + SetPollingMode(); + return DriverResult::Success; +} + +DriverResult JoyconDriver::SetActiveMode() { + motion_enabled = false; + hidbus_enabled = false; + nfc_enabled = false; + passive_enabled = false; + SetPollingMode(); + return DriverResult::Success; +} + +DriverResult JoyconDriver::SetNfcMode() { + motion_enabled = false; + hidbus_enabled = false; + nfc_enabled = true; + passive_enabled = false; + SetPollingMode(); + return DriverResult::Success; +} + +DriverResult JoyconDriver::SetRingConMode() { + motion_enabled = true; + hidbus_enabled = true; + nfc_enabled = false; + passive_enabled = false; + SetPollingMode(); + return DriverResult::Success; +} + +bool JoyconDriver::IsConnected() const { + std::scoped_lock lock{mutex}; + return is_connected; +} + +bool JoyconDriver::IsVibrationEnabled() const { + std::scoped_lock lock{mutex}; + return vibration_enabled; +} + +FirmwareVersion JoyconDriver::GetDeviceVersion() const { + std::scoped_lock lock{mutex}; + return version; +} + +Color JoyconDriver::GetDeviceColor() const { + std::scoped_lock lock{mutex}; + return color; +} + +std::size_t JoyconDriver::GetDevicePort() const { + std::scoped_lock lock{mutex}; + return port; +} + +ControllerType JoyconDriver::GetDeviceType() const { + std::scoped_lock lock{mutex}; + return handle_device_type; +} + +ControllerType JoyconDriver::GetHandleDeviceType() const { + std::scoped_lock lock{mutex}; + return handle_device_type; +} + +SerialNumber JoyconDriver::GetSerialNumber() const { + std::scoped_lock lock{mutex}; + return serial_number; +} + +SerialNumber JoyconDriver::GetHandleSerialNumber() const { + std::scoped_lock lock{mutex}; + return handle_serial_number; +} + +Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, + ControllerType& controller_type) { + std::array, 4> supported_devices{ + std::pair{0x2006, Joycon::ControllerType::Left}, + {0x2007, Joycon::ControllerType::Right}, + {0x2009, Joycon::ControllerType::Pro}, + {0x200E, Joycon::ControllerType::Grip}, + }; + constexpr u16 nintendo_vendor_id = 0x057e; + + controller_type = Joycon::ControllerType::None; + if (device_info->vendor_id != nintendo_vendor_id) { + return Joycon::DriverResult::UnsupportedControllerType; + } + + for (const auto& [product_id, type] : supported_devices) { + if (device_info->product_id == static_cast(product_id)) { + controller_type = type; + return Joycon::DriverResult::Success; + } + } + return Joycon::DriverResult::UnsupportedControllerType; +} + +Joycon::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, + Joycon::SerialNumber& serial_number) { + if (device_info->serial_number == nullptr) { + return Joycon::DriverResult::Unknown; + } + std::memcpy(&serial_number, device_info->serial_number, 15); + return Joycon::DriverResult::Success; +} + +} // namespace InputCommon::Joycon -- cgit v1.2.3 From 594b2ade6d8d829c65166aebe12f5eb3463a6fe9 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 20 Dec 2022 14:30:03 -0600 Subject: input_common: Add support for joycon generic functions --- src/input_common/helpers/joycon_driver.cpp | 54 ++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index a0a2a180b..0de55578b 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -64,13 +64,24 @@ DriverResult JoyconDriver::InitializeDevice() { accelerometer_performance = Joycon::AccelerometerPerformance::HZ100; // Initialize HW Protocols + generic_protocol = std::make_unique(hidapi_handle); // Get fixed joycon info + generic_protocol->GetVersionNumber(version); + 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); supported_features = GetSupportedFeatures(); // Get Calibration data // Set led status + generic_protocol->SetLedBlinkPattern(static_cast(1 + port)); // Apply HW configuration SetPollingMode(); @@ -137,6 +148,9 @@ void JoyconDriver::OnNewData(std::span buffer) { case InputReport::SIMPLE_HID_MODE: ReadPassiveMode(buffer); break; + case InputReport::SUBCMD_REPLY: + LOG_DEBUG(Input, "Unhandled command reply"); + break; default: LOG_ERROR(Input, "Report mode not Implemented {}", report_mode); break; @@ -145,6 +159,30 @@ void JoyconDriver::OnNewData(std::span buffer) { void JoyconDriver::SetPollingMode() { disable_input_thread = true; + + if (motion_enabled && supported_features.motion) { + generic_protocol->EnableImu(true); + generic_protocol->SetImuConfig(gyro_sensitivity, gyro_performance, + accelerometer_sensitivity, accelerometer_performance); + } else { + generic_protocol->EnableImu(false); + } + + if (passive_enabled && supported_features.passive) { + const auto result = generic_protocol->EnablePassiveMode(); + if (result == DriverResult::Success) { + disable_input_thread = false; + return; + } + LOG_ERROR(Input, "Error enabling passive mode"); + } + + // Default Mode + const auto result = generic_protocol->EnableActiveMode(); + if (result != DriverResult::Success) { + LOG_ERROR(Input, "Error enabling active mode"); + } + disable_input_thread = false; } @@ -257,15 +295,22 @@ bool JoyconDriver::IsPayloadCorrect(int status, std::span buffer) { DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { std::scoped_lock lock{mutex}; + if (disable_input_thread) { + return DriverResult::HandleInUse; + } return DriverResult::NotSupported; } DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { std::scoped_lock lock{mutex}; - return DriverResult::NotSupported; + if (disable_input_thread) { + return DriverResult::HandleInUse; + } + return generic_protocol->SetLedPattern(led_pattern); } DriverResult JoyconDriver::SetPasiveMode() { + std::scoped_lock lock{mutex}; motion_enabled = false; hidbus_enabled = false; nfc_enabled = false; @@ -275,7 +320,8 @@ DriverResult JoyconDriver::SetPasiveMode() { } DriverResult JoyconDriver::SetActiveMode() { - motion_enabled = false; + std::scoped_lock lock{mutex}; + motion_enabled = true; hidbus_enabled = false; nfc_enabled = false; passive_enabled = false; @@ -284,6 +330,7 @@ DriverResult JoyconDriver::SetActiveMode() { } DriverResult JoyconDriver::SetNfcMode() { + std::scoped_lock lock{mutex}; motion_enabled = false; hidbus_enabled = false; nfc_enabled = true; @@ -293,6 +340,7 @@ DriverResult JoyconDriver::SetNfcMode() { } DriverResult JoyconDriver::SetRingConMode() { + std::scoped_lock lock{mutex}; motion_enabled = true; hidbus_enabled = true; nfc_enabled = false; @@ -328,7 +376,7 @@ std::size_t JoyconDriver::GetDevicePort() const { ControllerType JoyconDriver::GetDeviceType() const { std::scoped_lock lock{mutex}; - return handle_device_type; + return device_type; } ControllerType JoyconDriver::GetHandleDeviceType() const { -- cgit v1.2.3 From 5676c2e17fe895e450e185029991fc20bdf56ec5 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 20 Dec 2022 18:09:59 -0600 Subject: input_common: Use calibration from joycon --- src/input_common/helpers/joycon_driver.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 0de55578b..ac11be1c1 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -64,6 +64,7 @@ DriverResult JoyconDriver::InitializeDevice() { accelerometer_performance = Joycon::AccelerometerPerformance::HZ100; // Initialize HW Protocols + calibration_protocol = std::make_unique(hidapi_handle); generic_protocol = std::make_unique(hidapi_handle); // Get fixed joycon info @@ -79,6 +80,9 @@ DriverResult JoyconDriver::InitializeDevice() { supported_features = GetSupportedFeatures(); // Get Calibration data + calibration_protocol->GetLeftJoyStickCalibration(left_stick_calibration); + calibration_protocol->GetRightJoyStickCalibration(right_stick_calibration); + calibration_protocol->GetImuCalibration(motion_calibration); // Set led status generic_protocol->SetLedBlinkPattern(static_cast(1 + port)); -- cgit v1.2.3 From f09a023292e659af46d551b9b134d94d000a57c7 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 20 Dec 2022 20:27:34 -0600 Subject: input_common: Add support for joycon input reports --- src/input_common/helpers/joycon_driver.cpp | 100 ++++++++++++----------------- 1 file changed, 40 insertions(+), 60 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index ac11be1c1..5d0aeabf5 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -66,6 +66,7 @@ DriverResult JoyconDriver::InitializeDevice() { // Initialize HW Protocols calibration_protocol = std::make_unique(hidapi_handle); generic_protocol = std::make_unique(hidapi_handle); + rumble_protocol = std::make_unique(hidapi_handle); // Get fixed joycon info generic_protocol->GetVersionNumber(version); @@ -90,6 +91,10 @@ DriverResult JoyconDriver::InitializeDevice() { // Apply HW configuration SetPollingMode(); + // Initialize joycon poller + joycon_poller = std::make_unique(device_type, left_stick_calibration, + right_stick_calibration, motion_calibration); + // Start pooling for data is_connected = true; if (!input_thread_running) { @@ -142,15 +147,40 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { void JoyconDriver::OnNewData(std::span buffer) { const auto report_mode = static_cast(buffer[0]); + // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion + // experience + switch (report_mode) { + case InputReport::STANDARD_FULL_60HZ: + case InputReport::NFC_IR_MODE_60HZ: + case InputReport::SIMPLE_HID_MODE: { + const auto now = std::chrono::steady_clock::now(); + const auto new_delta_time = static_cast( + std::chrono::duration_cast(now - last_update).count()); + delta_time = ((delta_time * 8) + (new_delta_time * 2)) / 10; + last_update = now; + joycon_poller->UpdateColor(color); + break; + } + default: + break; + } + + const MotionStatus motion_status{ + .is_enabled = motion_enabled, + .delta_time = delta_time, + .gyro_sensitivity = gyro_sensitivity, + .accelerometer_sensitivity = accelerometer_sensitivity, + }; + switch (report_mode) { case InputReport::STANDARD_FULL_60HZ: - ReadActiveMode(buffer); + joycon_poller->ReadActiveMode(buffer, motion_status); break; case InputReport::NFC_IR_MODE_60HZ: - ReadNfcIRMode(buffer); + joycon_poller->ReadNfcIRMode(buffer, motion_status); break; case InputReport::SIMPLE_HID_MODE: - ReadPassiveMode(buffer); + joycon_poller->ReadPassiveMode(buffer); break; case InputReport::SUBCMD_REPLY: LOG_DEBUG(Input, "Unhandled command reply"); @@ -164,6 +194,8 @@ void JoyconDriver::OnNewData(std::span buffer) { void JoyconDriver::SetPollingMode() { disable_input_thread = true; + rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); + if (motion_enabled && supported_features.motion) { generic_protocol->EnableImu(true); generic_protocol->SetImuConfig(gyro_sensitivity, gyro_performance, @@ -209,62 +241,6 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { return features; } -void JoyconDriver::ReadActiveMode(std::span buffer) { - InputReportActive data{}; - memcpy(&data, buffer.data(), sizeof(InputReportActive)); - - // Packages can be a litte bit inconsistent. Average the delta time to provide a smoother motion - // experience - const auto now = std::chrono::steady_clock::now(); - const auto new_delta_time = - std::chrono::duration_cast(now - last_update).count(); - delta_time = static_cast((delta_time * 0.8f) + (new_delta_time * 0.2)); - last_update = now; - - switch (device_type) { - case Joycon::ControllerType::Left: - break; - case Joycon::ControllerType::Right: - break; - case Joycon::ControllerType::Pro: - break; - case Joycon::ControllerType::Grip: - case Joycon::ControllerType::Dual: - case Joycon::ControllerType::None: - break; - } - - on_battery_data(data.battery_status); - on_color_data(color); -} - -void JoyconDriver::ReadPassiveMode(std::span buffer) { - InputReportPassive data{}; - memcpy(&data, buffer.data(), sizeof(InputReportPassive)); - - switch (device_type) { - case Joycon::ControllerType::Left: - break; - case Joycon::ControllerType::Right: - break; - case Joycon::ControllerType::Pro: - break; - case Joycon::ControllerType::Grip: - case Joycon::ControllerType::Dual: - case Joycon::ControllerType::None: - break; - } -} - -void JoyconDriver::ReadNfcIRMode(std::span buffer) { - // This mode is compatible with the active mode - ReadActiveMode(buffer); - - if (!nfc_enabled) { - return; - } -} - bool JoyconDriver::IsInputThreadValid() const { if (!is_connected) { return false; @@ -302,7 +278,7 @@ DriverResult JoyconDriver::SetVibration(const VibrationValue& vibration) { if (disable_input_thread) { return DriverResult::HandleInUse; } - return DriverResult::NotSupported; + return rumble_protocol->SendVibration(vibration); } DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { @@ -398,6 +374,10 @@ SerialNumber JoyconDriver::GetHandleSerialNumber() const { return handle_serial_number; } +void JoyconDriver::SetCallbacks(const Joycon::JoyconCallbacks& callbacks) { + joycon_poller->SetCallbacks(callbacks); +} + Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) { std::array, 4> supported_devices{ -- cgit v1.2.3 From 751d36e7392b0b1637f17988cfc1ef0d7cd95753 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Tue, 20 Dec 2022 19:10:42 -0600 Subject: input_common: Add support for joycon ring controller --- src/input_common/helpers/joycon_driver.cpp | 43 +++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 5d0aeabf5..c0a03fe2e 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -52,12 +52,18 @@ DriverResult JoyconDriver::InitializeDevice() { error_counter = 0; hidapi_handle->packet_counter = 0; + // Reset external device status + starlink_connected = false; + ring_connected = false; + amiibo_detected = false; + // Set HW default configuration vibration_enabled = true; motion_enabled = true; hidbus_enabled = false; nfc_enabled = false; passive_enabled = false; + irs_enabled = false; gyro_sensitivity = Joycon::GyroSensitivity::DPS2000; gyro_performance = Joycon::GyroPerformance::HZ833; accelerometer_sensitivity = Joycon::AccelerometerSensitivity::G8; @@ -66,6 +72,7 @@ DriverResult JoyconDriver::InitializeDevice() { // Initialize HW Protocols calibration_protocol = std::make_unique(hidapi_handle); generic_protocol = std::make_unique(hidapi_handle); + ring_protocol = std::make_unique(hidapi_handle); rumble_protocol = std::make_unique(hidapi_handle); // Get fixed joycon info @@ -172,9 +179,23 @@ void JoyconDriver::OnNewData(std::span buffer) { .accelerometer_sensitivity = accelerometer_sensitivity, }; + // TODO: Remove this when calibration is properly loaded and not calculated + if (ring_connected && report_mode == InputReport::STANDARD_FULL_60HZ) { + InputReportActive data{}; + memcpy(&data, buffer.data(), sizeof(InputReportActive)); + calibration_protocol->GetRingCalibration(ring_calibration, data.ring_input); + } + + const RingStatus ring_status{ + .is_enabled = ring_connected, + .default_value = ring_calibration.default_value, + .max_value = ring_calibration.max_value, + .min_value = ring_calibration.min_value, + }; + switch (report_mode) { case InputReport::STANDARD_FULL_60HZ: - joycon_poller->ReadActiveMode(buffer, motion_status); + joycon_poller->ReadActiveMode(buffer, motion_status, ring_status); break; case InputReport::NFC_IR_MODE_60HZ: joycon_poller->ReadNfcIRMode(buffer, motion_status); @@ -204,6 +225,26 @@ void JoyconDriver::SetPollingMode() { generic_protocol->EnableImu(false); } + if (ring_protocol->IsEnabled()) { + ring_connected = false; + ring_protocol->DisableRingCon(); + } + + if (hidbus_enabled && supported_features.hidbus) { + auto result = ring_protocol->EnableRingCon(); + if (result == DriverResult::Success) { + result = ring_protocol->StartRingconPolling(); + } + if (result == DriverResult::Success) { + ring_connected = true; + disable_input_thread = false; + return; + } + ring_connected = false; + ring_protocol->DisableRingCon(); + LOG_ERROR(Input, "Error enabling Ringcon"); + } + if (passive_enabled && supported_features.passive) { const auto result = generic_protocol->EnablePassiveMode(); if (result == DriverResult::Success) { -- cgit v1.2.3 From 6d6b7bdbc327528d155f0422ef096846559844c0 Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 22 Dec 2022 01:07:46 -0600 Subject: input_common: Implement joycon nfc --- src/input_common/helpers/joycon_driver.cpp | 44 ++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index c0a03fe2e..c3debffd1 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -5,6 +5,12 @@ #include "common/swap.h" #include "common/thread.h" #include "input_common/helpers/joycon_driver.h" +#include "input_common/helpers/joycon_protocol/calibration.h" +#include "input_common/helpers/joycon_protocol/generic_functions.h" +#include "input_common/helpers/joycon_protocol/nfc.h" +#include "input_common/helpers/joycon_protocol/poller.h" +#include "input_common/helpers/joycon_protocol/ringcon.h" +#include "input_common/helpers/joycon_protocol/rumble.h" namespace InputCommon::Joycon { JoyconDriver::JoyconDriver(std::size_t port_) : port{port_} { @@ -72,6 +78,7 @@ DriverResult JoyconDriver::InitializeDevice() { // Initialize HW Protocols calibration_protocol = std::make_unique(hidapi_handle); generic_protocol = std::make_unique(hidapi_handle); + nfc_protocol = std::make_unique(hidapi_handle); ring_protocol = std::make_unique(hidapi_handle); rumble_protocol = std::make_unique(hidapi_handle); @@ -193,6 +200,25 @@ void JoyconDriver::OnNewData(std::span buffer) { .min_value = ring_calibration.min_value, }; + if (nfc_protocol->IsEnabled()) { + if (amiibo_detected) { + if (!nfc_protocol->HasAmiibo()) { + joycon_poller->updateAmiibo({}); + amiibo_detected = false; + return; + } + } + + if (!amiibo_detected) { + std::vector data(0x21C); + const auto result = nfc_protocol->ScanAmiibo(data); + if (result == DriverResult::Success) { + joycon_poller->updateAmiibo(data); + amiibo_detected = true; + } + } + } + switch (report_mode) { case InputReport::STANDARD_FULL_60HZ: joycon_poller->ReadActiveMode(buffer, motion_status, ring_status); @@ -225,6 +251,24 @@ void JoyconDriver::SetPollingMode() { generic_protocol->EnableImu(false); } + if (nfc_protocol->IsEnabled()) { + amiibo_detected = false; + nfc_protocol->DisableNfc(); + } + + 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; + return; + } + nfc_protocol->DisableNfc(); + LOG_ERROR(Input, "Error enabling NFC"); + } + if (ring_protocol->IsEnabled()) { ring_connected = false; ring_protocol->DisableRingCon(); -- cgit v1.2.3 From 1c08d532e059fab603facb43f758f37fe148c1fc Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Thu, 22 Dec 2022 20:47:51 -0600 Subject: core: hid: Fix input regressions --- src/input_common/helpers/joycon_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index c3debffd1..db9ff4875 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -396,7 +396,7 @@ DriverResult JoyconDriver::SetActiveMode() { DriverResult JoyconDriver::SetNfcMode() { std::scoped_lock lock{mutex}; - motion_enabled = false; + motion_enabled = true; hidbus_enabled = false; nfc_enabled = true; passive_enabled = false; -- cgit v1.2.3 From e1a3bda4d9881cb99c36b64733b814a3bb437f13 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 23 Dec 2022 08:32:02 -0600 Subject: Address review comments --- src/input_common/helpers/joycon_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index db9ff4875..8982a2397 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -465,7 +465,7 @@ void JoyconDriver::SetCallbacks(const Joycon::JoyconCallbacks& callbacks) { Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) { - std::array, 4> supported_devices{ + static constexpr std::array, 4> supported_devices{ std::pair{0x2006, Joycon::ControllerType::Left}, {0x2007, Joycon::ControllerType::Right}, {0x2009, Joycon::ControllerType::Pro}, -- cgit v1.2.3 From 527dad70976a158e94defc51707347e064a31099 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 26 Dec 2022 11:11:01 -0600 Subject: input_common: Use DriverResult on all engines --- src/input_common/helpers/joycon_driver.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 8982a2397..b00b6110b 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -459,23 +459,23 @@ SerialNumber JoyconDriver::GetHandleSerialNumber() const { return handle_serial_number; } -void JoyconDriver::SetCallbacks(const Joycon::JoyconCallbacks& callbacks) { +void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { joycon_poller->SetCallbacks(callbacks); } -Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, - ControllerType& controller_type) { - static constexpr std::array, 4> supported_devices{ - std::pair{0x2006, Joycon::ControllerType::Left}, - {0x2007, Joycon::ControllerType::Right}, - {0x2009, Joycon::ControllerType::Pro}, - {0x200E, Joycon::ControllerType::Grip}, +DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, + ControllerType& controller_type) { + static constexpr std::array, 4> supported_devices{ + std::pair{0x2006, ControllerType::Left}, + {0x2007, ControllerType::Right}, + {0x2009, ControllerType::Pro}, + {0x200E, ControllerType::Grip}, }; constexpr u16 nintendo_vendor_id = 0x057e; - controller_type = Joycon::ControllerType::None; + controller_type = ControllerType::None; if (device_info->vendor_id != nintendo_vendor_id) { - return Joycon::DriverResult::UnsupportedControllerType; + return DriverResult::UnsupportedControllerType; } for (const auto& [product_id, type] : supported_devices) { @@ -487,10 +487,10 @@ Joycon::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_inf return Joycon::DriverResult::UnsupportedControllerType; } -Joycon::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, - Joycon::SerialNumber& serial_number) { +DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, + SerialNumber& serial_number) { if (device_info->serial_number == nullptr) { - return Joycon::DriverResult::Unknown; + return DriverResult::Unknown; } std::memcpy(&serial_number, device_info->serial_number, 15); return Joycon::DriverResult::Success; -- cgit v1.2.3 From 5cb437703fa441a08db295f8a916caedc3a581f2 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 26 Dec 2022 12:49:49 -0600 Subject: yuzu: Add ring controller test button --- src/input_common/helpers/joycon_driver.cpp | 38 ++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index b00b6110b..8217ba7f6 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -238,7 +238,7 @@ void JoyconDriver::OnNewData(std::span buffer) { } } -void JoyconDriver::SetPollingMode() { +DriverResult JoyconDriver::SetPollingMode() { disable_input_thread = true; rumble_protocol->EnableRumble(vibration_enabled && supported_features.vibration); @@ -263,7 +263,7 @@ void JoyconDriver::SetPollingMode() { } if (result == DriverResult::Success) { disable_input_thread = false; - return; + return result; } nfc_protocol->DisableNfc(); LOG_ERROR(Input, "Error enabling NFC"); @@ -282,7 +282,7 @@ void JoyconDriver::SetPollingMode() { if (result == DriverResult::Success) { ring_connected = true; disable_input_thread = false; - return; + return result; } ring_connected = false; ring_protocol->DisableRingCon(); @@ -293,7 +293,7 @@ void JoyconDriver::SetPollingMode() { const auto result = generic_protocol->EnablePassiveMode(); if (result == DriverResult::Success) { disable_input_thread = false; - return; + return result; } LOG_ERROR(Input, "Error enabling passive mode"); } @@ -305,6 +305,7 @@ void JoyconDriver::SetPollingMode() { } disable_input_thread = false; + return result; } JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { @@ -380,8 +381,7 @@ DriverResult JoyconDriver::SetPasiveMode() { hidbus_enabled = false; nfc_enabled = false; passive_enabled = true; - SetPollingMode(); - return DriverResult::Success; + return SetPollingMode(); } DriverResult JoyconDriver::SetActiveMode() { @@ -390,28 +390,42 @@ DriverResult JoyconDriver::SetActiveMode() { hidbus_enabled = false; nfc_enabled = false; passive_enabled = false; - SetPollingMode(); - return DriverResult::Success; + return SetPollingMode(); } DriverResult JoyconDriver::SetNfcMode() { std::scoped_lock lock{mutex}; + + if (!supported_features.nfc) { + return DriverResult::NotSupported; + } + motion_enabled = true; hidbus_enabled = false; nfc_enabled = true; passive_enabled = false; - SetPollingMode(); - return DriverResult::Success; + return SetPollingMode(); } DriverResult JoyconDriver::SetRingConMode() { std::scoped_lock lock{mutex}; + + if (!supported_features.hidbus) { + return DriverResult::NotSupported; + } + motion_enabled = true; hidbus_enabled = true; nfc_enabled = false; passive_enabled = false; - SetPollingMode(); - return DriverResult::Success; + + const auto result = SetPollingMode(); + + if (!ring_connected) { + return DriverResult::NoDeviceDetected; + } + + return result; } bool JoyconDriver::IsConnected() const { -- cgit v1.2.3 From 459fb2b21337bae60194a2a99ce68c87aaed522d Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Wed, 28 Dec 2022 15:21:12 -0600 Subject: input_common: Implement joycon ir camera --- src/input_common/helpers/joycon_driver.cpp | 55 ++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 8217ba7f6..040832a4b 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -7,6 +7,7 @@ #include "input_common/helpers/joycon_driver.h" #include "input_common/helpers/joycon_protocol/calibration.h" #include "input_common/helpers/joycon_protocol/generic_functions.h" +#include "input_common/helpers/joycon_protocol/irs.h" #include "input_common/helpers/joycon_protocol/nfc.h" #include "input_common/helpers/joycon_protocol/poller.h" #include "input_common/helpers/joycon_protocol/ringcon.h" @@ -78,6 +79,7 @@ DriverResult JoyconDriver::InitializeDevice() { // Initialize HW Protocols calibration_protocol = std::make_unique(hidapi_handle); generic_protocol = std::make_unique(hidapi_handle); + irs_protocol = std::make_unique(hidapi_handle); nfc_protocol = std::make_unique(hidapi_handle); ring_protocol = std::make_unique(hidapi_handle); rumble_protocol = std::make_unique(hidapi_handle); @@ -200,10 +202,15 @@ void JoyconDriver::OnNewData(std::span buffer) { .min_value = ring_calibration.min_value, }; + if (irs_protocol->IsEnabled()) { + irs_protocol->RequestImage(buffer); + joycon_poller->UpdateCamera(irs_protocol->GetImage(), irs_protocol->GetIrsFormat()); + } + if (nfc_protocol->IsEnabled()) { if (amiibo_detected) { if (!nfc_protocol->HasAmiibo()) { - joycon_poller->updateAmiibo({}); + joycon_poller->UpdateAmiibo({}); amiibo_detected = false; return; } @@ -213,7 +220,7 @@ void JoyconDriver::OnNewData(std::span buffer) { std::vector data(0x21C); const auto result = nfc_protocol->ScanAmiibo(data); if (result == DriverResult::Success) { - joycon_poller->updateAmiibo(data); + joycon_poller->UpdateAmiibo(data); amiibo_detected = true; } } @@ -251,6 +258,20 @@ DriverResult JoyconDriver::SetPollingMode() { generic_protocol->EnableImu(false); } + if (irs_protocol->IsEnabled()) { + irs_protocol->DisableIrs(); + } + + if (irs_enabled && supported_features.irs) { + auto result = irs_protocol->EnableIrs(); + if (result == DriverResult::Success) { + disable_input_thread = false; + return result; + } + irs_protocol->DisableIrs(); + LOG_ERROR(Input, "Error enabling IRS"); + } + if (nfc_protocol->IsEnabled()) { amiibo_detected = false; nfc_protocol->DisableNfc(); @@ -375,12 +396,24 @@ DriverResult JoyconDriver::SetLedConfig(u8 led_pattern) { return generic_protocol->SetLedPattern(led_pattern); } +DriverResult JoyconDriver::SetIrsConfig(IrsMode mode_, IrsResolution format_) { + std::scoped_lock lock{mutex}; + if (disable_input_thread) { + return DriverResult::HandleInUse; + } + disable_input_thread = true; + const auto result = irs_protocol->SetIrsConfig(mode_, format_); + disable_input_thread = false; + return result; +} + DriverResult JoyconDriver::SetPasiveMode() { std::scoped_lock lock{mutex}; motion_enabled = false; hidbus_enabled = false; nfc_enabled = false; passive_enabled = true; + irs_enabled = false; return SetPollingMode(); } @@ -390,6 +423,22 @@ DriverResult JoyconDriver::SetActiveMode() { hidbus_enabled = false; nfc_enabled = false; passive_enabled = false; + irs_enabled = false; + return SetPollingMode(); +} + +DriverResult JoyconDriver::SetIrMode() { + std::scoped_lock lock{mutex}; + + if (!supported_features.irs) { + return DriverResult::NotSupported; + } + + motion_enabled = false; + hidbus_enabled = false; + nfc_enabled = false; + passive_enabled = false; + irs_enabled = true; return SetPollingMode(); } @@ -404,6 +453,7 @@ DriverResult JoyconDriver::SetNfcMode() { hidbus_enabled = false; nfc_enabled = true; passive_enabled = false; + irs_enabled = false; return SetPollingMode(); } @@ -418,6 +468,7 @@ DriverResult JoyconDriver::SetRingConMode() { hidbus_enabled = true; nfc_enabled = false; passive_enabled = false; + irs_enabled = false; const auto result = SetPollingMode(); -- cgit v1.2.3 From d05ea2f3ebdf62e328d2edbfc5b9bc01e3453569 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 2 Jan 2023 22:11:03 -0600 Subject: input_common: Fix issue where ring and irs are enabled at the same time --- src/input_common/helpers/joycon_driver.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 040832a4b..e8aef028a 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -262,6 +262,16 @@ DriverResult JoyconDriver::SetPollingMode() { irs_protocol->DisableIrs(); } + if (nfc_protocol->IsEnabled()) { + amiibo_detected = false; + nfc_protocol->DisableNfc(); + } + + if (ring_protocol->IsEnabled()) { + ring_connected = false; + ring_protocol->DisableRingCon(); + } + if (irs_enabled && supported_features.irs) { auto result = irs_protocol->EnableIrs(); if (result == DriverResult::Success) { @@ -272,11 +282,6 @@ DriverResult JoyconDriver::SetPollingMode() { LOG_ERROR(Input, "Error enabling IRS"); } - if (nfc_protocol->IsEnabled()) { - amiibo_detected = false; - nfc_protocol->DisableNfc(); - } - if (nfc_enabled && supported_features.nfc) { auto result = nfc_protocol->EnableNfc(); if (result == DriverResult::Success) { @@ -290,11 +295,6 @@ DriverResult JoyconDriver::SetPollingMode() { LOG_ERROR(Input, "Error enabling NFC"); } - if (ring_protocol->IsEnabled()) { - ring_connected = false; - ring_protocol->DisableRingCon(); - } - if (hidbus_enabled && supported_features.hidbus) { auto result = ring_protocol->EnableRingCon(); if (result == DriverResult::Success) { @@ -418,6 +418,12 @@ DriverResult JoyconDriver::SetPasiveMode() { } DriverResult JoyconDriver::SetActiveMode() { + if (is_ring_disabled_by_irs) { + is_ring_disabled_by_irs = false; + SetActiveMode(); + return SetRingConMode(); + } + std::scoped_lock lock{mutex}; motion_enabled = true; hidbus_enabled = false; @@ -434,6 +440,10 @@ DriverResult JoyconDriver::SetIrMode() { return DriverResult::NotSupported; } + if (ring_connected) { + is_ring_disabled_by_irs = true; + } + motion_enabled = false; hidbus_enabled = false; nfc_enabled = false; -- cgit v1.2.3 From b40aefb39ea8b4259acdbe0616790c2234d9b9ef Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 8 Jan 2023 21:37:13 -0600 Subject: input_common: Drop Pro controller support from custom driver --- src/input_common/helpers/joycon_driver.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index e8aef028a..552572343 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -540,11 +540,9 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) { - static constexpr std::array, 4> supported_devices{ + static constexpr std::array, 2> supported_devices{ std::pair{0x2006, ControllerType::Left}, {0x2007, ControllerType::Right}, - {0x2009, ControllerType::Pro}, - {0x200E, ControllerType::Grip}, }; constexpr u16 nintendo_vendor_id = 0x057e; -- cgit v1.2.3 From 340f15d1fa79594dbe12a6e19140ba012751b533 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 13 Jan 2023 23:29:05 -0600 Subject: input_common: Address byte review --- src/input_common/helpers/joycon_driver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/input_common/helpers/joycon_driver.cpp') diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 552572343..4159e5717 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -123,7 +123,7 @@ DriverResult JoyconDriver::InitializeDevice() { } void JoyconDriver::InputThread(std::stop_token stop_token) { - LOG_INFO(Input, "JC Adapter input thread started"); + LOG_INFO(Input, "Joycon Adapter input thread started"); Common::SetCurrentThreadName("JoyconInput"); input_thread_running = true; @@ -157,7 +157,7 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { is_connected = false; input_thread_running = false; - LOG_INFO(Input, "JC Adapter input thread stopped"); + LOG_INFO(Input, "Joycon Adapter input thread stopped"); } void JoyconDriver::OnNewData(std::span buffer) { @@ -349,7 +349,7 @@ JoyconDriver::SupportedFeatures JoyconDriver::GetSupportedFeatures() { } bool JoyconDriver::IsInputThreadValid() const { - if (!is_connected) { + if (!is_connected.load()) { return false; } if (hidapi_handle->handle == nullptr) { @@ -491,7 +491,7 @@ DriverResult JoyconDriver::SetRingConMode() { bool JoyconDriver::IsConnected() const { std::scoped_lock lock{mutex}; - return is_connected; + return is_connected.load(); } bool JoyconDriver::IsVibrationEnabled() const { -- cgit v1.2.3