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:
parent
6c40c47472
commit
ebc2e58fa4
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<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 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<wm_accel*>(data + rptf.accel);
|
||||
wm_buttons& core = *reinterpret_cast<wm_buttons*>(data + rptf.core);
|
||||
// TODO: kill these ugly looking offsets
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 <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
|
||||
{
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue