From ebc2e58fa480a51c3a44762e9143aa84e230db7c Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Thu, 22 Nov 2018 15:08:49 -0600 Subject: [PATCH] WiimoteEmu: Partially emulate i2c bus to more closely simulate the real thing. Transfer most of IR camera logic to the i2c bus. Temporarily break everything else. --- .../Core/HW/WiimoteEmu/EmuSubroutines.cpp | 116 ++++------------- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp | 70 +++++++---- Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h | 118 ++++++++++++++++-- 3 files changed, 184 insertions(+), 120 deletions(-) diff --git a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp index 8f385f1916..eb532fb064 100644 --- a/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/EmuSubroutines.cpp @@ -261,66 +261,31 @@ void Wiimote::WriteData(const wm_write_data* const wd) { // Write to Control Register - // ignore second byte for extension area - if (0xA4 == (address >> 16)) - address &= 0xFF00FF; + // TODO: generate a writedata error reply for wrong number of bytes written.. + m_i2c_bus.BusWrite(address >> 17, address & 0xff, wd->size, wd->data); - const u8 region_offset = (u8)address; - void* region_ptr = nullptr; - int region_size = 0; + return; - switch (address >> 16) - { - // speaker - case 0xa2: - region_ptr = &m_reg_speaker; - region_size = WIIMOTE_REG_SPEAKER_SIZE; - break; + // TODO: extension register stuff.. - // extension register - case 0xa4: - region_ptr = (void*)&m_reg_ext; - region_size = WIIMOTE_REG_EXT_SIZE; - break; + //if (false)//&m_reg_ext == region_ptr) + //{ + // // Run the key generation on all writes in the key area, it doesn't matter + // // that we send it parts of a key, only the last full key will have an effect + // if (address >= 0xa40040 && address <= 0xa4004c) + // WiimoteGenerateKey(&m_ext_key, m_reg_ext.encryption_key); + //} + //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; - // motion plus - case 0xa6: - region_ptr = &m_reg_motion_plus; - region_size = WIIMOTE_REG_EXT_SIZE; - break; - - // ir - case 0xB0: - region_ptr = &m_reg_ir; - region_size = WIIMOTE_REG_IR_SIZE; - break; - } - - if (region_ptr && (region_offset + wd->size <= region_size)) - { - memcpy((u8*)region_ptr + region_offset, wd->data, wd->size); - } - else - return; // TODO: generate a writedata error reply - - if (&m_reg_ext == region_ptr) - { - // Run the key generation on all writes in the key area, it doesn't matter - // that we send it parts of a key, only the last full key will have an effect - if (address >= 0xa40040 && address <= 0xa4004c) - WiimoteGenerateKey(&m_ext_key, m_reg_ext.encryption_key); - } - 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(); - } - } + // RequestStatus(); + // } + //} } break; @@ -386,42 +351,11 @@ void Wiimote::ReadData(const wm_read_data* const rd) const u8 region_offset = (u8)address; void* region_ptr = nullptr; - int region_size = 0; + //int region_size = 0; - switch (address >> 16) - { - // speaker - case 0xa2: - region_ptr = &m_reg_speaker; - region_size = WIIMOTE_REG_SPEAKER_SIZE; - break; + m_i2c_bus.BusRead(address >> 17, address & 0xff, rd->size, block); - // extension - case 0xa4: - region_ptr = (void*)&m_reg_ext; - region_size = WIIMOTE_REG_EXT_SIZE; - break; - - // motion plus - case 0xa6: - // reading from 0xa6 returns error when mplus is activated - region_ptr = &m_reg_motion_plus; - region_size = WIIMOTE_REG_EXT_SIZE; - break; - - // ir - case 0xb0: - region_ptr = &m_reg_ir; - region_size = WIIMOTE_REG_IR_SIZE; - break; - } - - if (region_ptr && (region_offset + size <= region_size)) - { - memcpy(block, (u8*)region_ptr + region_offset, size); - } - else - size = 0; // generate read error + // TODO: generate read errors if (&m_reg_ext == region_ptr) { @@ -527,7 +461,7 @@ void Wiimote::DoState(PointerWrap& p) p.Do(m_ext_key); p.DoArray(m_eeprom); p.Do(m_reg_motion_plus); - p.Do(m_reg_ir); + p.Do(m_camera_logic.reg_data); p.Do(m_reg_ext); p.Do(m_reg_speaker); diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp index de8106797b..bddd03de3c 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.cpp @@ -82,27 +82,28 @@ static const u8 eeprom_data_16D0[] = {0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99, 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13}; +// Counts are how many bytes of each feature are in a particular report static const ReportFeatures reporting_mode_features[] = { // 0x30: Core Buttons {2, 0, 0, 0, 4}, // 0x31: Core Buttons and Accelerometer - {2, 4, 0, 0, 7}, + {2, 3, 0, 0, 7}, // 0x32: Core Buttons with 8 Extension bytes - {2, 0, 0, 4, 12}, + {2, 0, 0, 8, 12}, // 0x33: Core Buttons and Accelerometer with 12 IR bytes - {2, 4, 7, 0, 19}, + {2, 3, 12, 0, 19}, // 0x34: Core Buttons with 19 Extension bytes - {2, 0, 0, 4, 23}, + {2, 0, 0, 19, 23}, // 0x35: Core Buttons and Accelerometer with 16 Extension Bytes - {2, 4, 0, 7, 23}, + {2, 3, 0, 16, 23}, // 0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes - {2, 0, 4, 14, 23}, + {2, 0, 10, 9, 23}, // 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes - {2, 4, 7, 17, 23}, + {2, 3, 10, 6, 23}, + // 0x3d: 21 Extension Bytes + {0, 0, 0, 21, 23}, // UNSUPPORTED: - // 0x3d: 21 Extension Bytes - {0, 0, 0, 2, 23}, // 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes {0, 0, 0, 0, 23}, }; @@ -328,7 +329,8 @@ void Wiimote::Reset() // set up the register memset(&m_reg_speaker, 0, sizeof(m_reg_speaker)); - memset(&m_reg_ir, 0, sizeof(m_reg_ir)); + // TODO: kill/move this + memset(&m_camera_logic.reg_data, 0, sizeof(m_camera_logic.reg_data)); memset(&m_reg_ext, 0, sizeof(m_reg_ext)); memset(&m_reg_motion_plus, 0, sizeof(m_reg_motion_plus)); @@ -359,6 +361,9 @@ void Wiimote::Reset() // Yamaha ADPCM state initialize m_adpcm_state.predictor = 0; m_adpcm_state.step = 127; + + // Initialize i2c bus + m_i2c_bus.AddSlave(0x58, &m_camera_logic); } Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1) @@ -602,7 +607,7 @@ void Wiimote::GetButtonData(u8* const data) reinterpret_cast(data)->hex |= m_status.buttons.hex; } -void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf) +void Wiimote::GetAccelData(u8* const data) { const bool sideways_modifier_toggle = m_hotkeys->getSettingsModifier()[0]; const bool upright_modifier_toggle = m_hotkeys->getSettingsModifier()[1]; @@ -653,8 +658,9 @@ void Wiimote::GetAccelData(u8* const data, const ReportFeatures& rptf) EmulateDynamicShake(&m_accel, m_shake_dynamic_data, m_shake_dynamic, shake_config, m_shake_dynamic_step.data()); - wm_accel& accel = *reinterpret_cast(data + rptf.accel); - wm_buttons& core = *reinterpret_cast(data + rptf.core); + // TODO: kill these ugly looking offsets + wm_accel& accel = *reinterpret_cast(data + 4); + wm_buttons& core = *reinterpret_cast(data + 2); // We now use 2 bits more precision, so multiply by 4 before converting to int s16 x = (s16)(4 * (m_accel.x * ACCEL_RANGE + ACCEL_ZERO_G)); @@ -683,8 +689,11 @@ inline void LowPassFilter(double& var, double newval, double period) var = newval * alpha + var * (1.0 - alpha); } -void Wiimote::GetIRData(u8* const data, bool use_accel) +void Wiimote::UpdateIRData(bool use_accel) { + // IR data is stored at offset 0x37 + u8* const data = m_camera_logic.reg_data.camera_data; + u16 x[4], y[4]; memset(x, 0xFF, sizeof(x)); @@ -770,9 +779,9 @@ void Wiimote::GetIRData(u8* const data, bool use_accel) } // Fill report with valid data when full handshake was done - if (m_reg_ir.data[0x30]) + if (m_camera_logic.reg_data.data[0x30]) // ir mode - switch (m_reg_ir.mode) + switch (m_camera_logic.reg_data.mode) { // basic case 1: @@ -877,21 +886,40 @@ void Wiimote::Update() // hotkey/settings modifier m_hotkeys->GetState(); // data is later accessed in UpdateButtonsStatus and GetAccelData + // Data starts at byte 2 in the report + u8* feature_ptr = data + 2; + // core buttons if (rptf.core) - GetButtonData(data + rptf.core); + { + GetButtonData(feature_ptr); + feature_ptr += rptf.core; + } // acceleration if (rptf.accel) - GetAccelData(data, rptf); + { + // TODO: GetAccelData has hardcoded payload offsets.. + GetAccelData(data); + feature_ptr += rptf.accel; + } - // IR + // IR Camera + // TODO: kill use_accel param + // TODO: call only if camera logic is enabled? + UpdateIRData(rptf.accel != 0); if (rptf.ir) - GetIRData(data + rptf.ir, (rptf.accel != 0)); + { + m_i2c_bus.BusRead(0x58, 0x37, rptf.ir, feature_ptr); + feature_ptr += rptf.ir; + } // extension if (rptf.ext) - GetExtData(data + rptf.ext); + { + // GetExtData(feature_ptr, rptf.ext); + feature_ptr += rptf.ext; + } Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension, m_ext_key); } diff --git a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h index 6b50dc1296..8bf75d2712 100644 --- a/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/HW/WiimoteEmu/WiimoteEmu.h @@ -12,6 +12,7 @@ #include "Core/HW/WiimoteCommon/WiimoteReport.h" #include "Core/HW/WiimoteEmu/Encryption.h" #include "InputCommon/ControllerEmu/ControllerEmu.h" +#include "Common/Logging/Log.h" // Registry sizes #define WIIMOTE_EEPROM_SIZE (16 * 1024) @@ -207,6 +208,84 @@ enum ACCEL_RANGE = (ACCEL_ONE_G - ACCEL_ZERO_G), }; +class I2CSlave +{ +public: + virtual int BusRead(u8 addr, int count, u8* data_out) = 0; + virtual int BusWrite(u8 addr, int count, const u8* data_in) = 0; + + template + static int raw_read(T* reg_data, u8 addr, int count, u8* data_out) + { + static_assert(std::is_pod::value); + + u8* src = reinterpret_cast(reg_data) + addr; + count = std::min(count, int(reinterpret_cast(reg_data + 1) - src)); + + std::copy_n(src, count, data_out); + + return count; + } + + template + static int raw_write(T* reg_data, u8 addr, int count, const u8* data_in) + { + static_assert(std::is_pod::value); + + u8* dst = reinterpret_cast(reg_data) + addr; + count = std::min(count, int(reinterpret_cast(reg_data + 1) - dst)); + + std::copy_n(data_in, count, dst); + + return count; + } +}; + +class I2CBus +{ +public: + void AddSlave(u8 addr, I2CSlave* slave) + { + m_slaves.insert(std::make_pair(addr, slave)); + } + + void RemoveSlave(u8 addr) + { + m_slaves.erase(addr); + } + + void Reset() + { + m_slaves.clear(); + } + + 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); + + auto it = m_slaves.find(slave_addr); + if (m_slaves.end() != it) + return it->second->BusRead(addr, count, data_out); + else + return 0; + } + + 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); + + auto it = m_slaves.find(slave_addr); + if (m_slaves.end() != it) + return it->second->BusWrite(addr, count, data_in); + else + return 0; + } + +private: + // Organized by slave addr + std::map m_slaves; +}; + class Wiimote : public ControllerEmu::EmulatedController { friend class WiimoteReal::Wiimote; @@ -257,14 +336,41 @@ protected: void UpdateButtonsStatus(); void GetButtonData(u8* data); - void GetAccelData(u8* data, const ReportFeatures& rptf); - void GetIRData(u8* data, bool use_accel); + void GetAccelData(u8* data); + void UpdateIRData(bool use_accel); void GetExtData(u8* data); bool HaveExtension() const; bool WantExtension() const; private: + struct IRCameraLogic : public I2CSlave + { + struct + { + // Contains sensitivity and other unknown data + u8 data[0x33]; + u8 mode; + u8 unk[3]; + // addr 0x37 + u8 camera_data[36]; + u8 unk2[165]; + } reg_data; + + static_assert(0x100 == sizeof(reg_data)); + + int BusRead(u8 addr, int count, u8* data_out) override + { + return raw_read(®_data, addr, count, data_out); + } + + int BusWrite(u8 addr, int count, const u8* data_in) override + { + return raw_write(®_data, addr, count, data_in); + } + + } m_camera_logic; + struct ReadRequest { // u16 channel; @@ -306,6 +412,8 @@ private: DynamicData m_swing_dynamic_data; DynamicData m_shake_dynamic_data; + I2CBus m_i2c_bus; + // Wiimote accel data AccelData m_accel; @@ -354,12 +462,6 @@ private: u8 ext_identifier[6]; } m_reg_motion_plus; - struct IrReg - { - u8 data[0x33]; - u8 mode; - } m_reg_ir; - ExtensionReg m_reg_ext; struct SpeakerReg