From 6aa6301acdf1c29b80ebfc7fca2aac326400760f Mon Sep 17 00:00:00 2001 From: Narr the Reg <juangerman-13@hotmail.com> Date: Tue, 20 Dec 2022 13:54:17 -0600 Subject: input_common: Add joycon low level functions --- .../helpers/joycon_protocol/common_protocol.cpp | 286 +++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 src/input_common/helpers/joycon_protocol/common_protocol.cpp (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp') diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp new file mode 100644 index 0000000000..43a036e027 --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -0,0 +1,286 @@ +// 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/common_protocol.h" + +namespace InputCommon::Joycon { +JoyconCommonProtocol::JoyconCommonProtocol(std::shared_ptr<JoyconHandle> hidapi_handle_) + : hidapi_handle{hidapi_handle_} {} + +u8 JoyconCommonProtocol::GetCounter() { + hidapi_handle->packet_counter = (hidapi_handle->packet_counter + 1) & 0x0F; + return hidapi_handle->packet_counter; +} + +void JoyconCommonProtocol::SetBlocking() { + SDL_hid_set_nonblocking(hidapi_handle->handle, 0); +} + +void JoyconCommonProtocol::SetNonBlocking() { + SDL_hid_set_nonblocking(hidapi_handle->handle, 1); +} + +DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { + std::vector<u8> buffer; + const auto result = ReadSPI(CalAddr::DEVICE_TYPE, 1, buffer); + controller_type = ControllerType::None; + + if (result == DriverResult::Success) { + controller_type = static_cast<ControllerType>(buffer[0]); + // Fallback to 3rd party pro controllers + if (controller_type == ControllerType::None) { + controller_type = ControllerType::Pro; + } + } + + return result; +} + +DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { + ControllerType controller_type{ControllerType::None}; + const auto result = GetDeviceType(controller_type); + if (result != DriverResult::Success || controller_type == ControllerType::None) { + return DriverResult::UnsupportedControllerType; + } + + hidapi_handle->handle = + SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); + + 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; + } + + SetNonBlocking(); + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { + const std::vector<u8> buffer{static_cast<u8>(report_mode)}; + std::vector<u8> output; + return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer, output); +} + +DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { + const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); + + if (result == -1) { + return DriverResult::ErrorWritingData; + } + + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) { + constexpr int timeout_mili = 100; + constexpr int MaxTries = 10; + int tries = 0; + output.resize(MaxSubCommandResponseSize); + + do { + int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), + MaxSubCommandResponseSize, timeout_mili); + + if (result < 1) { + LOG_ERROR(Input, "No response from joycon"); + } + if (tries++ > MaxTries) { + return DriverResult::Timeout; + } + } while (output[0] != 0x21 && output[14] != static_cast<u8>(sc)); + + if (output[0] != 0x21 && output[14] != static_cast<u8>(sc)) { + return DriverResult::WrongReply; + } + + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer, + std::vector<u8>& output) { + std::vector<u8> local_buffer(MaxResponseSize); + + local_buffer[0] = static_cast<u8>(OutputReport::RUMBLE_AND_SUBCMD); + local_buffer[1] = GetCounter(); + local_buffer[10] = static_cast<u8>(sc); + for (std::size_t i = 0; i < buffer.size(); ++i) { + local_buffer[11 + i] = buffer[i]; + } + + auto result = SendData(local_buffer); + + if (result != DriverResult::Success) { + return result; + } + + result = GetSubCommandResponse(sc, output); + + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { + std::vector<u8> local_buffer(MaxResponseSize); + + local_buffer[0] = static_cast<u8>(Joycon::OutputReport::RUMBLE_ONLY); + local_buffer[1] = GetCounter(); + + memcpy(local_buffer.data() + 2, buffer.data(), buffer.size()); + + return SendData(local_buffer); +} + +DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) { + constexpr std::size_t MaxTries = 10; + std::size_t tries = 0; + std::vector<u8> buffer = {0x00, 0x00, 0x00, 0x00, size}; + std::vector<u8> local_buffer(size + 20); + + buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); + buffer[1] = static_cast<u8>((static_cast<u16>(addr) & 0xFF00) >> 8); + do { + const auto result = SendSubCommand(SubCommand::SPI_FLASH_READ, buffer, local_buffer); + if (result != DriverResult::Success) { + return result; + } + + if (tries++ > MaxTries) { + return DriverResult::Timeout; + } + } while (local_buffer[15] != buffer[0] || local_buffer[16] != buffer[1]); + + // Remove header from output + output = std::vector<u8>(local_buffer.begin() + 20, local_buffer.begin() + 20 + size); + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { + std::vector<u8> output; + + const std::vector<u8> mcu_state{static_cast<u8>(enable ? 1 : 0)}; + const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state, output); + + if (result != DriverResult::Success) { + LOG_ERROR(Input, "SendMCUData failed with error {}", result); + } + + return result; +} + +DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { + LOG_DEBUG(Input, "ConfigureMCU"); + std::vector<u8> output; + + std::array<u8, sizeof(MCUConfig)> config_buffer; + memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); + config_buffer[37] = CalculateMCU_CRC8(config_buffer.data() + 1, 36); + + const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer, output); + + if (result != DriverResult::Success) { + LOG_ERROR(Input, "Set MCU config failed with error {}", result); + } + + return result; +} + +DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode_, + std::vector<u8>& output) { + const int report_mode = static_cast<u8>(report_mode_); + constexpr int TimeoutMili = 200; + constexpr int MaxTries = 9; + int tries = 0; + output.resize(0x170); + + do { + int result = SDL_hid_read_timeout(hidapi_handle->handle, output.data(), 0x170, TimeoutMili); + + if (result < 1) { + LOG_ERROR(Input, "No response from joycon attempt {}", tries); + } + if (tries++ > MaxTries) { + return DriverResult::Timeout; + } + } while (output[0] != report_mode || output[49] == 0xFF); + + if (output[0] != report_mode || output[49] == 0xFF) { + return DriverResult::WrongReply; + } + + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::SendMCUData(ReportMode report_mode, SubCommand sc, + std::span<const u8> buffer, + std::vector<u8>& output) { + std::vector<u8> local_buffer(MaxResponseSize); + + local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); + local_buffer[1] = GetCounter(); + local_buffer[9] = static_cast<u8>(sc); + for (std::size_t i = 0; i < buffer.size(); ++i) { + local_buffer[10 + i] = buffer[i]; + } + + auto result = SendData(local_buffer); + + if (result != DriverResult::Success) { + return result; + } + + result = GetMCUDataResponse(report_mode, output); + + return DriverResult::Success; +} + +DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMode mode) { + std::vector<u8> output; + constexpr std::size_t MaxTries{8}; + std::size_t tries{}; + + do { + const std::vector<u8> mcu_data{static_cast<u8>(MCUMode::Standby)}; + const auto result = SendMCUData(report_mode, SubCommand::STATE, mcu_data, output); + + if (result != DriverResult::Success) { + return result; + } + + if (tries++ > MaxTries) { + return DriverResult::WrongReply; + } + } while (output[49] != 1 || output[56] != static_cast<u8>(mode)); + + return DriverResult::Success; +} + +// crc-8-ccitt / polynomial 0x07 look up table +static constexpr uint8_t mcu_crc8_table[256] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; + +u8 JoyconCommonProtocol::CalculateMCU_CRC8(u8* buffer, u8 size) const { + u8 crc8 = 0x0; + + for (int i = 0; i < size; ++i) { + crc8 = mcu_crc8_table[(u8)(crc8 ^ buffer[i])]; + } + return crc8; +} + +} // namespace InputCommon::Joycon -- cgit v1.2.3-70-g09d2 From e1a3bda4d9881cb99c36b64733b814a3bb437f13 Mon Sep 17 00:00:00 2001 From: german77 <juangerman-13@hotmail.com> Date: Fri, 23 Dec 2022 08:32:02 -0600 Subject: Address review comments --- src/core/hid/input_converter.cpp | 6 ++---- src/input_common/drivers/joycon.cpp | 2 +- src/input_common/helpers/joycon_driver.cpp | 2 +- src/input_common/helpers/joycon_protocol/calibration.cpp | 10 +++------- src/input_common/helpers/joycon_protocol/calibration.h | 2 +- .../helpers/joycon_protocol/common_protocol.cpp | 6 +++--- .../helpers/joycon_protocol/generic_functions.cpp | 12 ++++++------ .../helpers/joycon_protocol/generic_functions.h | 2 +- src/input_common/helpers/joycon_protocol/nfc.cpp | 9 +++++---- src/input_common/helpers/joycon_protocol/nfc.h | 4 ++-- src/input_common/helpers/joycon_protocol/ringcon.cpp | 16 ++++++++-------- src/input_common/helpers/joycon_protocol/ringcon.h | 4 ++-- src/input_common/helpers/joycon_protocol/rumble.cpp | 13 ++++++++----- src/input_common/helpers/joycon_protocol/rumble.h | 2 +- 14 files changed, 44 insertions(+), 46 deletions(-) (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp') diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index d7e253044a..3f7b8c0904 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -305,17 +305,15 @@ Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& cal } Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) { - Common::Input::BodyColorStatus color{}; switch (callback.type) { case Common::Input::InputType::Color: - color = callback.color_status; + return callback.color_status; break; default: LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type); + return {}; break; } - - return color; } void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 29f0dc0c89..696a6db393 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -316,7 +316,7 @@ void Joycons::OnBatteryUpdate(std::size_t port, Joycon::ControllerType type, return; } - Common::Input::BatteryLevel battery{value.status.Value()}; + Common::Input::BatteryLevel battery{}; switch (value.status) { case 0: battery = Common::Input::BatteryLevel::Empty; diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index db9ff4875e..8982a2397f 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<std::pair<u32, Joycon::ControllerType>, 4> supported_devices{ + static constexpr std::array<std::pair<u32, Joycon::ControllerType>, 4> supported_devices{ std::pair<u32, Joycon::ControllerType>{0x2006, Joycon::ControllerType::Left}, {0x2007, Joycon::ControllerType::Right}, {0x2009, Joycon::ControllerType::Pro}, diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp index ce1ff7061d..cd30ab8698 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.cpp +++ b/src/input_common/helpers/joycon_protocol/calibration.cpp @@ -9,7 +9,7 @@ namespace InputCommon::Joycon { CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) - : JoyconCommonProtocol(handle) {} + : JoyconCommonProtocol(std::move(handle)) {} DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { std::vector<u8> buffer; @@ -136,12 +136,8 @@ DriverResult CalibrationProtocol::GetRingCalibration(RingCalibration& calibratio 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; - } + ring_data_max = std::max(ring_data_max, current_value); + ring_data_min = std::min(ring_data_min, current_value); calibration = { .default_value = ring_data_default, .max_value = ring_data_max, diff --git a/src/input_common/helpers/joycon_protocol/calibration.h b/src/input_common/helpers/joycon_protocol/calibration.h index 32ddef4b85..afb52a36a4 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.h +++ b/src/input_common/helpers/joycon_protocol/calibration.h @@ -24,7 +24,7 @@ namespace InputCommon::Joycon { /// Driver functions related to retrieving calibration data from the device class CalibrationProtocol final : private JoyconCommonProtocol { public: - CalibrationProtocol(std::shared_ptr<JoyconHandle> handle); + explicit CalibrationProtocol(std::shared_ptr<JoyconHandle> handle); /** * Sends a request to obtain the left stick calibration from memory diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 43a036e027..a4d08fdafa 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -6,7 +6,7 @@ namespace InputCommon::Joycon { JoyconCommonProtocol::JoyconCommonProtocol(std::shared_ptr<JoyconHandle> hidapi_handle_) - : hidapi_handle{hidapi_handle_} {} + : hidapi_handle{std::move(hidapi_handle_)} {} u8 JoyconCommonProtocol::GetCounter() { hidapi_handle->packet_counter = (hidapi_handle->packet_counter + 1) & 0x0F; @@ -256,7 +256,7 @@ DriverResult JoyconCommonProtocol::WaitSetMCUMode(ReportMode report_mode, MCUMod } // crc-8-ccitt / polynomial 0x07 look up table -static constexpr uint8_t mcu_crc8_table[256] = { +constexpr std::array<u8, 256> mcu_crc8_table = { 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, @@ -278,7 +278,7 @@ u8 JoyconCommonProtocol::CalculateMCU_CRC8(u8* buffer, u8 size) const { u8 crc8 = 0x0; for (int i = 0; i < size; ++i) { - crc8 = mcu_crc8_table[(u8)(crc8 ^ buffer[i])]; + crc8 = mcu_crc8_table[static_cast<u8>(crc8 ^ buffer[i])]; } return crc8; } diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp index 829f7625d6..cbd9ff4f8b 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp +++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp @@ -7,7 +7,7 @@ namespace InputCommon::Joycon { GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) - : JoyconCommonProtocol(handle) {} + : JoyconCommonProtocol(std::move(handle)) {} DriverResult GenericProtocol::EnablePassiveMode() { SetBlocking(); @@ -43,7 +43,7 @@ DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) } DriverResult GenericProtocol::EnableImu(bool enable) { - const std::vector<u8> buffer{static_cast<u8>(enable ? 1 : 0)}; + const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; std::vector<u8> output; SetBlocking(); const auto result = SendSubCommand(SubCommand::ENABLE_IMU, buffer, output); @@ -54,8 +54,8 @@ DriverResult GenericProtocol::EnableImu(bool enable) { DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, AccelerometerSensitivity asen, AccelerometerPerformance afrec) { - const std::vector<u8> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), - static_cast<u8>(gfrec), static_cast<u8>(afrec)}; + const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), + static_cast<u8>(gfrec), static_cast<u8>(afrec)}; std::vector<u8> output; SetBlocking(); const auto result = SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer, output); @@ -115,7 +115,7 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { } DriverResult GenericProtocol::SetHomeLight() { - const std::vector<u8> buffer{0x0f, 0xf0, 0x00}; + static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; std::vector<u8> output; SetBlocking(); @@ -130,7 +130,7 @@ DriverResult GenericProtocol::SetLedBusy() { } DriverResult GenericProtocol::SetLedPattern(u8 leds) { - const std::vector<u8> buffer{leds}; + const std::array<u8, 1> buffer{leds}; std::vector<u8> output; SetBlocking(); diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.h b/src/input_common/helpers/joycon_protocol/generic_functions.h index c3e2ccadc0..239bb7dbf9 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.h +++ b/src/input_common/helpers/joycon_protocol/generic_functions.h @@ -16,7 +16,7 @@ namespace InputCommon::Joycon { /// Joycon driver functions that easily implemented class GenericProtocol final : private JoyconCommonProtocol { public: - GenericProtocol(std::shared_ptr<JoyconHandle> handle); + explicit GenericProtocol(std::shared_ptr<JoyconHandle> handle); /// Enables passive mode. This mode only sends button data on change. Sticks will return digital /// data instead of analog. Motion will be disabled diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index 69b2bfe050..8755e310b8 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp @@ -7,7 +7,8 @@ namespace InputCommon::Joycon { -NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) : JoyconCommonProtocol(handle) {} +NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) + : JoyconCommonProtocol(std::move(handle)) {} DriverResult NfcProtocol::EnableNfc() { LOG_INFO(Input, "Enable NFC"); @@ -160,9 +161,9 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { std::vector<u8> output; std::size_t tries = 0; - std::string uuid_string = ""; + std::string uuid_string; for (auto& content : data.uuid) { - uuid_string += " " + fmt::format("{:02x}", content); + uuid_string += fmt::format(" {:02x}", content); } LOG_INFO(Input, "Tag detected, type={}, uuid={}", data.type, uuid_string); @@ -407,7 +408,7 @@ NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(std::size_t pages) const { return {}; } -bool NfcProtocol::IsEnabled() { +bool NfcProtocol::IsEnabled() const { return is_enabled; } diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index 0ede03d505..5cb0e5a652 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h @@ -17,7 +17,7 @@ namespace InputCommon::Joycon { class NfcProtocol final : private JoyconCommonProtocol { public: - NfcProtocol(std::shared_ptr<JoyconHandle> handle); + explicit NfcProtocol(std::shared_ptr<JoyconHandle> handle); DriverResult EnableNfc(); @@ -29,7 +29,7 @@ public: bool HasAmiibo(); - bool IsEnabled(); + bool IsEnabled() const; private: struct TagFoundData { diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp index 47769f3441..8adad57dd6 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.cpp +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp @@ -7,7 +7,7 @@ namespace InputCommon::Joycon { RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) - : JoyconCommonProtocol(handle) {} + : JoyconCommonProtocol(std::move(handle)) {} DriverResult RingConProtocol::EnableRingCon() { LOG_DEBUG(Input, "Enable Ringcon"); @@ -78,7 +78,7 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { is_connected = false; do { - std::vector<u8> empty_data(0); + std::array<u8, 1> empty_data{}; const auto result = SendSubCommand(SubCommand::UNKNOWN_RINGCON, empty_data, output); if (result != DriverResult::Success) { @@ -101,11 +101,11 @@ DriverResult RingConProtocol::ConfigureRing() { std::vector<u8> output; std::size_t tries = 0; + 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}; 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) { @@ -116,13 +116,13 @@ DriverResult RingConProtocol::ConfigureRing() { } } while (output[14] != 0x5C); - std::vector<u8> ringcon_data{0x04, 0x01, 0x01, 0x02}; + static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02}; result = SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data, output); return result; } -bool RingConProtocol::IsEnabled() { +bool RingConProtocol::IsEnabled() const { return is_enabled; } diff --git a/src/input_common/helpers/joycon_protocol/ringcon.h b/src/input_common/helpers/joycon_protocol/ringcon.h index 0c25de23ee..6e858f3fcb 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.h +++ b/src/input_common/helpers/joycon_protocol/ringcon.h @@ -17,7 +17,7 @@ namespace InputCommon::Joycon { class RingConProtocol final : private JoyconCommonProtocol { public: - RingConProtocol(std::shared_ptr<JoyconHandle> handle); + explicit RingConProtocol(std::shared_ptr<JoyconHandle> handle); DriverResult EnableRingCon(); @@ -25,7 +25,7 @@ public: DriverResult StartRingconPolling(); - bool IsEnabled(); + bool IsEnabled() const; private: DriverResult IsRingConnected(bool& is_connected); diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp index 17ee388634..fad67a94ba 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.cpp +++ b/src/input_common/helpers/joycon_protocol/rumble.cpp @@ -1,17 +1,20 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <algorithm> +#include <cmath> + #include "common/logging/log.h" #include "input_common/helpers/joycon_protocol/rumble.h" namespace InputCommon::Joycon { RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) - : JoyconCommonProtocol(handle) {} + : JoyconCommonProtocol(std::move(handle)) {} DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { LOG_DEBUG(Input, "Enable Rumble"); - const std::vector<u8> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; + const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; std::vector<u8> output; SetBlocking(); const auto result = SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer, output); @@ -20,7 +23,7 @@ DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { } DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { - std::vector<u8> buffer(sizeof(DefaultVibrationBuffer)); + std::array<u8, sizeof(DefaultVibrationBuffer)> buffer{}; if (vibration.high_amplitude <= 0.0f && vibration.low_amplitude <= 0.0f) { return SendVibrationReport(DefaultVibrationBuffer); @@ -66,7 +69,7 @@ u8 RumbleProtocol::EncodeHighAmplitude(f32 amplitude) const { /* More information about these values can be found here: * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md */ - constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ + static constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ std::pair<f32, int>{0.0f, 0x0}, {0.01f, 0x2}, {0.012f, 0x4}, @@ -183,7 +186,7 @@ u16 RumbleProtocol::EncodeLowAmplitude(f32 amplitude) const { /* More information about these values can be found here: * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md */ - constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ + static constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ std::pair<f32, int>{0.0f, 0x0040}, {0.01f, 0x8040}, {0.012f, 0x0041}, diff --git a/src/input_common/helpers/joycon_protocol/rumble.h b/src/input_common/helpers/joycon_protocol/rumble.h index 7d0329f039..6c12b79258 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.h +++ b/src/input_common/helpers/joycon_protocol/rumble.h @@ -17,7 +17,7 @@ namespace InputCommon::Joycon { class RumbleProtocol final : private JoyconCommonProtocol { public: - RumbleProtocol(std::shared_ptr<JoyconHandle> handle); + explicit RumbleProtocol(std::shared_ptr<JoyconHandle> handle); DriverResult EnableRumble(bool is_enabled); -- cgit v1.2.3-70-g09d2 From 459fb2b21337bae60194a2a99ce68c87aaed522d Mon Sep 17 00:00:00 2001 From: Narr the Reg <juangerman-13@hotmail.com> Date: Wed, 28 Dec 2022 15:21:12 -0600 Subject: input_common: Implement joycon ir camera --- src/core/hid/emulated_controller.cpp | 21 +- src/core/hid/emulated_controller.h | 5 +- src/core/hle/service/hid/irs.cpp | 11 + src/input_common/CMakeLists.txt | 2 + src/input_common/drivers/joycon.cpp | 29 +- src/input_common/drivers/joycon.h | 5 +- src/input_common/helpers/joycon_driver.cpp | 55 +++- src/input_common/helpers/joycon_driver.h | 4 + .../helpers/joycon_protocol/common_protocol.cpp | 13 + .../helpers/joycon_protocol/common_protocol.h | 7 + src/input_common/helpers/joycon_protocol/irs.cpp | 300 +++++++++++++++++++++ src/input_common/helpers/joycon_protocol/irs.h | 63 +++++ .../helpers/joycon_protocol/joycon_types.h | 107 +++++++- .../helpers/joycon_protocol/poller.cpp | 6 +- src/input_common/helpers/joycon_protocol/poller.h | 3 +- 15 files changed, 608 insertions(+), 23 deletions(-) create mode 100644 src/input_common/helpers/joycon_protocol/irs.cpp create mode 100644 src/input_common/helpers/joycon_protocol/irs.h (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 915ffa4906..faf9e7c4e5 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -145,7 +145,9 @@ void EmulatedController::LoadDevices() { battery_params[LeftIndex].Set("battery", true); battery_params[RightIndex].Set("battery", true); - camera_params = Common::ParamPackage{"engine:camera,camera:1"}; + camera_params[0] = right_joycon; + camera_params[0].Set("camera", true); + camera_params[1] = Common::ParamPackage{"engine:camera,camera:1"}; ring_params[1] = Common::ParamPackage{"engine:joycon,axis_x:100,axis_y:101"}; nfc_params[0] = Common::ParamPackage{"engine:virtual_amiibo,nfc:1"}; nfc_params[1] = right_joycon; @@ -153,7 +155,7 @@ void EmulatedController::LoadDevices() { output_params[LeftIndex] = left_joycon; output_params[RightIndex] = right_joycon; - output_params[2] = camera_params; + output_params[2] = camera_params[1]; output_params[3] = nfc_params[0]; output_params[LeftIndex].Set("output", true); output_params[RightIndex].Set("output", true); @@ -171,7 +173,7 @@ void EmulatedController::LoadDevices() { std::ranges::transform(battery_params, battery_devices.begin(), Common::Input::CreateInputDevice); std::ranges::transform(color_params, color_devices.begin(), Common::Input::CreateInputDevice); - camera_devices = Common::Input::CreateInputDevice(camera_params); + std::ranges::transform(camera_params, camera_devices.begin(), Common::Input::CreateInputDevice); std::ranges::transform(ring_params, ring_analog_devices.begin(), Common::Input::CreateInputDevice); std::ranges::transform(nfc_params, nfc_devices.begin(), Common::Input::CreateInputDevice); @@ -362,12 +364,15 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } - if (camera_devices) { - camera_devices->SetCallback({ + for (std::size_t index = 0; index < camera_devices.size(); ++index) { + if (!camera_devices[index]) { + continue; + } + camera_devices[index]->SetCallback({ .on_change = [this](const Common::Input::CallbackStatus& callback) { SetCamera(callback); }, }); - camera_devices->ForceUpdate(); + camera_devices[index]->ForceUpdate(); } for (std::size_t index = 0; index < ring_analog_devices.size(); ++index) { @@ -477,7 +482,9 @@ void EmulatedController::UnloadInput() { for (auto& stick : virtual_stick_devices) { stick.reset(); } - camera_devices.reset(); + for (auto& camera : camera_devices) { + camera.reset(); + } for (auto& ring : ring_analog_devices) { ring.reset(); } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index fb931fc0a8..edebfc15c2 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -39,7 +39,8 @@ using ColorDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; using BatteryDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; -using CameraDevices = std::unique_ptr<Common::Input::InputDevice>; +using CameraDevices = + std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; using RingAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, max_emulated_controllers>; using NfcDevices = @@ -52,7 +53,7 @@ using ControllerMotionParams = std::array<Common::ParamPackage, Settings::Native using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; using ColorParams = std::array<Common::ParamPackage, max_emulated_controllers>; using BatteryParams = std::array<Common::ParamPackage, max_emulated_controllers>; -using CameraParams = Common::ParamPackage; +using CameraParams = std::array<Common::ParamPackage, max_emulated_controllers>; using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>; using NfcParams = std::array<Common::ParamPackage, max_emulated_controllers>; using OutputParams = std::array<Common::ParamPackage, output_devices_size>; diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 6a3453457f..3c1fa2274f 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -74,6 +74,8 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); + npad_device->SetPollingMode(Common::Input::PollingMode::Active); + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -108,6 +110,7 @@ void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { auto result = IsIrCameraHandleValid(parameters.camera_handle); if (result.IsSuccess()) { // TODO: Stop Image processor + npad_device->SetPollingMode(Common::Input::PollingMode::Active); result = ResultSuccess; } @@ -139,6 +142,7 @@ void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { MakeProcessor<MomentProcessor>(parameters.camera_handle, device); auto& image_transfer_processor = GetProcessor<MomentProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -170,6 +174,7 @@ void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { auto& image_transfer_processor = GetProcessor<ClusteringProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -219,6 +224,7 @@ void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { GetProcessor<ImageTransferProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); image_transfer_processor.SetTransferMemoryPointer(transfer_memory); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -294,6 +300,7 @@ void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { auto& image_transfer_processor = GetProcessor<TeraPluginProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -343,6 +350,7 @@ void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { MakeProcessor<PointingProcessor>(camera_handle, device); auto& image_transfer_processor = GetProcessor<PointingProcessor>(camera_handle); image_transfer_processor.SetConfig(processor_config); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -453,6 +461,7 @@ void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { GetProcessor<ImageTransferProcessor>(parameters.camera_handle); image_transfer_processor.SetConfig(parameters.processor_config); image_transfer_processor.SetTransferMemoryPointer(transfer_memory); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -479,6 +488,7 @@ void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { MakeProcessor<IrLedProcessor>(camera_handle, device); auto& image_transfer_processor = GetProcessor<IrLedProcessor>(camera_handle); image_transfer_processor.SetConfig(processor_config); + npad_device->SetPollingMode(Common::Input::PollingMode::IR); } IPC::ResponseBuilder rb{ctx, 2}; @@ -504,6 +514,7 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { auto result = IsIrCameraHandleValid(parameters.camera_handle); if (result.IsSuccess()) { // TODO: Stop image processor async + npad_device->SetPollingMode(Common::Input::PollingMode::IR); result = ResultSuccess; } diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 9c901af2ab..e3b627e4ff 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -64,6 +64,8 @@ if (ENABLE_SDL2) helpers/joycon_protocol/generic_functions.cpp helpers/joycon_protocol/generic_functions.h helpers/joycon_protocol/joycon_types.h + helpers/joycon_protocol/irs.cpp + helpers/joycon_protocol/irs.h helpers/joycon_protocol/nfc.cpp helpers/joycon_protocol/nfc.h helpers/joycon_protocol/poller.cpp diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index cf54f1b533..6c03e09537 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -191,6 +191,10 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { .on_amiibo_data = {[this, port](const std::vector<u8>& amiibo_data) { OnAmiiboUpdate(port, amiibo_data); }}, + .on_camera_data = {[this, port](const std::vector<u8>& camera_data, + Joycon::IrsResolution format) { + OnCameraUpdate(port, camera_data, format); + }}, }; handle->InitializeDevice(); @@ -265,9 +269,14 @@ Common::Input::DriverResult Joycons::SetLeds(const PadIdentifier& identifier, handle->SetLedConfig(static_cast<u8>(led_config))); } -Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier_, +Common::Input::DriverResult Joycons::SetCameraFormat(const PadIdentifier& identifier, Common::Input::CameraFormat camera_format) { - return Common::Input::DriverResult::NotSupported; + auto handle = GetHandle(identifier); + if (handle == nullptr) { + return Common::Input::DriverResult::InvalidHandle; + } + return static_cast<Common::Input::DriverResult>(handle->SetIrsConfig( + Joycon::IrsMode::ImageTransfer, static_cast<Joycon::IrsResolution>(camera_format))); }; Common::Input::NfcState Joycons::SupportsNfc(const PadIdentifier& identifier_) const { @@ -288,18 +297,16 @@ Common::Input::DriverResult Joycons::SetPollingMode(const PadIdentifier& identif } switch (polling_mode) { - case Common::Input::PollingMode::NFC: - return static_cast<Common::Input::DriverResult>(handle->SetNfcMode()); - break; case Common::Input::PollingMode::Active: return static_cast<Common::Input::DriverResult>(handle->SetActiveMode()); - break; case Common::Input::PollingMode::Pasive: return static_cast<Common::Input::DriverResult>(handle->SetPasiveMode()); - break; + case Common::Input::PollingMode::IR: + return static_cast<Common::Input::DriverResult>(handle->SetIrMode()); + case Common::Input::PollingMode::NFC: + return static_cast<Common::Input::DriverResult>(handle->SetNfcMode()); case Common::Input::PollingMode::Ring: return static_cast<Common::Input::DriverResult>(handle->SetRingConMode()); - break; default: return Common::Input::DriverResult::NotSupported; } @@ -390,6 +397,12 @@ void Joycons::OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_dat SetNfc(identifier, {nfc_state, amiibo_data}); } +void Joycons::OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, + Joycon::IrsResolution format) { + const auto identifier = GetIdentifier(port, Joycon::ControllerType::Right); + SetCamera(identifier, {static_cast<Common::Input::CameraFormat>(format), camera_data}); +} + std::shared_ptr<Joycon::JoyconDriver> Joycons::GetHandle(PadIdentifier identifier) const { auto is_handle_active = [&](std::shared_ptr<Joycon::JoyconDriver> device) { if (!device) { diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index 1a04c19fd3..f180b74783 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -17,6 +17,7 @@ struct Color; struct MotionData; enum class ControllerType; enum class DriverResult; +enum class IrsResolution; class JoyconDriver; } // namespace InputCommon::Joycon @@ -35,7 +36,7 @@ public: Common::Input::DriverResult SetLeds(const PadIdentifier& identifier, const Common::Input::LedStatus& led_status) override; - Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier_, + Common::Input::DriverResult SetCameraFormat(const PadIdentifier& identifier, Common::Input::CameraFormat camera_format) override; Common::Input::NfcState SupportsNfc(const PadIdentifier& identifier_) const override; @@ -81,6 +82,8 @@ private: const Joycon::MotionData& value); void OnRingConUpdate(f32 ring_data); void OnAmiiboUpdate(std::size_t port, const std::vector<u8>& amiibo_data); + void OnCameraUpdate(std::size_t port, const std::vector<u8>& camera_data, + Joycon::IrsResolution format); /// Returns a JoyconHandle corresponding to a PadIdentifier std::shared_ptr<Joycon::JoyconDriver> GetHandle(PadIdentifier identifier) const; diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 8217ba7f61..040832a4ba 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<CalibrationProtocol>(hidapi_handle); generic_protocol = std::make_unique<GenericProtocol>(hidapi_handle); + irs_protocol = std::make_unique<IrsProtocol>(hidapi_handle); nfc_protocol = std::make_unique<NfcProtocol>(hidapi_handle); ring_protocol = std::make_unique<RingConProtocol>(hidapi_handle); rumble_protocol = std::make_unique<RumbleProtocol>(hidapi_handle); @@ -200,10 +202,15 @@ void JoyconDriver::OnNewData(std::span<u8> 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<u8> buffer) { std::vector<u8> 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(); diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index 5ff15c7841..61ecf4a6c2 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -13,6 +13,7 @@ namespace InputCommon::Joycon { class CalibrationProtocol; class GenericProtocol; +class IrsProtocol; class NfcProtocol; class JoyconPoller; class RingConProtocol; @@ -41,8 +42,10 @@ public: DriverResult SetVibration(const VibrationValue& vibration); DriverResult SetLedConfig(u8 led_pattern); + DriverResult SetIrsConfig(IrsMode mode_, IrsResolution format_); DriverResult SetPasiveMode(); DriverResult SetActiveMode(); + DriverResult SetIrMode(); DriverResult SetNfcMode(); DriverResult SetRingConMode(); @@ -87,6 +90,7 @@ private: // Protocol Features std::unique_ptr<CalibrationProtocol> calibration_protocol; std::unique_ptr<GenericProtocol> generic_protocol; + std::unique_ptr<IrsProtocol> irs_protocol; std::unique_ptr<NfcProtocol> nfc_protocol; std::unique_ptr<JoyconPoller> joycon_poller; std::unique_ptr<RingConProtocol> ring_protocol; diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index a4d08fdafa..a329db1070 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -120,6 +120,19 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const return DriverResult::Success; } +DriverResult JoyconCommonProtocol::SendMcuCommand(SubCommand sc, std::span<const u8> buffer) { + std::vector<u8> local_buffer(MaxResponseSize); + + local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); + local_buffer[1] = GetCounter(); + local_buffer[10] = static_cast<u8>(sc); + for (std::size_t i = 0; i < buffer.size(); ++i) { + local_buffer[11 + i] = buffer[i]; + } + + return SendData(local_buffer); +} + DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffer) { std::vector<u8> local_buffer(MaxResponseSize); diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h index a65e4aa76a..2a3feaf598 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.h +++ b/src/input_common/helpers/joycon_protocol/common_protocol.h @@ -74,6 +74,13 @@ public: */ DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); + /** + * Sends a mcu command to the device + * @param sc sub command to be send + * @param buffer data to be send + */ + DriverResult SendMcuCommand(SubCommand sc, std::span<const u8> buffer); + /** * Sends vibration data to the joycon * @param buffer data to be send diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp new file mode 100644 index 0000000000..9dfa503c23 --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/irs.cpp @@ -0,0 +1,300 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include <thread> +#include "common/logging/log.h" +#include "input_common/helpers/joycon_protocol/irs.h" + +namespace InputCommon::Joycon { + +IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) + : JoyconCommonProtocol(std::move(handle)) {} + +DriverResult IrsProtocol::EnableIrs() { + LOG_INFO(Input, "Enable IRS"); + DriverResult result{DriverResult::Success}; + SetBlocking(); + + if (result == DriverResult::Success) { + result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); + } + if (result == DriverResult::Success) { + result = EnableMCU(true); + } + if (result == DriverResult::Success) { + result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::Standby); + } + if (result == DriverResult::Success) { + const MCUConfig config{ + .command = MCUCommand::ConfigureMCU, + .sub_command = MCUSubCommand::SetMCUMode, + .mode = MCUMode::IR, + .crc = {}, + }; + + result = ConfigureMCU(config); + } + if (result == DriverResult::Success) { + result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::IR); + } + if (result == DriverResult::Success) { + result = ConfigureIrs(); + } + if (result == DriverResult::Success) { + result = WriteRegistersStep1(); + } + if (result == DriverResult::Success) { + result = WriteRegistersStep2(); + } + + is_enabled = true; + + SetNonBlocking(); + return result; +} + +DriverResult IrsProtocol::DisableIrs() { + LOG_DEBUG(Input, "Disable IRS"); + DriverResult result{DriverResult::Success}; + SetBlocking(); + + if (result == DriverResult::Success) { + result = EnableMCU(false); + } + + is_enabled = false; + + SetNonBlocking(); + return result; +} + +DriverResult IrsProtocol::SetIrsConfig(IrsMode mode, IrsResolution format) { + irs_mode = mode; + switch (format) { + case IrsResolution::Size320x240: + resolution_code = IrsResolutionCode::Size320x240; + fragments = IrsFragments::Size320x240; + resolution = IrsResolution::Size320x240; + break; + case IrsResolution::Size160x120: + resolution_code = IrsResolutionCode::Size160x120; + fragments = IrsFragments::Size160x120; + resolution = IrsResolution::Size160x120; + break; + case IrsResolution::Size80x60: + resolution_code = IrsResolutionCode::Size80x60; + fragments = IrsFragments::Size80x60; + resolution = IrsResolution::Size80x60; + break; + case IrsResolution::Size20x15: + resolution_code = IrsResolutionCode::Size20x15; + fragments = IrsFragments::Size20x15; + resolution = IrsResolution::Size20x15; + break; + case IrsResolution::Size40x30: + default: + resolution_code = IrsResolutionCode::Size40x30; + fragments = IrsFragments::Size40x30; + resolution = IrsResolution::Size40x30; + break; + } + + // Restart feature + if (is_enabled) { + DisableIrs(); + return EnableIrs(); + } + + return DriverResult::Success; +} + +DriverResult IrsProtocol::RequestImage(std::span<u8> buffer) { + const u8 next_packet_fragment = + static_cast<u8>((packet_fragment + 1) % (static_cast<u8>(fragments) + 1)); + + if (buffer[0] == 0x31 && buffer[49] == 0x03) { + u8 new_packet_fragment = buffer[52]; + if (new_packet_fragment == next_packet_fragment) { + packet_fragment = next_packet_fragment; + memcpy(buf_image.data() + (300 * packet_fragment), buffer.data() + 59, 300); + + return RequestFrame(packet_fragment); + } + + if (new_packet_fragment == packet_fragment) { + return RequestFrame(packet_fragment); + } + + return ResendFrame(next_packet_fragment); + } + + return RequestFrame(packet_fragment); +} + +DriverResult IrsProtocol::ConfigureIrs() { + LOG_DEBUG(Input, "Configure IRS"); + constexpr std::size_t max_tries = 28; + std::vector<u8> output; + std::size_t tries = 0; + + const IrsConfigure irs_configuration{ + .command = MCUCommand::ConfigureIR, + .sub_command = MCUSubCommand::SetDeviceMode, + .irs_mode = IrsMode::ImageTransfer, + .number_of_fragments = fragments, + .mcu_major_version = 0x0500, + .mcu_minor_version = 0x1800, + .crc = {}, + }; + buf_image.resize((static_cast<u8>(fragments) + 1) * 300); + + std::vector<u8> request_data(sizeof(IrsConfigure)); + memcpy(request_data.data(), &irs_configuration, sizeof(IrsConfigure)); + request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); + do { + const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); + + if (result != DriverResult::Success) { + return result; + } + if (tries++ >= max_tries) { + return DriverResult::WrongReply; + } + } while (output[15] != 0x0b); + + return DriverResult::Success; +} + +DriverResult IrsProtocol::WriteRegistersStep1() { + LOG_DEBUG(Input, "WriteRegistersStep1"); + DriverResult result{DriverResult::Success}; + constexpr std::size_t max_tries = 28; + std::vector<u8> output; + std::size_t tries = 0; + + const IrsWriteRegisters irs_registers{ + .command = MCUCommand::ConfigureIR, + .sub_command = MCUSubCommand::WriteDeviceRegisters, + .number_of_registers = 0x9, + .registers = + { + IrsRegister{IrRegistersAddress::Resolution, static_cast<u8>(resolution_code)}, + {IrRegistersAddress::ExposureLSB, static_cast<u8>(exposure & 0xff)}, + {IrRegistersAddress::ExposureMSB, static_cast<u8>(exposure >> 8)}, + {IrRegistersAddress::ExposureTime, 0x00}, + {IrRegistersAddress::Leds, static_cast<u8>(leds)}, + {IrRegistersAddress::DigitalGainLSB, static_cast<u8>((digital_gain & 0x0f) << 4)}, + {IrRegistersAddress::DigitalGainMSB, static_cast<u8>((digital_gain & 0xf0) >> 4)}, + {IrRegistersAddress::LedFilter, static_cast<u8>(led_filter)}, + {IrRegistersAddress::WhitePixelThreshold, 0xc8}, + }, + .crc = {}, + }; + + std::vector<u8> request_data(sizeof(IrsWriteRegisters)); + memcpy(request_data.data(), &irs_registers, sizeof(IrsWriteRegisters)); + request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); + + std::array<u8, 38> mcu_request{0x02}; + mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); + mcu_request[37] = 0xFF; + + if (result != DriverResult::Success) { + return result; + } + + do { + result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); + + // First time we need to set the report mode + if (result == DriverResult::Success && tries == 0) { + result = SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request); + } + if (result == DriverResult::Success && tries == 0) { + GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); + } + + if (result != DriverResult::Success) { + return result; + } + if (tries++ >= max_tries) { + return DriverResult::WrongReply; + } + } while (!(output[15] == 0x13 && output[17] == 0x07) && output[15] != 0x23); + + return DriverResult::Success; +} + +DriverResult IrsProtocol::WriteRegistersStep2() { + LOG_DEBUG(Input, "WriteRegistersStep2"); + constexpr std::size_t max_tries = 28; + std::vector<u8> output; + std::size_t tries = 0; + + const IrsWriteRegisters irs_registers{ + .command = MCUCommand::ConfigureIR, + .sub_command = MCUSubCommand::WriteDeviceRegisters, + .number_of_registers = 0x8, + .registers = + { + IrsRegister{IrRegistersAddress::LedIntensitiyMSB, + static_cast<u8>(led_intensity >> 8)}, + {IrRegistersAddress::LedIntensitiyLSB, static_cast<u8>(led_intensity & 0xff)}, + {IrRegistersAddress::ImageFlip, static_cast<u8>(image_flip)}, + {IrRegistersAddress::DenoiseSmoothing, static_cast<u8>((denoise >> 16) & 0xff)}, + {IrRegistersAddress::DenoiseEdge, static_cast<u8>((denoise >> 8) & 0xff)}, + {IrRegistersAddress::DenoiseColor, static_cast<u8>(denoise & 0xff)}, + {IrRegistersAddress::UpdateTime, 0x2d}, + {IrRegistersAddress::FinalizeConfig, 0x01}, + }, + .crc = {}, + }; + + std::vector<u8> request_data(sizeof(IrsWriteRegisters)); + memcpy(request_data.data(), &irs_registers, sizeof(IrsWriteRegisters)); + request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); + do { + const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, request_data, output); + + if (result != DriverResult::Success) { + return result; + } + if (tries++ >= max_tries) { + return DriverResult::WrongReply; + } + } while (output[15] != 0x13 && output[15] != 0x23); + + return DriverResult::Success; +} + +DriverResult IrsProtocol::RequestFrame(u8 frame) { + std::array<u8, 38> mcu_request{}; + mcu_request[3] = frame; + mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); + mcu_request[37] = 0xFF; + return SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request); +} + +DriverResult IrsProtocol::ResendFrame(u8 frame) { + std::array<u8, 38> mcu_request{}; + mcu_request[1] = 0x1; + mcu_request[2] = frame; + mcu_request[3] = 0x0; + mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); + mcu_request[37] = 0xFF; + return SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request); +} + +std::vector<u8> IrsProtocol::GetImage() const { + return buf_image; +} + +IrsResolution IrsProtocol::GetIrsFormat() const { + return resolution; +} + +bool IrsProtocol::IsEnabled() const { + return is_enabled; +} + +} // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/irs.h b/src/input_common/helpers/joycon_protocol/irs.h new file mode 100644 index 0000000000..76dfa02ea5 --- /dev/null +++ b/src/input_common/helpers/joycon_protocol/irs.h @@ -0,0 +1,63 @@ +// 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 IrsProtocol final : private JoyconCommonProtocol { +public: + explicit IrsProtocol(std::shared_ptr<JoyconHandle> handle); + + DriverResult EnableIrs(); + + DriverResult DisableIrs(); + + DriverResult SetIrsConfig(IrsMode mode, IrsResolution format); + + DriverResult RequestImage(std::span<u8> buffer); + + std::vector<u8> GetImage() const; + + IrsResolution GetIrsFormat() const; + + bool IsEnabled() const; + +private: + DriverResult ConfigureIrs(); + + DriverResult WriteRegistersStep1(); + DriverResult WriteRegistersStep2(); + + DriverResult RequestFrame(u8 frame); + DriverResult ResendFrame(u8 frame); + + IrsMode irs_mode{IrsMode::ImageTransfer}; + IrsResolution resolution{IrsResolution::Size40x30}; + IrsResolutionCode resolution_code{IrsResolutionCode::Size40x30}; + IrsFragments fragments{IrsFragments::Size40x30}; + IrLeds leds{IrLeds::BrightAndDim}; + IrExLedFilter led_filter{IrExLedFilter::Enabled}; + IrImageFlip image_flip{IrImageFlip::Normal}; + u8 digital_gain{0x01}; + u16 exposure{0x2490}; + u16 led_intensity{0x0f10}; + u32 denoise{0x012344}; + + u8 packet_fragment{}; + std::vector<u8> buf_image; // 8bpp greyscale image. + + bool is_enabled{}; +}; + +} // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 36c00a8d70..273c8d07d3 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -18,7 +18,7 @@ namespace InputCommon::Joycon { constexpr u32 MaxErrorCount = 50; -constexpr u32 MaxBufferSize = 60; +constexpr u32 MaxBufferSize = 368; constexpr u32 MaxResponseSize = 49; constexpr u32 MaxSubCommandResponseSize = 64; constexpr std::array<u8, 8> DefaultVibrationBuffer{0x0, 0x1, 0x40, 0x40, 0x0, 0x1, 0x40, 0x40}; @@ -273,6 +273,80 @@ enum class NFCTagType : u8 { Ntag215 = 0x01, }; +enum class IrsMode : u8 { + None = 0x02, + Moment = 0x03, + Dpd = 0x04, + Clustering = 0x06, + ImageTransfer = 0x07, + Silhouette = 0x08, + TeraImage = 0x09, + SilhouetteTeraImage = 0x0A, +}; + +enum class IrsResolution { + Size320x240, + Size160x120, + Size80x60, + Size40x30, + Size20x15, + None, +}; + +enum class IrsResolutionCode : u8 { + Size320x240 = 0x00, // Full pixel array + Size160x120 = 0x50, // Sensor Binning [2 X 2] + Size80x60 = 0x64, // Sensor Binning [4 x 2] and Skipping [1 x 2] + Size40x30 = 0x69, // Sensor Binning [4 x 2] and Skipping [2 x 4] + Size20x15 = 0x6A, // Sensor Binning [4 x 2] and Skipping [4 x 4] +}; + +// Size of image divided by 300 +enum class IrsFragments : u8 { + Size20x15 = 0x00, + Size40x30 = 0x03, + Size80x60 = 0x0f, + Size160x120 = 0x3f, + Size320x240 = 0xFF, +}; + +enum class IrLeds : u8 { + BrightAndDim = 0x00, + Bright = 0x20, + Dim = 0x10, + None = 0x30, +}; + +enum class IrExLedFilter : u8 { + Disabled = 0x00, + Enabled = 0x03, +}; + +enum class IrImageFlip : u8 { + Normal = 0x00, + Inverted = 0x02, +}; + +enum class IrRegistersAddress : u16 { + UpdateTime = 0x0400, + FinalizeConfig = 0x0700, + LedFilter = 0x0e00, + Leds = 0x1000, + LedIntensitiyMSB = 0x1100, + LedIntensitiyLSB = 0x1200, + ImageFlip = 0x2d00, + Resolution = 0x2e00, + DigitalGainLSB = 0x2e01, + DigitalGainMSB = 0x2f01, + ExposureLSB = 0x3001, + ExposureMSB = 0x3101, + ExposureTime = 0x3201, + WhitePixelThreshold = 0x4301, + DenoiseSmoothing = 0x6701, + DenoiseEdge = 0x6801, + DenoiseColor = 0x6901, +}; + enum class DriverResult { Success, WrongReply, @@ -456,6 +530,36 @@ struct NFCRequestState { }; static_assert(sizeof(NFCRequestState) == 0x26, "NFCRequestState is an invalid size"); +struct IrsConfigure { + MCUCommand command; + MCUSubCommand sub_command; + IrsMode irs_mode; + IrsFragments number_of_fragments; + u16 mcu_major_version; + u16 mcu_minor_version; + INSERT_PADDING_BYTES(0x1D); + u8 crc; +}; +static_assert(sizeof(IrsConfigure) == 0x26, "IrsConfigure is an invalid size"); + +#pragma pack(push, 1) +struct IrsRegister { + IrRegistersAddress address; + u8 value; +}; +static_assert(sizeof(IrsRegister) == 0x3, "IrsRegister is an invalid size"); + +struct IrsWriteRegisters { + MCUCommand command; + MCUSubCommand sub_command; + u8 number_of_registers; + std::array<IrsRegister, 9> registers; + INSERT_PADDING_BYTES(0x7); + u8 crc; +}; +static_assert(sizeof(IrsWriteRegisters) == 0x26, "IrsWriteRegisters is an invalid size"); +#pragma pack(pop) + struct FirmwareVersion { u8 major; u8 minor; @@ -490,6 +594,7 @@ struct JoyconCallbacks { std::function<void(int, const MotionData&)> on_motion_data; std::function<void(f32)> on_ring_data; std::function<void(const std::vector<u8>&)> on_amiibo_data; + std::function<void(const std::vector<u8>&, IrsResolution)> on_camera_data; }; } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index fd05d98f38..940b20b7f0 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp @@ -74,10 +74,14 @@ void JoyconPoller::UpdateColor(const Color& color) { callbacks.on_color_data(color); } -void JoyconPoller::updateAmiibo(const std::vector<u8>& amiibo_data) { +void JoyconPoller::UpdateAmiibo(const std::vector<u8>& amiibo_data) { callbacks.on_amiibo_data(amiibo_data); } +void JoyconPoller::UpdateCamera(const std::vector<u8>& camera_data, IrsResolution format) { + callbacks.on_camera_data(camera_data, format); +} + void JoyconPoller::UpdateRing(s16 value, const RingStatus& ring_status) { float normalized_value = static_cast<float>(value - ring_status.default_value); if (normalized_value > 0) { diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index c40fc7bca8..354d41dad3 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h @@ -36,7 +36,8 @@ public: void UpdateColor(const Color& color); void UpdateRing(s16 value, const RingStatus& ring_status); - void updateAmiibo(const std::vector<u8>& amiibo_data); + void UpdateAmiibo(const std::vector<u8>& amiibo_data); + void UpdateCamera(const std::vector<u8>& amiibo_data, IrsResolution format); private: void UpdateActiveLeftPadInput(const InputReportActive& input, -- cgit v1.2.3-70-g09d2 From d05ea2f3ebdf62e328d2edbfc5b9bc01e3453569 Mon Sep 17 00:00:00 2001 From: german77 <juangerman-13@hotmail.com> 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/core/hle/service/hid/irs.cpp | 4 +-- src/input_common/helpers/joycon_driver.cpp | 30 ++++++++++++++-------- src/input_common/helpers/joycon_driver.h | 1 + .../helpers/joycon_protocol/common_protocol.cpp | 4 +-- 4 files changed, 24 insertions(+), 15 deletions(-) (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp') diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 3c1fa2274f..1a6fa2a44c 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -74,8 +74,6 @@ void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_IRS, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); - npad_device->SetPollingMode(Common::Input::PollingMode::Active); - IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -514,7 +512,7 @@ void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { auto result = IsIrCameraHandleValid(parameters.camera_handle); if (result.IsSuccess()) { // TODO: Stop image processor async - npad_device->SetPollingMode(Common::Input::PollingMode::IR); + npad_device->SetPollingMode(Common::Input::PollingMode::Active); result = ResultSuccess; } diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 040832a4ba..e8aef028af 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; diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index 61ecf4a6c2..e8e65e1331 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -107,6 +107,7 @@ private: bool starlink_connected{}; bool ring_connected{}; bool amiibo_detected{}; + bool is_ring_disabled_by_irs{}; // Harware configuration u8 leds{}; diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index a329db1070..153a3908c6 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -74,8 +74,8 @@ DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { } DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, std::vector<u8>& output) { - constexpr int timeout_mili = 100; - constexpr int MaxTries = 10; + constexpr int timeout_mili = 66; + constexpr int MaxTries = 15; int tries = 0; output.resize(MaxSubCommandResponseSize); -- cgit v1.2.3-70-g09d2 From 340f15d1fa79594dbe12a6e19140ba012751b533 Mon Sep 17 00:00:00 2001 From: german77 <juangerman-13@hotmail.com> Date: Fri, 13 Jan 2023 23:29:05 -0600 Subject: input_common: Address byte review --- src/input_common/drivers/joycon.cpp | 50 +++--- src/input_common/drivers/joycon.h | 1 - src/input_common/drivers/sdl_driver.cpp | 2 +- src/input_common/helpers/joycon_driver.cpp | 8 +- src/input_common/helpers/joycon_driver.h | 3 +- .../helpers/joycon_protocol/calibration.cpp | 9 +- .../helpers/joycon_protocol/common_protocol.cpp | 24 +-- .../helpers/joycon_protocol/common_protocol.h | 22 ++- .../helpers/joycon_protocol/generic_functions.cpp | 54 ++---- src/input_common/helpers/joycon_protocol/irs.cpp | 18 +- .../helpers/joycon_protocol/joycon_types.h | 12 ++ src/input_common/helpers/joycon_protocol/nfc.cpp | 183 ++++++++++----------- src/input_common/helpers/joycon_protocol/nfc.h | 4 +- .../helpers/joycon_protocol/poller.cpp | 18 +- .../helpers/joycon_protocol/ringcon.cpp | 36 ++-- .../helpers/joycon_protocol/rumble.cpp | 19 +-- 16 files changed, 220 insertions(+), 243 deletions(-) (limited to 'src/input_common/helpers/joycon_protocol/common_protocol.cpp') diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index fff886ca8a..1582def13c 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -60,15 +60,12 @@ void Joycons::Setup() { device = std::make_shared<Joycon::JoyconDriver>(port++); } - if (!scan_thread_running) { - scan_thread = std::jthread([this](std::stop_token stop_token) { ScanThread(stop_token); }); - } + scan_thread = std::jthread([this](std::stop_token stop_token) { ScanThread(stop_token); }); } void Joycons::ScanThread(std::stop_token stop_token) { constexpr u16 nintendo_vendor_id = 0x057e; - Common::SetCurrentThreadName("yuzu:input:JoyconScanThread"); - scan_thread_running = true; + Common::SetCurrentThreadName("JoyconScanThread"); while (!stop_token.stop_requested()) { SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); SDL_hid_device_info* cur_dev = devs; @@ -82,9 +79,9 @@ void Joycons::ScanThread(std::stop_token stop_token) { cur_dev = cur_dev->next; } + SDL_hid_free_enumeration(devs); std::this_thread::sleep_for(std::chrono::seconds(5)); } - scan_thread_running = false; } bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { @@ -185,19 +182,19 @@ void Joycons::RegisterNewDevice(SDL_hid_device_info* device_info) { std::shared_ptr<Joycon::JoyconDriver> Joycons::GetNextFreeHandle( Joycon::ControllerType type) const { - if (type == Joycon::ControllerType::Left) { - for (const auto& device : left_joycons) { - if (!device->IsConnected()) { - return device; - } + const auto unconnected_device = + std::ranges::find_if(left_joycons, [](auto& device) { return !device->IsConnected(); }); + if (unconnected_device != left_joycons.end()) { + return *unconnected_device; } } if (type == Joycon::ControllerType::Right) { - for (const auto& device : right_joycons) { - if (!device->IsConnected()) { - return device; - } + const auto unconnected_device = std::ranges::find_if( + right_joycons, [](auto& device) { return !device->IsConnected(); }); + + if (unconnected_device != right_joycons.end()) { + return *unconnected_device; } } return nullptr; @@ -391,20 +388,25 @@ std::shared_ptr<Joycon::JoyconDriver> Joycons::GetHandle(PadIdentifier identifie return false; }; const auto type = static_cast<Joycon::ControllerType>(identifier.pad); + if (type == Joycon::ControllerType::Left) { - for (const auto& device : left_joycons) { - if (is_handle_active(device)) { - return device; - } + const auto matching_device = std::ranges::find_if( + left_joycons, [is_handle_active](auto& device) { return is_handle_active(device); }); + + if (matching_device != left_joycons.end()) { + return *matching_device; } } + if (type == Joycon::ControllerType::Right) { - for (const auto& device : right_joycons) { - if (is_handle_active(device)) { - return device; - } + const auto matching_device = std::ranges::find_if( + right_joycons, [is_handle_active](auto& device) { return is_handle_active(device); }); + + if (matching_device != right_joycons.end()) { + return *matching_device; } } + return nullptr; } @@ -676,7 +678,7 @@ std::string Joycons::JoyconName(Joycon::ControllerType type) const { case Joycon::ControllerType::Dual: return "Dual Joycon"; default: - return "Unknow Joycon"; + return "Unknown Joycon"; } } } // namespace InputCommon diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index f5cc787db0..6d2e2ec786 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -99,7 +99,6 @@ private: std::string JoyconName(Joycon::ControllerType type) const; std::jthread scan_thread; - bool scan_thread_running{}; // Joycon types are split by type to ease supporting dualjoycon configurations std::array<std::shared_ptr<Joycon::JoyconDriver>, MaxSupportedControllers> left_joycons{}; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index e915ec0908..a0103edde2 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -321,7 +321,7 @@ void SDLDriver::InitJoystick(int joystick_index) { if (Settings::values.enable_joycon_driver) { if (guid.uuid[5] == 0x05 && guid.uuid[4] == 0x7e && (guid.uuid[8] == 0x06 || guid.uuid[8] == 0x07)) { - LOG_ERROR(Input, "Device black listed {}", joystick_index); + LOG_WARNING(Input, "Preferring joycon driver for device index {}", joystick_index); SDL_JoystickClose(sdl_joystick); return; } diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 5525723435..4159e5717a 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<u8> 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 { diff --git a/src/input_common/helpers/joycon_driver.h b/src/input_common/helpers/joycon_driver.h index e8e65e1331..c1e189fa52 100644 --- a/src/input_common/helpers/joycon_driver.h +++ b/src/input_common/helpers/joycon_driver.h @@ -3,6 +3,7 @@ #pragma once +#include <atomic> #include <functional> #include <mutex> #include <span> @@ -97,7 +98,7 @@ private: std::unique_ptr<RumbleProtocol> rumble_protocol; // Connection status - bool is_connected{}; + std::atomic<bool> is_connected{}; u64 delta_time; std::size_t error_counter{}; std::shared_ptr<JoyconHandle> hidapi_handle; diff --git a/src/input_common/helpers/joycon_protocol/calibration.cpp b/src/input_common/helpers/joycon_protocol/calibration.cpp index cd30ab8698..f6e7e97d59 100644 --- a/src/input_common/helpers/joycon_protocol/calibration.cpp +++ b/src/input_common/helpers/joycon_protocol/calibration.cpp @@ -12,10 +12,10 @@ CalibrationProtocol::CalibrationProtocol(std::shared_ptr<JoyconHandle> handle) : JoyconCommonProtocol(std::move(handle)) {} DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration& calibration) { + ScopedSetBlocking sb(this); std::vector<u8> buffer; DriverResult result{DriverResult::Success}; calibration = {}; - SetBlocking(); result = ReadSPI(CalAddr::USER_LEFT_MAGIC, sizeof(u16), buffer); @@ -44,15 +44,14 @@ DriverResult CalibrationProtocol::GetLeftJoyStickCalibration(JoyStickCalibration // Set a valid default calibration if data is missing ValidateCalibration(calibration); - SetNonBlocking(); return result; } DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibration& calibration) { + ScopedSetBlocking sb(this); std::vector<u8> buffer; DriverResult result{DriverResult::Success}; calibration = {}; - SetBlocking(); result = ReadSPI(CalAddr::USER_RIGHT_MAGIC, sizeof(u16), buffer); @@ -81,15 +80,14 @@ DriverResult CalibrationProtocol::GetRightJoyStickCalibration(JoyStickCalibratio // Set a valid default calibration if data is missing ValidateCalibration(calibration); - SetNonBlocking(); return result; } DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibration) { + ScopedSetBlocking sb(this); std::vector<u8> buffer; DriverResult result{DriverResult::Success}; calibration = {}; - SetBlocking(); result = ReadSPI(CalAddr::USER_IMU_MAGIC, sizeof(u16), buffer); @@ -124,7 +122,6 @@ DriverResult CalibrationProtocol::GetImuCalibration(MotionCalibration& calibrati ValidateCalibration(calibration); - SetNonBlocking(); return result; } diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 153a3908c6..417d0dcc50 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -58,9 +58,8 @@ DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device } DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { - const std::vector<u8> buffer{static_cast<u8>(report_mode)}; - std::vector<u8> output; - return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer, output); + const std::array<u8, 1> buffer{static_cast<u8>(report_mode)}; + return SendSubCommand(SubCommand::SET_REPORT_MODE, buffer); } DriverResult JoyconCommonProtocol::SendData(std::span<const u8> buffer) { @@ -120,7 +119,12 @@ DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const return DriverResult::Success; } -DriverResult JoyconCommonProtocol::SendMcuCommand(SubCommand sc, std::span<const u8> buffer) { +DriverResult JoyconCommonProtocol::SendSubCommand(SubCommand sc, std::span<const u8> buffer) { + std::vector<u8> output; + return SendSubCommand(sc, buffer, output); +} + +DriverResult JoyconCommonProtocol::SendMCUCommand(SubCommand sc, std::span<const u8> buffer) { std::vector<u8> local_buffer(MaxResponseSize); local_buffer[0] = static_cast<u8>(OutputReport::MCU_DATA); @@ -147,7 +151,7 @@ DriverResult JoyconCommonProtocol::SendVibrationReport(std::span<const u8> buffe DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8>& output) { constexpr std::size_t MaxTries = 10; std::size_t tries = 0; - std::vector<u8> buffer = {0x00, 0x00, 0x00, 0x00, size}; + std::array<u8, 5> buffer = {0x00, 0x00, 0x00, 0x00, size}; std::vector<u8> local_buffer(size + 20); buffer[0] = static_cast<u8>(static_cast<u16>(addr) & 0x00FF); @@ -169,10 +173,8 @@ DriverResult JoyconCommonProtocol::ReadSPI(CalAddr addr, u8 size, std::vector<u8 } DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { - std::vector<u8> output; - - const std::vector<u8> mcu_state{static_cast<u8>(enable ? 1 : 0)}; - const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state, output); + const std::array<u8, 1> mcu_state{static_cast<u8>(enable ? 1 : 0)}; + const auto result = SendSubCommand(SubCommand::SET_MCU_STATE, mcu_state); if (result != DriverResult::Success) { LOG_ERROR(Input, "SendMCUData failed with error {}", result); @@ -183,13 +185,11 @@ DriverResult JoyconCommonProtocol::EnableMCU(bool enable) { DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& config) { LOG_DEBUG(Input, "ConfigureMCU"); - std::vector<u8> output; - std::array<u8, sizeof(MCUConfig)> config_buffer; memcpy(config_buffer.data(), &config, sizeof(MCUConfig)); config_buffer[37] = CalculateMCU_CRC8(config_buffer.data() + 1, 36); - const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer, output); + const auto result = SendSubCommand(SubCommand::SET_MCU_CONFIG, config_buffer); if (result != DriverResult::Success) { LOG_ERROR(Input, "Set MCU config failed with error {}", result); diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.h b/src/input_common/helpers/joycon_protocol/common_protocol.h index 2a3feaf598..903bcf4025 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.h +++ b/src/input_common/helpers/joycon_protocol/common_protocol.h @@ -74,12 +74,19 @@ public: */ DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer, std::vector<u8>& output); + /** + * Sends a sub command to the device and waits for it's reply and ignores the output + * @param sc sub command to be send + * @param buffer data to be send + */ + DriverResult SendSubCommand(SubCommand sc, std::span<const u8> buffer); + /** * Sends a mcu command to the device * @param sc sub command to be send * @param buffer data to be send */ - DriverResult SendMcuCommand(SubCommand sc, std::span<const u8> buffer); + DriverResult SendMCUCommand(SubCommand sc, std::span<const u8> buffer); /** * Sends vibration data to the joycon @@ -150,4 +157,17 @@ private: std::shared_ptr<JoyconHandle> hidapi_handle; }; +class ScopedSetBlocking { +public: + explicit ScopedSetBlocking(JoyconCommonProtocol* self) : m_self{self} { + m_self->SetBlocking(); + } + + ~ScopedSetBlocking() { + m_self->SetNonBlocking(); + } + +private: + JoyconCommonProtocol* m_self{}; +}; } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/generic_functions.cpp b/src/input_common/helpers/joycon_protocol/generic_functions.cpp index cbd9ff4f8b..52bb8b61aa 100644 --- a/src/input_common/helpers/joycon_protocol/generic_functions.cpp +++ b/src/input_common/helpers/joycon_protocol/generic_functions.cpp @@ -10,22 +10,18 @@ GenericProtocol::GenericProtocol(std::shared_ptr<JoyconHandle> handle) : JoyconCommonProtocol(std::move(handle)) {} DriverResult GenericProtocol::EnablePassiveMode() { - SetBlocking(); - const auto result = SetReportMode(ReportMode::SIMPLE_HID_MODE); - SetNonBlocking(); - return result; + ScopedSetBlocking sb(this); + return SetReportMode(ReportMode::SIMPLE_HID_MODE); } DriverResult GenericProtocol::EnableActiveMode() { - SetBlocking(); - const auto result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); - SetNonBlocking(); - return result; + ScopedSetBlocking sb(this); + return SetReportMode(ReportMode::STANDARD_FULL_60HZ); } DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { + ScopedSetBlocking sb(this); std::vector<u8> output; - SetBlocking(); const auto result = SendSubCommand(SubCommand::REQ_DEV_INFO, {}, output); @@ -34,7 +30,6 @@ DriverResult GenericProtocol::GetDeviceInfo(DeviceInfo& device_info) { memcpy(&device_info, output.data(), sizeof(DeviceInfo)); } - SetNonBlocking(); return result; } @@ -43,36 +38,30 @@ DriverResult GenericProtocol::GetControllerType(ControllerType& controller_type) } DriverResult GenericProtocol::EnableImu(bool enable) { + ScopedSetBlocking sb(this); const std::array<u8, 1> buffer{static_cast<u8>(enable ? 1 : 0)}; - std::vector<u8> output; - SetBlocking(); - const auto result = SendSubCommand(SubCommand::ENABLE_IMU, buffer, output); - SetNonBlocking(); - return result; + return SendSubCommand(SubCommand::ENABLE_IMU, buffer); } DriverResult GenericProtocol::SetImuConfig(GyroSensitivity gsen, GyroPerformance gfrec, AccelerometerSensitivity asen, AccelerometerPerformance afrec) { + ScopedSetBlocking sb(this); const std::array<u8, 4> buffer{static_cast<u8>(gsen), static_cast<u8>(asen), static_cast<u8>(gfrec), static_cast<u8>(afrec)}; - std::vector<u8> output; - SetBlocking(); - const auto result = SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer, output); - SetNonBlocking(); - return result; + return SendSubCommand(SubCommand::SET_IMU_SENSITIVITY, buffer); } DriverResult GenericProtocol::GetBattery(u32& battery_level) { + // This function is meant to request the high resolution battery status battery_level = 0; return DriverResult::NotSupported; } DriverResult GenericProtocol::GetColor(Color& color) { + ScopedSetBlocking sb(this); std::vector<u8> buffer; - SetBlocking(); const auto result = ReadSPI(CalAddr::COLOR_DATA, 12, buffer); - SetNonBlocking(); color = {}; if (result == DriverResult::Success) { @@ -86,10 +75,9 @@ DriverResult GenericProtocol::GetColor(Color& color) { } DriverResult GenericProtocol::GetSerialNumber(SerialNumber& serial_number) { + ScopedSetBlocking sb(this); std::vector<u8> buffer; - SetBlocking(); const auto result = ReadSPI(CalAddr::SERIAL_NUMBER, 16, buffer); - SetNonBlocking(); serial_number = {}; if (result == DriverResult::Success) { @@ -115,14 +103,9 @@ DriverResult GenericProtocol::GetVersionNumber(FirmwareVersion& version) { } DriverResult GenericProtocol::SetHomeLight() { + ScopedSetBlocking sb(this); static constexpr std::array<u8, 3> buffer{0x0f, 0xf0, 0x00}; - std::vector<u8> output; - SetBlocking(); - - const auto result = SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer, output); - - SetNonBlocking(); - return result; + return SendSubCommand(SubCommand::SET_HOME_LIGHT, buffer); } DriverResult GenericProtocol::SetLedBusy() { @@ -130,14 +113,9 @@ DriverResult GenericProtocol::SetLedBusy() { } DriverResult GenericProtocol::SetLedPattern(u8 leds) { + ScopedSetBlocking sb(this); const std::array<u8, 1> buffer{leds}; - std::vector<u8> output; - SetBlocking(); - - const auto result = SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer, output); - - SetNonBlocking(); - return result; + return SendSubCommand(SubCommand::SET_PLAYER_LIGHTS, buffer); } DriverResult GenericProtocol::SetLedBlinkPattern(u8 leds) { diff --git a/src/input_common/helpers/joycon_protocol/irs.cpp b/src/input_common/helpers/joycon_protocol/irs.cpp index 9dfa503c23..09e17bc5b6 100644 --- a/src/input_common/helpers/joycon_protocol/irs.cpp +++ b/src/input_common/helpers/joycon_protocol/irs.cpp @@ -12,8 +12,8 @@ IrsProtocol::IrsProtocol(std::shared_ptr<JoyconHandle> handle) DriverResult IrsProtocol::EnableIrs() { LOG_INFO(Input, "Enable IRS"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); if (result == DriverResult::Success) { result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); @@ -49,14 +49,13 @@ DriverResult IrsProtocol::EnableIrs() { is_enabled = true; - SetNonBlocking(); return result; } DriverResult IrsProtocol::DisableIrs() { LOG_DEBUG(Input, "Disable IRS"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); if (result == DriverResult::Success) { result = EnableMCU(false); @@ -64,7 +63,6 @@ DriverResult IrsProtocol::DisableIrs() { is_enabled = false; - SetNonBlocking(); return result; } @@ -148,7 +146,7 @@ DriverResult IrsProtocol::ConfigureIrs() { }; buf_image.resize((static_cast<u8>(fragments) + 1) * 300); - std::vector<u8> request_data(sizeof(IrsConfigure)); + std::array<u8, sizeof(IrsConfigure)> request_data{}; memcpy(request_data.data(), &irs_configuration, sizeof(IrsConfigure)); request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); do { @@ -191,7 +189,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() { .crc = {}, }; - std::vector<u8> request_data(sizeof(IrsWriteRegisters)); + std::array<u8, sizeof(IrsWriteRegisters)> request_data{}; memcpy(request_data.data(), &irs_registers, sizeof(IrsWriteRegisters)); request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); @@ -208,7 +206,7 @@ DriverResult IrsProtocol::WriteRegistersStep1() { // First time we need to set the report mode if (result == DriverResult::Success && tries == 0) { - result = SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request); + result = SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); } if (result == DriverResult::Success && tries == 0) { GetSubCommandResponse(SubCommand::SET_MCU_CONFIG, output); @@ -250,7 +248,7 @@ DriverResult IrsProtocol::WriteRegistersStep2() { .crc = {}, }; - std::vector<u8> request_data(sizeof(IrsWriteRegisters)); + std::array<u8, sizeof(IrsWriteRegisters)> request_data{}; memcpy(request_data.data(), &irs_registers, sizeof(IrsWriteRegisters)); request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); do { @@ -272,7 +270,7 @@ DriverResult IrsProtocol::RequestFrame(u8 frame) { mcu_request[3] = frame; mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); mcu_request[37] = 0xFF; - return SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request); + return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); } DriverResult IrsProtocol::ResendFrame(u8 frame) { @@ -282,7 +280,7 @@ DriverResult IrsProtocol::ResendFrame(u8 frame) { mcu_request[3] = 0x0; mcu_request[36] = CalculateMCU_CRC8(mcu_request.data(), 36); mcu_request[37] = 0xFF; - return SendMcuCommand(SubCommand::SET_REPORT_MODE, mcu_request); + return SendMCUCommand(SubCommand::SET_REPORT_MODE, mcu_request); } std::vector<u8> IrsProtocol::GetImage() const { diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 273c8d07d3..e2d47349f0 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -273,6 +273,18 @@ enum class NFCTagType : u8 { Ntag215 = 0x01, }; +enum class NFCPages { + Block0 = 0, + Block45 = 45, + Block135 = 135, + Block231 = 231, +}; + +enum class NFCStatus : u8 { + LastPackage = 0x04, + TagLost = 0x07, +}; + enum class IrsMode : u8 { None = 0x02, Moment = 0x03, diff --git a/src/input_common/helpers/joycon_protocol/nfc.cpp b/src/input_common/helpers/joycon_protocol/nfc.cpp index 8755e310b8..5c0f717228 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.cpp +++ b/src/input_common/helpers/joycon_protocol/nfc.cpp @@ -12,8 +12,8 @@ NfcProtocol::NfcProtocol(std::shared_ptr<JoyconHandle> handle) DriverResult NfcProtocol::EnableNfc() { LOG_INFO(Input, "Enable NFC"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); if (result == DriverResult::Success) { result = SetReportMode(ReportMode::NFC_IR_MODE_60HZ); @@ -35,14 +35,13 @@ DriverResult NfcProtocol::EnableNfc() { result = ConfigureMCU(config); } - SetNonBlocking(); return result; } DriverResult NfcProtocol::DisableNfc() { LOG_DEBUG(Input, "Disable NFC"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); if (result == DriverResult::Success) { result = EnableMCU(false); @@ -50,15 +49,14 @@ DriverResult NfcProtocol::DisableNfc() { is_enabled = false; - SetNonBlocking(); return result; } DriverResult NfcProtocol::StartNFCPollingMode() { LOG_DEBUG(Input, "Start NFC pooling Mode"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; TagFoundData tag_data{}; - SetBlocking(); if (result == DriverResult::Success) { result = WaitSetMCUMode(ReportMode::NFC_IR_MODE_60HZ, MCUMode::NFC); @@ -70,15 +68,14 @@ DriverResult NfcProtocol::StartNFCPollingMode() { is_enabled = true; } - SetNonBlocking(); return result; } DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { LOG_DEBUG(Input, "Start NFC pooling Mode"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; TagFoundData tag_data{}; - SetBlocking(); if (result == DriverResult::Success) { result = StartPolling(tag_data); @@ -96,20 +93,18 @@ DriverResult NfcProtocol::ScanAmiibo(std::vector<u8>& data) { result = GetAmiiboData(data); } - SetNonBlocking(); return result; } bool NfcProtocol::HasAmiibo() { + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; TagFoundData tag_data{}; - SetBlocking(); if (result == DriverResult::Success) { result = StartPolling(tag_data); } - SetNonBlocking(); return result == DriverResult::Success; } @@ -169,55 +164,53 @@ DriverResult NfcProtocol::ReadTag(const TagFoundData& data) { LOG_INFO(Input, "Tag detected, type={}, uuid={}", data.type, uuid_string); tries = 0; - std::size_t ntag_pages = 0; + NFCPages ntag_pages = NFCPages::Block0; // Read Tag data -loop1: while (true) { auto result = SendReadAmiiboRequest(output, ntag_pages); + const auto mcu_report = static_cast<MCUReport>(output[49]); + const auto nfc_status = static_cast<NFCStatus>(output[56]); - int attempt = 0; - while (1) { - if (attempt != 0) { - result = GetMCUDataResponse(ReportMode::NFC_IR_MODE_60HZ, output); + if (result != DriverResult::Success) { + return result; + } + + if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && + nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07 && output[52] == 0x01) { + if (data.type != 2) { + continue; } - if ((output[49] == 0x3a || output[49] == 0x2a) && output[56] == 0x07) { + switch (output[74]) { + case 0: + ntag_pages = NFCPages::Block135; + break; + case 3: + ntag_pages = NFCPages::Block45; + break; + case 4: + ntag_pages = NFCPages::Block231; + break; + default: return DriverResult::ErrorReadingData; } - if (output[49] == 0x3a && output[51] == 0x07 && output[52] == 0x01) { - if (data.type != 2) { - goto loop1; - } - switch (output[74]) { - case 0: - ntag_pages = 135; - break; - case 3: - ntag_pages = 45; - break; - case 4: - ntag_pages = 231; - break; - default: - return DriverResult::ErrorReadingData; - } - goto loop1; - } - if (output[49] == 0x2a && output[56] == 0x04) { - // finished - SendStopPollingRequest(output); - return DriverResult::Success; - } - if (output[49] == 0x2a) { - goto loop1; - } - if (attempt++ > 6) { - goto loop1; - } + continue; } - if (result != DriverResult::Success) { - return result; + if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { + // finished + SendStopPollingRequest(output); + return DriverResult::Success; + } + + // Ignore other state reports + if (mcu_report == MCUReport::NFCState) { + continue; } + if (tries++ > timeout_limit) { return DriverResult::Timeout; } @@ -231,47 +224,44 @@ DriverResult NfcProtocol::GetAmiiboData(std::vector<u8>& ntag_data) { std::vector<u8> output; std::size_t tries = 0; - std::size_t ntag_pages = 135; + NFCPages ntag_pages = NFCPages::Block135; std::size_t ntag_buffer_pos = 0; // Read Tag data -loop1: while (true) { auto result = SendReadAmiiboRequest(output, ntag_pages); + const auto mcu_report = static_cast<MCUReport>(output[49]); + const auto nfc_status = static_cast<NFCStatus>(output[56]); - int attempt = 0; - while (1) { - if (attempt != 0) { - result = GetMCUDataResponse(ReportMode::NFC_IR_MODE_60HZ, output); - } - if ((output[49] == 0x3a || output[49] == 0x2a) && output[56] == 0x07) { - return DriverResult::ErrorReadingData; - } - if (output[49] == 0x3a && output[51] == 0x07) { - std::size_t payload_size = (output[54] << 8 | output[55]) & 0x7FF; - if (output[52] == 0x01) { - memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 116, - payload_size - 60); - ntag_buffer_pos += payload_size - 60; - } else { - memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 56, payload_size); - } - goto loop1; - } - if (output[49] == 0x2a && output[56] == 0x04) { - LOG_INFO(Input, "Finished reading amiibo"); - return DriverResult::Success; - } - if (output[49] == 0x2a) { - goto loop1; - } - if (attempt++ > 4) { - goto loop1; + if (result != DriverResult::Success) { + return result; + } + + if ((mcu_report == MCUReport::NFCReadData || mcu_report == MCUReport::NFCState) && + nfc_status == NFCStatus::TagLost) { + return DriverResult::ErrorReadingData; + } + + if (mcu_report == MCUReport::NFCReadData && output[51] == 0x07) { + std::size_t payload_size = (output[54] << 8 | output[55]) & 0x7FF; + if (output[52] == 0x01) { + memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 116, payload_size - 60); + ntag_buffer_pos += payload_size - 60; + } else { + memcpy(ntag_data.data() + ntag_buffer_pos, output.data() + 56, payload_size); } + continue; } - if (result != DriverResult::Success) { - return result; + if (mcu_report == MCUReport::NFCState && nfc_status == NFCStatus::LastPackage) { + LOG_INFO(Input, "Finished reading amiibo"); + return DriverResult::Success; + } + + // Ignore other state reports + if (mcu_report == MCUReport::NFCState) { + continue; } + if (tries++ > timeout_limit) { return DriverResult::Timeout; } @@ -298,7 +288,7 @@ DriverResult NfcProtocol::SendStartPollingRequest(std::vector<u8>& output) { .crc = {}, }; - std::vector<u8> request_data(sizeof(NFCRequestState)); + std::array<u8, sizeof(NFCRequestState)> request_data{}; memcpy(request_data.data(), &request, sizeof(NFCRequestState)); request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); @@ -315,7 +305,7 @@ DriverResult NfcProtocol::SendStopPollingRequest(std::vector<u8>& output) { .crc = {}, }; - std::vector<u8> request_data(sizeof(NFCRequestState)); + std::array<u8, sizeof(NFCRequestState)> request_data{}; memcpy(request_data.data(), &request, sizeof(NFCRequestState)); request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); @@ -338,7 +328,7 @@ DriverResult NfcProtocol::SendStartWaitingRecieveRequest(std::vector<u8>& output return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); } -DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, std::size_t ntag_pages) { +DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages) { NFCRequestState request{ .sub_command = MCUSubCommand::ReadDeviceMode, .command_argument = NFCReadCommand::Ntag, @@ -357,20 +347,19 @@ DriverResult NfcProtocol::SendReadAmiiboRequest(std::vector<u8>& output, std::si .crc = {}, }; - std::vector<u8> request_data(sizeof(NFCRequestState)); + std::array<u8, sizeof(NFCRequestState)> request_data{}; memcpy(request_data.data(), &request, sizeof(NFCRequestState)); request_data[37] = CalculateMCU_CRC8(request_data.data() + 1, 36); return SendMCUData(ReportMode::NFC_IR_MODE_60HZ, SubCommand::STATE, request_data, output); } -NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(std::size_t pages) const { - if (pages == 0) { +NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(NFCPages pages) const { + switch (pages) { + case NFCPages::Block0: return { .block_count = 1, }; - } - - if (pages == 45) { + case NFCPages::Block45: return { .block_count = 1, .blocks = @@ -378,9 +367,7 @@ NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(std::size_t pages) const { NFCReadBlock{0x00, 0x2C}, }, }; - } - - if (pages == 135) { + case NFCPages::Block135: return { .block_count = 3, .blocks = @@ -390,9 +377,7 @@ NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(std::size_t pages) const { {0x78, 0x86}, }, }; - } - - if (pages == 231) { + case NFCPages::Block231: return { .block_count = 4, .blocks = @@ -403,9 +388,9 @@ NFCReadBlockCommand NfcProtocol::GetReadBlockCommand(std::size_t pages) const { {0xb4, 0xe6}, }, }; - } - - return {}; + default: + return {}; + }; } bool NfcProtocol::IsEnabled() const { diff --git a/src/input_common/helpers/joycon_protocol/nfc.h b/src/input_common/helpers/joycon_protocol/nfc.h index 5cb0e5a652..e63665aa97 100644 --- a/src/input_common/helpers/joycon_protocol/nfc.h +++ b/src/input_common/helpers/joycon_protocol/nfc.h @@ -51,9 +51,9 @@ private: DriverResult SendStartWaitingRecieveRequest(std::vector<u8>& output); - DriverResult SendReadAmiiboRequest(std::vector<u8>& output, std::size_t ntag_pages); + DriverResult SendReadAmiiboRequest(std::vector<u8>& output, NFCPages ntag_pages); - NFCReadBlockCommand GetReadBlockCommand(std::size_t pages) const; + NFCReadBlockCommand GetReadBlockCommand(NFCPages pages) const; bool is_enabled{}; }; diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index 940b20b7f0..7f8e093faf 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp @@ -224,9 +224,9 @@ void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) { Joycon::PasivePadButton::StickL, }; - for (std::size_t i = 0; i < left_buttons.size(); ++i) { - const bool button_status = (input.button_input & static_cast<u32>(left_buttons[i])) != 0; - const int button = static_cast<int>(left_buttons[i]); + for (auto left_button : left_buttons) { + const bool button_status = (input.button_input & static_cast<u32>(left_button)) != 0; + const int button = static_cast<int>(left_button); callbacks.on_button_data(button, button_status); } } @@ -241,9 +241,9 @@ void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) { Joycon::PasivePadButton::StickR, }; - for (std::size_t i = 0; i < right_buttons.size(); ++i) { - const bool button_status = (input.button_input & static_cast<u32>(right_buttons[i])) != 0; - const int button = static_cast<int>(right_buttons[i]); + for (auto right_button : right_buttons) { + const bool button_status = (input.button_input & static_cast<u32>(right_button)) != 0; + const int button = static_cast<int>(right_button); callbacks.on_button_data(button, button_status); } } @@ -259,9 +259,9 @@ void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) { Joycon::PasivePadButton::StickL, Joycon::PasivePadButton::StickR, }; - for (std::size_t i = 0; i < pro_buttons.size(); ++i) { - const bool button_status = (input.button_input & static_cast<u32>(pro_buttons[i])) != 0; - const int button = static_cast<int>(pro_buttons[i]); + for (auto pro_button : pro_buttons) { + const bool button_status = (input.button_input & static_cast<u32>(pro_button)) != 0; + const int button = static_cast<int>(pro_button); callbacks.on_button_data(button, button_status); } } diff --git a/src/input_common/helpers/joycon_protocol/ringcon.cpp b/src/input_common/helpers/joycon_protocol/ringcon.cpp index 8adad57dd6..12f81309e1 100644 --- a/src/input_common/helpers/joycon_protocol/ringcon.cpp +++ b/src/input_common/helpers/joycon_protocol/ringcon.cpp @@ -11,8 +11,8 @@ RingConProtocol::RingConProtocol(std::shared_ptr<JoyconHandle> handle) DriverResult RingConProtocol::EnableRingCon() { LOG_DEBUG(Input, "Enable Ringcon"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); if (result == DriverResult::Success) { result = SetReportMode(ReportMode::STANDARD_FULL_60HZ); @@ -30,14 +30,13 @@ DriverResult RingConProtocol::EnableRingCon() { result = ConfigureMCU(config); } - SetNonBlocking(); return result; } DriverResult RingConProtocol::DisableRingCon() { LOG_DEBUG(Input, "Disable RingCon"); + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); if (result == DriverResult::Success) { result = EnableMCU(false); @@ -45,15 +44,14 @@ DriverResult RingConProtocol::DisableRingCon() { is_enabled = false; - SetNonBlocking(); return result; } DriverResult RingConProtocol::StartRingconPolling() { LOG_DEBUG(Input, "Enable Ringcon"); - bool is_connected = false; + ScopedSetBlocking sb(this); DriverResult result{DriverResult::Success}; - SetBlocking(); + bool is_connected = false; if (result == DriverResult::Success) { result = IsRingConnected(is_connected); @@ -66,13 +64,13 @@ DriverResult RingConProtocol::StartRingconPolling() { is_enabled = true; } - SetNonBlocking(); 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; @@ -88,7 +86,7 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { if (tries++ >= max_tries) { return DriverResult::NoDeviceDetected; } - } while (output[14] != 0x59 || output[16] != 0x20); + } while (output[16] != ring_controller_id); is_connected = true; return DriverResult::Success; @@ -96,30 +94,20 @@ DriverResult RingConProtocol::IsRingConnected(bool& is_connected) { 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; 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}; - do { - 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); + const DriverResult result = SendSubCommand(SubCommand::UNKNOWN_RINGCON3, ring_config); - static constexpr std::array<u8, 4> ringcon_data{0x04, 0x01, 0x01, 0x02}; - result = SendSubCommand(SubCommand::UNKNOWN_RINGCON2, ringcon_data, output); + if (result != DriverResult::Success) { + return result; + } - 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 { diff --git a/src/input_common/helpers/joycon_protocol/rumble.cpp b/src/input_common/helpers/joycon_protocol/rumble.cpp index fad67a94ba..63b60c9468 100644 --- a/src/input_common/helpers/joycon_protocol/rumble.cpp +++ b/src/input_common/helpers/joycon_protocol/rumble.cpp @@ -14,12 +14,9 @@ RumbleProtocol::RumbleProtocol(std::shared_ptr<JoyconHandle> handle) DriverResult RumbleProtocol::EnableRumble(bool is_enabled) { LOG_DEBUG(Input, "Enable Rumble"); + ScopedSetBlocking sb(this); const std::array<u8, 1> buffer{static_cast<u8>(is_enabled ? 1 : 0)}; - std::vector<u8> output; - SetBlocking(); - const auto result = SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer, output); - SetNonBlocking(); - return result; + return SendSubCommand(SubCommand::ENABLE_VIBRATION, buffer); } DriverResult RumbleProtocol::SendVibration(const VibrationValue& vibration) { @@ -66,9 +63,9 @@ u8 RumbleProtocol::EncodeLowFrequency(f32 frequency) const { } u8 RumbleProtocol::EncodeHighAmplitude(f32 amplitude) const { - /* More information about these values can be found here: - * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md - */ + // More information about these values can be found here: + // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md + static constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ std::pair<f32, int>{0.0f, 0x0}, {0.01f, 0x2}, @@ -183,9 +180,9 @@ u8 RumbleProtocol::EncodeHighAmplitude(f32 amplitude) const { } u16 RumbleProtocol::EncodeLowAmplitude(f32 amplitude) const { - /* More information about these values can be found here: - * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md - */ + // More information about these values can be found here: + // https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md + static constexpr std::array<std::pair<f32, int>, 101> high_fequency_amplitude{ std::pair<f32, int>{0.0f, 0x0040}, {0.01f, 0x8040}, -- cgit v1.2.3-70-g09d2