Stage1: Introducing MotionPlus as emulated extension, allowing us to boot games that require the MotionPlus itself.

I also already implemented most of the needed data structures and datareport handling for the motionplus-nunchuk passthrough mode, which I'll add up next as well.

Wii Sports Resort is now bootable by just using an emulated wiimote (only working under the old wiimote plugin atm,
I asked billiard to port my commit into his plugin since he knows his plugin better than me and its less work for him than for me,
I kept most parts of my code in modules to simplify that task).

Upcoming stage2: Faking the motionplus on the fly on real wiimotes, that means you will be able to play, e.g.  Redsteel2 with a real wiimote and nunchuk or wii sports resort with just your real wiimote.
and nunchuk, but w/o the need of having a real motionpluscontroller connected. The new Zelda 2010 will benefit by that, since it will require a motionplus controller.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5438 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
snzgoo 2010-05-07 22:39:06 +00:00
parent f6ce87765f
commit 7742e1a6dd
11 changed files with 530 additions and 77 deletions

View File

@ -167,7 +167,6 @@ void WiimoteBasicConfigDialog::CreateGUIControls()
m_UprightWiimote[i]->SetToolTip(wxT("Treat the upright position as neutral")); m_UprightWiimote[i]->SetToolTip(wxT("Treat the upright position as neutral"));
m_WiiMotionPlusConnected[i] = new wxCheckBox(m_Controller[i], IDC_MOTIONPLUSCONNECTED, wxT("Wii Motion Plus Connected")); m_WiiMotionPlusConnected[i] = new wxCheckBox(m_Controller[i], IDC_MOTIONPLUSCONNECTED, wxT("Wii Motion Plus Connected"));
m_WiiMotionPlusConnected[i]->Enable(false);
m_Extension[i] = new wxChoice(m_Controller[i], IDC_EXTCONNECTED, wxDefaultPosition, wxDefaultSize, arrayStringFor_extension, 0, wxDefaultValidator); m_Extension[i] = new wxChoice(m_Controller[i], IDC_EXTCONNECTED, wxDefaultPosition, wxDefaultSize, arrayStringFor_extension, 0, wxDefaultValidator);
@ -382,7 +381,7 @@ void WiimoteBasicConfigDialog::DoUseReal()
// Are we using an extension now? The report that it's removed, then reconnected. // Are we using an extension now? The report that it's removed, then reconnected.
bool UsingExtension = false; bool UsingExtension = false;
if (WiiMoteEmu::WiiMapping[m_Page].iExtensionConnected != WiiMoteEmu::EXT_NONE) if ((WiiMoteEmu::WiiMapping[m_Page].iExtensionConnected != WiiMoteEmu::EXT_NONE) || ( WiiMoteEmu::WiiMapping[m_Page].bMotionPlusConnected))
UsingExtension = true; UsingExtension = true;
DEBUG_LOG(WIIMOTE, "DoUseReal() Connect extension: %i", !UsingExtension); DEBUG_LOG(WIIMOTE, "DoUseReal() Connect extension: %i", !UsingExtension);
@ -466,6 +465,11 @@ void WiimoteBasicConfigDialog::GeneralSettingsChanged(wxCommandEvent& event)
break; break;
case IDC_MOTIONPLUSCONNECTED: case IDC_MOTIONPLUSCONNECTED:
WiiMoteEmu::WiiMapping[m_Page].bMotionPlusConnected = m_WiiMotionPlusConnected[m_Page]->IsChecked(); WiiMoteEmu::WiiMapping[m_Page].bMotionPlusConnected = m_WiiMotionPlusConnected[m_Page]->IsChecked();
DoExtensionConnectedDisconnected(WiiMoteEmu::EXT_NONE);
if (g_EmulatorRunning)
SLEEP(25);
WiiMoteEmu::UpdateExtRegisterBlocks(m_Page);
DoExtensionConnectedDisconnected();
break; break;
case IDC_WIIAUTORECONNECT: case IDC_WIIAUTORECONNECT:
WiiMoteEmu::WiiMapping[m_Page].bWiiAutoReconnect = m_WiiAutoReconnect[m_Page]->IsChecked(); WiiMoteEmu::WiiMapping[m_Page].bWiiAutoReconnect = m_WiiAutoReconnect[m_Page]->IsChecked();

View File

