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.

This commit is contained in:
Jordan Woyak 2018-11-22 15:08:49 -06:00
parent 6c40c47472
commit ebc2e58fa4
3 changed files with 184 additions and 120 deletions

View File

@ -261,66 +261,31 @@ void Wiimote::WriteData(const wm_write_data* const wd)
{ {
// Write to Control Register // Write to Control Register
// ignore second byte for extension area // TODO: generate a writedata error reply for wrong number of bytes written..
if (0xA4 == (address >> 16)) m_i2c_bus.BusWrite(address >> 17, address & 0xff, wd->size, wd->data);
address &= 0xFF00FF;
const u8 region_offset = (u8)address; return;
void* region_ptr = nullptr;
int region_size = 0;
switch (address >> 16) // TODO: extension register stuff..
{
// speaker
case 0xa2:
region_ptr = &m_reg_speaker;
region_size = WIIMOTE_REG_SPEAKER_SIZE;
break;
// extension register //if (false)//&m_reg_ext == region_ptr)
case 0xa4: //{
region_ptr = (void*)&m_reg_ext; // // Run the key generation on all writes in the key area, it doesn't matter
region_size = WIIMOTE_REG_EXT_SIZE; // // that we send it parts of a key, only the last full key will have an effect
break; // 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 // RequestStatus();
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();
}
}
} }
break; break;
@ -386,42 +351,11 @@ void Wiimote::ReadData(const wm_read_data* const rd)
const u8 region_offset = (u8)address; const u8 region_offset = (u8)address;
void* region_ptr = nullptr; void* region_ptr = nullptr;
int region_size = 0; //int region_size = 0;
switch (address >> 16) m_i2c_bus.BusRead(address >> 17, address & 0xff, rd->size, block);
{
// speaker
case 0xa2:
region_ptr = &m_reg_speaker;
region_size = WIIMOTE_REG_SPEAKER_SIZE;
break;
// extension // TODO: generate read errors
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
if (&m_reg_ext == region_ptr) if (&m_reg_ext == region_ptr)
{ {
@ -527,7 +461,7 @@ void Wiimote::DoState(PointerWrap& p)
p.Do(m_ext_key); p.Do(m_ext_key);
p.DoArray(m_eeprom); p.DoArray(m_eeprom);
p.Do(m_reg_motion_plus); 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_ext);
p.Do(m_reg_speaker); p.Do(m_reg_speaker);

View File

@ -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, 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99,
0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13}; 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[] = { static const ReportFeatures reporting_mode_features[] = {
// 0x30: Core Buttons // 0x30: Core Buttons
{2, 0, 0, 0, 4}, {2, 0, 0, 0, 4},
// 0x31: Core Buttons and Accelerometer // 0x31: Core Buttons and Accelerometer
{2, 4, 0, 0, 7}, {2, 3, 0, 0, 7},
// 0x32: Core Buttons with 8 Extension bytes // 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 // 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 // 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 // 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 // 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 // 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: // UNSUPPORTED:
// 0x3d: 21 Extension Bytes
{0, 0, 0, 2, 23},
// 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes // 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
{0, 0, 0, 0, 23}, {0, 0, 0, 0, 23},
}; };
@ -328,7 +329,8 @@ void Wiimote::Reset()
// set up the register // set up the register
memset(&m_reg_speaker, 0, sizeof(m_reg_speaker)); 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_ext, 0, sizeof(m_reg_ext));
memset(&m_reg_motion_plus, 0, sizeof(m_reg_motion_plus)); memset(&m_reg_motion_plus, 0, sizeof(m_reg_motion_plus));
@ -359,6 +361,9 @@ void Wiimote::Reset()
// Yamaha ADPCM state initialize // Yamaha ADPCM state initialize
m_adpcm_state.predictor = 0; m_adpcm_state.predictor = 0;
m_adpcm_state.step = 127; 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) 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<wm_buttons*>(data)->hex |= m_status.buttons.hex; reinterpret_cast<wm_buttons*>(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 sideways_modifier_toggle = m_hotkeys->getSettingsModifier()[0];
const bool upright_modifier_toggle = m_hotkeys->getSettingsModifier()[1]; 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, EmulateDynamicShake(&m_accel, m_shake_dynamic_data, m_shake_dynamic, shake_config,
m_shake_dynamic_step.data()); m_shake_dynamic_step.data());
wm_accel& accel = *reinterpret_cast<wm_accel*>(data + rptf.accel); // TODO: kill these ugly looking offsets
wm_buttons& core = *reinterpret_cast<wm_buttons*>(data + rptf.core); wm_accel& accel = *reinterpret_cast<wm_accel*>(data + 4);
wm_buttons& core = *reinterpret_cast<wm_buttons*>(data + 2);
// We now use 2 bits more precision, so multiply by 4 before converting to int // 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)); 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); 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]; u16 x[4], y[4];
memset(x, 0xFF, sizeof(x)); 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 // 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 // ir mode
switch (m_reg_ir.mode) switch (m_camera_logic.reg_data.mode)
{ {
// basic // basic
case 1: case 1:
@ -877,21 +886,40 @@ void Wiimote::Update()
// hotkey/settings modifier // hotkey/settings modifier
m_hotkeys->GetState(); // data is later accessed in UpdateButtonsStatus and GetAccelData 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 // core buttons
if (rptf.core) if (rptf.core)
GetButtonData(data + rptf.core); {
GetButtonData(feature_ptr);
feature_ptr += rptf.core;
}
// acceleration // acceleration
if (rptf.accel) 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) 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 // extension
if (rptf.ext) 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); Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension, m_ext_key);
} }

