diff options
author | Narr the Reg <juangerman-13@hotmail.com> | 2022-12-21 02:10:42 +0100 |
---|---|---|
committer | Narr the Reg <juangerman-13@hotmail.com> | 2023-01-20 01:05:21 +0100 |
commit | 751d36e7392b0b1637f17988cfc1ef0d7cd95753 (patch) | |
tree | 8ba772846be04719e41f82ef059ee81491a7c0e9 /src/input_common/helpers/joycon_protocol | |
parent | input_common: Add support for joycon input reports (diff) | |
download | yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.tar yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.tar.gz yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.tar.bz2 yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.tar.lz yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.tar.xz yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.tar.zst yuzu-751d36e7392b0b1637f17988cfc1ef0d7cd95753.zip |
Diffstat (limited to 'src/input_common/helpers/joycon_protocol')
6 files changed, 225 insertions, 3 deletions
diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp index 5c29af545..ce1ff7061 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.cpp +++ b/src/input_common/helpers/joycon_protocol/calibration.cpp @@ -128,6 +128,28 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati return result; } +DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibration, + s16 current_value) { + // TODO: Get default calibration form ring itself + if (ring_data_max == 0 && ring_data_min == 0) { + ring_data_max = current_value + 800; + ring_data_min = current_value - 800; + ring_data_default = current_value; + } + if (ring_data_max < current_value) { + ring_data_max = current_value; + } + if (ring_data_min > current_value) { + ring_data_min = current_value; + } + calibration = { + .default_value = ring_data_default, + .max_value = ring_data_max, + .min_value = ring_data_min, + }; + return DriverResult::Success; +} + void CalibrationProtocol::ValidateCalibration(JoyStickCalibration& calibration) { constexpr u16 DefaultStickCenter{2048}; constexpr u16 DefaultStickRange{1740}; diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h index 38214eed4..32ddef4b8 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.h +++ b/src/input_common/helpers/joycon_protocol/calibration.h @@ -46,9 +46,19 @@ public: */ DriverResult GetImuCalibration(MotionCalibration& calibration); + /** + * Calculates on run time the proper calibration of the ring controller + * @returns RingCalibration of the ring sensor + */ + DriverResult GetRingCalibration(RingCalibration& calibration, s16 current_value); + private: void ValidateCalibration(JoyStickCalibration& calibration); void ValidateCalibration(MotionCalibration& calibration); + + s16 ring_data_max = 0; + s16 ring_data_default = 0; + s16 ring_data_min = 0; }; } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index 341479c0c..cb76e1e06 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp @@ -16,7 +16,8 @@ void JoyconPoller::SetCallbacks(const Joycon::JoyconCallbacks& callbacks_) { callbacks = std::move(callbacks_); } -void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& motion_status) { +void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& motion_status, + const RingStatus& ring_status) { InputReportActive data{}; memcpy(&data, buffer.data(), sizeof(InputReportActive)); @@ -36,6 +37,10 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti break; } + if (ring_status.is_enabled) { + UpdateRing(data.ring_input, ring_status); + } + callbacks.on_battery_data(data.battery_status); } @@ -62,13 +67,26 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) { void JoyconPoller::ReadNfcIRMode(std::span<u8> buffer, const MotionStatus& motion_status) { // This mode is compatible with the active mode - ReadActiveMode(buffer, motion_status); + ReadActiveMode(buffer, motion_status, {}); } void JoyconPoller::UpdateColor(const Color& color) { callbacks.on_color_data(color); } +void JoyconPoller::UpdateRing(s16 value, const RingStatus& ring_status) { + float normalized_value = static_cast<float>(value - ring_status.default_value); + if (normalized_value > 0) { + normalized_value = normalized_value / + static_cast<float>(ring_status.max_value - ring_status.default_value); + } + if (normalized_value < 0) { + normalized_value = normalized_value / + static_cast<float>(ring_status.default_value - ring_status.min_value); + } + callbacks.on_ring_data(normalized_value); +} + void JoyconPoller::UpdateActiveLeftPadInput(const InputReportActive& input, const MotionStatus& motion_status) { static constexpr std::array<Joycon::PadButton, 11> left_buttons{ diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index fff681d0a..68b14b8ba 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h @@ -28,12 +28,14 @@ public: void ReadPassiveMode(std::span<u8> buffer); /// Handles data from active packages - void ReadActiveMode(std::span<u8> buffer, const MotionStatus& motion_status); + void ReadActiveMode(std::span<u8> buffer, const MotionStatus& motion_status, + const RingStatus& ring_status); /// Handles data from nfc or ir packages void ReadNfcIRMode(std::span<u8> buffer, const MotionStatus& motion_status); void UpdateColor(const Color& color); + void UpdateRing(s16 value, const RingStatus& ring_status); private: void UpdateActiveLeftPadInput(const InputReportActive& input, diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp new file mode 100644 index 000000000..2d137b85d --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "input_common/helpers/joycon_protocol/ringcon.h" + +namespace InputCommon::Joycon { + +RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) + : JoyconCommonProtocol(handle) {} + +DriverResult RingConProtocol::EnableRingCon() { + LOG_DEBUG(Input, "Enable Ringcon"); + DriverResult result{DriverResult::Success}; + SetBlocking(); + + if (result == DriverResult::Success) { + result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); + } + if (result == DriverResult::Success) { + result = EnableMCU(true); + } + if (result == DriverResult::Success) { + const MCUConfig config{ + .command = MCUCommand::ConfigureMCU, + .sub_command = MCUSubCommand::SetDeviceMode, + .mode = MCUMode::Standby, + .crc = {}, + }; + result = ConfigureMCU(config); + } + + SetNonBlocking(); + return result; +} + +DriverResult RingConProtocol::DisableRingCon() { + LOG_DEBUG(Input, "Disable RingCon"); + DriverResult result{DriverResult::Success}; + SetBlocking(); + + if (result == DriverResult::Success) { + result = EnableMCU(false); + } + + is_enabled = false; + + SetNonBlocking(); + return result; +} + +DriverResult RingConProtocol::StartRingconPolling() { + LOG_DEBUG(Input, "Enable Ringcon"); + bool is_connected = false; + DriverResult result{DriverResult::Success}; + SetBlocking(); + + if (result == DriverResult::Success) { + result = WaitSetMCUMode(ReportMode::STANDARD_FULL_60HZ, MCUMode::Standby); + } + if (result == DriverResult::Success) { + result = IsRingConnected(is_connected); + } + if (result == DriverResult::Success && is_connected) { + LOG_INFO(Input, "Ringcon detected"); + result = ConfigureRing(); + } + if (result == DriverResult::Success) { + is_enabled = true; + } + + SetNonBlocking(); + return result; +} + +DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { + LOG_DEBUG(Input, "IsRingConnected"); + constexpr std::size_t max_tries = 28; + std::vector<u8> output; + std::size_t tries = 0; + is_connected = false; + + do { + std::vector<u8> empty_data(0); + const auto result = SendSubCommand(SubCommand::UNKNOWN_RINGCON, empty_data, output); + + if (result != DriverResult::Success) { + return result; + } + + if (tries++ >= max_tries) { + return DriverResult::NoDeviceDetected; + } + } while (output[14] != 0x59 || output[16] != 0x20); + + is_connected = true; + return DriverResult::Success; +} + +DriverResult RingConProtocol::ConfigureRing() { + LOG_DEBUG(Input, "ConfigureRing"); + constexpr std::size_t max_tries = 28; + DriverResult result{DriverResult::Success}; + std::vector<u8> output; + std::size_t tries = 0; + + do { + std::vector<u8> ring_config{0x06, 0x03, 0x25, 0x06, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x16, + 0xED, 0x34, 0x36, 0x00, 0x00, 0x00, 0x0A, 0x64, 0x0B, 0xE6, + 0xA9, 0x22, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x90, 0xA8, 0xE1, 0x34, 0x36}; + result = SendSubCommand(SubCommand::UNKNOWN_RINGCON3, ring_config, output); + + if (result != DriverResult::Success) { + return result; + } + if (tries++ >= max_tries) { + return DriverResult::NoDeviceDetected; + } + } while (output[14] != 0x5C); + + std::vector<u8> ringcon_data{0x04, 0x01, 0x01, 0x02}; + result = SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data, output); + + return result; +} + +bool RingConProtocol::IsEnabled() { + return is_enabled; +} + +} // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/ringcon.h b/src/input_common/helpers/joycon_protocol/ringcon.h new file mode 100644 index 000000000..0c25de23e --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/ringcon.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// Based on dkms-hid-nintendo implementation, CTCaer joycon toolkit and dekuNukem reverse +// engineering https://github.com/nicman23/dkms-hid-nintendo/blob/master/src/hid-nintendo.c +// https://github.com/CTCaer/jc_toolkit +// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering + +#pragma once + +#include <vector> + +#include "input_common/helpers/joycon_protocol/common_protocol.h" +#include "input_common/helpers/joycon_protocol/joycon_types.h" + +namespace InputCommon::Joycon { + +class RingConProtocol final : private JoyconCommonProtocol { +public: + RingConProtocol(std::shared_ptr<JoyconHandle> handle); + + DriverResult EnableRingCon(); + + DriverResult DisableRingCon(); + + DriverResult StartRingconPolling(); + + bool IsEnabled(); + +private: + DriverResult IsRingConnected(bool& is_connected); + + DriverResult ConfigureRing(); + + bool is_enabled{}; +}; + +} // namespace InputCommon::Joycon |