diff options
Diffstat (limited to 'src/input_common/helpers/joycon_protocol/ringcon.cpp')
-rw-r--r-- | src/input_common/helpers/joycon_protocol/ringcon.cpp | 117 |
1 files changed, 117 insertions, 0 deletions
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..12f81309e --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp @@ -0,0 +1,117 @@ +// 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(std::move(handle)) {} + +DriverResult RingConProtocol::EnableRingCon() { + LOG_DEBUG(Input, "Enable Ringcon"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + + 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); + } + + return result; +} + +DriverResult RingConProtocol::DisableRingCon() { + LOG_DEBUG(Input, "Disable RingCon"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + + if (result == DriverResult::Success) { + result = EnableMCU(false); + } + + is_enabled = false; + + return result; +} + +DriverResult RingConProtocol::StartRingconPolling() { + LOG_DEBUG(Input, "Enable Ringcon"); + ScopedSetBlocking sb(this); + DriverResult result{DriverResult::Success}; + bool is_connected = false; + + 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; + } + + return result; +} + +DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { + LOG_DEBUG(Input, "IsRingConnected"); + constexpr std::size_t max_tries = 28; + constexpr u8 ring_controller_id = 0x20; + std::vector<u8> output; + std::size_t tries = 0; + is_connected = false; + + do { + std::array<u8, 1> empty_data{}; + 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[16] != ring_controller_id); + + is_connected = true; + return DriverResult::Success; +} + +DriverResult RingConProtocol::ConfigureRing() { + LOG_DEBUG(Input, "ConfigureRing"); + + static constexpr std::array<u8, 37> 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}; + + const DriverResult result = SendSubCommand(SubCommand::UNKNOWN_RINGCON3, ring_config); + + if (result != DriverResult::Success) { + return result; + } + + static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02}; + return SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data); +} + +bool RingConProtocol::IsEnabled() const { + return is_enabled; +} + +} // namespace InputCommon::Joycon |