WiimoteEmu: Cleanups, Kill more magic numbers and use some enum classes.

This commit is contained in:
Jordan Woyak 2018-12-02 12:32:52 -06:00
parent 86c94b8b22
commit 3a889c35ad
5 changed files with 149 additions and 122 deletions

View File

@ -41,17 +41,20 @@ enum WiimoteLED
LED_4 = 0x80 LED_4 = 0x80
}; };
enum WiimoteSpace enum class WiimoteAddressSpace : u8
{ {
WS_EEPROM = 0x00, EEPROM = 0x00,
WS_REGS1 = 0x01, // 0x01 is never used but it does function on a real wiimote:
WS_REGS2 = 0x02 I2C_BUS_ALT = 0x01,
I2C_BUS = 0x02,
}; };
enum WiimoteReadError enum class WiimoteErrorCode : u8
{ {
RDERR_WOREG = 7, SUCCESS = 0,
RDERR_NOMEM = 8 NACK = 7,
// TODO: Can there be a better name for this?
INVALID = 8,
}; };
constexpr u8 MAX_PAYLOAD = 23; constexpr u8 MAX_PAYLOAD = 23;

View File

@ -427,7 +427,7 @@ static_assert(sizeof(wm_status_report) == 6, "Wrong size");
struct wm_write_data struct wm_write_data
{ {
u8 rumble : 1; u8 rumble : 1;
u8 space : 2; // see WM_SPACE_* u8 space : 2;
u8 : 5; u8 : 5;
// A real wiimote ignores the i2c read/write bit. // A real wiimote ignores the i2c read/write bit.
u8 i2c_rw_ignored : 1; u8 i2c_rw_ignored : 1;
@ -451,7 +451,7 @@ static_assert(sizeof(wm_acknowledge) == 4, "Wrong size");
struct wm_read_data struct wm_read_data
{ {
u8 rumble : 1; u8 rumble : 1;
u8 space : 2; // see WM_SPACE_* u8 space : 2;
u8 : 5; u8 : 5;
// A real wiimote ignores the i2c read/write bit. // A real wiimote ignores the i2c read/write bit.
u8 i2c_rw_ignored : 1; u8 i2c_rw_ignored : 1;
@ -466,7 +466,7 @@ static_assert(sizeof(wm_read_data) == 6, "Wrong size");
struct wm_read_data_reply struct wm_read_data_reply
{ {
wm_buttons buttons; wm_buttons buttons;
u8 error : 4; // see WM_RDERR_* u8 error : 4;
u8 size_minus_one : 4; u8 size_minus_one : 4;
// big endian: // big endian:
u16 address; u16 address;

View File

@ -170,7 +170,7 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
The first two bytes are the core buttons data, The first two bytes are the core buttons data,
00 00 means nothing is pressed. 00 00 means nothing is pressed.
The last byte is the success code 00. */ The last byte is the success code 00. */
void Wiimote::SendAck(u8 report_id, u8 error_code) void Wiimote::SendAck(u8 report_id, WiimoteErrorCode error_code)
{ {
TypedHidPacket<wm_acknowledge> rpt; TypedHidPacket<wm_acknowledge> rpt;
rpt.type = HID_TYPE_DATA; rpt.type = HID_TYPE_DATA;
@ -181,7 +181,7 @@ void Wiimote::SendAck(u8 report_id, u8 error_code)
ack.buttons = m_status.buttons; ack.buttons = m_status.buttons;
ack.reportID = report_id; ack.reportID = report_id;
ack.errorID = error_code; ack.errorID = static_cast<u8>(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());
@ -266,11 +266,11 @@ void Wiimote::WriteData(const wm_write_data* const wd)
return; return;
} }
u8 error_code = 0; WiimoteErrorCode error_code = WiimoteErrorCode::SUCCESS;
switch (wd->space) switch (static_cast<WiimoteAddressSpace>(wd->space))
{ {
case WS_EEPROM: case WiimoteAddressSpace::EEPROM:
{ {
// Write to EEPROM // Write to EEPROM
@ -295,8 +295,8 @@ void Wiimote::WriteData(const wm_write_data* const wd)
} }
break; break;
case WS_REGS1: case WiimoteAddressSpace::I2C_BUS:
case WS_REGS2: case WiimoteAddressSpace::I2C_BUS_ALT:
{ {
// Write to Control Register // Write to Control Register
@ -306,7 +306,7 @@ void Wiimote::WriteData(const wm_write_data* const wd)
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)
error_code = 0x07; error_code = WiimoteErrorCode::NACK;
} }
} }
break; break;
@ -330,7 +330,7 @@ void Wiimote::ReadData(const wm_read_data* const rd)
} }
// Save the request and process it on the next "Update()" calls // Save the request and process it on the next "Update()" calls
m_read_request.space = rd->space; m_read_request.space = static_cast<WiimoteAddressSpace>(rd->space);
m_read_request.slave_address = rd->slave_address; m_read_request.slave_address = rd->slave_address;
m_read_request.address = Common::swap16(rd->address); m_read_request.address = Common::swap16(rd->address);
// A zero size request is just ignored, like on the real wiimote. // A zero size request is just ignored, like on the real wiimote.
@ -362,20 +362,24 @@ bool Wiimote::ProcessReadDataRequest()
rpt.report_id = RT_READ_DATA_REPLY; rpt.report_id = RT_READ_DATA_REPLY;
auto reply = &rpt.data; auto reply = &rpt.data;
reply->error = 0;
reply->buttons = m_status.buttons; reply->buttons = m_status.buttons;
reply->address = Common::swap16(m_read_request.address); reply->address = Common::swap16(m_read_request.address);
// Pre-fill with zeros in case of read-error or read < 16-bytes:
std::fill(std::begin(reply->data), std::end(reply->data), 0x00);
WiimoteErrorCode error_code = WiimoteErrorCode::SUCCESS;
switch (m_read_request.space) switch (m_read_request.space)
{ {
case WS_EEPROM: case WiimoteAddressSpace::EEPROM:
{ {
// Read from EEPROM // Read from EEPROM
if (m_read_request.address + m_read_request.size >= WIIMOTE_EEPROM_FREE_SIZE) if (m_read_request.address + m_read_request.size >= WIIMOTE_EEPROM_FREE_SIZE)
{ {
if (m_read_request.address + m_read_request.size > WIIMOTE_EEPROM_SIZE) if (m_read_request.address + m_read_request.size > WIIMOTE_EEPROM_SIZE)
{ {
PanicAlert("ReadData: address + size out of bounds"); ERROR_LOG(WIIMOTE, "ReadData: address + size out of bounds");
} }
// generate a read error, even if the start of the block is readable a real wiimote just sends // generate a read error, even if the start of the block is readable a real wiimote just sends
@ -386,8 +390,8 @@ bool Wiimote::ProcessReadDataRequest()
// read the calibration data at the beginning of Eeprom. I think this // read the calibration data at the beginning of Eeprom. I think this
// error is supposed to occur when we try to read above the freely // error is supposed to occur when we try to read above the freely
// usable space that ends at 0x16ff. // usable space that ends at 0x16ff.
INFO_LOG(WIIMOTE, "Responding with read error 8."); //INFO_LOG(WIIMOTE, "Responding with read error 8.");
reply->error = 0x08; error_code = WiimoteErrorCode::INVALID;
} }
else else
{ {
@ -410,8 +414,8 @@ bool Wiimote::ProcessReadDataRequest()
} }
break; break;
case WS_REGS1: case WiimoteAddressSpace::I2C_BUS:
case WS_REGS2: case WiimoteAddressSpace::I2C_BUS_ALT:
{ {
// Read from Control Register // Read from Control Register
@ -426,7 +430,7 @@ bool Wiimote::ProcessReadDataRequest()
// 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 @ 0x%x @ 0x%x (%d)", 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); m_read_request.slave_address, m_read_request.address, m_read_request.size);
reply->error = 0x07; error_code = WiimoteErrorCode::NACK;
} }
} }
break; break;
@ -436,13 +440,12 @@ bool Wiimote::ProcessReadDataRequest()
break; break;
} }
if (reply->error) if (WiimoteErrorCode::SUCCESS != error_code)
{ {
// Stop processing request on read error: // Stop processing request on read error:
m_read_request.size = 0; m_read_request.size = 0;
// TODO: what size does a real wiimote return on read error? // Real wiimote seems to set size to max value on read errors:
// it's 10 minus one (9) for some reason?? reply->size_minus_one = 0xf;
// reply->size_minus_one = 0;
} }
else else
{ {
@ -451,6 +454,8 @@ bool Wiimote::ProcessReadDataRequest()
m_read_request.size -= bytes_to_read; m_read_request.size -= bytes_to_read;
} }
reply->error = static_cast<u8>(error_code);
// 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(),
rpt.GetSize()); rpt.GetSize());

View File

@ -341,31 +341,25 @@ void Wiimote::Reset()
memset(&m_motion_plus_logic.reg_data, 0x00, sizeof(m_motion_plus_logic.reg_data)); memset(&m_motion_plus_logic.reg_data, 0x00, sizeof(m_motion_plus_logic.reg_data));
memcpy(&m_motion_plus_logic.reg_data.ext_identifier, motion_plus_id, sizeof(motion_plus_id)); memcpy(&m_motion_plus_logic.reg_data.ext_identifier, motion_plus_id, sizeof(motion_plus_id));
// calibration hackery // TODO: determine meaning of calibration data:
static const u8 c1[16] = {0x78, 0xd9, 0x78, 0x38, 0x77, 0x9d, 0x2f, 0x0c, static const u8 mplus_cdata[32] = {
0xcf, 0xf0, 0x31, 0xad, 0xc8, 0x0b, 0x5e, 0x39}; 0x78, 0xd9, 0x78, 0x38, 0x77, 0x9d, 0x2f, 0x0c, 0xcf, 0xf0, 0x31,
static const u8 c2[16] = {0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51, 0x33, 0x60, 0xad, 0xc8, 0x0b, 0x5e, 0x39, 0x6f, 0x81, 0x7b, 0x89, 0x78, 0x51,
0xc9, 0xf5, 0x37, 0xc1, 0x2d, 0xe9, 0x15, 0x8d}; 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, std::copy(std::begin(mplus_cdata), std::end(mplus_cdata),
//0xbb, 0xbb, 0x35, 0x49, 0x32, 0x04, 0xfd, 0x29, 0x1d, 0xc1, 0xb7, 0x5a, 0x7c, m_motion_plus_logic.reg_data.calibration_data);
//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, // TODO: determine the meaning behind this:
//0x49, 0x01, 0x7b, 0x2f, 0xb2, 0xc8, 0x5b, 0x12, 0x92, 0x47, 0xb8, 0x23 static const u8 mp_cert[64] = {
0x99, 0x1a, 0x07, 0x1b, 0x97, 0xf1, 0x11, 0x78, 0x0c, 0x42, 0x2b, 0x68, 0xdf,
//0xf0, 0x89, 0x3b, 0xf7, 0x1b, 0x6c, 0x92, 0x95, 0xa0, 0x05, 0xd4, 0x03, 0x82, 0x44, 0x38, 0x0d, 0x2b, 0x7e, 0xd6, 0x84, 0x84, 0x58, 0x65, 0xc9, 0xf2, 0x95,
//0x8e, 0xae, 0x73, 0x15, 0xc7, 0x95, 0xfb, 0xae, 0xee, 0xc0, 0x68, 0xbd, 0x49, 0xd9, 0xaf, 0xb6, 0xc4, 0x87, 0xd5, 0x18, 0xdb, 0x67, 0x3a, 0xc0, 0x71, 0xec,
//0xf5, 0x32, 0x48, 0x8d, 0x33, 0x00, 0x94, 0x32, 0xf5, 0xf1, 0x30, 0x66, 0x68, 0x3e, 0xf4, 0xe6, 0x7e, 0x35, 0xa3, 0x29, 0xf8, 0x1f, 0xc5, 0x7c, 0x3d, 0xb9,
//0x9e, 0xf3, 0xe5, 0xfa, 0x9b, 0xb6, 0xe3, 0x0b, 0xa8, 0x07, 0xd5, 0x25, 0x38, 0x56, 0x22, 0x95, 0x98, 0x8f, 0xfb, 0x66, 0x3e, 0x9a, 0xdd, 0xeb, 0x7e,
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(mp_cert), std::end(mp_cert), m_motion_plus_logic.reg_data.cert_data); std::copy(std::begin(mp_cert), std::end(mp_cert), m_motion_plus_logic.reg_data.cert_data);
// status // status
@ -399,7 +393,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)
@ -795,11 +789,12 @@ void Wiimote::UpdateIRData(bool use_accel)
} }
// IR data is read from offset 0x37 on real hardware // IR data is read from offset 0x37 on real hardware
u8* const data = m_camera_logic.reg_data.camera_data; auto& data = m_camera_logic.reg_data.camera_data;
// A maximum of 36 bytes. // A maximum of 36 bytes:
std::fill_n(data, sizeof(wm_ir_full) * 4, 0xff); std::fill(std::begin(data), std::end(data), 0xff);
// Fill report with valid data when full handshake was done // Fill report with valid data when full handshake was done
// TODO: kill magic number:
if (m_camera_logic.reg_data.data[0x30]) if (m_camera_logic.reg_data.data[0x30])
{ {
// ir mode // ir mode
@ -874,7 +869,8 @@ void Wiimote::UpdateIRData(bool use_accel)
break; break;
} }
default: default:
WARN_LOG(WIIMOTE, "Game is requesting IR data before setting IR mode."); // This is fairly normal, 0xff data is sent in this case:
// WARN_LOG(WIIMOTE, "Game is requesting IR data before setting IR mode.");
break; break;
} }
} }
@ -1009,7 +1005,13 @@ void Wiimote::Update()
m_ext_logic.Update(); m_ext_logic.Update();
m_motion_plus_logic.Update(); m_motion_plus_logic.Update();
m_i2c_bus.BusRead(ExtensionLogic::DEVICE_ADDR, 0x00, rptf.ext_size, feature_ptr); const u8 slave_addr = ExtensionLogic::DEVICE_ADDR;
if (rptf.ext_size != m_i2c_bus.BusRead(slave_addr, 0x00, rptf.ext_size, feature_ptr))
{
// Real wiimote seems to fill with 0xff on failed bus read
std::fill_n(feature_ptr, rptf.ext_size, 0xff);
}
feature_ptr += rptf.ext_size; feature_ptr += rptf.ext_size;
} }
@ -1231,14 +1233,14 @@ void Wiimote::MotionPlusLogic::Update()
if (0x0 == reg_data.cert_ready) if (0x0 == reg_data.cert_ready)
{ {
// Without sending this nonsense, inputs are unresponsive.. even regular buttons // 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 // 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 // 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}; // My M+ non-inside gives: 61,46,45,aa,0,2 or b6,46,45,9a,0,2
//std::copy(std::begin(init_data), std::end(init_data), data); static const u8 init_data[6] = {0x8e, 0xb0, 0x4f, 0x5a, 0xfc | 0x01, 0x02};
std::copy(std::begin(init_data), std::end(init_data), data);
reg_data.cert_ready = 0x2; reg_data.cert_ready = 0x2;
//return; return;
} }
if (0x2 == reg_data.cert_ready) if (0x2 == reg_data.cert_ready)
@ -1249,27 +1251,23 @@ void Wiimote::MotionPlusLogic::Update()
if (0x18 == reg_data.cert_ready) if (0x18 == reg_data.cert_ready)
{ {
// TODO: determine the meaning of this
const u8 mp_cert2[64] = { const u8 mp_cert2[64] = {
//0x39, 0x7c, 0xe9, 0x79, 0x15, 0x52, 0x0e, 0x4f, 0x28, 0x4d, 0x9d, 0x2c, 0xd3, 0xa5, 0x84, 0x1f, 0xd6, 0xbd, 0xdc, 0x7a, 0x4c, 0xf3, 0xc0, 0x24, 0xe0, 0x92,
//0x2a, 0x1a, 0x28, 0xa1, 0x25, 0x55, 0xb4, 0x4e, 0xb1, 0xd5, 0xae, 0x9d, 0x99, 0xef, 0x19, 0x28, 0x65, 0xe0, 0x62, 0x7c, 0x9b, 0x41, 0x6f, 0x12, 0xc3, 0xac,
//0x96, 0x96, 0x1d, 0x94, 0xd1, 0x22, 0xca, 0x1f, 0x51, 0x1d, 0x55, 0xee, 0x4d, 0x78, 0xe4, 0xfc, 0x6b, 0x7b, 0x0a, 0xb4, 0x50, 0xd6, 0xf2, 0x45, 0xf7, 0x93,
//0x58, 0x97, 0xd4, 0xb9, 0x3f, 0x0d, 0x0a, 0x04, 0xd8, 0x01, 0x21, 0xf9, 0x17, 0x04, 0xaf, 0xf2, 0xb7, 0x26, 0x94, 0xee, 0xad, 0x92, 0x05, 0x6d, 0xe5, 0xc6,
//0x45, 0xe4, 0x42, 0x58, 0x3f, 0x7c, 0x3c, 0x2c, 0x3a, 0xcd, 0xbd, 0x27, 0x3b, 0xd6, 0x36, 0xdc, 0xa5, 0x69, 0x0f, 0xc8, 0x99, 0xf2, 0x1c, 0x4e, 0x0d,
//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); std::copy(std::begin(mp_cert2), std::end(mp_cert2), reg_data.cert_data);
if (0x01 != reg_data.cert_enable)
{
PanicAlert("M+ Failure! Game requested cert2 with value other than 0x01. M+ will disconnect "
"shortly unfortunately. Reconnect wiimote and hope for the best.");
}
// A real wiimote takes about 2 seconds to reach this state: // A real wiimote takes about 2 seconds to reach this state:
reg_data.cert_ready = 0x1a; reg_data.cert_ready = 0x1a;
INFO_LOG(WIIMOTE, "M+ cert 2 ready!", reg_data.cert_ready); INFO_LOG(WIIMOTE, "M+ cert 2 ready!", reg_data.cert_ready);
@ -1288,23 +1286,32 @@ void Wiimote::MotionPlusLogic::Update()
// If an extension is not attached the data is always mplus data // If an extension is not attached the data is always mplus data
// even when passthrough is enabled // even when passthrough is enabled
switch (GetPassthroughMode()) // Real M+ seems to only ever read 6 bytes from the extension.
// Data after 6 bytes seems to be zero-filled.
// After reading, the real M+ uses that data for the next frame.
// But we are going to use it for the current frame instead.
const int ext_amt = 6;
// Always read from 0x52 @ 0x00:
const u8 ext_slave = ACTIVE_DEVICE_ADDR;
const u8 ext_addr = 0x00;
// Try to alternate between M+ and EXT data:
mplus_data.is_mp_data ^= true;
// If the last frame had M+ data try to send some non-M+ data:
if (!mplus_data.is_mp_data)
{ {
case PassthroughMode::PASSTHROUGH_DISABLED: switch (GetPassthroughMode())
{
mplus_data.is_mp_data = true;
break;
}
case PassthroughMode::PASSTHROUGH_NUNCHUK:
{
// If we sent mplus data last time now we will try to send ext data.
if (mplus_data.is_mp_data)
{ {
// The real mplus seems to only ever read 6 bytes from the extension case PassthroughMode::PASSTHROUGH_DISABLED:
// bytes after 6 seem to be zero filled {
// The real hardware uses these 6 bytes for the next frame, // Passthrough disabled, always send M+ data:
// but we aren't going to do that mplus_data.is_mp_data = true;
if (6 == i2c_bus.BusRead(ACTIVE_DEVICE_ADDR, 0x00, 6, data)) break;
}
case PassthroughMode::PASSTHROUGH_NUNCHUK:
{
if (ext_amt == i2c_bus.BusRead(ext_slave, ext_addr, ext_amt, data))
{ {
// Passthrough data modifications via wiibrew.org // Passthrough data modifications via wiibrew.org
// Data passing through drops the least significant bit of the three accelerometer values // Data passing through drops the least significant bit of the three accelerometer values
@ -1322,42 +1329,51 @@ void Wiimote::MotionPlusLogic::Update()
// Bit 0 and 1 of byte 5 contain a M+ flag and a zero bit which is set below. // 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;
} }
else
{
// Read failed (extension unplugged), Send M+ data instead
mplus_data.is_mp_data = true;
}
break;
} }
break; case PassthroughMode::PASSTHROUGH_CLASSIC:
}
case PassthroughMode::PASSTHROUGH_CLASSIC:
{
// If we sent mplus data last time now we will try to send ext data.
if (mplus_data.is_mp_data)
{ {
if (6 == i2c_bus.BusRead(ACTIVE_DEVICE_ADDR, 0x00, 6, data)) if (ext_amt == i2c_bus.BusRead(ext_slave, ext_addr, ext_amt, data))
{ {
// Passthrough data modifications via wiibrew.org // Passthrough data modifications via wiibrew.org
// 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. // 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;
} }
else
{
// Read failed (extension unplugged), Send M+ data instead
mplus_data.is_mp_data = true;
}
break;
}
default:
PanicAlert("MotionPlus unknown passthrough-mode %d", GetPassthroughMode());
break;
} }
break;
}
default:
PanicAlert("MotionPlus unknown passthrough-mode %d", GetPassthroughMode());
break;
} }
// If the above logic determined this should be mp data, update it here // If the above logic determined this should be M+ data, update it here
if (mplus_data.is_mp_data) if (mplus_data.is_mp_data)
{ {
// Wiibrew: "While the Wiimote is still, the values will be about 0x1F7F (8,063)" // Wiibrew: "While the Wiimote is still, the values will be about 0x1F7F (8,063)"
u16 yaw_value = 0x1F7F; // high-velocity range should be about +/- 1500 or 1600 dps
u16 roll_value = 0x1F7F; // low-velocity range should be about +/- 400 dps
u16 pitch_value = 0x1F7F; // Wiibrew implies it shoould be +/- 595 and 2700
u16 yaw_value = 0x2000;
u16 roll_value = 0x2000;
u16 pitch_value = 0x2000;
mplus_data.yaw_slow = 1; mplus_data.yaw_slow = 1;
mplus_data.roll_slow = 1; mplus_data.roll_slow = 1;
@ -1372,14 +1388,6 @@ void Wiimote::MotionPlusLogic::Update()
mplus_data.yaw2 = yaw_value >> 8; mplus_data.yaw2 = yaw_value >> 8;
mplus_data.roll2 = roll_value >> 8; mplus_data.roll2 = roll_value >> 8;
mplus_data.pitch2 = 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();

View File

@ -9,6 +9,7 @@
#include <string> #include <string>
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h"
#include "Core/HW/WiimoteCommon/WiimoteReport.h" #include "Core/HW/WiimoteCommon/WiimoteReport.h"
#include "Core/HW/WiimoteEmu/Encryption.h" #include "Core/HW/WiimoteEmu/Encryption.h"
@ -597,6 +598,7 @@ private:
// address 0xF1 // address 0xF1
u8 cert_enable; u8 cert_enable;
// Conduit 2 writes 1 byte to 0xf2 on calibration screen
u8 unknown_0xf2[5]; u8 unknown_0xf2[5];
// address 0xf7 // address 0xf7
@ -696,6 +698,11 @@ private:
// 0x1a is final value // 0x1a is final value
reg_data.cert_ready = 0x18; reg_data.cert_ready = 0x18;
} }
// TODO: kill magic number
else if (0xf2 == addr)
{
INFO_LOG(WIIMOTE, "M+ calibration ?? : 0x%x", reg_data.unknown_0xf2[0]);
}
return result; return result;
} }
@ -721,6 +728,10 @@ private:
// TODO: kill magic number // TODO: kill magic number
//reg_data.cert_ready = 0x2; //reg_data.cert_ready = 0x2;
// A real M+ is unresponsive on the bus for some time during activation
// Reads fail to ack and ext data gets filled with 0xff for a frame or two
// I don't think we need to emulate that.
// TODO: activate extension and disable encrption // TODO: activate extension and disable encrption
// also do this if an extension is attached after activation. // also do this if an extension is attached after activation.
std::array<u8, 1> data = {0x55}; std::array<u8, 1> data = {0x55};
@ -753,7 +764,7 @@ private:
} m_motion_plus_logic; } m_motion_plus_logic;
void ReportMode(const wm_report_mode* dr); void ReportMode(const wm_report_mode* dr);
void SendAck(u8 report_id, u8 error_code = 0x0); void SendAck(u8 report_id, WiimoteErrorCode error_code = WiimoteErrorCode::SUCCESS);
void RequestStatus(const wm_request_status* rs = nullptr); void RequestStatus(const wm_request_status* rs = nullptr);
void ReadData(const wm_read_data* rd); void ReadData(const wm_read_data* rd);
void WriteData(const wm_write_data* wd); void WriteData(const wm_write_data* wd);
@ -812,7 +823,7 @@ private:
struct ReadRequest struct ReadRequest
{ {
u8 space; WiimoteAddressSpace space;
u8 slave_address; u8 slave_address;
u16 address; u16 address;
u16 size; u16 size;