From 5af2081c756b6584236044acb198374b2e8b1422 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Tue, 21 Jan 2020 18:36:41 -0600 Subject: [PATCH] Core/WiimoteEmu: Add functions to Nunchuk, Classic Controller, and MotionPlus extensions to get/set data without duplicate bithacks everywhere. --- .../Core/Core/HW/WiimoteCommon/DataReport.cpp | 76 +++---- .../Core/Core/HW/WiimoteCommon/DataReport.h | 12 +- .../Core/HW/WiimoteCommon/WiimoteConstants.h | 4 + .../Core/HW/WiimoteCommon/WiimoteReport.h | 104 ++++++++++ .../Core/HW/WiimoteEmu/Extension/Classic.cpp | 28 ++- .../Core/HW/WiimoteEmu/Extension/Classic.h | 108 +++++++++- .../Core/HW/WiimoteEmu/Extension/Nunchuk.cpp | 15 +- .../Core/HW/WiimoteEmu/Extension/Nunchuk.h | 102 ++++++++-- Source/Core/Core/HW/WiimoteEmu/MotionPlus.cpp | 188 +++++++++++------- Source/Core/Core/HW/WiimoteEmu/MotionPlus.h | 144 ++++++++++---- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 2 +- Source/Core/Core/Movie.cpp | 22 +- .../Core/DolphinQt/TAS/WiiTASInputWindow.cpp | 127 +++++------- 13 files changed, 649 insertions(+), 283 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteCommon/DataReport.cpp b/Source/Core/Core/HW/WiimoteCommon/DataReport.cpp index 8f258665f0..0197553517 100644 --- a/Source/Core/Core/HW/WiimoteCommon/DataReport.cpp +++ b/Source/Core/Core/HW/WiimoteCommon/DataReport.cpp @@ -5,6 +5,7 @@ #include #include "Common/BitUtils.h" +#include "Common/MathUtil.h" #include "Core/HW/WiimoteCommon/DataReport.h" namespace WiimoteCommon @@ -75,40 +76,35 @@ struct IncludeAccel : virtual DataReportManipulator void GetAccelData(AccelData* result) const override { const AccelMSB accel = Common::BitCastPtr(data_ptr + 2); - result->x = accel.x << 2; - result->y = accel.y << 2; - result->z = accel.z << 2; - - // LSBs const CoreData core = Common::BitCastPtr(data_ptr); - result->x |= core.acc_bits & 0b11; - result->y |= (core.acc_bits2 & 0b1) << 1; - result->z |= core.acc_bits2 & 0b10; + + // X has 10 bits of precision. + result->value.x = accel.x << 2; + result->value.x |= core.acc_bits & 0b11; + + // Y and Z only have 9 bits of precision. (convert them to 10) + result->value.y = + Common::ExpandValue(accel.y << 1 | Common::ExtractBit<0>(core.acc_bits2), 1); + result->value.z = + Common::ExpandValue(accel.z << 1 | Common::ExtractBit<1>(core.acc_bits2), 1); } void SetAccelData(const AccelData& new_accel) override { - AccelMSB accel = {}; - accel.x = new_accel.x >> 2; - accel.y = new_accel.y >> 2; - accel.z = new_accel.z >> 2; - Common::BitCastPtr(data_ptr + 2) = accel; + Common::BitCastPtr(data_ptr + 2) = AccelMSB(new_accel.value / 4); // LSBs CoreData core = Common::BitCastPtr(data_ptr); - core.acc_bits = (new_accel.x >> 0) & 0b11; - core.acc_bits2 = (new_accel.y >> 1) & 0x1; - core.acc_bits2 |= (new_accel.z & 0xb10); + core.acc_bits = (new_accel.value.x >> 0) & 0b11; + core.acc_bits2 = (new_accel.value.y >> 1) & 0x1; + core.acc_bits2 |= (new_accel.value.z & 0xb10); Common::BitCastPtr(data_ptr) = core; } bool HasAccel() const override { return true; } private: - struct AccelMSB - { - u8 x, y, z; - }; + using AccelMSB = Common::TVec3; static_assert(sizeof(AccelMSB) == 3, "Wrong size"); }; @@ -195,26 +191,28 @@ struct ReportExt21 : NoCore, NoAccel, NoIR, IncludeExt<0, 21> struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt { // FYI: Only 8-bits of precision in this report, and no Y axis. - // Only contains 4 MSB of Z axis. - void GetAccelData(AccelData* accel) const override { - accel->x = data_ptr[2] << 2; + // X axis only has 8 bits of precision. (converted to 10) + accel->value.x = Common::ExpandValue(data_ptr[2], 2); - // Retain lower 6 bits. - accel->z &= 0b111111; + // Y axis is not contained in this report. (provided by "Interleave2") + // Clear upper bits, retain lower bits. (provided by "Interleave2") + accel->value.z &= 0b111111; + + // Report only contains 4 MSB of Z axis. const CoreData core = Common::BitCastPtr(data_ptr); - accel->z |= (core.acc_bits << 6) | (core.acc_bits2 << 8); + accel->value.z |= (core.acc_bits << 6) | (core.acc_bits2 << 8); } void SetAccelData(const AccelData& accel) override { - data_ptr[2] = accel.x >> 2; + data_ptr[2] = accel.value.x >> 2; CoreData core = Common::BitCastPtr(data_ptr); - core.acc_bits = (accel.z >> 6) & 0b11; - core.acc_bits2 = (accel.z >> 8) & 0b11; + core.acc_bits = (accel.value.z >> 6) & 0b11; + core.acc_bits2 = (accel.value.z >> 8) & 0b11; Common::BitCastPtr(data_ptr) = core; } @@ -226,26 +224,28 @@ struct ReportInterleave1 : IncludeCore, IncludeIR<3, 18, 0>, NoExt struct ReportInterleave2 : IncludeCore, IncludeIR<3, 18, 18>, NoExt { // FYI: Only 8-bits of precision in this report, and no X axis. - // Only contains 4 LSB of Z axis. - void GetAccelData(AccelData* accel) const override { - accel->y = data_ptr[2] << 2; + // X axis is not contained in this report. (provided by "Interleave1") - // Retain upper 4 bits. - accel->z &= ~0b111111; + // Y axis only has 8 bits of precision. (converted to 10) + accel->value.y = Common::ExpandValue(data_ptr[2], 2); + // Clear lower bits, retain upper bits. (provided by "Interleave1") + accel->value.z &= ~0b111111; + + // Report only contains 4 LSBs of Z axis. (converted to 6) const CoreData core = Common::BitCastPtr(data_ptr); - accel->z |= (core.acc_bits << 2) | (core.acc_bits2 << 4); + accel->value.z |= Common::ExpandValue(core.acc_bits | core.acc_bits2 << 2, 2); } void SetAccelData(const AccelData& accel) override { - data_ptr[2] = accel.y >> 2; + data_ptr[2] = accel.value.y >> 2; CoreData core = Common::BitCastPtr(data_ptr); - core.acc_bits = (accel.z >> 2) & 0b11; - core.acc_bits2 = (accel.z >> 4) & 0b11; + core.acc_bits = (accel.value.z >> 2) & 0b11; + core.acc_bits2 = (accel.value.z >> 4) & 0b11; Common::BitCastPtr(data_ptr) = core; } diff --git a/Source/Core/Core/HW/WiimoteCommon/DataReport.h b/Source/Core/Core/HW/WiimoteCommon/DataReport.h index dd2833728d..75b649d854 100644 --- a/Source/Core/Core/HW/WiimoteCommon/DataReport.h +++ b/Source/Core/Core/HW/WiimoteCommon/DataReport.h @@ -8,9 +8,11 @@ #include #include "Common/CommonTypes.h" +#include "Common/Matrix.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h" +#include "InputCommon/ControllerEmu/ControllerEmu.h" namespace WiimoteCommon { @@ -21,12 +23,6 @@ class DataReportManipulator public: virtual ~DataReportManipulator() = default; - // Accel data handled as if there were always 10 bits of precision. - struct AccelData - { - u16 x, y, z; - }; - using CoreData = ButtonData; virtual bool HasCore() const = 0; @@ -66,7 +62,6 @@ public: explicit DataReportBuilder(InputReportID rpt_id); using CoreData = ButtonData; - using AccelData = DataReportManipulator::AccelData; void SetMode(InputReportID rpt_id); InputReportID GetMode() const; @@ -99,11 +94,10 @@ public: u32 GetDataSize() const; -private: static constexpr int HEADER_SIZE = 2; - static constexpr int MAX_DATA_SIZE = MAX_PAYLOAD - 2; +private: TypedHIDInputData> m_data; std::unique_ptr m_manip; diff --git a/Source/Core/Core/HW/WiimoteCommon/WiimoteConstants.h b/Source/Core/Core/HW/WiimoteCommon/WiimoteConstants.h index 99cf0e04e7..2203eb3df2 100644 --- a/Source/Core/Core/HW/WiimoteCommon/WiimoteConstants.h +++ b/Source/Core/Core/HW/WiimoteCommon/WiimoteConstants.h @@ -10,6 +10,10 @@ namespace WiimoteCommon { constexpr u8 MAX_PAYLOAD = 23; +// Based on testing, old WiiLi.org docs, and WiiUse library: +// Max battery level seems to be 0xc8 (decimal 200) +constexpr u8 MAX_BATTERY_LEVEL = 0xc8; + enum class InputReportID : u8 { Status = 0x20, diff --git a/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h b/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h index 58332383d0..35c81518bb 100644 --- a/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h +++ b/Source/Core/Core/HW/WiimoteCommon/WiimoteReport.h @@ -7,7 +7,9 @@ #include #include "Common/CommonTypes.h" +#include "Common/Matrix.h" #include "Core/HW/WiimoteCommon/WiimoteConstants.h" +#include "InputCommon/ControllerEmu/ControllerEmu.h" #ifdef _MSC_VER #pragma warning(push) @@ -41,6 +43,8 @@ static_assert(sizeof(OutputReportGeneric) == 2, "Wrong size"); struct OutputReportRumble { + static constexpr OutputReportID REPORT_ID = OutputReportID::Rumble; + u8 rumble : 1; }; static_assert(sizeof(OutputReportRumble) == 1, "Wrong size"); @@ -55,8 +59,34 @@ struct OutputReportEnableFeature }; static_assert(sizeof(OutputReportEnableFeature) == 1, "Wrong size"); +struct OutputReportIRLogicEnable : OutputReportEnableFeature +{ + static constexpr OutputReportID REPORT_ID = OutputReportID::IRLogicEnable; +}; +static_assert(sizeof(OutputReportIRLogicEnable) == 1, "Wrong size"); + +struct OutputReportIRLogicEnable2 : OutputReportEnableFeature +{ + static constexpr OutputReportID REPORT_ID = OutputReportID::IRLogicEnable2; +}; +static_assert(sizeof(OutputReportIRLogicEnable2) == 1, "Wrong size"); + +struct OutputReportSpeakerEnable : OutputReportEnableFeature +{ + static constexpr OutputReportID REPORT_ID = OutputReportID::SpeakerEnable; +}; +static_assert(sizeof(OutputReportSpeakerEnable) == 1, "Wrong size"); + +struct OutputReportSpeakerMute : OutputReportEnableFeature +{ + static constexpr OutputReportID REPORT_ID = OutputReportID::SpeakerMute; +}; +static_assert(sizeof(OutputReportSpeakerMute) == 1, "Wrong size"); + struct OutputReportLeds { + static constexpr OutputReportID REPORT_ID = OutputReportID::LED; + u8 rumble : 1; u8 ack : 1; u8 : 2; @@ -66,6 +96,8 @@ static_assert(sizeof(OutputReportLeds) == 1, "Wrong size"); struct OutputReportMode { + static constexpr OutputReportID REPORT_ID = OutputReportID::ReportMode; + u8 rumble : 1; u8 ack : 1; u8 continuous : 1; @@ -76,6 +108,8 @@ static_assert(sizeof(OutputReportMode) == 2, "Wrong size"); struct OutputReportRequestStatus { + static constexpr OutputReportID REPORT_ID = OutputReportID::RequestStatus; + u8 rumble : 1; u8 : 7; }; @@ -83,6 +117,8 @@ static_assert(sizeof(OutputReportRequestStatus) == 1, "Wrong size"); struct OutputReportWriteData { + static constexpr OutputReportID REPORT_ID = OutputReportID::WriteData; + u8 rumble : 1; u8 : 1; u8 space : 2; @@ -100,6 +136,8 @@ static_assert(sizeof(OutputReportWriteData) == 21, "Wrong size"); struct OutputReportReadData { + static constexpr OutputReportID REPORT_ID = OutputReportID::ReadData; + u8 rumble : 1; u8 : 1; u8 space : 2; @@ -116,6 +154,8 @@ static_assert(sizeof(OutputReportReadData) == 6, "Wrong size"); struct OutputReportSpeakerData { + static constexpr OutputReportID REPORT_ID = OutputReportID::SpeakerData; + u8 rumble : 1; u8 : 2; u8 length : 5; @@ -157,6 +197,8 @@ static_assert(sizeof(ButtonData) == 2, "Wrong size"); struct InputReportStatus { + static constexpr InputReportID REPORT_ID = InputReportID::Status; + ButtonData buttons; u8 battery_low : 1; u8 extension : 1; @@ -170,6 +212,8 @@ static_assert(sizeof(InputReportStatus) == 6, "Wrong size"); struct InputReportAck { + static constexpr InputReportID REPORT_ID = InputReportID::Ack; + ButtonData buttons; OutputReportID rpt_id; ErrorCode error_code; @@ -178,6 +222,8 @@ static_assert(sizeof(InputReportAck) == 4, "Wrong size"); struct InputReportReadDataReply { + static constexpr InputReportID REPORT_ID = InputReportID::ReadDataReply; + ButtonData buttons; u8 error : 4; u8 size_minus_one : 4; @@ -187,6 +233,64 @@ struct InputReportReadDataReply }; static_assert(sizeof(InputReportReadDataReply) == 21, "Wrong size"); +// Accel data handled as if there were always 10 bits of precision. +using AccelType = Common::TVec3; +using AccelData = ControllerEmu::RawValue; + +// Found in Wiimote EEPROM and Nunchuk "register". +// 0g and 1g points exist. +struct AccelCalibrationPoint +{ + // All components have 10 bits of precision. + u16 GetX() const { return x2 << 2 | x1; } + u16 GetY() const { return y2 << 2 | y1; } + u16 GetZ() const { return z2 << 2 | z1; } + auto Get() const { return AccelType{GetX(), GetY(), GetZ()}; } + + void SetX(u16 x) + { + x2 = x >> 2; + x1 = x; + } + void SetY(u16 y) + { + y2 = y >> 2; + y1 = y; + } + void SetZ(u16 z) + { + z2 = z >> 2; + z1 = z; + } + void Set(AccelType accel) + { + SetX(accel.x); + SetY(accel.y); + SetZ(accel.z); + } + + u8 x2, y2, z2; + u8 z1 : 2; + u8 y1 : 2; + u8 x1 : 2; + u8 : 2; +}; + +// Located at 0x16 and 0x20 of Wii Remote EEPROM. +struct AccelCalibrationData +{ + using Calibration = ControllerEmu::TwoPointCalibration; + + auto GetCalibration() const { return Calibration(zero_g.Get(), one_g.Get()); } + + AccelCalibrationPoint zero_g; + AccelCalibrationPoint one_g; + + u8 volume : 7; + u8 motor : 1; + u8 checksum; +}; + } // namespace WiimoteCommon #pragma pack(pop) diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp index d7c34320c9..761950a24e 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.cpp @@ -114,8 +114,10 @@ void Classic::Update() { const ControllerEmu::AnalogStick::StateData left_stick_state = m_left_stick->GetState(); - classic_data.lx = static_cast(LEFT_STICK_CENTER + (left_stick_state.x * LEFT_STICK_RADIUS)); - classic_data.ly = static_cast(LEFT_STICK_CENTER + (left_stick_state.y * LEFT_STICK_RADIUS)); + const u8 x = static_cast(LEFT_STICK_CENTER + (left_stick_state.x * LEFT_STICK_RADIUS)); + const u8 y = static_cast(LEFT_STICK_CENTER + (left_stick_state.y * LEFT_STICK_RADIUS)); + + classic_data.SetLeftStick({x, y}); } // right stick @@ -125,10 +127,7 @@ void Classic::Update() const u8 x = static_cast(RIGHT_STICK_CENTER + (right_stick_data.x * RIGHT_STICK_RADIUS)); const u8 y = static_cast(RIGHT_STICK_CENTER + (right_stick_data.y * RIGHT_STICK_RADIUS)); - classic_data.rx1 = x; - classic_data.rx2 = x >> 1; - classic_data.rx3 = x >> 3; - classic_data.ry = y; + classic_data.SetRightStick({x, y}); } // triggers @@ -139,18 +138,15 @@ void Classic::Update() const u8 lt = static_cast(trigs[0] * TRIGGER_RANGE); const u8 rt = static_cast(trigs[1] * TRIGGER_RANGE); - classic_data.lt1 = lt; - classic_data.lt2 = lt >> 3; - classic_data.rt = rt; + classic_data.SetLeftTrigger(lt); + classic_data.SetRightTrigger(rt); } - // buttons - m_buttons->GetState(&classic_data.bt.hex, classic_button_bitmasks.data()); - // dpad - m_dpad->GetState(&classic_data.bt.hex, classic_dpad_bitmasks.data()); - - // flip button bits - classic_data.bt.hex ^= 0xFFFF; + // buttons and dpad + u16 buttons = 0; + m_buttons->GetState(&buttons, classic_button_bitmasks.data()); + m_dpad->GetState(&buttons, classic_dpad_bitmasks.data()); + classic_data.SetButtons(buttons); Common::BitCastPtr(&m_reg.controller_data) = classic_data; } diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h index 124674783b..87397282c7 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Classic.h @@ -4,6 +4,9 @@ #pragma once +#include + +#include "Common/Matrix.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h" #include "Core/HW/WiimoteEmu/Extension/Extension.h" @@ -56,12 +59,59 @@ public: }; static_assert(sizeof(ButtonFormat) == 2, "Wrong size"); + static constexpr int LEFT_STICK_BITS = 6; + static constexpr int RIGHT_STICK_BITS = 5; + static constexpr int TRIGGER_BITS = 5; + struct DataFormat { - // lx/ly/lz; left joystick - // rx/ry/rz; right joystick - // lt; left trigger - // rt; left trigger + using StickType = Common::TVec2; + using LeftStickRawValue = ControllerEmu::RawValue; + using RightStickRawValue = ControllerEmu::RawValue; + + using TriggerType = u8; + using TriggerRawValue = ControllerEmu::RawValue; + + // 6-bit X and Y values (0-63) + auto GetLeftStick() const { return LeftStickRawValue{StickType(lx, ly)}; }; + void SetLeftStick(const StickType& value) + { + lx = value.x; + ly = value.y; + } + // 5-bit X and Y values (0-31) + auto GetRightStick() const + { + return RightStickRawValue{StickType(rx1 | rx2 << 1 | rx3 << 3, ry)}; + }; + void SetRightStick(const StickType& value) + { + rx1 = value.x & 0b1; + rx2 = (value.x >> 1) & 0b11; + rx3 = (value.x >> 3) & 0b11; + ry = value.y; + } + // 5-bit values (0-31) + auto GetLeftTrigger() const { return TriggerRawValue(lt1 | lt2 << 3); } + void SetLeftTrigger(TriggerType value) + { + lt1 = value & 0b111; + lt2 = (value >> 3) & 0b11; + } + auto GetRightTrigger() const { return TriggerRawValue(rt); } + void SetRightTrigger(TriggerType value) { rt = value; } + + u16 GetButtons() const + { + // 0 == pressed. + return ~bt.hex; + } + + void SetButtons(u16 value) + { + // 0 == pressed. + bt.hex = ~value; + } u8 lx : 6; // byte 0 u8 rx3 : 2; @@ -80,6 +130,53 @@ public: }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + static constexpr int CAL_STICK_BITS = 8; + static constexpr int CAL_TRIGGER_BITS = 8; + + struct CalibrationData + { + using StickType = DataFormat::StickType; + using TriggerType = DataFormat::TriggerType; + + using StickCalibration = ControllerEmu::ThreePointCalibration; + using TriggerCalibration = ControllerEmu::TwoPointCalibration; + + static constexpr TriggerType TRIGGER_MAX = std::numeric_limits::max(); + + struct StickAxis + { + u8 max; + u8 min; + u8 center; + }; + + auto GetLeftStick() const + { + return StickCalibration{StickType{left_stick_x.min, left_stick_y.min}, + StickType{left_stick_x.center, left_stick_y.center}, + StickType{left_stick_x.max, left_stick_y.max}}; + } + auto GetRightStick() const + { + return StickCalibration{StickType{right_stick_x.min, right_stick_y.min}, + StickType{right_stick_x.center, right_stick_y.center}, + StickType{right_stick_x.max, right_stick_y.max}}; + } + auto GetLeftTrigger() const { return TriggerCalibration{left_trigger_zero, TRIGGER_MAX}; } + auto GetRightTrigger() const { return TriggerCalibration{right_trigger_zero, TRIGGER_MAX}; } + + StickAxis left_stick_x; + StickAxis left_stick_y; + StickAxis right_stick_x; + StickAxis right_stick_y; + + u8 left_trigger_zero; + u8 right_trigger_zero; + + std::array checksum; + }; + static_assert(sizeof(CalibrationData) == 16, "Wrong size"); + Classic(); void Update() override; @@ -110,13 +207,10 @@ public: static constexpr u8 CAL_STICK_CENTER = 0x80; static constexpr u8 CAL_STICK_RANGE = 0x7f; - static constexpr int CAL_STICK_BITS = 8; - static constexpr int LEFT_STICK_BITS = 6; static constexpr u8 LEFT_STICK_CENTER = CAL_STICK_CENTER >> (CAL_STICK_BITS - LEFT_STICK_BITS); static constexpr u8 LEFT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - LEFT_STICK_BITS); - static constexpr int RIGHT_STICK_BITS = 5; static constexpr u8 RIGHT_STICK_CENTER = CAL_STICK_CENTER >> (CAL_STICK_BITS - RIGHT_STICK_BITS); static constexpr u8 RIGHT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - RIGHT_STICK_BITS); diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp index d1125ba05a..548d62638b 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.cpp @@ -87,10 +87,9 @@ void Nunchuk::Update() } // buttons - m_buttons->GetState(&nc_data.bt.hex, nunchuk_button_bitmasks.data()); - - // flip the button bits :/ - nc_data.bt.hex ^= 0x03; + u8 buttons = 0; + m_buttons->GetState(&buttons, nunchuk_button_bitmasks.data()); + nc_data.SetButtons(buttons); // Acceleration data: EmulateSwing(&m_swing_state, m_swing, 1.f / ::Wiimote::UPDATE_FREQ); @@ -109,13 +108,7 @@ void Nunchuk::Update() // Calibration values are 8-bit but we want 10-bit precision, so << 2. const auto acc = ConvertAccelData(accel, ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); - - nc_data.ax = (acc.x >> 2) & 0xFF; - nc_data.ay = (acc.y >> 2) & 0xFF; - nc_data.az = (acc.z >> 2) & 0xFF; - nc_data.bt.acc_x_lsb = acc.x & 0x3; - nc_data.bt.acc_y_lsb = acc.y & 0x3; - nc_data.bt.acc_z_lsb = acc.z & 0x3; + nc_data.SetAccel(acc.value); Common::BitCastPtr(&m_reg.controller_data) = nc_data; } diff --git a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h index af55a02b4b..19236e24f9 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h +++ b/Source/Core/Core/HW/WiimoteEmu/Extension/Nunchuk.h @@ -51,25 +51,103 @@ public: }; static_assert(sizeof(ButtonFormat) == 1, "Wrong size"); - union DataFormat + struct DataFormat { - struct + using StickType = Common::TVec2; + using StickRawValue = ControllerEmu::RawValue; + + using AccelType = WiimoteCommon::AccelType; + using AccelData = WiimoteCommon::AccelData; + + auto GetStick() const { return StickRawValue(StickType(jx, jy)); } + + // Components have 10 bits of precision. + u16 GetAccelX() const { return ax << 2 | bt.acc_x_lsb; } + u16 GetAccelY() const { return ay << 2 | bt.acc_y_lsb; } + u16 GetAccelZ() const { return az << 2 | bt.acc_z_lsb; } + auto GetAccel() const { return AccelData{AccelType{GetAccelX(), GetAccelY(), GetAccelZ()}}; } + + void SetAccelX(u16 val) { - // joystick x, y - u8 jx; - u8 jy; + ax = val >> 2; + bt.acc_x_lsb = val & 0b11; + } + void SetAccelY(u16 val) + { + ay = val >> 2; + bt.acc_y_lsb = val & 0b11; + } + void SetAccelZ(u16 val) + { + az = val >> 2; + bt.acc_z_lsb = val & 0b11; + } + void SetAccel(const AccelType& accel) + { + SetAccelX(accel.x); + SetAccelY(accel.y); + SetAccelZ(accel.z); + } - // accelerometer - u8 ax; - u8 ay; - u8 az; + u8 GetButtons() const + { + // 0 == pressed. + return ~bt.hex & (BUTTON_C | BUTTON_Z); + } + void SetButtons(u8 value) + { + // 0 == pressed. + bt.hex |= (BUTTON_C | BUTTON_Z); + bt.hex ^= value & (BUTTON_C | BUTTON_Z); + } - // buttons + accelerometer LSBs - ButtonFormat bt; - }; + // joystick x, y + u8 jx; + u8 jy; + + // accelerometer + u8 ax; + u8 ay; + u8 az; + + // buttons + accelerometer LSBs + ButtonFormat bt; }; static_assert(sizeof(DataFormat) == 6, "Wrong size"); + struct CalibrationData + { + using StickType = DataFormat::StickType; + using StickCalibration = ControllerEmu::ThreePointCalibration; + + using AccelType = WiimoteCommon::AccelType; + using AccelCalibration = ControllerEmu::TwoPointCalibration; + + struct Stick + { + u8 max; + u8 min; + u8 center; + }; + + auto GetStick() const + { + return StickCalibration(StickType{stick_x.min, stick_y.min}, + StickType{stick_x.center, stick_y.center}, + StickType{stick_x.max, stick_y.max}); + } + auto GetAccel() const { return AccelCalibration(accel_zero_g.Get(), accel_one_g.Get()); } + + WiimoteCommon::AccelCalibrationPoint accel_zero_g; + WiimoteCommon::AccelCalibrationPoint accel_one_g; + + Stick stick_x; + Stick stick_y; + + std::array checksum; + }; + static_assert(sizeof(CalibrationData) == 16, "Wrong size"); + Nunchuk(); void Update() override; diff --git a/Source/Core/Core/HW/WiimoteEmu/MotionPlus.cpp b/Source/Core/Core/HW/WiimoteEmu/MotionPlus.cpp index a9ec9cb6cd..ab8be7c19c 100644 --- a/Source/Core/Core/HW/WiimoteEmu/MotionPlus.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/MotionPlus.cpp @@ -16,7 +16,6 @@ #include "Common/Logging/Log.h" #include "Common/MathUtil.h" #include "Common/MsgHandler.h" -#include "Common/Swap.h" #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteEmu/Dynamics.h" @@ -56,6 +55,41 @@ struct MPI : mbedtls_mpi namespace WiimoteEmu { +Common::Vec3 MotionPlus::DataFormat::Data::GetAngularVelocity(const CalibrationBlocks& blocks) const +{ + // Each axis may be using either slow or fast calibration. + const auto calibration = blocks.GetRelevantCalibration(is_slow); + + // It seems M+ calibration data does not follow the "right-hand rule". + const auto sign_fix = Common::Vec3(-1, +1, -1); + + // Adjust deg/s to rad/s. + constexpr auto scalar = float(MathUtil::TAU / 360); + + return gyro.GetNormalizedValue(calibration.value) * sign_fix * Common::Vec3(calibration.degrees) * + scalar; +} + +auto MotionPlus::CalibrationBlocks::GetRelevantCalibration(SlowType is_slow) const + -> RelevantCalibration +{ + RelevantCalibration result; + + const auto& pitch_block = is_slow.x ? slow : fast; + const auto& roll_block = is_slow.y ? slow : fast; + const auto& yaw_block = is_slow.z ? slow : fast; + + result.value.max = {pitch_block.pitch_scale, roll_block.roll_scale, yaw_block.yaw_scale}; + + result.value.zero = {pitch_block.pitch_zero, roll_block.roll_zero, yaw_block.yaw_zero}; + + result.degrees.x = pitch_block.degrees_div_6 * 6; + result.degrees.y = roll_block.degrees_div_6 * 6; + result.degrees.z = yaw_block.degrees_div_6 * 6; + + return result; +} + MotionPlus::MotionPlus() : Extension("MotionPlus") { } @@ -82,35 +116,20 @@ void MotionPlus::Reset() constexpr u16 ROLL_SCALE = CALIBRATION_ZERO + CALIBRATION_SCALE_OFFSET; constexpr u16 PITCH_SCALE = CALIBRATION_ZERO - CALIBRATION_SCALE_OFFSET; -#pragma pack(push, 1) - struct CalibrationBlock - { - u16 yaw_zero = Common::swap16(CALIBRATION_ZERO); - u16 roll_zero = Common::swap16(CALIBRATION_ZERO); - u16 pitch_zero = Common::swap16(CALIBRATION_ZERO); - u16 yaw_scale = Common::swap16(YAW_SCALE); - u16 roll_scale = Common::swap16(ROLL_SCALE); - u16 pitch_scale = Common::swap16(PITCH_SCALE); - u8 degrees_div_6; - }; - - struct CalibrationData - { - CalibrationBlock fast; - u8 uid_1; - Common::BigEndianValue crc32_msb; - CalibrationBlock slow; - u8 uid_2; - Common::BigEndianValue crc32_lsb; - }; -#pragma pack(pop) - static_assert(sizeof(CalibrationData) == 0x20, "Bad size."); static_assert(CALIBRATION_FAST_SCALE_DEGREES % 6 == 0, "Value should be divisible by 6."); static_assert(CALIBRATION_SLOW_SCALE_DEGREES % 6 == 0, "Value should be divisible by 6."); CalibrationData calibration; + calibration.fast.yaw_zero = calibration.slow.yaw_zero = CALIBRATION_ZERO; + calibration.fast.roll_zero = calibration.slow.roll_zero = CALIBRATION_ZERO; + calibration.fast.pitch_zero = calibration.slow.pitch_zero = CALIBRATION_ZERO; + + calibration.fast.yaw_scale = calibration.slow.yaw_scale = YAW_SCALE; + calibration.fast.roll_scale = calibration.slow.roll_scale = ROLL_SCALE; + calibration.fast.pitch_scale = calibration.slow.pitch_scale = PITCH_SCALE; + calibration.fast.degrees_div_6 = CALIBRATION_FAST_SCALE_DEGREES / 6; calibration.slow.degrees_div_6 = CALIBRATION_SLOW_SCALE_DEGREES / 6; @@ -120,17 +139,22 @@ void MotionPlus::Reset() calibration.uid_1 = 0x0b; calibration.uid_2 = 0xe9; - // Update checksum (crc32 of all data other than the checksum itself): - auto crc_result = crc32(0, Z_NULL, 0); - crc_result = crc32(crc_result, reinterpret_cast(&calibration), 0xe); - crc_result = crc32(crc_result, reinterpret_cast(&calibration) + 0x10, 0xe); - - calibration.crc32_lsb = u16(crc_result); - calibration.crc32_msb = u16(crc_result >> 16); + calibration.UpdateChecksum(); Common::BitCastPtr(m_reg_data.calibration_data.data()) = calibration; } +void MotionPlus::CalibrationData::UpdateChecksum() +{ + // Checksum is crc32 of all data other than the checksum itself. + auto crc_result = crc32(0, Z_NULL, 0); + crc_result = crc32(crc_result, reinterpret_cast(this), 0xe); + crc_result = crc32(crc_result, reinterpret_cast(this) + 0x10, 0xe); + + crc32_lsb = u16(crc_result); + crc32_msb = u16(crc_result >> 16); +} + void MotionPlus::DoState(PointerWrap& p) { p.Do(m_reg_data); @@ -547,47 +571,10 @@ void MotionPlus::PrepareInput(const Common::Vec3& angular_velocity) break; } case PassthroughMode::Nunchuk: - { - if (EXT_AMT == m_i2c_bus.BusRead(EXT_SLAVE, EXT_ADDR, EXT_AMT, data)) - { - // Passthrough data modifications via wiibrew.org - // Verified on real hardware via a test of every bit. - // Data passing through drops the least significant bit of the three accelerometer values. - // Bit 7 of byte 5 is moved to bit 6 of byte 5, overwriting it - Common::SetBit(data[5], 6, Common::ExtractBit(data[5], 7)); - // Bit 0 of byte 4 is moved to bit 7 of byte 5 - Common::SetBit(data[5], 7, Common::ExtractBit(data[4], 0)); - // Bit 3 of byte 5 is moved to bit 4 of byte 5, overwriting it - Common::SetBit(data[5], 4, Common::ExtractBit(data[5], 3)); - // Bit 1 of byte 5 is moved to bit 3 of byte 5 - Common::SetBit(data[5], 3, Common::ExtractBit(data[5], 1)); - // Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it - Common::SetBit(data[5], 2, Common::ExtractBit(data[5], 0)); - - mplus_data = Common::BitCastPtr(data); - - // Bit 0 and 1 of byte 5 contain a M+ flag and a zero bit which is set below. - mplus_data.is_mp_data = false; - } - else - { - // Read failed (extension unplugged), Send M+ data instead - mplus_data.is_mp_data = true; - } - break; - } case PassthroughMode::Classic: - { if (EXT_AMT == m_i2c_bus.BusRead(EXT_SLAVE, EXT_ADDR, EXT_AMT, data)) { - // Passthrough data modifications via wiibrew.org - // Verified on real hardware via a test of every bit. - // Data passing through drops the least significant bit of the axes of the left (or only) - // joystick Bit 0 of Byte 4 is overwritten [by the 'extension_connected' flag] Bits 0 and - // 1 of Byte 5 are moved to bit 0 of Bytes 0 and 1, overwriting what was there before. - Common::SetBit(data[0], 0, Common::ExtractBit(data[5], 0)); - Common::SetBit(data[1], 0, Common::ExtractBit(data[5], 1)); - + ApplyPassthroughModifications(GetPassthroughMode(), data); mplus_data = Common::BitCastPtr(data); // Bit 0 and 1 of byte 5 contain a M+ flag and a zero bit which is set below. @@ -599,7 +586,6 @@ void MotionPlus::PrepareInput(const Common::Vec3& angular_velocity) mplus_data.is_mp_data = true; } break; - } default: // This really shouldn't happen as the M+ deactivates on an invalid mode write. ERROR_LOG(WIIMOTE, "M+ unknown passthrough-mode %d", int(GetPassthroughMode())); @@ -664,4 +650,66 @@ void MotionPlus::PrepareInput(const Common::Vec3& angular_velocity) Common::BitCastPtr(data) = mplus_data; } +void MotionPlus::ApplyPassthroughModifications(PassthroughMode mode, u8* data) +{ + if (mode == PassthroughMode::Nunchuk) + { + // Passthrough data modifications via wiibrew.org + // Verified on real hardware via a test of every bit. + // Data passing through drops the least significant bit of the three accelerometer values. + // Bit 7 of byte 5 is moved to bit 6 of byte 5, overwriting it + Common::SetBit<6>(data[5], Common::ExtractBit<7>(data[5])); + // Bit 0 of byte 4 is moved to bit 7 of byte 5 + Common::SetBit<7>(data[5], Common::ExtractBit<0>(data[4])); + // Bit 3 of byte 5 is moved to bit 4 of byte 5, overwriting it + Common::SetBit<4>(data[5], Common::ExtractBit<3>(data[5])); + // Bit 1 of byte 5 is moved to bit 3 of byte 5 + Common::SetBit<3>(data[5], Common::ExtractBit<1>(data[5])); + // Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it + Common::SetBit<2>(data[5], Common::ExtractBit<0>(data[5])); + } + else if (mode == PassthroughMode::Classic) + { + // Passthrough data modifications via wiibrew.org + // Verified on real hardware via a test of every bit. + // Data passing through drops the least significant bit of the axes of the left (or only) + // joystick Bit 0 of Byte 4 is overwritten [by the 'extension_connected' flag] Bits 0 and + // 1 of Byte 5 are moved to bit 0 of Bytes 0 and 1, overwriting what was there before. + Common::SetBit<0>(data[0], Common::ExtractBit<0>(data[5])); + Common::SetBit<0>(data[1], Common::ExtractBit<1>(data[5])); + } +} + +void MotionPlus::ReversePassthroughModifications(PassthroughMode mode, u8* data) +{ + if (mode == PassthroughMode::Nunchuk) + { + // Undo M+'s "nunchuk passthrough" modifications. + Common::SetBit<0>(data[5], Common::ExtractBit<2>(data[5])); + Common::SetBit<1>(data[5], Common::ExtractBit<3>(data[5])); + Common::SetBit<3>(data[5], Common::ExtractBit<4>(data[5])); + Common::SetBit<0>(data[4], Common::ExtractBit<7>(data[5])); + Common::SetBit<7>(data[5], Common::ExtractBit<6>(data[5])); + + // Set the overwritten bits from the next LSB. + Common::SetBit<2>(data[5], Common::ExtractBit<3>(data[5])); + Common::SetBit<4>(data[5], Common::ExtractBit<5>(data[5])); + Common::SetBit<6>(data[5], Common::ExtractBit<7>(data[5])); + } + else if (mode == PassthroughMode::Classic) + { + // Undo M+'s "classic controller passthrough" modifications. + Common::SetBit<0>(data[5], Common::ExtractBit<0>(data[0])); + Common::SetBit<1>(data[5], Common::ExtractBit<0>(data[1])); + + // Set the overwritten bits from the next LSB. + Common::SetBit<0>(data[0], Common::ExtractBit<1>(data[0])); + Common::SetBit<0>(data[1], Common::ExtractBit<1>(data[1])); + + // This is an overwritten unused button bit on the Classic Controller. + // Note it's a significant bit on the DJ Hero Turntable. (passthrough not feasible) + Common::SetBit<0>(data[4], 1); + } +} + } // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/MotionPlus.h b/Source/Core/Core/HW/WiimoteEmu/MotionPlus.h index 07869957f7..63807db415 100644 --- a/Source/Core/Core/HW/WiimoteEmu/MotionPlus.h +++ b/Source/Core/Core/HW/WiimoteEmu/MotionPlus.h @@ -7,59 +7,90 @@ #include #include "Common/CommonTypes.h" +#include "Common/Swap.h" #include "Core/HW/WiimoteEmu/Dynamics.h" #include "Core/HW/WiimoteEmu/ExtensionPort.h" #include "Core/HW/WiimoteEmu/I2CBus.h" namespace WiimoteEmu { -struct AngularVelocity; - struct MotionPlus : public Extension { public: - MotionPlus(); - - void Update() override; - void Reset() override; - void DoState(PointerWrap& p) override; - - ExtensionPort& GetExtPort(); - - // Vec3 is interpreted as radians/s about the x,y,z axes following the "right-hand rule". - void PrepareInput(const Common::Vec3& angular_velocity); - -private: - enum class ChallengeState : u8 - { - // Note: This is not a value seen on a real M+. - // Used to emulate activation state during which the M+ is not responsive. - Activating = 0x00, - - PreparingX = 0x02, - ParameterXReady = 0x0e, - PreparingY = 0x14, - ParameterYReady = 0x1a, - }; - enum class PassthroughMode : u8 { + // Note: `Disabled` is an M+ enabled with no passthrough. Maybe there is a better name. Disabled = 0x04, Nunchuk = 0x05, Classic = 0x07, }; - enum class ActivationStatus +#pragma pack(push, 1) + struct CalibrationBlock { - Inactive, - Activating, - Deactivating, - Active, + Common::BigEndianValue yaw_zero; + Common::BigEndianValue roll_zero; + Common::BigEndianValue pitch_zero; + Common::BigEndianValue yaw_scale; + Common::BigEndianValue roll_scale; + Common::BigEndianValue pitch_scale; + u8 degrees_div_6; }; -#pragma pack(push, 1) + struct CalibrationBlocks + { + using GyroType = Common::TVec3; + using SlowType = Common::TVec3; + + struct RelevantCalibration + { + ControllerEmu::TwoPointCalibration value; + Common::TVec3 degrees; + }; + + // Each axis may be using either slow or fast calibration. + // This function builds calibration that is relevant for current data. + RelevantCalibration GetRelevantCalibration(SlowType is_slow) const; + + CalibrationBlock fast; + CalibrationBlock slow; + }; + + struct CalibrationData + { + void UpdateChecksum(); + + CalibrationBlock fast; + u8 uid_1; + Common::BigEndianValue crc32_msb; + CalibrationBlock slow; + u8 uid_2; + Common::BigEndianValue crc32_lsb; + }; + static_assert(sizeof(CalibrationData) == 0x20, "Wrong size"); + struct DataFormat { + using GyroType = CalibrationBlocks::GyroType; + using SlowType = CalibrationBlocks::SlowType; + using GyroRawValue = ControllerEmu::RawValue; + + struct Data + { + // Return radian/s following "right-hand rule" with given calibration blocks. + Common::Vec3 GetAngularVelocity(const CalibrationBlocks&) const; + + GyroRawValue gyro; + SlowType is_slow; + }; + + auto GetData() const + { + return Data{ + GyroRawValue{GyroType(pitch1 | pitch2 << 8, roll1 | roll2 << 8, yaw1 | yaw2 << 8)}, + SlowType(pitch_slow, roll_slow, yaw_slow)}; + } + // yaw1, roll1, pitch1: Bits 0-7 // yaw2, roll2, pitch2: Bits 8-13 @@ -79,7 +110,50 @@ private: u8 is_mp_data : 1; u8 pitch2 : 6; }; + static_assert(sizeof(DataFormat) == 6, "Wrong size"); +#pragma pack(pop) + static constexpr u8 INACTIVE_DEVICE_ADDR = 0x53; + static constexpr u8 ACTIVE_DEVICE_ADDR = 0x52; + static constexpr u8 PASSTHROUGH_MODE_OFFSET = 0xfe; + + MotionPlus(); + + void Update() override; + void Reset() override; + void DoState(PointerWrap& p) override; + + ExtensionPort& GetExtPort(); + + // Vec3 is interpreted as radians/s about the x,y,z axes following the "right-hand rule". + void PrepareInput(const Common::Vec3& angular_velocity); + + // Pointer to 6 bytes is expected. + static void ApplyPassthroughModifications(PassthroughMode, u8* data); + static void ReversePassthroughModifications(PassthroughMode, u8* data); + +private: + enum class ChallengeState : u8 + { + // Note: This is not a value seen on a real M+. + // Used to emulate activation state during which the M+ is not responsive. + Activating = 0x00, + + PreparingX = 0x02, + ParameterXReady = 0x0e, + PreparingY = 0x14, + ParameterYReady = 0x1a, + }; + + enum class ActivationStatus + { + Inactive, + Activating, + Deactivating, + Active, + }; + +#pragma pack(push, 1) struct Register { std::array controller_data; @@ -135,14 +209,8 @@ private: std::array ext_identifier; }; #pragma pack(pop) - static_assert(sizeof(DataFormat) == 6, "Wrong size"); static_assert(0x100 == sizeof(Register), "Wrong size"); - static constexpr u8 INACTIVE_DEVICE_ADDR = 0x53; - static constexpr u8 ACTIVE_DEVICE_ADDR = 0x52; - - static constexpr u8 PASSTHROUGH_MODE_OFFSET = 0xfe; - static constexpr int CALIBRATION_BITS = 16; static constexpr u16 CALIBRATION_ZERO = 1 << (CALIBRATION_BITS - 1); diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 65eaa0612b..a9d564d116 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -500,7 +500,7 @@ void Wiimote::SendDataReport() if (rpt_builder.HasAccel()) { // Calibration values are 8-bit but we want 10-bit precision, so << 2. - DataReportBuilder::AccelData accel = + AccelData accel = ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2); rpt_builder.SetAccelData(accel); } diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index d5ceda57f5..f85c625016 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -678,12 +678,13 @@ static void SetWiiInputDisplayString(int remoteID, const DataReportBuilder& rpt, if (rpt.HasAccel()) { - DataReportBuilder::AccelData accel_data; + AccelData accel_data; rpt.GetAccelData(&accel_data); // FYI: This will only print partial data for interleaved reports. - display_str += fmt::format(" ACC:{},{},{}", accel_data.x, accel_data.y, accel_data.z); + display_str += + fmt::format(" ACC:{},{},{}", accel_data.value.x, accel_data.value.y, accel_data.value.z); } if (rpt.HasIR()) @@ -707,9 +708,8 @@ static void SetWiiInputDisplayString(int remoteID, const DataReportBuilder& rpt, key.Decrypt((u8*)&nunchuk, 0, sizeof(nunchuk)); nunchuk.bt.hex = nunchuk.bt.hex ^ 0x3; - const std::string accel = fmt::format( - " N-ACC:{},{},{}", (nunchuk.ax << 2) | nunchuk.bt.acc_x_lsb, - (nunchuk.ay << 2) | nunchuk.bt.acc_y_lsb, (nunchuk.az << 2) | nunchuk.bt.acc_z_lsb); + const std::string accel = fmt::format(" N-ACC:{},{},{}", nunchuk.GetAccelX(), + nunchuk.GetAccelY(), nunchuk.GetAccelZ()); if (nunchuk.bt.c) display_str += " C"; @@ -756,10 +756,14 @@ static void SetWiiInputDisplayString(int remoteID, const DataReportBuilder& rpt, if (cc.bt.home) display_str += " HOME"; - display_str += Analog1DToString(cc.lt1 | (cc.lt2 << 3), " L", 31); - display_str += Analog1DToString(cc.rt, " R", 31); - display_str += Analog2DToString(cc.lx, cc.ly, " ANA", 63); - display_str += Analog2DToString(cc.rx1 | (cc.rx2 << 1) | (cc.rx3 << 3), cc.ry, " R-ANA", 31); + display_str += Analog1DToString(cc.GetLeftTrigger().value, " L", 31); + display_str += Analog1DToString(cc.GetRightTrigger().value, " R", 31); + + const auto left_stick = cc.GetLeftStick().value; + display_str += Analog2DToString(left_stick.x, left_stick.y, " ANA", 63); + + const auto right_stick = cc.GetRightStick().value; + display_str += Analog2DToString(right_stick.x, right_stick.y, " R-ANA", 31); } std::lock_guard guard(s_input_display_lock); diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp index 904e21bf15..b656ca280d 100644 --- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp +++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp @@ -334,18 +334,20 @@ void WiiTASInputWindow::GetValues(DataReportBuilder& rpt, int ext, DataReportBuilder::CoreData core; rpt.GetCoreData(&core); + using EmuWiimote = WiimoteEmu::Wiimote; + u16& buttons = core.hex; - GetButton(m_a_button, buttons, WiimoteEmu::Wiimote::BUTTON_A); - GetButton(m_b_button, buttons, WiimoteEmu::Wiimote::BUTTON_B); - GetButton(m_1_button, buttons, WiimoteEmu::Wiimote::BUTTON_ONE); - GetButton(m_2_button, buttons, WiimoteEmu::Wiimote::BUTTON_TWO); - GetButton(m_plus_button, buttons, WiimoteEmu::Wiimote::BUTTON_PLUS); - GetButton(m_minus_button, buttons, WiimoteEmu::Wiimote::BUTTON_MINUS); - GetButton(m_home_button, buttons, WiimoteEmu::Wiimote::BUTTON_HOME); - GetButton(m_left_button, buttons, WiimoteEmu::Wiimote::PAD_LEFT); - GetButton(m_up_button, buttons, WiimoteEmu::Wiimote::PAD_UP); - GetButton(m_down_button, buttons, WiimoteEmu::Wiimote::PAD_DOWN); - GetButton(m_right_button, buttons, WiimoteEmu::Wiimote::PAD_RIGHT); + GetButton(m_a_button, buttons, EmuWiimote::BUTTON_A); + GetButton(m_b_button, buttons, EmuWiimote::BUTTON_B); + GetButton(m_1_button, buttons, EmuWiimote::BUTTON_ONE); + GetButton(m_2_button, buttons, EmuWiimote::BUTTON_TWO); + GetButton(m_plus_button, buttons, EmuWiimote::BUTTON_PLUS); + GetButton(m_minus_button, buttons, EmuWiimote::BUTTON_MINUS); + GetButton(m_home_button, buttons, EmuWiimote::BUTTON_HOME); + GetButton(m_left_button, buttons, EmuWiimote::PAD_LEFT); + GetButton(m_up_button, buttons, EmuWiimote::PAD_UP); + GetButton(m_down_button, buttons, EmuWiimote::PAD_DOWN); + GetButton(m_right_button, buttons, EmuWiimote::PAD_RIGHT); rpt.SetCoreData(core); } @@ -354,12 +356,12 @@ void WiiTASInputWindow::GetValues(DataReportBuilder& rpt, int ext, { // FYI: Interleaved reports may behave funky as not all data is always available. - DataReportBuilder::AccelData accel; + AccelData accel; rpt.GetAccelData(&accel); - GetSpinBoxU16(m_remote_orientation_x_value, accel.x); - GetSpinBoxU16(m_remote_orientation_y_value, accel.y); - GetSpinBoxU16(m_remote_orientation_z_value, accel.z); + GetSpinBoxU16(m_remote_orientation_x_value, accel.value.x); + GetSpinBoxU16(m_remote_orientation_y_value, accel.value.y); + GetSpinBoxU16(m_remote_orientation_z_value, accel.value.z); rpt.SetAccelData(accel); } @@ -439,26 +441,16 @@ void WiiTASInputWindow::GetValues(DataReportBuilder& rpt, int ext, GetSpinBoxU8(m_nunchuk_stick_x_value, nunchuk.jx); GetSpinBoxU8(m_nunchuk_stick_y_value, nunchuk.jy); - u16 accel_x = nunchuk.ax << 2 & (nunchuk.bt.acc_x_lsb & 0b11); - u16 accel_y = nunchuk.ay << 2 & (nunchuk.bt.acc_y_lsb & 0b11); - u16 accel_z = nunchuk.az << 2 & (nunchuk.bt.acc_z_lsb & 0b11); + auto accel = nunchuk.GetAccel().value; + GetSpinBoxU16(m_nunchuk_orientation_x_value, accel.x); + GetSpinBoxU16(m_nunchuk_orientation_y_value, accel.y); + GetSpinBoxU16(m_nunchuk_orientation_z_value, accel.z); + nunchuk.SetAccel(accel); - GetSpinBoxU16(m_nunchuk_orientation_x_value, accel_x); - GetSpinBoxU16(m_nunchuk_orientation_y_value, accel_y); - GetSpinBoxU16(m_nunchuk_orientation_z_value, accel_z); - - nunchuk.ax = accel_x >> 2; - nunchuk.ay = accel_y >> 2; - nunchuk.az = accel_z >> 2; - - nunchuk.bt.acc_x_lsb = accel_x & 0b11; - nunchuk.bt.acc_y_lsb = accel_y & 0b11; - nunchuk.bt.acc_z_lsb = accel_z & 0b11; - - nunchuk.bt.hex ^= 0b11; - GetButton(m_c_button, nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_C); - GetButton(m_z_button, nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_Z); - nunchuk.bt.hex ^= 0b11; + u8 bt = nunchuk.GetButtons(); + GetButton(m_c_button, bt, WiimoteEmu::Nunchuk::BUTTON_C); + GetButton(m_z_button, bt, WiimoteEmu::Nunchuk::BUTTON_Z); + nunchuk.SetButtons(bt); key.Encrypt(reinterpret_cast(&nunchuk), 0, sizeof(nunchuk)); } @@ -470,50 +462,41 @@ void WiiTASInputWindow::GetValues(DataReportBuilder& rpt, int ext, auto& cc = *reinterpret_cast(ext_data); key.Decrypt(reinterpret_cast(&cc), 0, sizeof(cc)); - cc.bt.hex ^= 0xFFFF; - GetButton(m_classic_a_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_A); - GetButton(m_classic_b_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_B); - GetButton(m_classic_x_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_X); - GetButton(m_classic_y_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_Y); - GetButton(m_classic_plus_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_PLUS); - GetButton(m_classic_minus_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_MINUS); - GetButton(m_classic_l_button, cc.bt.hex, WiimoteEmu::Classic::TRIGGER_L); - GetButton(m_classic_r_button, cc.bt.hex, WiimoteEmu::Classic::TRIGGER_R); - GetButton(m_classic_zl_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZL); - GetButton(m_classic_zr_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZR); - GetButton(m_classic_home_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_HOME); - GetButton(m_classic_left_button, cc.bt.hex, WiimoteEmu::Classic::PAD_LEFT); - GetButton(m_classic_up_button, cc.bt.hex, WiimoteEmu::Classic::PAD_UP); - GetButton(m_classic_down_button, cc.bt.hex, WiimoteEmu::Classic::PAD_DOWN); - GetButton(m_classic_right_button, cc.bt.hex, WiimoteEmu::Classic::PAD_RIGHT); - cc.bt.hex ^= 0xFFFF; + u16 bt = cc.GetButtons(); + GetButton(m_classic_a_button, bt, WiimoteEmu::Classic::BUTTON_A); + GetButton(m_classic_b_button, bt, WiimoteEmu::Classic::BUTTON_B); + GetButton(m_classic_x_button, bt, WiimoteEmu::Classic::BUTTON_X); + GetButton(m_classic_y_button, bt, WiimoteEmu::Classic::BUTTON_Y); + GetButton(m_classic_plus_button, bt, WiimoteEmu::Classic::BUTTON_PLUS); + GetButton(m_classic_minus_button, bt, WiimoteEmu::Classic::BUTTON_MINUS); + GetButton(m_classic_l_button, bt, WiimoteEmu::Classic::TRIGGER_L); + GetButton(m_classic_r_button, bt, WiimoteEmu::Classic::TRIGGER_R); + GetButton(m_classic_zl_button, bt, WiimoteEmu::Classic::BUTTON_ZL); + GetButton(m_classic_zr_button, bt, WiimoteEmu::Classic::BUTTON_ZR); + GetButton(m_classic_home_button, bt, WiimoteEmu::Classic::BUTTON_HOME); + GetButton(m_classic_left_button, bt, WiimoteEmu::Classic::PAD_LEFT); + GetButton(m_classic_up_button, bt, WiimoteEmu::Classic::PAD_UP); + GetButton(m_classic_down_button, bt, WiimoteEmu::Classic::PAD_DOWN); + GetButton(m_classic_right_button, bt, WiimoteEmu::Classic::PAD_RIGHT); + cc.SetButtons(bt); - u8 rx = (cc.rx1 & 0b1) & ((cc.rx2 & 0b11) << 1) & ((cc.rx3 & 0b11) << 3); - GetSpinBoxU8(m_classic_right_stick_x_value, rx); - cc.rx1 = rx & 0b1; - cc.rx2 = (rx >> 1) & 0b11; - cc.rx3 = (rx >> 3) & 0b11; + auto right_stick = cc.GetRightStick().value; + GetSpinBoxU8(m_classic_right_stick_x_value, right_stick.x); + GetSpinBoxU8(m_classic_right_stick_y_value, right_stick.y); + cc.SetRightStick(right_stick); - u8 ry = cc.ry; - GetSpinBoxU8(m_classic_right_stick_y_value, ry); - cc.ry = ry; + auto left_stick = cc.GetLeftStick().value; + GetSpinBoxU8(m_classic_left_stick_x_value, left_stick.x); + GetSpinBoxU8(m_classic_left_stick_y_value, left_stick.y); + cc.SetLeftStick(left_stick); - u8 lx = cc.lx; - GetSpinBoxU8(m_classic_left_stick_x_value, lx); - cc.lx = lx; - - u8 ly = cc.ly; - GetSpinBoxU8(m_classic_left_stick_y_value, ly); - cc.ly = ly; - - u8 rt = cc.rt; + u8 rt = cc.GetRightTrigger().value; GetSpinBoxU8(m_right_trigger_value, rt); - cc.rt = rt; + cc.SetRightTrigger(rt); - u8 lt = (cc.lt1 & 0b111) & (cc.lt2 >> 3); + u8 lt = cc.GetLeftTrigger().value; GetSpinBoxU8(m_left_trigger_value, lt); - cc.lt1 = lt & 0b111; - cc.lt2 = (lt >> 3) & 0b11; + cc.SetLeftTrigger(lt); key.Encrypt(reinterpret_cast(&cc), 0, sizeof(cc)); }