WiimoteEmu: Motion plus now works half of the time in Wii Sports Resort.

This commit is contained in:
Jordan Woyak 2018-11-29 17:42:59 -06:00
parent 0b4329e077
commit 86c94b8b22
4 changed files with 205 additions and 78 deletions

View File

@ -63,6 +63,8 @@ union wm_buttons // also just called "core data"
u8 down : 1;
u8 up : 1;
u8 plus : 1;
// For most input reports this is the 2 LSbs of accel.x:
// For interleaved reports this is alternating bits of accel.z:
u8 acc_bits : 2;
u8 unknown : 1;
@ -71,6 +73,8 @@ union wm_buttons // also just called "core data"
u8 b : 1;
u8 a : 1;
u8 minus : 1;
// For most input reports this is bits of accel.y/z:
// For interleaved reports this is alternating bits of accel.z:
u8 acc_bits2 : 2;
u8 home : 1;
};
@ -425,8 +429,10 @@ struct wm_write_data
u8 rumble : 1;
u8 space : 2; // see WM_SPACE_*
u8 : 5;
// used only for register space (i2c bus)
u8 slave_address;
// A real wiimote ignores the i2c read/write bit.
u8 i2c_rw_ignored : 1;
// Used only for register space (i2c bus) (7-bits):
u8 slave_address : 7;
// big endian:
u8 address[2];
u8 size;
@ -447,8 +453,10 @@ struct wm_read_data
u8 rumble : 1;
u8 space : 2; // see WM_SPACE_*
u8 : 5;
// used only for register space (i2c bus)
u8 slave_address;
// A real wiimote ignores the i2c read/write bit.
u8 i2c_rw_ignored : 1;
// Used only for register space (i2c bus) (7-bits):
u8 slave_address : 7;
// big endian:
u8 address[2];
u8 size[2];
@ -460,6 +468,7 @@ struct wm_read_data_reply
wm_buttons buttons;
u8 error : 4; // see WM_RDERR_*
u8 size_minus_one : 4;
// big endian:
u16 address;
u8 data[16];
};

View File