@ -755,7 +755,7 @@ void WiimotePadConfigDialog::CreatePadGUIControls()
m_gWiimote[i]->Add(m_sWmVertRight[i], 0, (wxLEFT | wxRIGHT | wxDOWN), 1); m_gWiimote[i]->Add(m_sWmVertRight[i], 0, (wxLEFT | wxRIGHT | wxDOWN), 1);
// Extension Mapping // Extension Mapping
if(WiiMoteEmu::WiiMapping[i].iExtensionConnected == WiiMoteEmu::EXT_NUNCHUCK) if(WiiMoteEmu::WiiMapping[i].iExtensionConnected == WiiMoteEmu::EXT_NUNCHUK)
{ {
// Stick controls // Stick controls
m_NunchuckTextStick[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Stick")); m_NunchuckTextStick[i] = new wxStaticText(m_Controller[i], wxID_ANY, wxT("Stick"));
@ -763,11 +763,11 @@ void WiimotePadConfigDialog::CreatePadGUIControls()
for (int x = 0; x <= IDB_NC_SHAKE - IDB_NC_Z; x++) for (int x = 0; x <= IDB_NC_SHAKE - IDB_NC_Z; x++)
{ {
m_statictext_NunChuck[x][i] = new wxStaticText(m_Controller[i], wxID_ANY, ncText[x]); m_statictext_Nunchuk[x][i] = new wxStaticText(m_Controller[i], wxID_ANY, ncText[x]);
m_Button_NunChuck[x][i] = new wxButton(m_Controller[i], x + IDB_NC_Z, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH)); m_Button_NunChuck[x][i] = new wxButton(m_Controller[i], x + IDB_NC_Z, wxEmptyString, wxDefaultPosition, wxSize(BtW, BtH));
m_Button_NunChuck[x][i]->SetFont(m_SmallFont); m_Button_NunChuck[x][i]->SetFont(m_SmallFont);
m_Sizer_NunChuck[x][i] = new wxBoxSizer(wxHORIZONTAL); m_Sizer_NunChuck[x][i] = new wxBoxSizer(wxHORIZONTAL);
m_Sizer_NunChuck[x][i]->Add(m_statictext_NunChuck[x][i], 0, (wxUP), 4); m_Sizer_NunChuck[x][i]->Add(m_statictext_Nunchuk[x][i], 0, (wxUP), 4);
m_Sizer_NunChuck[x][i]->Add(m_Button_NunChuck[x][i], 0, (wxLEFT), 2); m_Sizer_NunChuck[x][i]->Add(m_Button_NunChuck[x][i], 0, (wxLEFT), 2);
} }
@ -895,7 +895,7 @@ void WiimotePadConfigDialog::CreatePadGUIControls()
m_sHorizControllerMapping[i]->Add(m_gWiimote[i], 0, (wxLEFT), 5); m_sHorizControllerMapping[i]->Add(m_gWiimote[i], 0, (wxLEFT), 5);
switch(WiiMoteEmu::WiiMapping[i].iExtensionConnected) switch(WiiMoteEmu::WiiMapping[i].iExtensionConnected)
{ {
case WiiMoteEmu::EXT_NUNCHUCK: case WiiMoteEmu::EXT_NUNCHUK:
m_sHorizControllerMapping[i]->Add(m_gNunchuck[i], 0, (wxLEFT), 5); m_sHorizControllerMapping[i]->Add(m_gNunchuck[i], 0, (wxLEFT), 5);
break; break;
case WiiMoteEmu::EXT_CLASSIC_CONTROLLER: case WiiMoteEmu::EXT_CLASSIC_CONTROLLER:
@ -1074,7 +1074,7 @@ void WiimotePadConfigDialog::UpdateGUI()
m_Button_Wiimote[x][m_Page]->SetLabel(wxString::FromAscii( m_Button_Wiimote[x][m_Page]->SetLabel(wxString::FromAscii(
InputCommon::VKToString(WiiMoteEmu::WiiMapping[m_Page].Button[x + WiiMoteEmu::EWM_A]).c_str())); InputCommon::VKToString(WiiMoteEmu::WiiMapping[m_Page].Button[x + WiiMoteEmu::EWM_A]).c_str()));
} }
if(WiiMoteEmu::WiiMapping[m_Page].iExtensionConnected == WiiMoteEmu::EXT_NUNCHUCK) if(WiiMoteEmu::WiiMapping[m_Page].iExtensionConnected == WiiMoteEmu::EXT_NUNCHUK)
{ {
m_NunchuckComboStick[m_Page]->SetSelection(WiiMoteEmu::WiiMapping[m_Page].Stick.NC); m_NunchuckComboStick[m_Page]->SetSelection(WiiMoteEmu::WiiMapping[m_Page].Stick.NC);
for (int x = 0; x <= IDB_NC_SHAKE - IDB_NC_Z; x++) for (int x = 0; x <= IDB_NC_SHAKE - IDB_NC_Z; x++)
@ -1104,7 +1104,7 @@ void WiimotePadConfigDialog::UpdateGUI()
InputCommon::XKeyToString(WiiMoteEmu::WiiMapping[m_Page].Button[x + WiiMoteEmu::EWM_A], keyStr); InputCommon::XKeyToString(WiiMoteEmu::WiiMapping[m_Page].Button[x + WiiMoteEmu::EWM_A], keyStr);
m_Button_Wiimote[x][m_Page]->SetLabel(wxString::FromAscii(keyStr)); m_Button_Wiimote[x][m_Page]->SetLabel(wxString::FromAscii(keyStr));
} }
if(WiiMoteEmu::WiiMapping[m_Page].iExtensionConnected == WiiMoteEmu::EXT_NUNCHUCK) if(WiiMoteEmu::WiiMapping[m_Page].iExtensionConnected == WiiMoteEmu::EXT_NUNCHUK)
{ {
m_NunchuckComboStick[m_Page]->SetSelection(WiiMoteEmu::WiiMapping[m_Page].Stick.NC); m_NunchuckComboStick[m_Page]->SetSelection(WiiMoteEmu::WiiMapping[m_Page].Stick.NC);
for (int x = 0; x <= IDB_NC_SHAKE - IDB_NC_Z; x++) for (int x = 0; x <= IDB_NC_SHAKE - IDB_NC_Z; x++)

View File

@ -257,7 +257,7 @@ class WiimotePadConfigDialog : public wxDialog
*m_tTriggerSource[MAX_WIIMOTES], *m_tTriggerSource[MAX_WIIMOTES],
*m_statictext_Analog[IDB_TRIGGER_R - IDB_ANALOG_LEFT_X + 1][MAX_WIIMOTES], *m_statictext_Analog[IDB_TRIGGER_R - IDB_ANALOG_LEFT_X + 1][MAX_WIIMOTES],
*m_statictext_Wiimote[IDB_WM_SHAKE - IDB_WM_A + 1][MAX_WIIMOTES], *m_statictext_Wiimote[IDB_WM_SHAKE - IDB_WM_A + 1][MAX_WIIMOTES],
*m_statictext_NunChuck[IDB_NC_SHAKE - IDB_NC_Z + 1][MAX_WIIMOTES], *m_statictext_Nunchuk[IDB_NC_SHAKE - IDB_NC_Z + 1][MAX_WIIMOTES],
*m_statictext_Classic[IDB_CC_RD - IDB_CC_A + 1][MAX_WIIMOTES], *m_statictext_Classic[IDB_CC_RD - IDB_CC_A + 1][MAX_WIIMOTES],
*m_statictext_GH3[IDB_GH3_STRUM_DOWN - IDB_GH3_GREEN + 1][MAX_WIIMOTES], *m_statictext_GH3[IDB_GH3_STRUM_DOWN - IDB_GH3_GREEN + 1][MAX_WIIMOTES],
*m_NunchuckTextStick[5], *m_NunchuckTextStick[5],

View File

@ -196,7 +196,7 @@ void SendReportCoreAccelExt16(u16 _channelID)
FillReportAcc(pReport->a); FillReportAcc(pReport->a);
#endif #endif
if(WiiMapping[g_ID].iExtensionConnected == EXT_NUNCHUCK) if(WiiMapping[g_ID].iExtensionConnected == EXT_NUNCHUK)
{ {
#if defined(HAVE_WX) && HAVE_WX #if defined(HAVE_WX) && HAVE_WX
FillReportExtension(pReport->ext); FillReportExtension(pReport->ext);
@ -233,38 +233,53 @@ void SendReportCoreAccelIr10Ext(u16 _channelID)
memset(pReport, 0, sizeof(wm_report_core_accel_ir10_ext6)); memset(pReport, 0, sizeof(wm_report_core_accel_ir10_ext6));
// Make a classic extension struct // Make a classic extension struct
wm_classic_extension _ext;
wm_GH3_extension _GH3_ext;
memset(&_ext, 0, sizeof(wm_classic_extension));
memset(&_GH3_ext, 0, sizeof(wm_GH3_extension));
#if defined(HAVE_WX) && HAVE_WX #if defined(HAVE_WX) && HAVE_WX
FillReportInfo(pReport->c); FillReportInfo(pReport->c);
FillReportAcc(pReport->a); FillReportAcc(pReport->a);
FillReportIRBasic(pReport->ir[0], pReport->ir[1]); FillReportIRBasic(pReport->ir[0], pReport->ir[1]);
#endif if ((WiiMapping[g_ID].bMotionPlusConnected) && (( WiiMapping[g_ID].iExtensionConnected == EXT_NUNCHUK ) || (WiiMapping[g_ID].iExtensionConnected == EXT_NONE)) )
if(WiiMapping[g_ID].iExtensionConnected == EXT_NUNCHUCK)
{ {
#if defined(HAVE_WX) && HAVE_WX if(WiiMapping[g_ID].iExtensionConnected == EXT_NUNCHUK)
FillReportExtension(pReport->ext); {
#endif FillReportMotionPlus(pReport->ext, true);
}
else if(WiiMapping[g_ID].iExtensionConnected == EXT_CLASSIC_CONTROLLER)
{
#if defined(HAVE_WX) && HAVE_WX
FillReportClassicExtension(_ext);
#endif
// Copy _ext to pReport->ext
memcpy(&pReport->ext, &_ext, sizeof(_ext));
}
else if(WiiMapping[g_ID].iExtensionConnected == EXT_GUITARHERO)
{
#if defined(HAVE_WX) && HAVE_WX
FillReportGuitarHero3Extension(_GH3_ext);
#endif
memcpy(&pReport->ext, &_GH3_ext, sizeof(_GH3_ext));
}
}
else if (WiiMapping[g_ID].iExtensionConnected == EXT_NONE)
{
FillReportMotionPlus(pReport->ext, false);
}
}
else {
if(WiiMapping[g_ID].iExtensionConnected == EXT_NUNCHUK)
{
FillReportExtension(pReport->ext);
}
else if(WiiMapping[g_ID].iExtensionConnected == EXT_CLASSIC_CONTROLLER)
{
wm_classic_extension _ext;
memset(&_ext, 0, sizeof(wm_classic_extension));
FillReportClassicExtension(_ext);
// Copy _ext to pReport->ext
memcpy(&pReport->ext, &_ext, sizeof(_ext));
}
else if(WiiMapping[g_ID].iExtensionConnected == EXT_GUITARHERO)
{
wm_GH3_extension _GH3_ext;
memset(&_GH3_ext, 0, sizeof(wm_GH3_extension));
FillReportGuitarHero3Extension(_GH3_ext);
memcpy(&pReport->ext, &_GH3_ext, sizeof(_GH3_ext));
}
}
#endif
INFO_LOG(WIIMOTE, " SendReportCoreAccelIr10Ext(0x37)"); INFO_LOG(WIIMOTE, " SendReportCoreAccelIr10Ext(0x37)");
DEBUG_LOG(WIIMOTE, " Channel: %04x", _channelID); DEBUG_LOG(WIIMOTE, " Channel: %04x", _channelID);
DEBUG_LOG(WIIMOTE, " Size: %08x", Offset); DEBUG_LOG(WIIMOTE, " Size: %08x", Offset);

View File

@ -44,12 +44,16 @@ u8 g_IRClock[MAX_WIIMOTES];
u8 g_IR[MAX_WIIMOTES]; u8 g_IR[MAX_WIIMOTES];
u8 g_Leds[MAX_WIIMOTES]; u8 g_Leds[MAX_WIIMOTES];
u8 g_Speaker[MAX_WIIMOTES]; u8 g_Speaker[MAX_WIIMOTES];
u8 g_MotionPlus[MAX_WIIMOTES];
u8 g_SpeakerMute[MAX_WIIMOTES]; u8 g_SpeakerMute[MAX_WIIMOTES];
int g_MotionPlusReadError[MAX_WIIMOTES];
u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE]; u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
int g_ID; // Current refreshing Wiimote int g_ID; // Current refreshing Wiimote
bool g_ReportingAuto[MAX_WIIMOTES]; // Auto report or passive report bool g_ReportingAuto[MAX_WIIMOTES]; // Auto report or passive report
bool g_MotionPlusConnected[MAX_WIIMOTES]; //MotionPlusinitiated
bool g_InterleavedData[MAX_WIIMOTES]; //sending alternated data packets from the nunchuk/motionplus
u8 g_ReportingMode[MAX_WIIMOTES]; // The reporting mode and channel id u8 g_ReportingMode[MAX_WIIMOTES]; // The reporting mode and channel id
u16 g_ReportingChannel[MAX_WIIMOTES]; u16 g_ReportingChannel[MAX_WIIMOTES];

View File

@ -86,14 +86,17 @@ extern u8 g_IRClock[MAX_WIIMOTES];
extern u8 g_IR[MAX_WIIMOTES]; extern u8 g_IR[MAX_WIIMOTES];
extern u8 g_Leds[MAX_WIIMOTES]; extern u8 g_Leds[MAX_WIIMOTES];
extern u8 g_Speaker[MAX_WIIMOTES]; extern u8 g_Speaker[MAX_WIIMOTES];
extern u8 g_MotionPlus[MAX_WIIMOTES];
extern u8 g_SpeakerMute[MAX_WIIMOTES]; extern u8 g_SpeakerMute[MAX_WIIMOTES];
extern int g_MotionPlusReadError[MAX_WIIMOTES];
extern u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE]; extern u8 g_RegExtTmp[WIIMOTE_REG_EXT_SIZE];
extern int g_ID; extern int g_ID;
extern bool g_ReportingAuto[MAX_WIIMOTES]; extern bool g_ReportingAuto[MAX_WIIMOTES];
extern u8 g_ReportingMode[MAX_WIIMOTES]; extern u8 g_ReportingMode[MAX_WIIMOTES];
extern u16 g_ReportingChannel[MAX_WIIMOTES]; extern u16 g_ReportingChannel[MAX_WIIMOTES];
extern bool g_InterleavedData[MAX_WIIMOTES];
extern wiimote_key g_ExtKey[MAX_WIIMOTES]; // extension encryption key extern wiimote_key g_ExtKey[MAX_WIIMOTES]; // extension encryption key
extern bool g_Encryption; extern bool g_Encryption;
@ -113,7 +116,24 @@ static const u8 EepromData_16D0[] = {
0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99, 0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99,
0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13 0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13
}; };
static const u8 motionplus_register[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x79, 0x83, 0x73, 0x54, 0x72, 0xE8, 0x30, 0xC3, 0xCC, 0x4A, 0x34, 0xFC, 0xC8, 0x4F, 0xCC, 0x5B,
0x77, 0x49, 0x75, 0xA4, 0x73, 0x9A, 0x35, 0x52, 0xCA, 0x22, 0x37, 0x26, 0x2D, 0xE5, 0xB5, 0xA2,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x78, 0x76, 0xDD, 0xF5, 0x6A, 0x3C, 0xCF, 0xF7, 0x2A, 0x0E, 0x32, 0xEE, 0x82, 0xFE, 0x2E, 0xFD,
0x19, 0xE7, 0x0A, 0xCA, 0x67, 0x3B, 0x3A, 0x75, 0xF6, 0x45, 0x55, 0x8E, 0x9D, 0x33, 0xCC, 0xEA,
0x6E, 0x52, 0xC6, 0xC6, 0x16, 0x9B, 0xEE, 0x12, 0x2E, 0x3F, 0x77, 0xB1, 0xA1, 0x80, 0x0B, 0x0E,
0xC2, 0x25, 0x05, 0xEA, 0xC3, 0x2F, 0x85, 0x1E, 0x31, 0x53, 0x74, 0xC7, 0xF1, 0x93, 0xF1, 0x2D,
0xC1, 0x6D, 0x84, 0x2A, 0xD8, 0x6F, 0x8A, 0xE5, 0x2D, 0x3B, 0x7B, 0xCC, 0xD2, 0x59, 0xD5, 0xD1,
0x9F, 0x5B, 0x6F, 0xAE, 0x82, 0xDE, 0xEA, 0xC3, 0x73, 0x42, 0x06, 0xA9, 0x77, 0xFF, 0x61, 0xA8,
0x1A, 0x70, 0xE4, 0x16, 0x90, 0x7A, 0x80, 0xF7, 0x79, 0x4B, 0x41, 0x18, 0x82, 0x6C, 0x62, 0x1A,
0x3B, 0xBF, 0xFC, 0xFF, 0x2C, 0xF2, 0x32, 0x97, 0xB8, 0x2F, 0x17, 0xE7, 0xBD, 0x35, 0x1D, 0x0A,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x55, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x10, 0xff, 0xff, 0x00, 0x00, 0xa6, 0x20, 0x00, 0x05
};
/* Default calibration for the nunchuck. It should be written to 0x20 - 0x3f of the /* Default calibration for the nunchuck. It should be written to 0x20 - 0x3f of the
extension register. 0x80 is the neutral x and y accelerators and 0xb3 is the extension register. 0x80 is the neutral x and y accelerators and 0xb3 is the
@ -133,6 +153,12 @@ static const u8 wireless_nunchuck_calibration[] =
255, 0, 125, 255, 255, 0, 125, 255,
0, 126, 0xed, 0x43 0, 126, 0xed, 0x43
}; };
/* Default calibration for the motion plus*/
static const u8 motion_plus_calibration[] =
{
0x79, 0xbe, 0x77, 0x5a, 0x77, 0x38, 0x2f, 0x90, 0xcd, 0x3b, 0x2f, 0xfd, 0xc8, 0x29, 0x9c, 0x75,
0x7d, 0xd4, 0x78, 0xef, 0x78, 0x8a, 0x35, 0xa6, 0xc9, 0x9b, 0x33, 0x50, 0x2d, 0x00, 0xbd, 0x23
};
/* Classic Controller calibration */ /* Classic Controller calibration */
static const u8 classic_calibration[] = static const u8 classic_calibration[] =
@ -146,6 +172,11 @@ static const u8 nunchuck_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x00, 0x00 };
static const u8 classic_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x01 }; static const u8 classic_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x01 };
static const u8 gh3glp_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x03 }; static const u8 gh3glp_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x03 };
static const u8 ghwtdrums_id[] = { 0x01, 0x00, 0xa4, 0x20, 0x01, 0x03 }; static const u8 ghwtdrums_id[] = { 0x01, 0x00, 0xa4, 0x20, 0x01, 0x03 };
static const u8 wbb_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x4, 0x02 };
static const u8 motionplus_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x04, 0x05 };
static const u8 motionplusnunchuk_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x05, 0x05 };
//initial control packet for datatransfers over 0x37 reports
static const u8 motionpluscheck_id[] = { 0xa3, 0x62, 0x45, 0xaa, 0x04, 0x02};
// The id for nothing inserted // The id for nothing inserted
static const u8 nothing_id[] = { 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e }; static const u8 nothing_id[] = { 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e };
// The id for a partially inserted extension // The id for a partially inserted extension
@ -155,9 +186,10 @@ static const u8 partially_id[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
enum EExtensionType enum EExtensionType
{ {
EXT_NONE = 0, EXT_NONE = 0,
EXT_NUNCHUCK, EXT_NUNCHUK,
EXT_CLASSIC_CONTROLLER, EXT_CLASSIC_CONTROLLER,
EXT_GUITARHERO, EXT_GUITARHERO,
EXT_WBB,
}; };
enum EInputType enum EInputType

View File

@ -416,6 +416,8 @@ void ResetVariables()
for (int i = 0; i < MAX_WIIMOTES; i++) for (int i = 0; i < MAX_WIIMOTES; i++)
{ {
g_ReportingAuto[i] = false; g_ReportingAuto[i] = false;
g_MotionPlusReadError[i] = 0;
g_InterleavedData[i] = false;
g_ReportingMode[i] = 0; g_ReportingMode[i] = 0;
g_ReportingChannel[i] = 0; g_ReportingChannel[i] = 0;
WiiMapping[i].Motion.TiltWM.Shake = 0; WiiMapping[i].Motion.TiltWM.Shake = 0;
@ -492,25 +494,56 @@ void InitCalibration()
// Update the extension calibration values with our default values // Update the extension calibration values with our default values
void UpdateExtRegisterBlocks(int Slot) void UpdateExtRegisterBlocks(int Slot)
{ {
// Copy extension id and calibration to its register if (WiiMapping[Slot].bMotionPlusConnected)
if(WiiMapping[Slot].iExtensionConnected == EXT_NUNCHUCK)
{ {
memcpy(g_RegExt[Slot] + 0x20, nunchuck_calibration, sizeof(nunchuck_calibration)); // Copy extension id and calibration to its register
memcpy(g_RegExt[Slot] + 0x30, nunchuck_calibration, sizeof(nunchuck_calibration)); if (WiiMapping[Slot].iExtensionConnected == EXT_NONE)
memcpy(g_RegExt[Slot] + 0xfa, nunchuck_id, sizeof(nunchuck_id)); {
} memset(g_RegExt[Slot],0,sizeof(g_RegExt[0]));
else if(WiiMapping[Slot].iExtensionConnected == EXT_CLASSIC_CONTROLLER) memcpy(g_RegMotionPlus[Slot], motionplus_register, sizeof(motionplus_register));
{ memcpy(g_RegMotionPlus[Slot] + 0x20, motion_plus_calibration, sizeof(motion_plus_calibration)); //reg 32bytes 0x20-3f;
memcpy(g_RegExt[Slot] + 0x20, classic_calibration, sizeof(classic_calibration)); g_MotionPlus[Slot] = 0;
memcpy(g_RegExt[Slot] + 0x30, classic_calibration, sizeof(classic_calibration)); //memcpy(g_RegMotionPlus[Slot] + 0xfa, motionplus_id, sizeof(motionplus_id));
memcpy(g_RegExt[Slot] + 0xfa, classic_id, sizeof(classic_id)); }
} else if(WiiMapping[Slot].iExtensionConnected == EXT_NUNCHUK)
else if(WiiMapping[Slot].iExtensionConnected == EXT_GUITARHERO) {
{ memset(g_RegMotionPlus[Slot],0,sizeof(g_RegExt[0]));
// TODO get the correct values here memcpy(g_RegMotionPlus[Slot], motionplus_register, sizeof(motionplus_register));
memcpy(g_RegExt[Slot] + 0x20, classic_calibration, sizeof(classic_calibration)); memcpy(g_RegMotionPlus[Slot] + 0x20, motion_plus_calibration, sizeof(motion_plus_calibration)); //reg 32bytes 0x20-3f;
memcpy(g_RegExt[Slot] + 0x30, classic_calibration, sizeof(classic_calibration)); memcpy(g_RegExt[Slot] + 0x20, nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(g_RegExt[Slot] + 0xfa, gh3glp_id, sizeof(gh3glp_id)); memcpy(g_RegExt[Slot] + 0x30, nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(g_RegExt[Slot] + 0xfa, nunchuck_id, sizeof(nunchuck_id));
g_MotionPlus[Slot] = 1;
}
g_MotionPlusReadError[Slot] = 0;
} else {
// Copy extension id and calibration to its register
if(WiiMapping[Slot].iExtensionConnected == EXT_NUNCHUK)
{
memcpy(g_RegExt[Slot] + 0x20, nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(g_RegExt[Slot] + 0x30, nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(g_RegExt[Slot] + 0xfa, nunchuck_id, sizeof(nunchuck_id));
}
else if(WiiMapping[Slot].iExtensionConnected == EXT_CLASSIC_CONTROLLER)
{
memcpy(g_RegExt[Slot] + 0x20, classic_calibration, sizeof(classic_calibration));
memcpy(g_RegExt[Slot] + 0x30, classic_calibration, sizeof(classic_calibration));
memcpy(g_RegExt[Slot] + 0xfa, classic_id, sizeof(classic_id));
}
else if(WiiMapping[Slot].iExtensionConnected == EXT_GUITARHERO)
{
// TODO get the correct values here
memcpy(g_RegExt[Slot] + 0x20, classic_calibration, sizeof(classic_calibration));
memcpy(g_RegExt[Slot] + 0x30, classic_calibration, sizeof(classic_calibration));
memcpy(g_RegExt[Slot] + 0xfa, gh3glp_id, sizeof(gh3glp_id));
}
else if(WiiMapping[Slot].iExtensionConnected == EXT_WBB)
{
// TODO
}
} }
INFO_LOG(WIIMOTE, "UpdateExtRegisterBlocks()"); INFO_LOG(WIIMOTE, "UpdateExtRegisterBlocks()");
@ -546,6 +579,7 @@ void DoState(PointerWrap &p)
p.Do(g_IR[i]); p.Do(g_IR[i]);
p.Do(g_Leds[i]); p.Do(g_Leds[i]);
p.Do(g_Speaker[i]); p.Do(g_Speaker[i]);
p.Do(g_MotionPlus[i]);
//p.Do(g_SpeakerMute[i]); //p.Do(g_SpeakerMute[i]);
p.Do(g_ExtKey[i]); p.Do(g_ExtKey[i]);
} }

View File

@ -45,7 +45,6 @@ extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiiMoteEmu namespace WiiMoteEmu
{ {
extern void PAD_Rumble(u8 _numPAD, unsigned int _uType); extern void PAD_Rumble(u8 _numPAD, unsigned int _uType);
/* Here we process the Output Reports that the Wii sends. Our response will be /* Here we process the Output Reports that the Wii sends. Our response will be
@ -190,7 +189,7 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
{ {
u32 address = convert24bit(rd->address); u32 address = convert24bit(rd->address);
u16 size = convert16bit(rd->size); u16 size = convert16bit(rd->size);
u8 addressHI = (address >> 16) & 0xFE;
INFO_LOG(WIIMOTE, "Read data"); INFO_LOG(WIIMOTE, "Read data");
DEBUG_LOG(WIIMOTE, " Read data Space: %x", rd->space); DEBUG_LOG(WIIMOTE, " Read data Space: %x", rd->space);
DEBUG_LOG(WIIMOTE, " Read data Address: 0x%06x", address); DEBUG_LOG(WIIMOTE, " Read data Address: 0x%06x", address);
@ -205,7 +204,7 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
PanicAlert("WmReadData: address + size out of bounds"); PanicAlert("WmReadData: address + size out of bounds");
return; return;
} }
SendReadDataReply(_channelID, g_Eeprom[g_ID] + address, address, (int)size); SendReadDataReply(_channelID, g_Eeprom[g_ID] + address, address, addressHI, (int)size);
/*DEBUG_LOG(WIIMOTE, "Read RegEeprom: Size: %i, Address: %08x, Offset: %08x", /*DEBUG_LOG(WIIMOTE, "Read RegEeprom: Size: %i, Address: %08x, Offset: %08x",
size, address, (address & 0xffff));*/ size, address, (address & 0xffff));*/
} }
@ -213,7 +212,7 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
{ {
u8* block; u8* block;
u32 blockSize; u32 blockSize;
switch((address >> 16) & 0xFE) switch(addressHI)
{ {
case 0xA2: case 0xA2:
block = g_RegSpeaker[g_ID]; block = g_RegSpeaker[g_ID];
@ -230,10 +229,6 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
// MotionPlus is pretty much just a dummy atm :p // MotionPlus is pretty much just a dummy atm :p
case 0xA6: case 0xA6:
block = g_RegMotionPlus[g_ID]; block = g_RegMotionPlus[g_ID];
block[0xFC] = 0xA6;
block[0xFD] = 0x20;
block[0xFE] = 0x00;
block[0xFF] = 0x05;
blockSize = WIIMOTE_REG_EXT_SIZE; blockSize = WIIMOTE_REG_EXT_SIZE;
DEBUG_LOG(WIIMOTE, " Case 0xa6: MotionPlusReg [%x]", address); DEBUG_LOG(WIIMOTE, " Case 0xa6: MotionPlusReg [%x]", address);
break; break;
@ -251,7 +246,7 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
} }
// Encrypt data that is read from the Wiimote Extension Register // Encrypt data that is read from the Wiimote Extension Register
if(((address >> 16) & 0xfe) == 0xa4) if(addressHI == 0xa4)
{ {
// Check if encrypted reads is on // Check if encrypted reads is on
if(g_RegExt[g_ID][0xf0] == 0xaa) if(g_RegExt[g_ID][0xf0] == 0xaa)
@ -274,9 +269,13 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
PanicAlert("WmReadData: address + size out of bounds! [%d %d %d]", address, size, blockSize); PanicAlert("WmReadData: address + size out of bounds! [%d %d %d]", address, size, blockSize);
return; return;
} }
//3x read error due activated(or not present device, which is not the case), WII will await a status report after init and attempting to read from write-only area @A600FE/FF
if ((g_MotionPlusReadError[g_ID] == 2) && (g_RegExt[g_ID][0xFF]== 0x05)) { //if motionplus is active, its in the current ExtReg, 0xFF will be always 0x05
WmRequestStatus(_channelID, (wm_request_status*) rd, 1);
}
// Let this function process the message and send it to the Wii // Let this function process the message and send it to the Wii
SendReadDataReply(_channelID, block + address, address, (u8)size); SendReadDataReply(_channelID, block + address, address, addressHI, (u8)size);
} }
else else
{ {
@ -295,7 +294,7 @@ void WmReadData(u16 _channelID, wm_read_data* rd)
_Address: The starting address inside the registry, this is used to check for out of bounds reading _Address: The starting address inside the registry, this is used to check for out of bounds reading
_Size: The total size to send _Size: The total size to send
*/ */
void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, int _Size) void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, u8 _AddressHI, int _Size)
{ {
int dataOffset = 0; int dataOffset = 0;
const u8* data = (const u8*)_Base; const u8* data = (const u8*)_Base;
@ -340,6 +339,24 @@ void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, int _Size)
pReply->size = 0x0f; pReply->size = 0x0f;
pReply->error = 0x08; pReply->error = 0x08;
} }
if (WiiMapping[g_ID].bMotionPlusConnected)
{
//MP+ will try to read from this Registeraddress, expecting an error if a previous WM+ activation has been succesful
//it also returns an error if there was no WM+ present at all
if (((_Address == 0x00FE ) || (_Address == 0x00FF )) && (_AddressHI == 0xA6))
{
//Check if MP+ is activated, resp. if its in the current RegExt.
if ((g_RegExt[g_ID][0xFF] == 0x05) && (g_RegMotionPlus[g_ID][0xFF] != 0x05))
{
pReply->size = 0x0f;
pReply->error = 0x07; //error: write-only area when activated/or not present
// we use the read error at the same time as an indicator whether we need to send a faked 0x37 report or not
g_MotionPlusReadError[g_ID]++;
}
}
}
// Logging // Logging
DEBUG_LOG(WIIMOTE, "SendReadDataReply"); DEBUG_LOG(WIIMOTE, "SendReadDataReply");
@ -369,12 +386,11 @@ void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, int _Size)
void WmWriteData(u16 _channelID, wm_write_data* wd) void WmWriteData(u16 _channelID, wm_write_data* wd)
{ {
u32 address = convert24bit(wd->address); u32 address = convert24bit(wd->address);
u8 addressHI = (address >> 16) & 0xFE;
INFO_LOG(WIIMOTE, "Write data"); INFO_LOG(WIIMOTE, "Write data");
DEBUG_LOG(WIIMOTE, " Space: %x", wd->space); DEBUG_LOG(WIIMOTE, " Space: %x", wd->space);
DEBUG_LOG(WIIMOTE, " Address: 0x%06x", address); DEBUG_LOG(WIIMOTE, " Address: 0x%06x", address);
DEBUG_LOG(WIIMOTE, " Size: 0x%02x", wd->size); DEBUG_LOG(WIIMOTE, " Size: 0x%02x", wd->size);
// Write to EEPROM // Write to EEPROM
if(wd->size <= 16 && wd->space == WM_SPACE_EEPROM) if(wd->size <= 16 && wd->space == WM_SPACE_EEPROM)
{ {
@ -390,7 +406,7 @@ void WmWriteData(u16 _channelID, wm_write_data* wd)
{ {
u8* block; u8* block;
u32 blockSize; u32 blockSize;
switch((address >> 16) & 0xFE) switch(addressHI)
{ {
case 0xA2: case 0xA2:
block = g_RegSpeaker[g_ID]; block = g_RegSpeaker[g_ID];
@ -422,7 +438,6 @@ void WmWriteData(u16 _channelID, wm_write_data* wd)
return; return;
} }
// Remove for example 0xa40000 from the address
address &= 0xFFFF; address &= 0xFFFF;
// Check if the address is within bounds // Check if the address is within bounds
@ -430,7 +445,7 @@ void WmWriteData(u16 _channelID, wm_write_data* wd)
PanicAlert("WmWriteData: address + size out of bounds!"); PanicAlert("WmWriteData: address + size out of bounds!");
return; return;
} }
// Finally write the registers to the right structure // Finally write the registers to the right structure
memcpy(block + address, wd->data, wd->size); memcpy(block + address, wd->data, wd->size);
@ -442,7 +457,10 @@ void WmWriteData(u16 _channelID, wm_write_data* wd)
if(address >= 0x40 && address <= 0x4c) if(address >= 0x40 && address <= 0x4c)
wiimote_gen_key(&g_ExtKey[g_ID], &g_RegExt[g_ID][0x40]); wiimote_gen_key(&g_ExtKey[g_ID], &g_RegExt[g_ID][0x40]);
} }
if (WiiMapping[g_ID].bMotionPlusConnected) {
HandlingMotionPlusWrites(wd->data, addressHI, address);
}
} }
else else
{ {
@ -487,7 +505,7 @@ void WmRequestStatus(u16 _channelID, wm_request_status* rs, int Extension)
if (Extension == -1) if (Extension == -1)
{ {
// Read config value for the first time // Read config value for the first time
pStatus->extension = (WiiMapping[g_ID].iExtensionConnected == EXT_NONE) ? 0 : 1; pStatus->extension = ((g_MotionPlus[g_ID]) || (WiiMapping[g_ID].iExtensionConnected != EXT_NONE)) ? 1 : 0;
} }
else else
{ {
@ -501,10 +519,121 @@ void WmRequestStatus(u16 _channelID, wm_request_status* rs, int Extension)
DEBUG_LOG(WIIMOTE, " IR: %x", pStatus->ir); DEBUG_LOG(WIIMOTE, " IR: %x", pStatus->ir);
DEBUG_LOG(WIIMOTE, " LEDs: %x", pStatus->leds); DEBUG_LOG(WIIMOTE, " LEDs: %x", pStatus->leds);
g_WiimoteInitialize.pWiimoteInput(g_ID, _channelID, DataFrame, Offset); g_WiimoteInitialize.pWiimoteInput(g_ID, _channelID, DataFrame, Offset);
// Debugging // Debugging
//ReadDebugging(true, DataFrame, Offset); //ReadDebugging(true, DataFrame, Offset);
} }
void HandlingMotionPlusWrites(u8* data, u8 addressHI, u32 address){
switch (addressHI)
{
case 0xA4:
switch (address)
{
case 0x00FE:
if (data[0] == 0x00) {
if ((g_RegExt[g_ID][0xFF] == 0x05) && (g_RegMotionPlus[g_ID][0xFF] != 0x05))
{
SwapExtRegisters();
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: Disabling WM+ and swapping registers back", data[0], addressHI, address);
}
else {
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: WM+ already inactive", data[0], addressHI, address);
}
g_MotionPlus[g_ID] = 1;
}
break;
case 0x00FB:
//1. Initializing the extension: writing 0x55 ->0xA400F0 and then 0x00 to 0xA400FB.
//2. Disables an active wiimote; ext disconnect.
if (data[0] == 0x00) {
//1. connecting extension
if ((g_RegExt[g_ID][0xFF] != 0x05) && (g_RegMotionPlus[g_ID][0xFF] == 0x05))
{
g_RegMotionPlus[g_ID][0xFE] = 0x04;
g_RegMotionPlus[g_ID][0xF7] = 0x08; //control init byte, ingame check
SwapExtRegisters();
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: Enabling WM+ and swapping rgisters", data[0], addressHI, address);
g_MotionPlus[g_ID] = 0;
} //2. disconnecting extension
else if ((g_RegExt[g_ID][0xFF] == 0x05) && (g_RegMotionPlus[g_ID][0xFF] != 0x05)){
g_RegExt[g_ID][0xFE] = 0x04;
g_MotionPlus[g_ID] = 1;
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: Disabling WM+ and swapping registers back", data[0], addressHI, address);
}
}
break;
}
break;
case 0xA6:
switch (address)
{
case 0x00FE:
//Enabling WM+, swapping extension registers
if (data[0] == 0x05) {
if ((g_RegExt[g_ID][0xFF] != 0x05) && (g_RegMotionPlus[g_ID][0xFF] == 0x05) ) {
//The WII will try to read from the readprotected A6 WM+ register now, we need to reply with an error each time,
//plus sent an statusreport 0x20(depending on if nunchuk inserted or not)
g_MotionPlusReadError[g_ID] = 0;
g_MotionPlus[g_ID] = 1;
SwapExtRegisters();
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: Enabling WM+ and swapping rgisters back", data[0], addressHI, address);
}
else {
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: WM already enabled no register swapping", data[0], addressHI, address);
}
}
break;
case 0x00F0: //init() WM+, this will change some control bits in the WM+ register
if (data[0] == 0x55) { //enables passthroug, convert to 0405* A6 swap
if ((g_RegMotionPlus[g_ID][0xFF] == 0x05))
{
//control init byte, ingame check
g_RegMotionPlus[g_ID][0xF7] = 0x08;
//motion plus id
g_RegMotionPlus[g_ID][0xFE] = 0x05;
//we will swap the register on write to 0x00FE
}
else if (g_RegExt[g_ID][0xFF] == 0x05) { //if the wiimote is already active, we will init() the WM+ directly in the ExtReg
g_RegExt[g_ID][0xFE] = 0x05;
g_RegExt[g_ID][0xF7] = 0x08;
}
g_MotionPlus[g_ID] = 0;
}
break;
default:
DEBUG_LOG(WIIMOTE, "Writing [0x%02x] to [0x%02x:%04x]: unknown reason", data[0], addressHI, address);
break;
}
break;
}
}
//Swapping Ext/WM+-registers
void SwapExtRegisters(){
memset(g_RegExtTmp, 0, sizeof(g_RegExtTmp));
memcpy(g_RegExtTmp, g_RegExt[g_ID], sizeof(g_RegExt[0]));
memset(g_RegExt[0], 0, sizeof(g_RegExt[0]));
memcpy(g_RegExt[g_ID], g_RegMotionPlus[g_ID], sizeof(g_RegMotionPlus[0]));
memset(g_RegMotionPlus[0], 0, sizeof(g_RegMotionPlus[0]));
memcpy(g_RegMotionPlus[g_ID], g_RegExtTmp, sizeof(g_RegExtTmp));
if (g_RegMotionPlus[g_ID][0xFC]) {
g_RegMotionPlus[g_ID][0xFC] = 0xa6;
}
if (g_RegExt[g_ID][0xFC]) {
g_RegExt[g_ID][0xFC] = 0xa4;
}
}
} // WiiMoteEmu } // WiiMoteEmu

View File

@ -51,7 +51,9 @@ void SendReportCoreAccelIr10Ext(u16 _channelID);
int WriteWmReportHdr(u8* dst, u8 wm); int WriteWmReportHdr(u8* dst, u8 wm);
void WmSendAck(u16 _channelID, u8 _reportID); void WmSendAck(u16 _channelID, u8 _reportID);
void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, int _Size); void SendReadDataReply(u16 _channelID, void* _Base, u16 _Address, u8 _AddressHI, int _Size);
void SwapExtRegisters();
void HandlingMotionPlusWrites(u8* data, u8 addressHI, u32 address);
void FillReportAcc(wm_accel& _acc); void FillReportAcc(wm_accel& _acc);
void FillReportInfo(wm_core& _core); void FillReportInfo(wm_core& _core);
@ -60,7 +62,9 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1);
void FillReportExtension(wm_extension& _ext); void FillReportExtension(wm_extension& _ext);
void FillReportClassicExtension(wm_classic_extension& _ext); void FillReportClassicExtension(wm_classic_extension& _ext);
void FillReportGuitarHero3Extension(wm_GH3_extension& _ext); void FillReportGuitarHero3Extension(wm_GH3_extension& _ext);
void FillReportMotionPlusNunchukExtension(wm_extension& _ext);
void FillReportMotionPlusNoExtension(wm_extension& _ext);
void FillReportMotionPlus(wm_extension& ext, bool extension);
} // namespace } // namespace
#endif //_EMU_DECLARATIONS_ #endif //_EMU_DECLARATIONS_

View File

@ -710,7 +710,8 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1)
);*/ );*/
// ------------------ // ------------------
} }
/* Generate the 6 byte extension report for the motionplus&nunchuk, encrypted. The bytes
void FillReportExtension(wm_extension& _ext)
/* Generate the 6 byte extension report for the Nunchuck, encrypted. The bytes /* Generate the 6 byte extension report for the Nunchuck, encrypted. The bytes
are JX JY AX AY AZ BT. */ are JX JY AX AY AZ BT. */
@ -1247,4 +1248,201 @@ void FillReportGuitarHero3Extension(wm_GH3_extension& _ext)
memcpy(&_ext, Tmp, sizeof(_ext)); memcpy(&_ext, Tmp, sizeof(_ext));
} }
/* Generate the 6 byte extension report for the MotionPlus Controller.
pass-through mode supported for MotionPlus+Nunchuk */
void FillReportMotionPlus(wm_extension& ext, bool extension){
//sending initial control packet, this must be sent first, its some kind of verifiation, all control bits are set to 0!
if (g_MotionPlusReadError[g_ID]) {
memcpy(&ext, motionpluscheck_id, sizeof(motionpluscheck_id));
g_MotionPlus[g_ID] = (extension) ? 1 : 0;
g_MotionPlusReadError[g_ID] = 0;
} //nunchuk inserted
else if (extension == 1) {
switch (g_InterleavedData[g_ID])
{
case false://MPlus
FillReportMotionPlusNoExtension(ext);
break;
case true: //Nunchuk
FillReportMotionPlusNunchukExtension(ext);
break;
}
//alternate between nunchuk and wm+ interleaved reports
g_InterleavedData[g_ID] = g_InterleavedData[g_ID] ? false : true;
}//no additional extension inserted, no interleaving, always sending mp+ data
else if (extension == 0) {
FillReportMotionPlusNoExtension(ext);
g_InterleavedData[g_ID] = false;
}
}
void FillReportMotionPlusNoExtension(wm_extension& _ext)
{
wm_mp_nc_0 ext;
memset(&ext, 0, sizeof(wm_mp_nc_0));
ext.YawLeftLS = 0x00; //dummy data atm
ext.RollLeftLS = 0x00;
ext.PitchDownLS = 0x00;
ext.pitchfast = 0x00;
ext.yawfast = 0x00;
ext.YawLeftHI = 0x00;
ext.ExtCon = 0x00; // 0 (important, since we don't use a nunchuk here)
ext.rollfast = 0x00;
ext.RollLeftHI = 0x00;
ext.dummy = 0x00; // 0 (important)
ext.mpdata = 0x01; //1 (important, using MP+ report instead of NC report)
ext.PitchDownHI = 0x00;
memcpy(&_ext, &ext, sizeof(ext));
}
void FillReportMotionPlusNunchukExtension(wm_extension& _ext)
{
wm_mp_nc_1 ext;
memset(&ext, 0, sizeof(wm_mp_nc_1));
ext.jx = g_nu.jx.center;
ext.jy = g_nu.jy.center;
// Use the neutral values
ext.ax = g_nu.cal_zero.x;
ext.ay = g_nu.cal_zero.y;
ext.az = g_nu.cal_zero.z + g_nu.cal_g.z;
ext.axLS = 0x00;
ext.ayLS = 0x00;
ext.azLS = 0x00;
ext.bz = 0x01;
ext.bc = 0x01;
ext.dummy = 0; //0 (important)
ext.mpdata = 0; //0 NC report, interleaved data (important)
ext.ExtCon = 1; // must be 1 when in NC-MP+ Mode
if (IsFocus())
{
int acc_x = g_nu.cal_zero.x;
int acc_y = g_nu.cal_zero.y;
int acc_z = g_nu.cal_zero.z + g_nu.cal_g.z;
if (IsKey(ENC_SHAKE) && !WiiMapping[g_ID].Motion.TiltNC.Shake)
WiiMapping[g_ID].Motion.TiltNC.Shake = 1;
// Step the shake simulation one step
ShakeToAccelerometer(acc_x, acc_y, acc_z, WiiMapping[g_ID].Motion.TiltNC);
// Tilt Nunchuck, allow the shake function to interrupt it
if (!WiiMapping[g_ID].Motion.TiltNC.Shake)
TiltNunchuck(acc_x, acc_y, acc_z);
// Boundary check
if (acc_x > 0xFF) acc_x = 0xFF;
else if (acc_x < 0x00) acc_x = 0x00;
if (acc_y > 0xFF) acc_y = 0xFF;
else if (acc_y < 0x00) acc_y = 0x00;
if (acc_z > 0xFF) acc_z = 0xFF;
else if (acc_z < 0x00) acc_z = 0x00;
ext.ax = acc_x;
ext.ay = acc_y;
ext.az = acc_z>>1;
ext.azLS = acc_z<<1; //LS0=0
// Update the analog stick
if (WiiMapping[g_ID].Stick.NC == FROM_KEYBOARD)
{
// Set the max values to the current calibration values
if(IsKey(ENC_L)) // x
ext.jx = g_nu.jx.min;
if(IsKey(ENC_R))
ext.jx = g_nu.jx.max;
if(IsKey(ENC_D)) // y
ext.jy = g_nu.jy.min;
if(IsKey(ENC_U))
ext.jy = g_nu.jy.max;
// On a real stick, the initialization value of center is 0x80,
// but after a first time touch, the center value automatically changes to 0x7F
if(ext.jx != g_nu.jx.center)
g_nu.jx.center = 0x7F;
if(ext.jy != g_nu.jy.center)
g_nu.jy.center = 0x7F;
}
else
{
// Get adjusted pad state values
int _Lx = WiiMapping[g_ID].AxisState.Lx;
int _Ly = WiiMapping[g_ID].AxisState.Ly;
int _Rx = WiiMapping[g_ID].AxisState.Rx;
int _Ry = WiiMapping[g_ID].AxisState.Ry;
// The Y-axis is inverted
_Ly = 0xff - _Ly;
_Ry = 0xff - _Ry;
/* This is if we are also using a real Nunchuck that we are sharing the
calibration with. It's not needed if we are using our default
values. We adjust the values to the configured range, we even allow
the center to not be 0x80. */
if(g_nu.jx.max != 0xff || g_nu.jy.max != 0xff
|| g_nu.jx.min != 0 || g_nu.jy.min != 0
|| g_nu.jx.center != 0x80 || g_nu.jy.center != 0x80)
{
float Lx = (float)_Lx;
float Ly = (float)_Ly;
float Rx = (float)_Rx;
float Ry = (float)_Ry;
//float Tl = (float)_Tl;
//float Tr = (float)_Tr;
float XRangePos = (float) (g_nu.jx.max - g_nu.jx.center);
float XRangeNeg = (float) (g_nu.jx.center - g_nu.jx.min);
float YRangePos = (float) (g_nu.jy.max - g_nu.jy.center);
float YRangeNeg = (float) (g_nu.jy.center - g_nu.jy.min);
if (Lx > 0x80) Lx = Lx * (XRangePos / 128.0);
if (Lx < 0x80) Lx = Lx * (XRangeNeg / 128.0);
if (Lx == 0x80) Lx = (float)g_nu.jx.center;
if (Ly > 0x80) Ly = Ly * (YRangePos / 128.0);
if (Ly < 0x80) Ly = Ly * (YRangeNeg / 128.0);
if (Ly == 0x80) Lx = (float)g_nu.jy.center;
// Boundaries
_Lx = (int)Lx;
_Ly = (int)Ly;
_Rx = (int)Rx;
_Ry = (int)Ry;
if (_Lx > 0xff) _Lx = 0xff; if (_Lx < 0) _Lx = 0;
if (_Rx > 0xff) _Rx = 0xff; if (_Rx < 0) _Rx = 0;
if (_Ly > 0xff) _Ly = 0xff; if (_Ly < 0) _Ly = 0;
if (_Ry > 0xff) _Ry = 0xff; if (_Ry < 0) _Ry = 0;
}
if (WiiMapping[g_ID].Stick.NC == FROM_ANALOG1)
{
ext.jx = _Lx;
ext.jy = _Ly;
}
else // ANALOG2
{
ext.jx = _Rx;
ext.jy = _Ry;
}
}
if(IsKey(ENC_C)) ext.bc = 0x00; ///////////////
if(IsKey(ENC_Z)) ext.bz = 0x00;
}
memcpy(&_ext, &ext, sizeof(ext));
}
} // end of namespace } // end of namespace

