From d2f9412cf1717f884855af22793f3a1e5815c967 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 8 Jan 2022 23:23:40 -0600 Subject: yuzu: Add custom ringcon configuration --- src/core/hid/emulated_devices.cpp | 45 ++++++++++++++ src/core/hid/emulated_devices.h | 34 +++++++++++ src/core/hle/service/hid/hidbus.cpp | 4 +- src/core/hle/service/hid/hidbus/hidbus_base.cpp | 4 +- src/core/hle/service/hid/hidbus/hidbus_base.h | 3 +- src/core/hle/service/hid/hidbus/ringcon.cpp | 78 +++++++++---------------- src/core/hle/service/hid/hidbus/ringcon.h | 29 +++++---- 7 files changed, 133 insertions(+), 64 deletions(-) (limited to 'src/core') diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index cc0dcd931..2f84d2b52 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -15,6 +15,7 @@ EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; void EmulatedDevices::ReloadFromSettings() { + ring_params = Common::ParamPackage(Settings::values.ringcon_analogs); ReloadInput(); } @@ -66,6 +67,8 @@ void EmulatedDevices::ReloadInput() { key_index++; } + ring_analog_device = Common::Input::CreateDevice(ring_params); + for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { continue; @@ -120,6 +123,13 @@ void EmulatedDevices::ReloadInput() { }, }); } + + if (ring_analog_device) { + ring_analog_device->SetCallback({ + .on_change = + [this](const Common::Input::CallbackStatus& callback) { SetRingAnalog(callback); }, + }); + } } void EmulatedDevices::UnloadInput() { @@ -155,6 +165,7 @@ void EmulatedDevices::SaveCurrentConfig() { if (!is_configuring) { return; } + Settings::values.ringcon_analogs = ring_params.Serialize(); } void EmulatedDevices::RestoreConfig() { @@ -164,6 +175,15 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } +Common::ParamPackage EmulatedDevices::GetRingParam() const { + return ring_params; +} + +void EmulatedDevices::SetRingParam(Common::ParamPackage param) { + ring_params = std::move(param); + ReloadInput(); +} + void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { @@ -410,6 +430,23 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac TriggerOnChange(DeviceTriggerType::Mouse); } +void EmulatedDevices::SetRingAnalog(const Common::Input::CallbackStatus& callback) { + std::lock_guard lock{mutex}; + const auto force_value = TransformToStick(callback); + + device_status.ring_analog_value = force_value.x; + + if (is_configuring) { + device_status.ring_analog_value = {}; + TriggerOnChange(DeviceTriggerType::RingController); + return; + } + + device_status.ring_analog_state.force = force_value.x.value; + + TriggerOnChange(DeviceTriggerType::RingController); +} + KeyboardValues EmulatedDevices::GetKeyboardValues() const { std::scoped_lock lock{mutex}; return device_status.keyboard_values; @@ -425,6 +462,10 @@ MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { return device_status.mouse_button_values; } +RingAnalogValue EmulatedDevices::GetRingSensorValues() const { + return device_status.ring_analog_value; +} + KeyboardKey EmulatedDevices::GetKeyboard() const { std::scoped_lock lock{mutex}; return device_status.keyboard_state; @@ -450,6 +491,10 @@ AnalogStickState EmulatedDevices::GetMouseWheel() const { return device_status.mouse_wheel_state; } +RingSensorForce EmulatedDevices::GetRingSensorForce() const { + return device_status.ring_analog_state; +} + void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 73e9f0293..fb6451e7a 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -26,9 +26,11 @@ using MouseButtonDevices = std::array, Settings::NativeMouseWheel::NumMouseWheels>; using MouseStickDevice = std::unique_ptr; +using RingAnalogDevice = std::unique_ptr; using MouseButtonParams = std::array; +using RingAnalogParams = Common::ParamPackage; using KeyboardValues = std::array; @@ -39,12 +41,17 @@ using MouseButtonValues = using MouseAnalogValues = std::array; using MouseStickValue = Common::Input::TouchStatus; +using RingAnalogValue = Common::Input::AnalogStatus; struct MousePosition { f32 x; f32 y; }; +struct RingSensorForce { + f32 force; +}; + struct DeviceStatus { // Data from input_common KeyboardValues keyboard_values{}; @@ -52,6 +59,7 @@ struct DeviceStatus { MouseButtonValues mouse_button_values{}; MouseAnalogValues mouse_analog_values{}; MouseStickValue mouse_stick_value{}; + RingAnalogValue ring_analog_value{}; // Data for HID serices KeyboardKey keyboard_state{}; @@ -59,12 +67,14 @@ struct DeviceStatus { MouseButton mouse_button_state{}; MousePosition mouse_position_state{}; AnalogStickState mouse_wheel_state{}; + RingSensorForce ring_analog_state{}; }; enum class DeviceTriggerType { Keyboard, KeyboardModdifier, Mouse, + RingController, }; struct InterfaceUpdateCallback { @@ -110,6 +120,15 @@ public: /// Reverts any mapped changes made that weren't saved void RestoreConfig(); + // Returns the current mapped ring device + Common::ParamPackage GetRingParam() const; + + /** + * Updates the current mapped ring device + * @param param ParamPackage with ring sensor data to be mapped + */ + void SetRingParam(Common::ParamPackage param); + /// Returns the latest status of button input from the keyboard with parameters KeyboardValues GetKeyboardValues() const; @@ -119,6 +138,9 @@ public: /// Returns the latest status of button input from the mouse with parameters MouseButtonValues GetMouseButtonsValues() const; + /// Returns the latest status of analog input from the ring sensor with parameters + RingAnalogValue GetRingSensorValues() const; + /// Returns the latest status of button input from the keyboard KeyboardKey GetKeyboard() const; @@ -134,6 +156,9 @@ public: /// Returns the latest mouse wheel change AnalogStickState GetMouseWheel() const; + /// Returns the latest ringcon force sensor value + RingSensorForce GetRingSensorForce() const; + /** * Adds a callback to the list of events * @param update_callback InterfaceUpdateCallback that will be triggered @@ -185,6 +210,12 @@ private: */ void SetMouseStick(const Common::Input::CallbackStatus& callback); + /** + * Updates the ring analog sensor status of the ring controller + * @param callback A CallbackStatus containing the force status + */ + void SetRingAnalog(const Common::Input::CallbackStatus& callback); + /** * Triggers a callback that something has changed on the device status * @param type Input type of the event to trigger @@ -193,11 +224,14 @@ private: bool is_configuring{false}; + RingAnalogParams ring_params; + KeyboardDevices keyboard_devices; KeyboardModifierDevices keyboard_modifier_devices; MouseButtonDevices mouse_button_devices; MouseAnalogDevices mouse_analog_devices; MouseStickDevice mouse_stick_device; + RingAnalogDevice ring_analog_device; mutable std::mutex mutex; mutable std::mutex callback_mutex; diff --git a/src/core/hle/service/hid/hidbus.cpp b/src/core/hle/service/hid/hidbus.cpp index db2864277..af7662a15 100644 --- a/src/core/hle/service/hid/hidbus.cpp +++ b/src/core/hle/service/hid/hidbus.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/logging/log.h" +#include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -190,6 +191,7 @@ void HidBus::IsExternalDeviceConnected(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(is_attached); + return; } LOG_ERROR(Service_HID, "Invalid handle"); @@ -217,7 +219,7 @@ void HidBus::Initialize(Kernel::HLERequestContext& ctx) { const auto entry_index = devices[device_index.value()].handle.internal_index; auto& cur_entry = hidbus_status.entries[entry_index]; - if (bus_handle_.internal_index == 0) { + if (bus_handle_.internal_index == 0 && Settings::values.enable_ring_controller) { MakeDevice(bus_handle_); devices[device_index.value()].is_device_initializated = true; devices[device_index.value()].device->ActivateDevice(); diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.cpp b/src/core/hle/service/hid/hidbus/hidbus_base.cpp index 9cac0be80..09bff10e5 100644 --- a/src/core/hle/service/hid/hidbus/hidbus_base.cpp +++ b/src/core/hle/service/hid/hidbus/hidbus_base.cpp @@ -12,7 +12,7 @@ namespace Service::HID { HidbusBase::HidbusBase(KernelHelpers::ServiceContext& service_context_) : service_context(service_context_) { - send_command_asyc_event = service_context.CreateEvent("hidbus:SendCommandAsycEvent"); + send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent"); } HidbusBase::~HidbusBase() = default; @@ -66,7 +66,7 @@ void HidbusBase::SetTransferMemoryPointer(u8* t_mem) { } Kernel::KReadableEvent& HidbusBase::GetSendCommandAsycEvent() const { - return send_command_asyc_event->GetReadableEvent(); + return send_command_async_event->GetReadableEvent(); } } // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.h b/src/core/hle/service/hid/hidbus/hidbus_base.h index 41e571998..13d073a3d 100644 --- a/src/core/hle/service/hid/hidbus/hidbus_base.h +++ b/src/core/hle/service/hid/hidbus/hidbus_base.h @@ -165,6 +165,7 @@ protected: bool device_enabled{}; bool polling_mode_enabled{}; JoyPollingMode polling_mode = {}; + // TODO(German77): All data accessors need to be replaced with a ring lifo object JoyDisableSixAxisDataAccessor disable_sixaxis_data{}; JoyEnableSixAxisDataAccessor enable_sixaxis_data{}; ButtonOnlyPollingDataAccessor button_only_data{}; @@ -172,7 +173,7 @@ protected: u8* transfer_memory{nullptr}; bool is_transfer_memory_set{}; - Kernel::KEvent* send_command_asyc_event; + Kernel::KEvent* send_command_async_event; KernelHelpers::ServiceContext& service_context; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hidbus/ringcon.cpp b/src/core/hle/service/hid/hidbus/ringcon.cpp index 6fe68081f..5ec3cc83c 100644 --- a/src/core/hle/service/hid/hidbus/ringcon.cpp +++ b/src/core/hle/service/hid/hidbus/ringcon.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hid/emulated_controller.h" +#include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" @@ -13,9 +13,7 @@ namespace Service::HID { RingController::RingController(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_) : HidbusBase(service_context_) { - // Use the horizontal axis of left stick for emulating input - // There is no point on adding a frontend implementation since Ring Fit Adventure doesn't work - input = hid_core_.GetEmulatedController(Core::HID::NpadIdType::Player1); + input = hid_core_.GetEmulatedDevices(); } RingController::~RingController() = default; @@ -41,6 +39,8 @@ void RingController::OnUpdate() { return; } + // TODO: Increment multitasking counters from motion and sensor data + switch (polling_mode) { case JoyPollingMode::SixAxisSensorEnable: { enable_sixaxis_data.header.total_entries = 10; @@ -74,9 +74,8 @@ RingController::RingConData RingController::GetSensorValue() const { .data = 0, }; - const f32 stick_value = static_cast(input->GetSticks().left.x) / 32767.0f; - - ringcon_sensor_value.data = static_cast(stick_value * range) + idle_value; + const f32 force_value = input->GetRingSensorForce().force * range; + ringcon_sensor_value.data = static_cast(force_value) + idle_value; return ringcon_sensor_value; } @@ -105,6 +104,8 @@ std::vector RingController::GetReply() const { return GetReadRepCountReply(); case RingConCommands::ReadTotalPushCount: return GetReadTotalPushCountReply(); + case RingConCommands::ResetRepCount: + return GetResetRepCountReply(); case RingConCommands::SaveCalData: return GetSaveDataReply(); default: @@ -119,36 +120,9 @@ bool RingController::SetCommand(const std::vector& data) { return false; } - // There must be a better way to do this - const u32 command_id = - u32{data[0]} + (u32{data[1]} << 8) + (u32{data[2]} << 16) + (u32{data[3]} << 24); - static constexpr std::array supported_commands = { - RingConCommands::GetFirmwareVersion, - RingConCommands::ReadId, - RingConCommands::c20105, - RingConCommands::ReadUnkCal, - RingConCommands::ReadFactoryCal, - RingConCommands::ReadUserCal, - RingConCommands::ReadRepCount, - RingConCommands::ReadTotalPushCount, - RingConCommands::SaveCalData, - }; - - for (RingConCommands cmd : supported_commands) { - if (command_id == static_cast(cmd)) { - return ExcecuteCommand(cmd, data); - } - } - - LOG_ERROR(Service_HID, "Command not implemented {}", command_id); - command = RingConCommands::Error; - // Signal a reply to avoid softlocking - send_command_asyc_event->GetWritableEvent().Signal(); - return false; -} + std::memcpy(&command, data.data(), sizeof(RingConCommands)); -bool RingController::ExcecuteCommand(RingConCommands cmd, const std::vector& data) { - switch (cmd) { + switch (command) { case RingConCommands::GetFirmwareVersion: case RingConCommands::ReadId: case RingConCommands::c20105: @@ -158,23 +132,27 @@ bool RingController::ExcecuteCommand(RingConCommands cmd, const std::vector& case RingConCommands::ReadRepCount: case RingConCommands::ReadTotalPushCount: ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes"); - command = cmd; - send_command_asyc_event->GetWritableEvent().Signal(); + send_command_async_event->GetWritableEvent().Signal(); + return true; + case RingConCommands::ResetRepCount: + ASSERT_MSG(data.size() == 0x4, "data.size is not 0x4 bytes"); + total_rep_count = 0; + send_command_async_event->GetWritableEvent().Signal(); return true; case RingConCommands::SaveCalData: { ASSERT_MSG(data.size() == 0x14, "data.size is not 0x14 bytes"); SaveCalData save_info{}; - std::memcpy(&save_info, &data, sizeof(SaveCalData)); + std::memcpy(&save_info, data.data(), sizeof(SaveCalData)); user_calibration = save_info.calibration; - - command = cmd; - send_command_asyc_event->GetWritableEvent().Signal(); + send_command_async_event->GetWritableEvent().Signal(); return true; } default: - LOG_ERROR(Service_HID, "Command not implemented {}", cmd); + LOG_ERROR(Service_HID, "Command not implemented {}", command); command = RingConCommands::Error; + // Signal a reply to avoid softlocking the game + send_command_async_event->GetWritableEvent().Signal(); return false; } } @@ -240,27 +218,29 @@ std::vector RingController::GetReadUserCalReply() const { } std::vector RingController::GetReadRepCountReply() const { - // The values are hardcoded from a real joycon const GetThreeByteReply reply{ .status = DataValid::Valid, - .data = {30, 0, 0}, - .crc = GetCrcValue({30, 0, 0, 0}), + .data = {total_rep_count, 0, 0}, + .crc = GetCrcValue({total_rep_count, 0, 0, 0}), }; return GetDataVector(reply); } std::vector RingController::GetReadTotalPushCountReply() const { - // The values are hardcoded from a real joycon const GetThreeByteReply reply{ .status = DataValid::Valid, - .data = {30, 0, 0}, - .crc = GetCrcValue({30, 0, 0, 0}), + .data = {total_push_count, 0, 0}, + .crc = GetCrcValue({total_push_count, 0, 0, 0}), }; return GetDataVector(reply); } +std::vector RingController::GetResetRepCountReply() const { + return GetReadRepCountReply(); +} + std::vector RingController::GetSaveDataReply() const { const StatusReply reply{ .status = DataValid::Valid, diff --git a/src/core/hle/service/hid/hidbus/ringcon.h b/src/core/hle/service/hid/hidbus/ringcon.h index e8b3d8254..2dbc6150e 100644 --- a/src/core/hle/service/hid/hidbus/ringcon.h +++ b/src/core/hle/service/hid/hidbus/ringcon.h @@ -10,7 +10,7 @@ #include "core/hle/service/hid/hidbus/hidbus_base.h" namespace Core::HID { -class EmulatedController; +class EmulatedDevices; } // namespace Core::HID namespace Service::HID { @@ -43,6 +43,7 @@ private: static constexpr s16 idle_deadzone = 120; static constexpr s16 range = 2500; + // Most missing command names are leftovers from other firmware versions enum class RingConCommands : u32 { GetFirmwareVersion = 0x00020000, ReadId = 0x00020100, @@ -60,10 +61,10 @@ private: ReadUserCal = 0x00021A04, ReadRepCount = 0x00023104, ReadTotalPushCount = 0x00023204, - Unknown9 = 0x04013104, - Unknown10 = 0x04011104, - Unknown11 = 0x04011204, - Unknown12 = 0x04011304, + ResetRepCount = 0x04013104, + Unknown8 = 0x04011104, + Unknown9 = 0x04011204, + Unknown10 = 0x04011304, SaveCalData = 0x10011A04, Error = 0xFFFFFFFF, }; @@ -180,9 +181,6 @@ private: }; static_assert(sizeof(RingConData) == 0x8, "RingConData is an invalid size"); - // Executes the command requested - bool ExcecuteCommand(RingConCommands cmd, const std::vector& data); - // Returns RingConData struct with pressure sensor values RingConData GetSensorValue() const; @@ -204,12 +202,15 @@ private: // Returns 20 byte reply with user calibration values std::vector GetReadUserCalReply() const; - // (STUBBED) Returns 8 byte reply + // Returns 8 byte reply std::vector GetReadRepCountReply() const; - // (STUBBED) Returns 8 byte reply + // Returns 8 byte reply std::vector GetReadTotalPushCountReply() const; + // Returns 8 byte reply + std::vector GetResetRepCountReply() const; + // Returns 4 byte save data reply std::vector GetSaveDataReply() const; @@ -225,6 +226,12 @@ private: RingConCommands command{RingConCommands::Error}; + // These counters are used in multitasking mode while the switch is sleeping + // Total steps taken + u8 total_rep_count = 0; + // Total times the ring was pushed + u8 total_push_count = 0; + const u8 device_id = 0x20; const FirmwareVersion version = { .sub = 0x0, @@ -242,6 +249,6 @@ private: .zero = {.value = idle_value, .crc = 225}, }; - Core::HID::EmulatedController* input; + Core::HID::EmulatedDevices* input; }; } // namespace Service::HID -- cgit v1.2.3