View File

@ -12,6 +12,7 @@
#include "Core/HW/WiimoteCommon/WiimoteReport.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h"
#include "Core/HW/WiimoteEmu/Encryption.h" #include "Core/HW/WiimoteEmu/Encryption.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h" #include "InputCommon/ControllerEmu/ControllerEmu.h"
#include "Common/Logging/Log.h"
// Registry sizes // Registry sizes
#define WIIMOTE_EEPROM_SIZE (16 * 1024) #define WIIMOTE_EEPROM_SIZE (16 * 1024)
@ -207,6 +208,84 @@ enum
ACCEL_RANGE = (ACCEL_ONE_G - ACCEL_ZERO_G), 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 <typename T>
static int raw_read(T* reg_data, u8 addr, int count, u8* data_out)
{
static_assert(std::is_pod<T>::value);
u8* src = reinterpret_cast<u8*>(reg_data) + addr;
count = std::min(count, int(reinterpret_cast<u8*>(reg_data + 1) - src));
std::copy_n(src, count, data_out);
return count;
}
template <typename T>
static int raw_write(T* reg_data, u8 addr, int count, const u8* data_in)
{
static_assert(std::is_pod<T>::value);
u8* dst = reinterpret_cast<u8*>(reg_data) + addr;
count = std::min(count, int(reinterpret_cast<u8*>(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<u8, I2CSlave*> m_slaves;
};
class Wiimote : public ControllerEmu::EmulatedController class Wiimote : public ControllerEmu::EmulatedController
{ {
friend class WiimoteReal::Wiimote; friend class WiimoteReal::Wiimote;
@ -257,14 +336,41 @@ protected:
void UpdateButtonsStatus(); void UpdateButtonsStatus();
void GetButtonData(u8* data); void GetButtonData(u8* data);
void GetAccelData(u8* data, const ReportFeatures& rptf); void GetAccelData(u8* data);
void GetIRData(u8* data, bool use_accel); void UpdateIRData(bool use_accel);
void GetExtData(u8* data); void GetExtData(u8* data);
bool HaveExtension() const; bool HaveExtension() const;
bool WantExtension() const; bool WantExtension() const;
private: 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(&reg_data, addr, count, data_out);
}
int BusWrite(u8 addr, int count, const u8* data_in) override
{
return raw_write(&reg_data, addr, count, data_in);
}
} m_camera_logic;
struct ReadRequest struct ReadRequest
{ {
// u16 channel; // u16 channel;
@ -306,6 +412,8 @@ private:
DynamicData m_swing_dynamic_data; DynamicData m_swing_dynamic_data;
DynamicData m_shake_dynamic_data; DynamicData m_shake_dynamic_data;
I2CBus m_i2c_bus;
// Wiimote accel data // Wiimote accel data
AccelData m_accel; AccelData m_accel;
@ -354,12 +462,6 @@ private:
u8 ext_identifier[6]; u8 ext_identifier[6];
} m_reg_motion_plus; } m_reg_motion_plus;
struct IrReg
{
u8 data[0x33];
u8 mode;
} m_reg_ir;
ExtensionReg m_reg_ext; ExtensionReg m_reg_ext;
struct SpeakerReg struct SpeakerReg