View File

@ -138,6 +138,39 @@ struct wm_classic_extension
wm_cc_5 b2; // byte 5 wm_cc_5 b2; // byte 5
}; };
struct wm_mp_nc_0 //motionplus+nunchuk_pass-through
{
u8 YawLeftLS; //7e
u8 RollLeftLS; //82
u8 PitchDownLS; //83
u8 pitchfast : 1; //1
u8 yawfast : 1; //0
u8 YawLeftHI : 6; //01 1010 /1a
u8 ExtCon : 1; // 1 usually
u8 rollfast : 1; //0
u8 RollLeftHI : 6; //00 1010
u8 dummy : 1; // 0 usually. 1 in dem fall mhh
u8 mpdata : 1; //1 in this case, interleaved motion+ data
u8 PitchDownHI : 6;//01 1100
}; // default for yaw/roll/pitch around 0x1F7F
struct wm_mp_nc_1 //motionplus+nunchuk_pass-through
{
u8 jx;
u8 jy;
u8 ax;
u8 ay;
u8 ExtCon : 1; // 1 usually
u8 az : 7;
u8 dummy : 1; //0 always
u8 mpdata : 1; //0 when nunchuk interleaved data
u8 bz : 1;
u8 bc : 1;
u8 axLS : 1; // ls 1, ls0 = 0 by default,
u8 ayLS : 1;
u8 azLS : 2;
};
struct wm_GH3_extension struct wm_GH3_extension
{ {
u8 SX : 6; u8 SX : 6;