@ -40,7 +40,7 @@ namespace WiimoteEmu
void Wiimote::ReportMode(const wm_report_mode* const dr)
{
if (dr->mode < RT_REPORT_CORE || dr->mode > RT_REPORT_INTERLEAVE2 ||
(dr->mode > RT_REPORT_CORE_ACCEL_IR10_EXT6 && dr->mode < RT_REPORT_EXT21))
(dr->mode > RT_REPORT_CORE_ACCEL_IR10_EXT6 && dr->mode < RT_REPORT_EXT21))
{
// A real wiimote ignores the entire message if the mode is invalid.
WARN_LOG(WIIMOTE, "Game requested invalid report mode: 0x%02x", dr->mode);
@ -177,11 +177,11 @@ void Wiimote::SendAck(u8 report_id, u8 error_code)
rpt.param = HID_PARAM_INPUT;
rpt.report_id = RT_ACK_DATA;
auto ack = &rpt.data;
auto& ack = rpt.data;
ack->buttons = m_status.buttons;
ack->reportID = report_id;
ack->errorID = error_code;
ack.buttons = m_status.buttons;
ack.reportID = report_id;
ack.errorID = error_code;
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, rpt.GetData(),
rpt.GetSize());
@ -194,12 +194,22 @@ void Wiimote::HandleExtensionSwap()
{
// if an extension is currently connected and we want to switch to a different extension
if ((m_extension->active_extension > 0) && m_extension->switch_extension)
{
// detach extension first, wait til next Update() or RequestStatus() call to change to the new
// extension
m_extension->active_extension = 0;
}
else
{
// set the wanted extension
m_extension->active_extension = m_extension->switch_extension;
}
// TODO: this is a bit ugly:
if (m_extension->active_extension != 0)
m_motion_plus_logic.extension_port.SetAttachment(&m_ext_logic);
else
m_motion_plus_logic.extension_port.SetAttachment(nullptr);
// reset register
((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension].get())
@ -209,7 +219,7 @@ void Wiimote::HandleExtensionSwap()
void Wiimote::RequestStatus(const wm_request_status* const rs)
{
INFO_LOG(WIIMOTE, "Wiimote::RequestStatus");
// INFO_LOG(WIIMOTE, "Wiimote::RequestStatus");
// update status struct
m_status.extension = m_extension_port.IsDeviceConnected();
@ -247,7 +257,8 @@ void Wiimote::WriteData(const wm_write_data* const wd)
return;
}
INFO_LOG(WIIMOTE, "Wiimote::WriteData: 0x%02x @ 0x%02x @ 0x%02x (%d)", wd->space, wd->slave_address, address, wd->size);
INFO_LOG(WIIMOTE, "Wiimote::WriteData: 0x%02x @ 0x%02x @ 0x%02x (%d)", wd->space,
wd->slave_address, address, wd->size);
if (wd->size > 16)
{
@ -290,7 +301,8 @@ void Wiimote::WriteData(const wm_write_data* const wd)
// Write to Control Register
// Top byte of address is ignored on the bus.
auto const bytes_written = m_i2c_bus.BusWrite(wd->slave_address >> 1, (u8)address, wd->size, wd->data);
auto const bytes_written =
m_i2c_bus.BusWrite(wd->slave_address, (u8)address, wd->size, wd->data);
if (bytes_written != wd->size)
{
// A real wiimote gives error 7 for failed write to i2c bus (mainly a non-existant slave)
@ -325,7 +337,7 @@ void Wiimote::ReadData(const wm_read_data* const rd)
m_read_request.size = Common::swap16(rd->size);
INFO_LOG(WIIMOTE, "Wiimote::ReadData: %d @ 0x%02x @ 0x%02x (%d)", m_read_request.space,
m_read_request.slave_address, m_read_request.address, m_read_request.size);
m_read_request.slave_address, m_read_request.address, m_read_request.size);
// Send up to one read-data-reply.
// If more data needs to be sent it will happen on the next "Update()"
@ -336,7 +348,7 @@ bool Wiimote::ProcessReadDataRequest()
{
// Limit the amt to 16 bytes
// AyuanX: the MTU is 640B though... what a waste!
u16 const bytes_to_read = std::min((u16)16, m_read_request.size);
const u16 bytes_to_read = std::min<u16>(16, m_read_request.size);
if (0 == bytes_to_read)
{
@ -404,28 +416,40 @@ bool Wiimote::ProcessReadDataRequest()
// Read from Control Register
// Top byte of address is ignored on the bus, but it IS maintained in the read-reply.
auto const bytes_read = m_i2c_bus.BusRead(m_read_request.slave_address >> 1,
(u8)m_read_request.address, bytes_to_read, reply->data);
auto const bytes_read = m_i2c_bus.BusRead(
m_read_request.slave_address, (u8)m_read_request.address, bytes_to_read, reply->data);
reply->size_minus_one = bytes_read - 1;
if (bytes_read != bytes_to_read)
{
// generate read error, 7 == no such slave (no ack)
INFO_LOG(WIIMOTE, "Responding with read error 7.");
INFO_LOG(WIIMOTE, "Responding with read error 7 @ 0x%x @ 0x%x (%d)",
m_read_request.slave_address, m_read_request.address, m_read_request.size);
reply->error = 0x07;
}
}
break;
default:
PanicAlert("Wiimote::ReadData: unimplemented address space (space: 0x%x)!", m_read_request.space);
PanicAlert("Wiimote::ReadData: invalid address space (space: 0x%x)!", m_read_request.space);
break;
}
// Modify the read request, zero size == complete
m_read_request.address += bytes_to_read;
m_read_request.size -= bytes_to_read;
if (reply->error)
{
// Stop processing request on read error:
m_read_request.size = 0;
// TODO: what size does a real wiimote return on read error?
// it's 10 minus one (9) for some reason??
// reply->size_minus_one = 0;
}
else
{
// Modify the read request, zero size == complete
m_read_request.address += bytes_to_read;
m_read_request.size -= bytes_to_read;
}
// Send the data
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, rpt.GetData(),

View File

@ -101,7 +101,7 @@ static const ReportFeatures reporting_mode_features[] = {
{2, 0, 10, 9, 23},
// 0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
{2, 3, 10, 6, 23},
// Ugly padding members so 0x3d,3e,3f are properly placed in the array:
// 0x38 - 0x3c: Nothing
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
@ -109,7 +109,8 @@ static const ReportFeatures reporting_mode_features[] = {
{0, 0, 0, 0, 0},
// 0x3d: 21 Extension Bytes
{0, 0, 0, 21, 23},
// 0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
// 0x3e - 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
{2, 1, 0, 18, 23},
{2, 1, 0, 18, 23},
};
@ -313,6 +314,7 @@ static const char* const named_buttons[] = {
void Wiimote::Reset()
{
// TODO: Is a wiimote in CORE or DISABLED reporting mode on sync?
m_reporting_mode = RT_REPORT_DISABLED;
m_reporting_channel = 0;
m_reporting_auto = false;
@ -345,8 +347,26 @@ void Wiimote::Reset()
static const u8 c2[16] = {0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51, 0x33, 0x60,
0xc9, 0xf5, 0x37, 0xc1, 0x2d, 0xe9, 0x15, 0x8d};
static const u8 mp_cert[64] = {
//0x50, 0xc3, 0x0c, 0xab, 0x16, 0x07, 0xf6, 0x89, 0x51, 0x93, 0xbe, 0xa5, 0xb2,
//0xbb, 0xbb, 0x35, 0x49, 0x32, 0x04, 0xfd, 0x29, 0x1d, 0xc1, 0xb7, 0x5a, 0x7c,
//0x85, 0xb9, 0x78, 0x14, 0xf4, 0xfe, 0x21, 0x30, 0xa2, 0x5f, 0xb2, 0xc2, 0x8b,
//0x72, 0x02, 0xf8, 0x60, 0xdf, 0x03, 0x30, 0xdc, 0xb6, 0x86, 0xa4, 0x41, 0xdd,
//0x49, 0x01, 0x7b, 0x2f, 0xb2, 0xc8, 0x5b, 0x12, 0x92, 0x47, 0xb8, 0x23
//0xf0, 0x89, 0x3b, 0xf7, 0x1b, 0x6c, 0x92, 0x95, 0xa0, 0x05, 0xd4, 0x03, 0x82,
//0x8e, 0xae, 0x73, 0x15, 0xc7, 0x95, 0xfb, 0xae, 0xee, 0xc0, 0x68, 0xbd, 0x49,
//0xf5, 0x32, 0x48, 0x8d, 0x33, 0x00, 0x94, 0x32, 0xf5, 0xf1, 0x30, 0x66, 0x68,
//0x9e, 0xf3, 0xe5, 0xfa, 0x9b, 0xb6, 0xe3, 0x0b, 0xa8, 0x07, 0xd5, 0x25, 0x38,
0x99, 0x1a, 0x07, 0x1b, 0x97, 0xf1, 0x11, 0x78, 0x0c, 0x42, 0x2b, 0x68, 0xdf, 0x44, 0x38, 0x0d,
0x2b, 0x7e, 0xd6, 0x84, 0x84, 0x58, 0x65, 0xc9, 0xf2, 0x95, 0xd9, 0xaf, 0xb6, 0xc4, 0x87, 0xd5,
0x18, 0xdb, 0x67, 0x3a, 0xc0, 0x71, 0xec, 0x3e, 0xf4, 0xe6, 0x7e, 0x35, 0xa3, 0x29, 0xf8, 0x1f,
0xc5, 0x7c, 0x3d, 0xb9, 0x56, 0x22, 0x95, 0x98, 0x8f, 0xfb, 0x66, 0x3e, 0x9a, 0xdd, 0xeb, 0x7e,
};
// std::copy(std::begin(c1), std::end(c1), m_motion_plus_logic.reg_data.calibration_data);
// std::copy(std::begin(c2), std::end(c2), m_motion_plus_logic.reg_data.calibration_data + 0x10);
std::copy(std::begin(mp_cert), std::end(mp_cert), m_motion_plus_logic.reg_data.cert_data);
// status
memset(&m_status, 0, sizeof(m_status));
@ -379,7 +399,7 @@ void Wiimote::Reset()
// 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.extension_port.SetAttachment(&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)
@ -563,19 +583,12 @@ bool Wiimote::Step()
UpdateButtonsStatus();
}
if (ProcessReadDataRequest())
{
// Read requests suppress normal input reports
// Don't send any other reports
return true;
}
// 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
// Check if a status report needs to be sent. This happens when extensions are switched.
// ..even during read requests which continue after the status report is sent.
if (m_status.extension != m_extension_port.IsDeviceConnected())
{
// WiiBrew: Following a connection or disconnection event on the Extension Port,
@ -583,11 +596,20 @@ bool Wiimote::Step()
// arrive.
m_reporting_mode = RT_REPORT_DISABLED;
INFO_LOG(WIIMOTE, "Sending status report due to extension status change.");
RequestStatus();
return true;
}
if (ProcessReadDataRequest())
{
// Read requests suppress normal input reports
// Don't send any other reports
return true;
}
return false;
}
@ -878,7 +900,7 @@ void Wiimote::Update()
if (RT_REPORT_DISABLED == m_reporting_mode)
{
// The wiimote is in this disabled state on boot and after an extension change.
// The wiimote is in this disabled after an extension change.
// Input reports are not sent, even on button change.
return;
}
@ -932,14 +954,14 @@ void Wiimote::Update()
if (RT_REPORT_INTERLEAVE1 == m_reporting_mode)
{
*feature_ptr = (x >> 2) & 0xff;
core.acc_bits = (z >> 4) & 0b11;
core.acc_bits2 = (z >> 6) & 0b11;
core.acc_bits = (z >> 6) & 0b11;
core.acc_bits2 = (z >> 8) & 0b11;
}
if (RT_REPORT_INTERLEAVE2 == m_reporting_mode)
{
*feature_ptr = (y >> 2) & 0xff;
core.acc_bits = (z >> 0) & 0b11;
core.acc_bits2 = (z >> 2) & 0b11;
core.acc_bits = (z >> 2) & 0b11;
core.acc_bits2 = (z >> 4) & 0b11;
}
else
{
@ -999,6 +1021,7 @@ void Wiimote::Update()
Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension,
m_ext_logic.ext_key);
}
if (NetPlay::IsNetPlayRunning())
{
NetPlay_GetWiimoteData(m_index, data, rptf.total_size, m_reporting_mode);
@ -1006,7 +1029,6 @@ void Wiimote::Update()
m_status.buttons = *reinterpret_cast<wm_buttons*>(data + rptf.core_size);
}
// TODO: need to fix usage of rptf probably
Movie::CheckWiimoteStatus(m_index, data, rptf, m_extension->active_extension,
m_ext_logic.ext_key);
@ -1180,7 +1202,7 @@ int Wiimote::CurrentExtension() const
bool Wiimote::ExtensionLogic::ReadDeviceDetectPin()
{
return extension->active_extension ? true : false;
return extension->active_extension != 0;
}
void Wiimote::ExtensionLogic::Update()
@ -1204,25 +1226,54 @@ void Wiimote::MotionPlusLogic::Update()
return;
}
// TODO: clean up this hackery:
// the value seems to increase based on time starting after the first read of 0x00
if (IsActive() && times_updated_since_activation < 0xff)
{
++times_updated_since_activation;
auto& data = reg_data.controller_data;
auto& mplus_data = *reinterpret_cast<wm_motionplus_data*>(data);
// TODO: wtf is this value actually..
if (times_updated_since_activation == 9)
reg_data.initialization_status = 0x4;
else if (times_updated_since_activation == 10)
reg_data.initialization_status = 0x8;
else if (times_updated_since_activation == 18)
reg_data.initialization_status = 0xc;
else if (times_updated_since_activation == 53)
reg_data.initialization_status = 0xe;
if (0x0 == reg_data.cert_ready)
{
// Without sending this nonsense, inputs are unresponsive.. even regular buttons
// Device still operates when changing the data slightly so its not any sort of encrpytion
// It even works when removing the is_mp_data bit in the last byte
static const u8 init_data[6] = {0x8e, 0xb0, 0x4f, 0x5a, 0xfc, 0x02};
//std::copy(std::begin(init_data), std::end(init_data), data);
reg_data.cert_ready = 0x2;
//return;
}
auto& mplus_data = *reinterpret_cast<wm_motionplus_data*>(reg_data.controller_data);
auto& data = reg_data.controller_data;
if (0x2 == reg_data.cert_ready)
{
// A real wiimote takes about 2 seconds to reach this state:
reg_data.cert_ready = 0xe;
}
if (0x18 == reg_data.cert_ready)
{
const u8 mp_cert2[64] = {
//0x39, 0x7c, 0xe9, 0x79, 0x15, 0x52, 0x0e, 0x4f, 0x28, 0x4d, 0x9d, 0x2c, 0xd3,
//0x2a, 0x1a, 0x28, 0xa1, 0x25, 0x55, 0xb4, 0x4e, 0xb1, 0xd5, 0xae, 0x9d, 0x99,
//0x96, 0x96, 0x1d, 0x94, 0xd1, 0x22, 0xca, 0x1f, 0x51, 0x1d, 0x55, 0xee, 0x4d,
//0x58, 0x97, 0xd4, 0xb9, 0x3f, 0x0d, 0x0a, 0x04, 0xd8, 0x01, 0x21, 0xf9, 0x17,
//0x45, 0xe4, 0x42, 0x58, 0x3f, 0x7c, 0x3c, 0x2c, 0x3a, 0xcd, 0xbd, 0x27, 0x3b,
//0xea, 0x7c, 0x25, 0xaf, 0xcc, 0xc8, 0xef, 0x22, 0x99, 0xb3, 0x79, 0x72, 0x60,
//0xe8, 0x16, 0x4f, 0x5a, 0x47, 0x07, 0x04, 0x02, 0x14, 0x7b, 0xd0, 0xf6, 0xc9,
//0x77, 0x28, 0x9f, 0x77, 0x78, 0xce, 0x19, 0x74, 0x89, 0xe3, 0x56, 0x3a, 0x23,
//0x13, 0x63, 0xbb, 0x86, 0xf9, 0x13, 0x0e, 0x62, 0xfb, 0x61, 0xf5, 0x42, 0x65,
//0x48, 0x8e, 0xed, 0xc2, 0xc4, 0xc1, 0x18, 0xd0, 0x19, 0x9c, 0xe5, 0x1e
0xa5, 0x84, 0x1f, 0xd6, 0xbd, 0xdc, 0x7a, 0x4c, 0xf3, 0xc0, 0x24, 0xe0, 0x92, 0xef, 0x19, 0x28,
0x65, 0xe0, 0x62, 0x7c, 0x9b, 0x41, 0x6f, 0x12, 0xc3, 0xac, 0x78, 0xe4, 0xfc, 0x6b, 0x7b, 0x0a,
0xb4, 0x50, 0xd6, 0xf2, 0x45, 0xf7, 0x93, 0x04, 0xaf, 0xf2, 0xb7, 0x26, 0x94, 0xee, 0xad, 0x92,
0x05, 0x6d, 0xe5, 0xc6, 0xd6, 0x36, 0xdc, 0xa5, 0x69, 0x0f, 0xc8, 0x99, 0xf2, 0x1c, 0x4e, 0x0d,
};
std::copy(std::begin(mp_cert2), std::end(mp_cert2), reg_data.cert_data);
// A real wiimote takes about 2 seconds to reach this state:
reg_data.cert_ready = 0x1a;
INFO_LOG(WIIMOTE, "M+ cert 2 ready!", reg_data.cert_ready);
}
// TODO: make sure a motion plus report is sent first after init
@ -1268,6 +1319,7 @@ void Wiimote::MotionPlusLogic::Update()
// Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it
SetBit(data[5], 2, Common::ExtractBit(data[5], 0));
// Bit 0 and 1 of byte 5 contain a M+ flag and a zero bit which is set below.
mplus_data.is_mp_data = false;
}
}
@ -1284,9 +1336,11 @@ void Wiimote::MotionPlusLogic::Update()
// Data passing through drops the least significant bit of the axes of the left (or only)
// joystick Bit 0 of Byte 4 is overwritten [by the 'extension_connected' flag] Bits 0 and 1
// of Byte 5 are moved to bit 0 of Bytes 0 and 1, overwriting what was there before
SetBit(data[0], 0, Common::ExtractBit(data[5], 0));
SetBit(data[1], 0, Common::ExtractBit(data[5], 1));
// Bit 0 and 1 of byte 5 contain a M+ flag and a zero bit which is set below.
mplus_data.is_mp_data = false;
}
}
@ -1315,9 +1369,17 @@ void Wiimote::MotionPlusLogic::Update()
mplus_data.pitch1 = pitch_value & 0xff;
// Bits 8-13
mplus_data.yaw1 = yaw_value >> 8;
mplus_data.roll1 = roll_value >> 8;
mplus_data.pitch1 = pitch_value >> 8;
mplus_data.yaw2 = yaw_value >> 8;
mplus_data.roll2 = roll_value >> 8;
mplus_data.pitch2 = pitch_value >> 8;
// hax:
//data[0] = 0x6d;
//data[1] = 0xfa;
//data[2] = 0x13;
//data[3] = 0x7f;
//data[4] = 0x83;
//data[5] = 0x7e;
}
mplus_data.extension_connected = extension_port.IsDeviceConnected();

