From a2dadbb2f0c150a5e82088e0a04dfcdc36d709a7 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sun, 25 Sep 2022 02:29:35 +0200 Subject: [PATCH] Wiimote: Separate the Input system state update from the emulated state update. --- .../Core/Core/HW/WiimoteCommon/WiimoteHid.h | 14 +++++-- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 41 ++++++++++--------- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 7 ++-- .../Core/Core/HW/WiimoteReal/WiimoteReal.cpp | 13 ++++-- Source/Core/Core/HW/WiimoteReal/WiimoteReal.h | 5 ++- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 15 +++++-- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h | 2 +- .../Core/IOS/USB/Bluetooth/WiimoteDevice.cpp | 41 +++++++++++++++---- .../Core/IOS/USB/Bluetooth/WiimoteDevice.h | 15 ++++++- 9 files changed, 109 insertions(+), 44 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteCommon/WiimoteHid.h b/Source/Core/Core/HW/WiimoteCommon/WiimoteHid.h index 5ab296a9cc..0b3b5d37d6 100644 --- a/Source/Core/Core/HW/WiimoteCommon/WiimoteHid.h +++ b/Source/Core/Core/HW/WiimoteCommon/WiimoteHid.h @@ -7,6 +7,11 @@ #include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h" +namespace WiimoteEmu +{ +struct DesiredWiimoteState; +} + namespace WiimoteCommon { // Source: HID_010_SPC_PFL/1.0 (official HID specification) @@ -34,7 +39,8 @@ public: virtual void SetWiimoteDeviceIndex(u8 index) = 0; // Called every ~200hz after HID channels are established. - virtual void Update() = 0; + virtual void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) = 0; + virtual void Update(const WiimoteEmu::DesiredWiimoteState& target_state) = 0; void SetInterruptCallback(InterruptCallbackType callback) { m_callback = std::move(callback); } @@ -42,8 +48,10 @@ public: // Does not include HID-type header. virtual void InterruptDataOutput(const u8* data, u32 size) = 0; - // Used to connect a disconnected wii remote on button press. - virtual bool IsButtonPressed() = 0; + // Get a snapshot of the current state of the Wiimote's buttons. + // Note that only the button bits of the return value are meaningful, the rest should be ignored. + // This is used to query a disconnected Wiimote whether it wants to reconnect. + virtual ButtonData GetCurrentlyPressedButtons() = 0; protected: void InterruptDataInputCallback(const u8* data, u32 size) diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index deac5a98ef..de676f8f4a 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -448,7 +448,7 @@ void Wiimote::UpdateButtonsStatus(const DesiredWiimoteState& target_state) m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK; } -DesiredWiimoteState Wiimote::BuildDesiredWiimoteState() +void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state) { // Hotkey / settings modifier // Data is later accessed in IsSideways and IsUpright @@ -457,36 +457,35 @@ DesiredWiimoteState Wiimote::BuildDesiredWiimoteState() // Update our motion simulations. StepDynamics(); - DesiredWiimoteState wiimote_state; - // Fetch pressed buttons from user input. - m_buttons->GetState(&wiimote_state.buttons.hex, button_bitmasks); - m_dpad->GetState(&wiimote_state.buttons.hex, + target_state->buttons.hex = 0; + m_buttons->GetState(&target_state->buttons.hex, button_bitmasks); + m_dpad->GetState(&target_state->buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks); // Calculate accelerometer state. // Calibration values are 8-bit but we want 10-bit precision, so << 2. - wiimote_state.acceleration = + target_state->acceleration = ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); // Calculate IR camera state. - wiimote_state.camera_points = CameraLogic::GetCameraPoints( + target_state->camera_points = CameraLogic::GetCameraPoints( GetTotalTransformation(), Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 * float(MathUtil::TAU)); // Calculate MotionPlus state. if (m_motion_plus_setting.GetValue()) - wiimote_state.motion_plus = MotionPlus::GetGyroscopeData(GetTotalAngularVelocity()); + target_state->motion_plus = MotionPlus::GetGyroscopeData(GetTotalAngularVelocity()); + else + target_state->motion_plus = std::nullopt; // Build Extension state. // This also allows the extension to perform any regular duties it may need. // (e.g. Nunchuk motion simulation step) static_cast( m_attachments->GetAttachmentList()[m_attachments->GetSelectedAttachment()].get()) - ->BuildDesiredExtensionState(&wiimote_state.extension); - - return wiimote_state; + ->BuildDesiredExtensionState(&target_state->extension); } u8 Wiimote::GetWiimoteDeviceIndex() const @@ -500,13 +499,14 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index) } // This is called every ::Wiimote::UPDATE_FREQ (200hz) -void Wiimote::Update() +void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) { const auto lock = GetStateLock(); + BuildDesiredWiimoteState(target_state); +} - // Build target state. - auto target_state = BuildDesiredWiimoteState(); - +void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state) +{ // Update buttons in the status struct which is sent in 99% of input reports. UpdateButtonsStatus(target_state); @@ -656,14 +656,15 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state) m_reporting_mode = InputReportID::ReportInterleave1; } -bool Wiimote::IsButtonPressed() +ButtonData Wiimote::GetCurrentlyPressedButtons() { - u16 buttons = 0; const auto lock = GetStateLock(); - m_buttons->GetState(&buttons, button_bitmasks); - m_dpad->GetState(&buttons, dpad_bitmasks); - return buttons != 0; + ButtonData buttons{}; + m_buttons->GetState(&buttons.hex, button_bitmasks); + m_dpad->GetState(&buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks); + + return buttons; } void Wiimote::LoadDefaults(const ControllerInterface& ciface) diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 2dd3f79800..9b07085cef 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -132,11 +132,12 @@ public: u8 GetWiimoteDeviceIndex() const override; void SetWiimoteDeviceIndex(u8 index) override; - void Update() override; + void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) override; + void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override; void EventLinked() override; void EventUnlinked() override; void InterruptDataOutput(const u8* data, u32 size) override; - bool IsButtonPressed() override; + WiimoteCommon::ButtonData GetCurrentlyPressedButtons() override; void Reset(); @@ -157,7 +158,7 @@ private: void StepDynamics(); void UpdateButtonsStatus(const DesiredWiimoteState& target_state); - DesiredWiimoteState BuildDesiredWiimoteState(); + void BuildDesiredWiimoteState(DesiredWiimoteState* target_state); // Returns simulated accelerometer data in m/s^2. Common::Vec3 GetAcceleration( diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 6ef990744a..10fa8f2686 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -460,7 +460,12 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index) m_bt_device_index = index; } -void Wiimote::Update() +void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) +{ + // Nothing to do here on real Wiimotes. +} + +void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state) { // Wii remotes send input at 200hz once a Wii enables "sniff mode" on the connection. // PC bluetooth stacks do not enable sniff mode causing remotes to send input at only 100hz. @@ -485,7 +490,7 @@ void Wiimote::Update() u32(rpt.size() - REPORT_HID_HEADER_SIZE)); } -bool Wiimote::IsButtonPressed() +ButtonData Wiimote::GetCurrentlyPressedButtons() { Report& rpt = m_last_input_report; if (rpt.size() >= 4) @@ -499,10 +504,10 @@ bool Wiimote::IsButtonPressed() ButtonData buttons = {}; builder->GetCoreData(&buttons); - return buttons.hex != 0; + return buttons; } } - return false; + return ButtonData{}; } void Wiimote::Prepare() diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index 859aadad45..e597d774bc 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -66,10 +66,11 @@ public: u8 GetWiimoteDeviceIndex() const override; void SetWiimoteDeviceIndex(u8 index) override; - void Update() override; + void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) override; + void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override; void EventLinked() override; void EventUnlinked() override; - bool IsButtonPressed() override; + WiimoteCommon::ButtonData GetCurrentlyPressedButtons() override; void EmuStop(); diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index fae22f35de..94abbb0b14 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -19,6 +19,7 @@ #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" #include "Core/HW/Wiimote.h" +#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h" #include "Core/IOS/Device.h" #include "Core/IOS/IOS.h" #include "Core/SysConf.h" @@ -58,7 +59,7 @@ BluetoothEmuDevice::BluetoothEmuDevice(Kernel& ios, const std::string& device_na DEBUG_LOG_FMT(IOS_WIIMOTE, "Wii Remote {} BT ID {:x},{:x},{:x},{:x},{:x},{:x}", i, tmp_bd[0], tmp_bd[1], tmp_bd[2], tmp_bd[3], tmp_bd[4], tmp_bd[5]); - m_wiimotes.emplace_back(std::make_unique(this, tmp_bd, i)); + m_wiimotes[i] = std::make_unique(this, tmp_bd, i); } bt_dinf.num_registered = MAX_BBMOTES; @@ -340,8 +341,16 @@ void BluetoothEmuDevice::Update() { g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Bluetooth); g_controller_interface.UpdateInput(); - for (auto& wiimote : m_wiimotes) - wiimote->UpdateInput(); + + std::array wiimote_states; + std::array next_call; + + for (size_t i = 0; i < m_wiimotes.size(); ++i) + next_call[i] = m_wiimotes[i]->PrepareInput(&wiimote_states[i]); + + for (size_t i = 0; i < m_wiimotes.size(); ++i) + m_wiimotes[i]->UpdateInput(next_call[i], wiimote_states[i]); + m_last_ticks = now; } diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h index e3b649d252..038ed2f5e2 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.h @@ -60,7 +60,7 @@ public: void DoState(PointerWrap& p) override; private: - std::vector> m_wiimotes; + std::array, MAX_BBMOTES> m_wiimotes; bdaddr_t m_controller_bd{{0x11, 0x02, 0x19, 0x79, 0x00, 0xff}}; diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp index 37d63f8455..5a59315606 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.cpp @@ -21,6 +21,7 @@ #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h" +#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h" #include "Core/Host.h" #include "Core/IOS/USB/Bluetooth/BTEmu.h" #include "Core/IOS/USB/Bluetooth/WiimoteHIDAttr.h" @@ -341,25 +342,51 @@ void WiimoteDevice::Update() } } -void WiimoteDevice::UpdateInput() +WiimoteDevice::NextUpdateInputCall +WiimoteDevice::PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state) { if (m_connection_request_counter) --m_connection_request_counter; if (!IsSourceValid()) - return; + return NextUpdateInputCall::None; - // Allow button press to trigger activation after a second of no connection activity. - if (!m_connection_request_counter && m_baseband_state == BasebandState::Inactive) + if (m_baseband_state == BasebandState::Inactive) { - if (Wiimote::NetPlay_GetButtonPress(GetNumber(), m_hid_source->IsButtonPressed())) - Activate(true); + // Allow button press to trigger activation after a second of no connection activity. + if (!m_connection_request_counter) + { + wiimote_state->buttons = m_hid_source->GetCurrentlyPressedButtons(); + return NextUpdateInputCall::Activate; + } + return NextUpdateInputCall::None; } // Verify interrupt channel is connected and configured. const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR); if (channel && channel->IsComplete()) - m_hid_source->Update(); + { + m_hid_source->PrepareInput(wiimote_state); + return NextUpdateInputCall::Update; + } + return NextUpdateInputCall::None; +} + +void WiimoteDevice::UpdateInput(NextUpdateInputCall next_call, + const WiimoteEmu::DesiredWiimoteState& wiimote_state) +{ + switch (next_call) + { + case NextUpdateInputCall::Activate: + if (wiimote_state.buttons.hex & WiimoteCommon::ButtonData::BUTTON_MASK) + Activate(true); + break; + case NextUpdateInputCall::Update: + m_hid_source->Update(wiimote_state); + break; + default: + break; + } } // This function receives L2CAP commands from the CPU diff --git a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h index d0dbb4dc5e..99ac995f78 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h +++ b/Source/Core/Core/IOS/USB/Bluetooth/WiimoteDevice.h @@ -13,6 +13,11 @@ class PointerWrap; +namespace WiimoteEmu +{ +struct DesiredWiimoteState; +} + namespace IOS::HLE { class BluetoothEmuDevice; @@ -38,7 +43,15 @@ public: void Update(); // Called every ~200hz. - void UpdateInput(); + enum class NextUpdateInputCall + { + None, + Activate, + Update + }; + NextUpdateInputCall PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state); + void UpdateInput(NextUpdateInputCall next_call, + const WiimoteEmu::DesiredWiimoteState& wiimote_state); void DoState(PointerWrap& p);