From 372b12c67fe2afbe749d6c6c8de3629a1b942c62 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Sat, 24 Nov 2018 11:49:08 -0600 Subject: [PATCH] WiimoteEmu: Emulated motion plus is detected by game now. --- .../Core/HW/WiimoteEmu/EmuSubroutines.cpp | 36 ++--- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 51 +++---- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 131 ++++++++++-------- 3 files changed, 114 insertions(+), 104 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index e2b53cb95b..5158c59bbf 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -33,6 +33,7 @@ #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "InputCommon/ControllerEmu/ControlGroup/Extension.h" +#include "InputCommon/ControllerEmu/ControlGroup/ModifySettingsButton.h" namespace WiimoteEmu { @@ -146,9 +147,6 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack) break; case RT_IR_LOGIC: // 0x1a - // comment from old plugin: - // This enables or disables the IR lights, we update the global variable g_IR - // so that WmRequestStatus() knows about it m_status.ir = sr->enable; if (false == sr->ack) return; @@ -206,10 +204,18 @@ void Wiimote::HandleExtensionSwap() void Wiimote::RequestStatus(const wm_request_status* const rs) { - HandleExtensionSwap(); + INFO_LOG(WIIMOTE, "Wiimote::RequestStatus"); // update status struct - m_status.extension = m_extension->active_extension ? 1 : 0; + m_status.extension = m_extension_port.IsDeviceConnected(); + // Battery levels in voltage + // 0x00 - 0x32: level 1 + // 0x33 - 0x43: level 2 + // 0x33 - 0x54: level 3 + // 0x55 - 0xff: level 4 + m_status.battery = (u8)(m_battery_setting->GetValue() * 0xff); + // TODO: this right? + m_status.battery_low = m_status.battery < 0x33; // set up report u8 data[8]; @@ -228,7 +234,13 @@ void Wiimote::WriteData(const wm_write_data* const wd) { u16 address = Common::swap16(wd->address); - INFO_LOG(WIIMOTE, "Wiimote::WriteData: 0x%02x @ 0x%02x (%d)", wd->space, address, wd->size); + if (0 == wd->size) + { + // Ignore requests of zero size + return; + } + + INFO_LOG(WIIMOTE, "Wiimote::WriteData: 0x%02x @ 0x%02x @ 0x%02x (%d)", wd->space, wd->slave_address, address, wd->size); if (wd->size > 16) { @@ -277,18 +289,6 @@ void Wiimote::WriteData(const wm_write_data* const wd) // A real wiimote gives error 7 for failed write to i2c bus (mainly a non-existant slave) error_code = 0x07; } - - // else if (&m_reg_motion_plus == region_ptr) - //{ - // // activate/deactivate motion plus - // if (0x55 == m_reg_motion_plus.activated) - // { - // // maybe hacky - // m_reg_motion_plus.activated = 0; - - // RequestStatus(); - // } - //} } break; diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index 0a3735560a..af98f7ec45 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -308,16 +308,13 @@ static const char* const named_buttons[] = { void Wiimote::Reset() { m_reporting_mode = RT_REPORT_CORE; - // i think these two are good m_reporting_channel = 0; m_reporting_auto = false; m_rumble_on = false; m_speaker_mute = false; - // will make the first Update() call send a status request - // the first call to RequestStatus() will then set up the status struct extension bit - m_extension->active_extension = -1; + m_extension->active_extension = 0; // eeprom memset(m_eeprom, 0, sizeof(m_eeprom)); @@ -338,12 +335,6 @@ void Wiimote::Reset() // status memset(&m_status, 0, sizeof(m_status)); - // Battery levels in voltage - // 0x00 - 0x32: level 1 - // 0x33 - 0x43: level 2 - // 0x33 - 0x54: level 3 - // 0x55 - 0xff: level 4 - m_status.battery = (u8)(m_battery_setting->GetValue() * 100); m_shake_step = {}; m_shake_soft_step = {}; @@ -358,22 +349,22 @@ void Wiimote::Reset() m_speaker_logic.adpcm_state.step = 127; // Initialize i2c bus - // TODO: kill magic numbers m_i2c_bus.Reset(); // Address 0x51 m_i2c_bus.AddSlave(&m_speaker_logic); - - // TODO: only add to bus when enabled - // Address 0x53 (or 0x52 when activated) - m_i2c_bus.AddSlave(&m_motion_plus_logic); // Address 0x58 m_i2c_bus.AddSlave(&m_camera_logic); + // TODO: only add to bus when enabled + // This also adds the motion plus to the i2c bus + // Address 0x53 (or 0x52 when activated) + m_extension_port.SetAttachment(&m_motion_plus_logic); + // TODO: add directly to wiimote bus when mplus is disabled // TODO: only add to bus when connected: // Address 0x52 (when motion plus is not activated) // Connected to motion plus i2c_bus (with passthrough by default) - m_motion_plus_logic.i2c_bus.AddSlave(&m_ext_logic); + m_motion_plus_logic.extension_port.SetAttachment(&m_ext_logic); } Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1) @@ -564,19 +555,22 @@ bool Wiimote::Step() return true; } - // check if a status report needs to be sent - // this happens on Wii Remote sync and when extensions are switched - if (m_extension->active_extension != m_extension->switch_extension) - { - RequestStatus(); + // If an extension change is requested in the GUI it will first be disconnected here. + // causing IsDeviceConnected() to return false below: + HandleExtensionSwap(); + // check if a status report needs to be sent + // this happens when extensions are switched + if (m_status.extension != m_extension_port.IsDeviceConnected()) + { // WiiBrew: Following a connection or disconnection event on the Extension Port, // data reporting is disabled and the Data Reporting Mode must be reset before new data can // arrive. - // after a game receives an unrequested status report, - // it expects data reports to stop until it sets the reporting mode again + m_reporting_mode = RT_REPORT_CORE; m_reporting_auto = false; + RequestStatus(); + return true; } @@ -859,9 +853,6 @@ void Wiimote::Update() Movie::SetPolledDevice(); - // TODO: Is max battery really 100 and not 0xff? - m_status.battery = (u8)(m_battery_setting->GetValue() * 100); - const ReportFeatures& rptf = reporting_mode_features[m_reporting_mode - RT_REPORT_CORE]; s8 rptf_size = rptf.total_size; if (Movie::IsPlayingInput() && @@ -1113,13 +1104,9 @@ int Wiimote::CurrentExtension() const return m_extension->active_extension; } -bool Wiimote::HaveExtension() const +bool Wiimote::ExtensionLogic::ReadDeviceDetectPin() { - return m_extension->active_extension > 0; + return extension->active_extension ? true : false; } -bool Wiimote::WantExtension() const -{ - return m_extension->switch_extension != 0; -} } // namespace WiimoteEmu diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index b2e6218acc..b44a6f81a5 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -225,6 +225,7 @@ public: static int RawRead(T* reg_data, u8 addr, int count, u8* data_out) { static_assert(std::is_pod::value); + static_assert(0x100 == sizeof(T)); // TODO: addr wraps around after 0xff @@ -240,6 +241,7 @@ public: static int RawWrite(T* reg_data, u8 addr, int count, const u8* data_in) { static_assert(std::is_pod::value); + static_assert(0x100 == sizeof(T)); // TODO: addr wraps around after 0xff @@ -255,10 +257,7 @@ public: class I2CBus { public: - void AddSlave(I2CSlave* slave) - { - m_slaves.emplace_back(slave); - } + void AddSlave(I2CSlave* slave) { m_slaves.emplace_back(slave); } void RemoveSlave(I2CSlave* slave) { @@ -270,7 +269,6 @@ public: int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) { INFO_LOG(WIIMOTE, "i2c bus read: 0x%02x @ 0x%02x (%d)", slave_addr, addr, count); - for (auto& slave : m_slaves) { auto const bytes_read = slave->BusRead(slave_addr, addr, count, data_out); @@ -286,7 +284,6 @@ public: int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) { INFO_LOG(WIIMOTE, "i2c bus write: 0x%02x @ 0x%02x (%d)", slave_addr, addr, count); - for (auto& slave : m_slaves) { auto const bytes_written = slave->BusWrite(slave_addr, addr, count, data_in); @@ -312,9 +309,7 @@ public: class ExtensionPort { public: - ExtensionPort(I2CBus& _i2c_bus) - : m_i2c_bus(_i2c_bus) - {} + ExtensionPort(I2CBus& _i2c_bus) : m_i2c_bus(_i2c_bus) {} // Simulates the "device-detect" pin. // Wiimote uses this to detect extension change.. @@ -392,9 +387,6 @@ protected: void UpdateIRData(bool use_accel); void UpdateExtData(); - bool HaveExtension() const; - bool WantExtension() const; - private: I2CBus m_i2c_bus; @@ -435,13 +427,15 @@ private: } m_camera_logic; - struct ExtensionLogic : public ExtensionAttachment + class ExtensionLogic : public ExtensionAttachment { + public: ExtensionReg reg_data; wiimote_key ext_key; ControllerEmu::Extension* extension; + private: static const u8 DEVICE_ADDR = 0x52; int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) override @@ -476,10 +470,7 @@ private: return result; } - bool ReadDeviceDetectPin() override - { - return true; - } + bool ReadDeviceDetectPin() override; } m_ext_logic; @@ -499,8 +490,11 @@ private: u8 unk_7; u8 play; u8 unk_9; + u8 unknown[0xf4]; } reg_data; + static_assert(0x100 == sizeof(reg_data)); + ADPCMState adpcm_state; static const u8 DEVICE_ADDR = 0x51; @@ -526,7 +520,10 @@ private: return count; } else + { + // TODO: should address wrap around after 0xff result in processing speaker data? return RawWrite(®_data, addr, count, data_in); + } } } m_speaker_logic; @@ -560,67 +557,93 @@ private: static_assert(0x100 == sizeof(reg_data)); - static const u8 DEVICE_ADDR = 0x53; - static const u8 EXT_DEVICE_ADDR = 0x52; + static const u8 INACTIVE_DEVICE_ADDR = 0x53; + static const u8 ACTIVE_DEVICE_ADDR = 0x52; - bool IsActive() const { return reg_data.activated; } + bool IsActive() const { return ACTIVE_DEVICE_ADDR << 1 == reg_data.ext_identifier[2]; } u8 GetPassthroughMode() const { return reg_data.ext_identifier[4]; } - // Return the status of the "device detect" pin - // used to product status reports on device change - bool GetDevicePresent() const + int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) override { if (IsActive()) { - return true; + // TODO: does mplus respond to reads on 0xa6 when activated? + if (ACTIVE_DEVICE_ADDR == slave_addr || INACTIVE_DEVICE_ADDR == slave_addr) + return RawRead(®_data, addr, count, data_out); + else + return 0; } else { - // TODO: passthrough other extension attachment status - return false; + if (INACTIVE_DEVICE_ADDR == slave_addr) + return RawRead(®_data, addr, count, data_out); + else + { + // Passthrough to the connected extension (if any) + return i2c_bus.BusRead(slave_addr, addr, count, data_out); + } } } - int BusRead(u8 slave_addr, u8 addr, int count, u8* data_out) override - { - // if (DEVICE_ADDR != slave_addr) - // return 0; - - return i2c_bus.BusRead(slave_addr, addr, count, data_out); - - auto const result = RawRead(®_data, addr, count, data_out); - - return result; - } - int BusWrite(u8 slave_addr, u8 addr, int count, const u8* data_in) override { - // if (DEVICE_ADDR != slave_addr) - // return 0; - - return i2c_bus.BusWrite(slave_addr, addr, count, data_in); - - auto const result = RawWrite(®_data, addr, count, data_in); - - if (0xfe == addr) + if (IsActive()) { - if (true) // 0x55 == reg_data.activated) + // TODO: does mplus respond to reads on 0xa6 when activated? + if (ACTIVE_DEVICE_ADDR == slave_addr || INACTIVE_DEVICE_ADDR == slave_addr) { - // i2c_bus.SetSlave(0x52, this); - // i2c_bus.RemoveSlave(0x53); + auto const result = RawWrite(®_data, addr, count, data_in); + return result; + + // TODO: Should any write (of any value) trigger activation? + if (0xf0 == addr) + { + // Deactivate motion plus: + reg_data.ext_identifier[2] = INACTIVE_DEVICE_ADDR << 1; + } + } + else + return 0; + } + else + { + if (INACTIVE_DEVICE_ADDR == slave_addr) + { + auto const result = RawWrite(®_data, addr, count, data_in); + + // TODO: Should any write (of any value) trigger activation? + if (0xfe == addr) + { + // Activate motion plus: + reg_data.ext_identifier[2] = ACTIVE_DEVICE_ADDR << 1; + } + + return result; + } + else + { + // Passthrough to the connected extension (if any) + return i2c_bus.BusWrite(slave_addr, addr, count, data_in); } } - - return result; } + private: bool ReadDeviceDetectPin() override { - return true; + if (IsActive()) + { + // TODO: logic for when motion plus deactivates + return true; + } + else + { + return extension_port.IsDeviceConnected(); + } } - - } m_motion_plus_logic; + } + m_motion_plus_logic; void ReportMode(const wm_report_mode* dr); void SendAck(u8 report_id, u8 error_code = 0x0);