View File

@ -306,6 +306,7 @@ public:
}
private:
// Pointers are unowned:
std::vector<I2CSlave*> m_slaves;
};
@ -334,7 +335,10 @@ public:
void SetAttachment(ExtensionAttachment* dev)
{
m_i2c_bus.RemoveSlave(m_attachment);
m_i2c_bus.AddSlave(m_attachment = dev);
m_attachment = dev;
if (dev)
m_i2c_bus.AddSlave(dev);
}
private:
@ -470,12 +474,12 @@ private:
// Check if encrypted reads is on
if (0xaa == reg_data.encryption)
{
INFO_LOG(WIIMOTE, "Encrypted read.");
//INFO_LOG(WIIMOTE, "Encrypted read.");
WiimoteEncrypt(&ext_key, data_out, addr, (u8)count);
}
else
{
INFO_LOG(WIIMOTE, "Unencrypted read.");
//INFO_LOG(WIIMOTE, "Unencrypted read.");
}
return result;
@ -561,9 +565,11 @@ private:
struct MotionPlusLogic : public ExtensionAttachment
{
private:
// The bus on the end of the motion plus:
I2CBus i2c_bus;
public:
// The port on the end of the motion plus:
ExtensionPort extension_port{i2c_bus};
@ -573,24 +579,37 @@ private:
struct MotionPlusRegister
{
u8 controller_data[21];
u8 unknown[11];
u8 unknown_0x15[11];
// address 0x20
u8 calibration_data[0x20];
u8 unknown2[0xb0];
u8 unknown_0x40[0x10];
// address 0x50
u8 cert_data[0x40];
u8 unknown_0x90[0x60];
// address 0xF0
u8 initialized;
u8 unknown3[6];
// address 0xF1
u8 cert_enable;
u8 unknown_0xf2[5];
// address 0xf7
// Wii Sports Resort reads regularly and claims mplus is disconnected if not to its liking
// Wii Sports Resort reads regularly
// Value starts at 0x00 and goes up after activation (not initialization)
// Immediately returns 0x02, even still after 15 and 30 seconds
u8 initialization_status;
// After the first data read the value seems to progress to 0x4,0x8,0xc,0xe
// More typical seems to be 2,8,c,e
// A value of 0xe triggers the game to read 64 bytes from 0x50
// The game claims M+ is disconnected after this read of unsatisfactory data
u8 cert_ready;
u8 unknown4[2];
u8 unknown_0xf8[2];
// address 0xFA
u8 ext_identifier[6];
@ -610,9 +629,6 @@ private:
PASSTHROUGH_CLASSIC = 0x07,
};
// TODO: savestate
u8 times_updated_since_activation = 0;
bool IsActive() const { return ACTIVE_DEVICE_ADDR << 1 == reg_data.ext_identifier[2]; }
PassthroughMode GetPassthroughMode() const
@ -659,15 +675,29 @@ private:
if (ACTIVE_DEVICE_ADDR == slave_addr)
{
auto const result = RawWrite(&reg_data, addr, count, data_in);
return result;
// It seems a write of any value triggers deactivation.
// TODO: kill magic number
if (0xf0 == addr)
{
// Deactivate motion plus:
reg_data.ext_identifier[2] = INACTIVE_DEVICE_ADDR << 1;
times_updated_since_activation = 0;
reg_data.cert_ready = 0x0;
// Pass through the activation write to the attached extension:
// The M+ deactivation signal is cleverly the same as EXT activation:
i2c_bus.BusWrite(slave_addr, addr, count, data_in);
}
// TODO: kill magic number
else if (0xf1 == addr)
{
INFO_LOG(WIIMOTE, "M+ cert activation: 0x%x", reg_data.cert_enable);
// 0x14,0x18 is also a valid value
// 0x1a is final value
reg_data.cert_ready = 0x18;
}
return result;
}
else
{
@ -684,13 +714,15 @@ private:
// It seems a write of any value triggers activation.
if (0xfe == addr)
{
INFO_LOG(WIIMOTE, "Motion Plus has been activated with value: %d", data_in[0]);
INFO_LOG(WIIMOTE, "M+ has been activated: %d", data_in[0]);
// Activate motion plus:
reg_data.ext_identifier[2] = ACTIVE_DEVICE_ADDR << 1;
reg_data.initialization_status = 0x2;
// TODO: kill magic number
//reg_data.cert_ready = 0x2;
// Some hax to disable encryption:
// TODO: activate extension and disable encrption
// also do this if an extension is attached after activation.
std::array<u8, 1> data = {0x55};
i2c_bus.BusWrite(ACTIVE_DEVICE_ADDR, 0xf0, (int)data.size(), data.data());
}
@ -710,11 +742,11 @@ private:
{
if (IsActive())
{
// TODO: logic for when motion plus deactivates
return true;
}
else
{
// When inactive the device detect pin reads from ext port:
return extension_port.IsDeviceConnected();
}
}