mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
WiimoteEmu: Motion plus now works half of the time in Wii Sports Resort.
This commit is contained in:
@ -63,6 +63,8 @@ union wm_buttons // also just called "core data"
|
|||||||
u8 down : 1;
|
u8 down : 1;
|
||||||
u8 up : 1;
|
u8 up : 1;
|
||||||
u8 plus : 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 acc_bits : 2;
|
||||||
u8 unknown : 1;
|
u8 unknown : 1;
|
||||||
|
|
||||||
@ -71,6 +73,8 @@ union wm_buttons // also just called "core data"
|
|||||||
u8 b : 1;
|
u8 b : 1;
|
||||||
u8 a : 1;
|
u8 a : 1;
|
||||||
u8 minus : 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 acc_bits2 : 2;
|
||||||
u8 home : 1;
|
u8 home : 1;
|
||||||
};
|
};
|
||||||
@ -425,8 +429,10 @@ struct wm_write_data
|
|||||||
u8 rumble : 1;
|
u8 rumble : 1;
|
||||||
u8 space : 2; // see WM_SPACE_*
|
u8 space : 2; // see WM_SPACE_*
|
||||||
u8 : 5;
|
u8 : 5;
|
||||||
// used only for register space (i2c bus)
|
// A real wiimote ignores the i2c read/write bit.
|
||||||
u8 slave_address;
|
u8 i2c_rw_ignored : 1;
|
||||||
|
// Used only for register space (i2c bus) (7-bits):
|
||||||
|
u8 slave_address : 7;
|
||||||
// big endian:
|
// big endian:
|
||||||
u8 address[2];
|
u8 address[2];
|
||||||
u8 size;
|
u8 size;
|
||||||
@ -447,8 +453,10 @@ struct wm_read_data
|
|||||||
u8 rumble : 1;
|
u8 rumble : 1;
|
||||||
u8 space : 2; // see WM_SPACE_*
|
u8 space : 2; // see WM_SPACE_*
|
||||||
u8 : 5;
|
u8 : 5;
|
||||||
// used only for register space (i2c bus)
|
// A real wiimote ignores the i2c read/write bit.
|
||||||
u8 slave_address;
|
u8 i2c_rw_ignored : 1;
|
||||||
|
// Used only for register space (i2c bus) (7-bits):
|
||||||
|
u8 slave_address : 7;
|
||||||
// big endian:
|
// big endian:
|
||||||
u8 address[2];
|
u8 address[2];
|
||||||
u8 size[2];
|
u8 size[2];
|
||||||
@ -460,6 +468,7 @@ struct wm_read_data_reply
|
|||||||
wm_buttons buttons;
|
wm_buttons buttons;
|
||||||
u8 error : 4; // see WM_RDERR_*
|
u8 error : 4; // see WM_RDERR_*
|
||||||
u8 size_minus_one : 4;
|
u8 size_minus_one : 4;
|
||||||
|
// big endian:
|
||||||
u16 address;
|
u16 address;
|
||||||
u8 data[16];
|
u8 data[16];
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,7 @@ namespace WiimoteEmu
|
|||||||
void Wiimote::ReportMode(const wm_report_mode* const dr)
|
void Wiimote::ReportMode(const wm_report_mode* const dr)
|
||||||
{
|
{
|
||||||
if (dr->mode < RT_REPORT_CORE || dr->mode > RT_REPORT_INTERLEAVE2 ||
|
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.
|
// A real wiimote ignores the entire message if the mode is invalid.
|
||||||
WARN_LOG(WIIMOTE, "Game requested invalid report mode: 0x%02x", dr->mode);
|
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.param = HID_PARAM_INPUT;
|
||||||
rpt.report_id = RT_ACK_DATA;
|
rpt.report_id = RT_ACK_DATA;
|
||||||
|
|
||||||
auto ack = &rpt.data;
|
auto& ack = rpt.data;
|
||||||
|
|
||||||
ack->buttons = m_status.buttons;
|
ack.buttons = m_status.buttons;
|
||||||
ack->reportID = report_id;
|
ack.reportID = report_id;
|
||||||
ack->errorID = error_code;
|
ack.errorID = error_code;
|
||||||
|
|
||||||
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, rpt.GetData(),
|
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, rpt.GetData(),
|
||||||
rpt.GetSize());
|
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 an extension is currently connected and we want to switch to a different extension
|
||||||
if ((m_extension->active_extension > 0) && m_extension->switch_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
|
// detach extension first, wait til next Update() or RequestStatus() call to change to the new
|
||||||
// extension
|
// extension
|
||||||
m_extension->active_extension = 0;
|
m_extension->active_extension = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
// set the wanted extension
|
// set the wanted extension
|
||||||
m_extension->active_extension = m_extension->switch_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
|
// reset register
|
||||||
((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension].get())
|
((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)
|
void Wiimote::RequestStatus(const wm_request_status* const rs)
|
||||||
{
|
{
|
||||||
INFO_LOG(WIIMOTE, "Wiimote::RequestStatus");
|
// INFO_LOG(WIIMOTE, "Wiimote::RequestStatus");
|
||||||
|
|
||||||
// update status struct
|
// update status struct
|
||||||
m_status.extension = m_extension_port.IsDeviceConnected();
|
m_status.extension = m_extension_port.IsDeviceConnected();
|
||||||
@ -247,7 +257,8 @@ void Wiimote::WriteData(const wm_write_data* const wd)
|
|||||||
return;
|
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)
|
if (wd->size > 16)
|
||||||
{
|
{
|
||||||
@ -290,7 +301,8 @@ void Wiimote::WriteData(const wm_write_data* const wd)
|
|||||||
// Write to Control Register
|
// Write to Control Register
|
||||||
|
|
||||||
// Top byte of address is ignored on the bus.
|
// 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)
|
if (bytes_written != wd->size)
|
||||||
{
|
{
|
||||||
// A real wiimote gives error 7 for failed write to i2c bus (mainly a non-existant slave)
|
// 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);
|
m_read_request.size = Common::swap16(rd->size);
|
||||||
|
|
||||||
INFO_LOG(WIIMOTE, "Wiimote::ReadData: %d @ 0x%02x @ 0x%02x (%d)", m_read_request.space,
|
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.
|
// Send up to one read-data-reply.
|
||||||
// If more data needs to be sent it will happen on the next "Update()"
|
// 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
|
// Limit the amt to 16 bytes
|
||||||
// AyuanX: the MTU is 640B though... what a waste!
|
// 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)
|
if (0 == bytes_to_read)
|
||||||
{
|
{
|
||||||
@ -404,28 +416,40 @@ bool Wiimote::ProcessReadDataRequest()
|
|||||||
// Read from Control Register
|
// Read from Control Register
|
||||||
|
|
||||||
// Top byte of address is ignored on the bus, but it IS maintained in the read-reply.
|
// 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,
|
auto const bytes_read = m_i2c_bus.BusRead(
|
||||||
(u8)m_read_request.address, bytes_to_read, reply->data);
|
m_read_request.slave_address, (u8)m_read_request.address, bytes_to_read, reply->data);
|
||||||
|
|
||||||
reply->size_minus_one = bytes_read - 1;
|
reply->size_minus_one = bytes_read - 1;
|
||||||
|
|
||||||
if (bytes_read != bytes_to_read)
|
if (bytes_read != bytes_to_read)
|
||||||
{
|
{
|
||||||
// generate read error, 7 == no such slave (no ack)
|
// 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;
|
reply->error = 0x07;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modify the read request, zero size == complete
|
if (reply->error)
|
||||||
m_read_request.address += bytes_to_read;
|
{
|
||||||
m_read_request.size -= bytes_to_read;
|
// 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
|
// Send the data
|
||||||
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, rpt.GetData(),
|
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, rpt.GetData(),
|
||||||
|
@ -101,7 +101,7 @@ static const ReportFeatures reporting_mode_features[] = {
|
|||||||
{2, 0, 10, 9, 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, 3, 10, 6, 23},
|
{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},
|
{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},
|
{0, 0, 0, 0, 0},
|
||||||
// 0x3d: 21 Extension Bytes
|
// 0x3d: 21 Extension Bytes
|
||||||
{0, 0, 0, 21, 23},
|
{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},
|
{2, 1, 0, 18, 23},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -313,6 +314,7 @@ static const char* const named_buttons[] = {
|
|||||||
|
|
||||||
void Wiimote::Reset()
|
void Wiimote::Reset()
|
||||||
{
|
{
|
||||||
|
// TODO: Is a wiimote in CORE or DISABLED reporting mode on sync?
|
||||||
m_reporting_mode = RT_REPORT_DISABLED;
|
m_reporting_mode = RT_REPORT_DISABLED;
|
||||||
m_reporting_channel = 0;
|
m_reporting_channel = 0;
|
||||||
m_reporting_auto = false;
|
m_reporting_auto = false;
|
||||||
@ -345,8 +347,26 @@ void Wiimote::Reset()
|
|||||||
static const u8 c2[16] = {0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51, 0x33, 0x60,
|
static const u8 c2[16] = {0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51, 0x33, 0x60,
|
||||||
0xc9, 0xf5, 0x37, 0xc1, 0x2d, 0xe9, 0x15, 0x8d};
|
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(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
|
// status
|
||||||
memset(&m_status, 0, sizeof(m_status));
|
memset(&m_status, 0, sizeof(m_status));
|
||||||
@ -379,7 +399,7 @@ void Wiimote::Reset()
|
|||||||
// TODO: only add to bus when connected:
|
// TODO: only add to bus when connected:
|
||||||
// Address 0x52 (when motion plus is not activated)
|
// Address 0x52 (when motion plus is not activated)
|
||||||
// Connected to motion plus i2c_bus (with passthrough by default)
|
// 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)
|
Wiimote::Wiimote(const unsigned int index) : m_index(index), ir_sin(0), ir_cos(1)
|
||||||
@ -563,19 +583,12 @@ bool Wiimote::Step()
|
|||||||
UpdateButtonsStatus();
|
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.
|
// If an extension change is requested in the GUI it will first be disconnected here.
|
||||||
// causing IsDeviceConnected() to return false below:
|
// causing IsDeviceConnected() to return false below:
|
||||||
HandleExtensionSwap();
|
HandleExtensionSwap();
|
||||||
|
|
||||||
// check if a status report needs to be sent
|
// Check if a status report needs to be sent. This happens when extensions are switched.
|
||||||
// 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())
|
if (m_status.extension != m_extension_port.IsDeviceConnected())
|
||||||
{
|
{
|
||||||
// WiiBrew: Following a connection or disconnection event on the Extension Port,
|
// WiiBrew: Following a connection or disconnection event on the Extension Port,
|
||||||
@ -583,11 +596,20 @@ bool Wiimote::Step()
|
|||||||
// arrive.
|
// arrive.
|
||||||
m_reporting_mode = RT_REPORT_DISABLED;
|
m_reporting_mode = RT_REPORT_DISABLED;
|
||||||
|
|
||||||
|
INFO_LOG(WIIMOTE, "Sending status report due to extension status change.");
|
||||||
|
|
||||||
RequestStatus();
|
RequestStatus();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ProcessReadDataRequest())
|
||||||
|
{
|
||||||
|
// Read requests suppress normal input reports
|
||||||
|
// Don't send any other reports
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,7 +900,7 @@ void Wiimote::Update()
|
|||||||
|
|
||||||
if (RT_REPORT_DISABLED == m_reporting_mode)
|
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.
|
// Input reports are not sent, even on button change.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -932,14 +954,14 @@ void Wiimote::Update()
|
|||||||
if (RT_REPORT_INTERLEAVE1 == m_reporting_mode)
|
if (RT_REPORT_INTERLEAVE1 == m_reporting_mode)
|
||||||
{
|
{
|
||||||
*feature_ptr = (x >> 2) & 0xff;
|
*feature_ptr = (x >> 2) & 0xff;
|
||||||
core.acc_bits = (z >> 4) & 0b11;
|
core.acc_bits = (z >> 6) & 0b11;
|
||||||
core.acc_bits2 = (z >> 6) & 0b11;
|
core.acc_bits2 = (z >> 8) & 0b11;
|
||||||
}
|
}
|
||||||
if (RT_REPORT_INTERLEAVE2 == m_reporting_mode)
|
if (RT_REPORT_INTERLEAVE2 == m_reporting_mode)
|
||||||
{
|
{
|
||||||
*feature_ptr = (y >> 2) & 0xff;
|
*feature_ptr = (y >> 2) & 0xff;
|
||||||
core.acc_bits = (z >> 0) & 0b11;
|
core.acc_bits = (z >> 2) & 0b11;
|
||||||
core.acc_bits2 = (z >> 2) & 0b11;
|
core.acc_bits2 = (z >> 4) & 0b11;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -999,6 +1021,7 @@ void Wiimote::Update()
|
|||||||
Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension,
|
Movie::CallWiiInputManip(data, rptf, m_index, m_extension->active_extension,
|
||||||
m_ext_logic.ext_key);
|
m_ext_logic.ext_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NetPlay::IsNetPlayRunning())
|
if (NetPlay::IsNetPlayRunning())
|
||||||
{
|
{
|
||||||
NetPlay_GetWiimoteData(m_index, data, rptf.total_size, m_reporting_mode);
|
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);
|
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,
|
Movie::CheckWiimoteStatus(m_index, data, rptf, m_extension->active_extension,
|
||||||
m_ext_logic.ext_key);
|
m_ext_logic.ext_key);
|
||||||
|
|
||||||
@ -1180,7 +1202,7 @@ int Wiimote::CurrentExtension() const
|
|||||||
|
|
||||||
bool Wiimote::ExtensionLogic::ReadDeviceDetectPin()
|
bool Wiimote::ExtensionLogic::ReadDeviceDetectPin()
|
||||||
{
|
{
|
||||||
return extension->active_extension ? true : false;
|
return extension->active_extension != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::ExtensionLogic::Update()
|
void Wiimote::ExtensionLogic::Update()
|
||||||
@ -1204,25 +1226,54 @@ void Wiimote::MotionPlusLogic::Update()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: clean up this hackery:
|
auto& data = reg_data.controller_data;
|
||||||
// the value seems to increase based on time starting after the first read of 0x00
|
auto& mplus_data = *reinterpret_cast<wm_motionplus_data*>(data);
|
||||||
if (IsActive() && times_updated_since_activation < 0xff)
|
|
||||||
{
|
|
||||||
++times_updated_since_activation;
|
|
||||||
|
|
||||||
// TODO: wtf is this value actually..
|
if (0x0 == reg_data.cert_ready)
|
||||||
if (times_updated_since_activation == 9)
|
{
|
||||||
reg_data.initialization_status = 0x4;
|
|
||||||
else if (times_updated_since_activation == 10)
|
// Without sending this nonsense, inputs are unresponsive.. even regular buttons
|
||||||
reg_data.initialization_status = 0x8;
|
// Device still operates when changing the data slightly so its not any sort of encrpytion
|
||||||
else if (times_updated_since_activation == 18)
|
// It even works when removing the is_mp_data bit in the last byte
|
||||||
reg_data.initialization_status = 0xc;
|
static const u8 init_data[6] = {0x8e, 0xb0, 0x4f, 0x5a, 0xfc, 0x02};
|
||||||
else if (times_updated_since_activation == 53)
|
//std::copy(std::begin(init_data), std::end(init_data), data);
|
||||||
reg_data.initialization_status = 0xe;
|
reg_data.cert_ready = 0x2;
|
||||||
|
//return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& mplus_data = *reinterpret_cast<wm_motionplus_data*>(reg_data.controller_data);
|
if (0x2 == reg_data.cert_ready)
|
||||||
auto& data = reg_data.controller_data;
|
{
|
||||||
|
// 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
|
// 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
|
// Bit 0 of byte 5 is moved to bit 2 of byte 5, overwriting it
|
||||||
SetBit(data[5], 2, Common::ExtractBit(data[5], 0));
|
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;
|
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)
|
// 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
|
// 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
|
// 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[0], 0, Common::ExtractBit(data[5], 0));
|
||||||
SetBit(data[1], 0, Common::ExtractBit(data[5], 1));
|
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;
|
mplus_data.is_mp_data = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1315,9 +1369,17 @@ void Wiimote::MotionPlusLogic::Update()
|
|||||||
mplus_data.pitch1 = pitch_value & 0xff;
|
mplus_data.pitch1 = pitch_value & 0xff;
|
||||||
|
|
||||||
// Bits 8-13
|
// Bits 8-13
|
||||||
mplus_data.yaw1 = yaw_value >> 8;
|
mplus_data.yaw2 = yaw_value >> 8;
|
||||||
mplus_data.roll1 = roll_value >> 8;
|
mplus_data.roll2 = roll_value >> 8;
|
||||||
mplus_data.pitch1 = pitch_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();
|
mplus_data.extension_connected = extension_port.IsDeviceConnected();
|
||||||
|
@ -306,6 +306,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Pointers are unowned:
|
||||||
std::vector<I2CSlave*> m_slaves;
|
std::vector<I2CSlave*> m_slaves;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -334,7 +335,10 @@ public:
|
|||||||
void SetAttachment(ExtensionAttachment* dev)
|
void SetAttachment(ExtensionAttachment* dev)
|
||||||
{
|
{
|
||||||
m_i2c_bus.RemoveSlave(m_attachment);
|
m_i2c_bus.RemoveSlave(m_attachment);
|
||||||
m_i2c_bus.AddSlave(m_attachment = dev);
|
m_attachment = dev;
|
||||||
|
|
||||||
|
if (dev)
|
||||||
|
m_i2c_bus.AddSlave(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -470,12 +474,12 @@ private:
|
|||||||
// Check if encrypted reads is on
|
// Check if encrypted reads is on
|
||||||
if (0xaa == reg_data.encryption)
|
if (0xaa == reg_data.encryption)
|
||||||
{
|
{
|
||||||
INFO_LOG(WIIMOTE, "Encrypted read.");
|
//INFO_LOG(WIIMOTE, "Encrypted read.");
|
||||||
WiimoteEncrypt(&ext_key, data_out, addr, (u8)count);
|
WiimoteEncrypt(&ext_key, data_out, addr, (u8)count);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INFO_LOG(WIIMOTE, "Unencrypted read.");
|
//INFO_LOG(WIIMOTE, "Unencrypted read.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -561,9 +565,11 @@ private:
|
|||||||
|
|
||||||
struct MotionPlusLogic : public ExtensionAttachment
|
struct MotionPlusLogic : public ExtensionAttachment
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
// The bus on the end of the motion plus:
|
// The bus on the end of the motion plus:
|
||||||
I2CBus i2c_bus;
|
I2CBus i2c_bus;
|
||||||
|
|
||||||
|
public:
|
||||||
// The port on the end of the motion plus:
|
// The port on the end of the motion plus:
|
||||||
ExtensionPort extension_port{i2c_bus};
|
ExtensionPort extension_port{i2c_bus};
|
||||||
|
|
||||||
@ -573,24 +579,37 @@ private:
|
|||||||
struct MotionPlusRegister
|
struct MotionPlusRegister
|
||||||
{
|
{
|
||||||
u8 controller_data[21];
|
u8 controller_data[21];
|
||||||
u8 unknown[11];
|
u8 unknown_0x15[11];
|
||||||
|
|
||||||
// address 0x20
|
// address 0x20
|
||||||
u8 calibration_data[0x20];
|
u8 calibration_data[0x20];
|
||||||
u8 unknown2[0xb0];
|
|
||||||
|
u8 unknown_0x40[0x10];
|
||||||
|
|
||||||
|
// address 0x50
|
||||||
|
u8 cert_data[0x40];
|
||||||
|
|
||||||
|
u8 unknown_0x90[0x60];
|
||||||
|
|
||||||
// address 0xF0
|
// address 0xF0
|
||||||
u8 initialized;
|
u8 initialized;
|
||||||
|
|
||||||
u8 unknown3[6];
|
// address 0xF1
|
||||||
|
u8 cert_enable;
|
||||||
|
|
||||||
|
u8 unknown_0xf2[5];
|
||||||
|
|
||||||
// address 0xf7
|
// 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)
|
// Value starts at 0x00 and goes up after activation (not initialization)
|
||||||
// Immediately returns 0x02, even still after 15 and 30 seconds
|
// 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
|
// address 0xFA
|
||||||
u8 ext_identifier[6];
|
u8 ext_identifier[6];
|
||||||
@ -610,9 +629,6 @@ private:
|
|||||||
PASSTHROUGH_CLASSIC = 0x07,
|
PASSTHROUGH_CLASSIC = 0x07,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: savestate
|
|
||||||
u8 times_updated_since_activation = 0;
|
|
||||||
|
|
||||||
bool IsActive() const { return ACTIVE_DEVICE_ADDR << 1 == reg_data.ext_identifier[2]; }
|
bool IsActive() const { return ACTIVE_DEVICE_ADDR << 1 == reg_data.ext_identifier[2]; }
|
||||||
|
|
||||||
PassthroughMode GetPassthroughMode() const
|
PassthroughMode GetPassthroughMode() const
|
||||||
@ -659,15 +675,29 @@ private:
|
|||||||
if (ACTIVE_DEVICE_ADDR == slave_addr)
|
if (ACTIVE_DEVICE_ADDR == slave_addr)
|
||||||
{
|
{
|
||||||
auto const result = RawWrite(®_data, addr, count, data_in);
|
auto const result = RawWrite(®_data, addr, count, data_in);
|
||||||
return result;
|
|
||||||
|
|
||||||
// It seems a write of any value triggers deactivation.
|
// It seems a write of any value triggers deactivation.
|
||||||
|
// TODO: kill magic number
|
||||||
if (0xf0 == addr)
|
if (0xf0 == addr)
|
||||||
{
|
{
|
||||||
// Deactivate motion plus:
|
// Deactivate motion plus:
|
||||||
reg_data.ext_identifier[2] = INACTIVE_DEVICE_ADDR << 1;
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -684,13 +714,15 @@ private:
|
|||||||
// It seems a write of any value triggers activation.
|
// It seems a write of any value triggers activation.
|
||||||
if (0xfe == addr)
|
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:
|
// Activate motion plus:
|
||||||
reg_data.ext_identifier[2] = ACTIVE_DEVICE_ADDR << 1;
|
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};
|
std::array<u8, 1> data = {0x55};
|
||||||
i2c_bus.BusWrite(ACTIVE_DEVICE_ADDR, 0xf0, (int)data.size(), data.data());
|
i2c_bus.BusWrite(ACTIVE_DEVICE_ADDR, 0xf0, (int)data.size(), data.data());
|
||||||
}
|
}
|
||||||
@ -710,11 +742,11 @@ private:
|
|||||||
{
|
{
|
||||||
if (IsActive())
|
if (IsActive())
|
||||||
{
|
{
|
||||||
// TODO: logic for when motion plus deactivates
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// When inactive the device detect pin reads from ext port:
|
||||||
return extension_port.IsDeviceConnected();
|
return extension_port.IsDeviceConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user