From 6848812a3191133359a626ed73e3906e32bb971b Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 15 Dec 2018 09:43:45 -0600 Subject: [PATCH 1/4] Produce emulated nunchuk calibration data. --- .../Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp | 31 ++++++++++++++++++- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 14 +++++++-- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 6 ++-- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp index 6bd4bd6c1f..4cced8be4d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp @@ -69,6 +69,35 @@ Nunchuk::Nunchuk(ExtensionReg& reg) : Attachment(_trans("Nunchuk"), reg) m_shake_hard->controls.emplace_back(new ControllerEmu::Input(ControllerEmu::DoNotTranslate, "Z")); m_id = nunchuk_id; + + // Build calibration data: + m_calibration = {{ + // Accel Zero X,Y,Z: + ACCEL_ZERO_G, + ACCEL_ZERO_G, + ACCEL_ZERO_G, + // Possibly LSBs of zero values: + 0x00, + // Accel 1G X,Y,Z: + ACCEL_ONE_G, + ACCEL_ONE_G, + ACCEL_ONE_G, + // Possibly LSBs of 1G values: + 0x00, + // Stick X max,min,center: + STICK_CENTER + STICK_RADIUS, + STICK_CENTER - STICK_RADIUS, + STICK_CENTER, + // Stick Y max,min,center: + STICK_CENTER + STICK_RADIUS, + STICK_CENTER - STICK_RADIUS, + STICK_CENTER, + // 2 checksum bytes calculated below: + 0x00, + 0x00, + }}; + + UpdateCalibrationDataChecksum(m_calibration); } void Nunchuk::GetState(u8* const data) @@ -186,4 +215,4 @@ void Nunchuk::LoadDefaults(const ControllerInterface& ciface) m_buttons->SetControlExpression(1, "Shift_L"); // Z #endif } -} +} // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index adff30830c..7e33d2492d 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" @@ -101,6 +102,15 @@ static const ReportFeatures reporting_mode_features[] = { {0, 0, 0, 0, 23}, }; +// Used for extension calibration data: +// Last two bytes are the sum of the previous bytes plus 0x55 and 0xaa +void UpdateCalibrationDataChecksum(std::array& data) +{ + const u8 ck1 = std::accumulate(std::begin(data), std::end(data) - 2, (u8)0x55); + data[0xe] = ck1; + data[0xf] = ck1 + 0x55; +} + void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_group, const double intensity, u8* const shake_step) { @@ -1028,8 +1038,8 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface) m_buttons->SetControlExpression(0, "Click 1"); // A m_buttons->SetControlExpression(1, "Click 3"); // B #else - m_buttons->SetControlExpression(0, "Click 0"); // A - m_buttons->SetControlExpression(1, "Click 1"); // B + m_buttons->SetControlExpression(0, "Click 0"); // A + m_buttons->SetControlExpression(1, "Click 1"); // B #endif m_buttons->SetControlExpression(2, "1"); // 1 m_buttons->SetControlExpression(3, "2"); // 2 diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 4a1bca6d9a..6b50dc1296 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -34,7 +34,7 @@ class ModifySettingsButton; class NumericSetting; class Output; class Tilt; -} +} // namespace ControllerEmu namespace WiimoteReal { @@ -181,6 +181,8 @@ struct ExtensionReg }; #pragma pack(pop) +void UpdateCalibrationDataChecksum(std::array& data); + void EmulateShake(AccelData* accel, ControllerEmu::Buttons* buttons_group, double intensity, u8* shake_step); @@ -377,4 +379,4 @@ private: #pragma pack(pop) }; -} +} // namespace WiimoteEmu From a8a6bdcdd2b23573ac6ab913edf501f112a4c588 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 15 Dec 2018 10:12:04 -0600 Subject: [PATCH 2/4] Compute emulated classic controller calibration data instead of having hardcoded values. --- .../Core/HW/WiimoteEmu/Attachment/Classic.cpp | 52 +++++++++++-------- .../Core/HW/WiimoteEmu/Attachment/Classic.h | 29 +++++++---- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp index 0e9b592ce1..bf2b41fc6b 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.cpp @@ -21,26 +21,6 @@ namespace WiimoteEmu { constexpr std::array classic_id{{0x00, 0x00, 0xa4, 0x20, 0x01, 0x01}}; -// Classic Controller calibration -constexpr std::array classic_calibration{{ - 0xff, - 0x00, - 0x80, - 0xff, - 0x00, - 0x80, - 0xff, - 0x00, - 0x80, - 0xff, - 0x00, - 0x80, - 0x00, - 0x00, - 0x51, - 0xa6, -}}; - constexpr std::array classic_button_bitmasks{{ Classic::BUTTON_A, Classic::BUTTON_B, @@ -124,9 +104,35 @@ Classic::Classic(ExtensionReg& reg) : Attachment(_trans("Classic"), reg) new ControllerEmu::Input(ControllerEmu::Translate, named_direction)); } - // Set up register - m_calibration = classic_calibration; m_id = classic_id; + + // Build calibration data: + m_calibration = {{ + // Left Stick X max,min,center: + CAL_STICK_CENTER + CAL_STICK_RANGE, + CAL_STICK_CENTER - CAL_STICK_RANGE, + CAL_STICK_CENTER, + // Left Stick Y max,min,center: + CAL_STICK_CENTER + CAL_STICK_RANGE, + CAL_STICK_CENTER - CAL_STICK_RANGE, + CAL_STICK_CENTER, + // Right Stick X max,min,center: + CAL_STICK_CENTER + CAL_STICK_RANGE, + CAL_STICK_CENTER - CAL_STICK_RANGE, + CAL_STICK_CENTER, + // Right Stick Y max,min,center: + CAL_STICK_CENTER + CAL_STICK_RANGE, + CAL_STICK_CENTER - CAL_STICK_RANGE, + CAL_STICK_CENTER, + // Left/Right trigger range: (assumed based on real calibration data values) + LEFT_TRIGGER_RANGE, + RIGHT_TRIGGER_RANGE, + // 2 checksum bytes calculated below: + 0x00, + 0x00, + }}; + + UpdateCalibrationDataChecksum(m_calibration); } void Classic::GetState(u8* const data) @@ -213,4 +219,4 @@ ControllerEmu::ControlGroup* Classic::GetGroup(ClassicGroup group) return nullptr; } } -} +} // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h index 9125667ebb..a914569516 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Classic.h @@ -12,7 +12,7 @@ class AnalogStick; class Buttons; class ControlGroup; class MixedTriggers; -} +} // namespace ControllerEmu namespace WiimoteEmu { @@ -48,16 +48,25 @@ public: PAD_UP = 0x0100, }; - static const u8 LEFT_STICK_CENTER_X = 0x20; - static const u8 LEFT_STICK_CENTER_Y = 0x20; - static const u8 LEFT_STICK_RADIUS = 0x1F; + enum + { + CAL_STICK_CENTER = 0x80, + CAL_STICK_RANGE = 0x7f, + CAL_STICK_BITS = 8, - static const u8 RIGHT_STICK_CENTER_X = 0x10; - static const u8 RIGHT_STICK_CENTER_Y = 0x10; - static const u8 RIGHT_STICK_RADIUS = 0x0F; + LEFT_STICK_BITS = 6, + LEFT_STICK_CENTER_X = CAL_STICK_CENTER >> (CAL_STICK_BITS - LEFT_STICK_BITS), + LEFT_STICK_CENTER_Y = CAL_STICK_CENTER >> (CAL_STICK_BITS - LEFT_STICK_BITS), + LEFT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - LEFT_STICK_BITS), - static const u8 LEFT_TRIGGER_RANGE = 0x1F; - static const u8 RIGHT_TRIGGER_RANGE = 0x1F; + RIGHT_STICK_BITS = 5, + RIGHT_STICK_CENTER_X = CAL_STICK_CENTER >> (CAL_STICK_BITS - RIGHT_STICK_BITS), + RIGHT_STICK_CENTER_Y = CAL_STICK_CENTER >> (CAL_STICK_BITS - RIGHT_STICK_BITS), + RIGHT_STICK_RADIUS = CAL_STICK_RANGE >> (CAL_STICK_BITS - RIGHT_STICK_BITS), + + LEFT_TRIGGER_RANGE = 0x1F, + RIGHT_TRIGGER_RANGE = 0x1F, + }; private: ControllerEmu::Buttons* m_buttons; @@ -66,4 +75,4 @@ private: ControllerEmu::AnalogStick* m_left_stick; ControllerEmu::AnalogStick* m_right_stick; }; -} +} // namespace WiimoteEmu From 79eb065cf31e5cfc3280e6baadbb71bbd2d1ad33 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 15 Dec 2018 10:26:51 -0600 Subject: [PATCH 3/4] Reduce emulated shaking frequency to 6hz. (something more humanly possible) (was ~13hz) --- Source/Core/Core/HW/Wiimote.h | 9 +++-- .../Core/HW/WiimoteEmu/Attachment/Nunchuk.h | 4 +-- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 33 ++++++++++--------- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 3 +- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/Source/Core/Core/HW/Wiimote.h b/Source/Core/Core/HW/Wiimote.h index 1e3e9c9c2a..a9e9405696 100644 --- a/Source/Core/Core/HW/Wiimote.h +++ b/Source/Core/Core/HW/Wiimote.h @@ -23,7 +23,7 @@ enum class ClassicGroup; enum class GuitarGroup; enum class DrumsGroup; enum class TurntableGroup; -} +} // namespace WiimoteEmu enum { @@ -55,6 +55,9 @@ enum class InitializeMode DO_NOT_WAIT_FOR_WIIMOTES, }; +// The Real Wii Remote sends report every ~5ms (200 Hz). +constexpr int UPDATE_FREQ = 200; + void Shutdown(); void Initialize(InitializeMode init_mode); void Connect(unsigned int index, bool connect); @@ -78,7 +81,7 @@ void InterruptChannel(int number, u16 channel_id, const void* data, u32 size); bool ButtonPressed(int number); void Update(int number, bool connected); bool NetPlay_GetButtonPress(int wiimote, bool pressed); -} +} // namespace Wiimote namespace WiimoteReal { @@ -90,4 +93,4 @@ void Pause(); void Refresh(); void LoadSettings(); -} +} // namespace WiimoteReal diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h index 8a8f5d5d08..b16df713d7 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.h @@ -14,7 +14,7 @@ class Buttons; class ControlGroup; class Force; class Tilt; -} +} // namespace ControllerEmu namespace WiimoteEmu { @@ -69,4 +69,4 @@ private: std::array m_shake_soft_step{}; std::array m_shake_hard_step{}; }; -} +} // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 7e33d2492d..95896dcbb6 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -57,6 +57,11 @@ auto const PI = TAU / 2.0; namespace WiimoteEmu { +constexpr int SHAKE_FREQ = 6; +// Frame count of one up/down shake +// < 9 no shake detection in "Wario Land: Shake It" +constexpr int SHAKE_STEP_MAX = ::Wiimote::UPDATE_FREQ / SHAKE_FREQ; + // clang-format off static const u8 eeprom_data_0[] = { // IR, maybe more @@ -114,10 +119,6 @@ void UpdateCalibrationDataChecksum(std::array& data) void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_group, const double intensity, u8* const shake_step) { - // frame count of one up/down shake - // < 9 no shake detection in "Wario Land: Shake It" - auto const shake_step_max = 15; - // shake is a bitfield of X,Y,Z shake button states static const unsigned int btns[] = {0x01, 0x02, 0x04}; unsigned int shake = 0; @@ -127,8 +128,8 @@ void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_ { if (shake & (1 << i)) { - (&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * intensity; - shake_step[i] = (shake_step[i] + 1) % shake_step_max; + (&(accel->x))[i] = std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * intensity; + shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX; } else shake_step[i] = 0; @@ -139,10 +140,6 @@ void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data, ControllerEmu::Buttons* const buttons_group, const DynamicConfiguration& config, u8* const shake_step) { - // frame count of one up/down shake - // < 9 no shake detection in "Wario Land: Shake It" - auto const shake_step_max = 15; - // shake is a bitfield of X,Y,Z shake button states static const unsigned int btns[] = {0x01, 0x02, 0x04}; unsigned int shake = 0; @@ -156,8 +153,8 @@ void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data, } else if (dynamic_data.executing_frames_left[i] > 0) { - (&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * dynamic_data.intensity[i]; - shake_step[i] = (shake_step[i] + 1) % shake_step_max; + (&(accel->x))[i] = std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * dynamic_data.intensity[i]; + shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX; dynamic_data.executing_frames_left[i]--; } else if (shake == 0 && dynamic_data.timing[i] > 0) @@ -1035,11 +1032,15 @@ void Wiimote::LoadDefaults(const ControllerInterface& ciface) // Buttons #if defined HAVE_X11 && HAVE_X11 - m_buttons->SetControlExpression(0, "Click 1"); // A - m_buttons->SetControlExpression(1, "Click 3"); // B + // A + m_buttons->SetControlExpression(0, "Click 1"); + // B + m_buttons->SetControlExpression(1, "Click 3"); #else - m_buttons->SetControlExpression(0, "Click 0"); // A - m_buttons->SetControlExpression(1, "Click 1"); // B + // A + m_buttons->SetControlExpression(0, "Click 0"); + // B + m_buttons->SetControlExpression(1, "Click 1"); #endif m_buttons->SetControlExpression(2, "1"); // 1 m_buttons->SetControlExpression(3, "2"); // 2 diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index 806151bbd4..02e8a7c79a 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -356,8 +356,7 @@ void BluetoothEmu::Update() } } - // The Real Wii Remote sends report every ~5ms (200 Hz). - const u64 interval = SystemTimers::GetTicksPerSecond() / 200; + const u64 interval = SystemTimers::GetTicksPerSecond() / Wiimote::UPDATE_FREQ; const u64 now = CoreTiming::GetTicks(); if (now - m_last_ticks > interval) From 43f5d4973e4235b11acf07e4224bb8e6b0e7e182 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sun, 16 Dec 2018 06:39:30 -0600 Subject: [PATCH 4/4] Fix wiimote/nunchuk acceleration value clamping (off-by-one). Add in shaking acceleration rather than overwritting it so it doesn't look like the device is in free-fall. This fixes shaking in "Batman: TBATB". It appears the game only detects shaking along the z-axis and expects gravity to exist. --- .../Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp | 6 +++--- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 21 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp index 4cced8be4d..d280272e6b 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Attachment/Nunchuk.cpp @@ -154,9 +154,9 @@ void Nunchuk::GetState(u8* const data) s16 accel_y = (s16)(4 * (accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); s16 accel_z = (s16)(4 * (accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); - accel_x = MathUtil::Clamp(accel_x, 0, 1024); - accel_y = MathUtil::Clamp(accel_y, 0, 1024); - accel_z = MathUtil::Clamp(accel_z, 0, 1024); + accel_x = MathUtil::Clamp(accel_x, 0, 0x3ff); + accel_y = MathUtil::Clamp(accel_y, 0, 0x3ff); + accel_z = MathUtil::Clamp(accel_z, 0, 0x3ff); nc_data.ax = (accel_x >> 2) & 0xFF; nc_data.ay = (accel_y >> 2) & 0xFF; diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 95896dcbb6..e6c5fdcc2f 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -108,12 +108,14 @@ static const ReportFeatures reporting_mode_features[] = { }; // Used for extension calibration data: -// Last two bytes are the sum of the previous bytes plus 0x55 and 0xaa void UpdateCalibrationDataChecksum(std::array& data) { - const u8 ck1 = std::accumulate(std::begin(data), std::end(data) - 2, (u8)0x55); - data[0xe] = ck1; - data[0xf] = ck1 + 0x55; + // Last two bytes are the sum of the previous bytes plus 0x55 and 0xaa (0x55 + 0x55) + const u8 checksum1 = std::accumulate(std::begin(data), std::end(data) - 2, u8(0x55)); + const u8 checksum2 = checksum1 + 0x55; + + data[0xe] = checksum1; + data[0xf] = checksum2; } void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_group, @@ -128,7 +130,7 @@ void EmulateShake(AccelData* const accel, ControllerEmu::Buttons* const buttons_ { if (shake & (1 << i)) { - (&(accel->x))[i] = std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * intensity; + (&(accel->x))[i] += std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * intensity; shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX; } else @@ -153,7 +155,8 @@ void EmulateDynamicShake(AccelData* const accel, DynamicData& dynamic_data, } else if (dynamic_data.executing_frames_left[i] > 0) { - (&(accel->x))[i] = std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * dynamic_data.intensity[i]; + (&(accel->x))[i] += + std::sin(TAU * shake_step[i] / SHAKE_STEP_MAX) * dynamic_data.intensity[i]; shake_step[i] = (shake_step[i] + 1) % SHAKE_STEP_MAX; dynamic_data.executing_frames_left[i]--; } @@ -658,9 +661,9 @@ void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf) s16 y = (s16)(4 * (m_accel.y * ACCEL_RANGE + ACCEL_ZERO_G)); s16 z = (s16)(4 * (m_accel.z * ACCEL_RANGE + ACCEL_ZERO_G)); - x = MathUtil::Clamp(x, 0, 1024); - y = MathUtil::Clamp(y, 0, 1024); - z = MathUtil::Clamp(z, 0, 1024); + x = MathUtil::Clamp(x, 0, 0x3ff); + y = MathUtil::Clamp(y, 0, 0x3ff); + z = MathUtil::Clamp(z, 0, 0x3ff); accel.x = (x >> 2) & 0xFF; accel.y = (y >> 2) & 0xFF;