mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 16:49:12 +01:00
fcdd2a8e17
1. Fixed the dual mode. You should now be able to change between the real and emulated Wiimote at any time, even when the Nunchuck is connected. It also supports third party Wireless Nunchucks that never sends any calibration values. The Nunchuck status should be automatically updated. The Nunchuck stick may get stuck, but that should fix itself if you disconnect and reconnect again. The only important problems seems to be that the real Wiimote fails to answer sometimes so that the Core functions disconnect it. 2. Began looking at how to reconnect the Wiimote after an unwanted HCI disconnect command git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2129 8ced0084-cf51-0410-be5f-012b33b47a6e
360 lines
13 KiB
C++
360 lines
13 KiB
C++
// Copyright (C) 2003-2008 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
|
// Includes
|
|
#include <iostream> // System
|
|
|
|
#include "wiiuse.h" // Externals
|
|
|
|
#include "ConsoleWindow.h" // Common
|
|
#include "StringUtil.h"
|
|
#include "Timer.h"
|
|
#include "pluginspecs_wiimote.h"
|
|
|
|
#include "wiimote_real.h" // Local
|
|
#include "wiimote_hid.h"
|
|
#include "EmuDefinitions.h"
|
|
#include "EmuMain.h"
|
|
#include "main.h"
|
|
#if defined(HAVE_WX) && HAVE_WX
|
|
#include "ConfigDlg.h"
|
|
#endif
|
|
#include "Config.h"
|
|
////////////////////////////////////////
|
|
|
|
namespace WiiMoteReal
|
|
{
|
|
int GetReportSize(struct wiimote_t* wm)
|
|
{
|
|
// The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
|
|
if(WIIUSE_USING_EXP(wm)) return 22; else return 18;
|
|
}
|
|
|
|
void handle_ctrl_status(struct wiimote_t* wm)
|
|
{
|
|
Console::Print("\n\n--- CONTROLLER STATUS [wiimote id %i] ---\n", wm->unid);
|
|
|
|
Console::Print("attachment: %i\n", wm->exp.type);
|
|
Console::Print("speaker: %i\n", WIIUSE_USING_SPEAKER(wm));
|
|
Console::Print("ir: %i\n", WIIUSE_USING_IR(wm));
|
|
Console::Print("leds: %i %i %i %i\n", WIIUSE_IS_LED_SET(wm, 1), WIIUSE_IS_LED_SET(wm, 2), WIIUSE_IS_LED_SET(wm, 3), WIIUSE_IS_LED_SET(wm, 4));
|
|
Console::Print("battery: %f %%\n", wm->battery_level);
|
|
}
|
|
|
|
bool IRDataOK(struct wiimote_t* wm)
|
|
{
|
|
//Console::Print("IRDataOK: ");
|
|
// The report size is 0x33 = 18, 0x37 = 22 withouth the leading (a1) byte
|
|
int ReportSize = GetReportSize(wm);
|
|
for(int i = 0; i < ReportSize; i++)
|
|
{
|
|
//Console::Print("%02x ", wm->event_buf[i]);
|
|
if (wm->event_buf[i] > 0)
|
|
{
|
|
//Console::Print("\n");
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void handle_event(struct wiimote_t* wm)
|
|
{
|
|
//Console::Print("\n\n--- EVENT [id %i] ---\n", wm->unid);
|
|
|
|
/* if a button is pressed, report it */
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) Console::Print("A pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_B)) Console::Print("B pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_UP)) Console::Print("UP pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_DOWN)) Console::Print("DOWN pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_LEFT)) Console::Print("LEFT pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_RIGHT)) Console::Print("RIGHT pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) Console::Print("MINUS pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) Console::Print("PLUS pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) Console::Print("ONE pressed\n");
|
|
//if (IS_PRESSED(wm, WIIMOTE_BUTTON_ONE)) g_Run = false;
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_TWO)) Console::Print("TWO pressed\n");
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_HOME)) Console::Print("HOME pressed\n");
|
|
|
|
/*
|
|
* Pressing minus will tell the wiimote we are no longer interested in movement.
|
|
* This is useful because it saves battery power.
|
|
*/
|
|
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS))
|
|
{
|
|
wiiuse_motion_sensing(wm, 0);
|
|
wiiuse_set_ir(wm, 0);
|
|
g_MotionSensing = false;
|
|
}
|
|
// Turn aceelerometer and IR reporting on, there is some kind of bug that prevents us from turing these on
|
|
// directly after each other, so we have to wait for another wiiuse_poll() this way
|
|
if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS))
|
|
{
|
|
wiiuse_motion_sensing(wm, 1);
|
|
g_MotionSensing = true;
|
|
}
|
|
// Turn IR reporting on
|
|
if (g_MotionSensing && !WIIUSE_USING_IR(wm))
|
|
wiiuse_set_ir(wm, 1);
|
|
|
|
/* Print battery status */
|
|
if(frame && g_Config.bUpdateRealWiimote)
|
|
frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5));
|
|
|
|
/* Create shortcut to the nunchuck */
|
|
struct nunchuk_t* nc = NULL;
|
|
if (wm->exp.type == EXP_NUNCHUK)
|
|
nc = (nunchuk_t*)&wm->exp.nunchuk;
|
|
|
|
/* If the accelerometer is turned on then print angles */
|
|
if (WIIUSE_USING_ACC(wm) && WIIUSE_USING_IR(wm))
|
|
{
|
|
std::string Tmp;
|
|
Tmp += StringFromFormat("Roll: %2.1f ", wm->orient.roll);
|
|
Tmp += StringFromFormat("Pitch: %2.1f ", wm->orient.pitch);
|
|
Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level);
|
|
Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z);
|
|
Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z);
|
|
|
|
// The report size is 0x33 = 18, 0x37 = 22
|
|
int ReportSize; if(WIIUSE_USING_EXP(wm)) ReportSize = 22; else ReportSize = 18;
|
|
|
|
// wm->event_buf is cleared at the end of all wiiuse_poll(), so wm->event_buf will always be zero
|
|
// after that. To get the raw IR data we need to read the wiimote again. This seems to work most of the time,
|
|
// it seems to fails with a regular interval about each tenth read.
|
|
if(wiiuse_io_read(wm))
|
|
{
|
|
// Check that it's not zero
|
|
if (IRDataOK(wm)) memcpy(g_EventBuffer, wm->event_buf, ReportSize);
|
|
}
|
|
|
|
// Go through each of the 4 possible IR sources
|
|
for (int i = 0; i < 4; ++i)
|
|
{
|
|
// Check if the source is visible
|
|
if (wm->ir.dot[i].visible)
|
|
Tmp += StringFromFormat("IR source %i: (%u, %u)\n", i, wm->ir.dot[i].x, wm->ir.dot[i].y);
|
|
}
|
|
|
|
Tmp += "\n";
|
|
Tmp += StringFromFormat("IR cursor: (%u, %u)\n", wm->ir.x, wm->ir.y);
|
|
Tmp += StringFromFormat("IR z distance: %f\n", wm->ir.z);
|
|
|
|
if(wm->exp.type == EXP_NUNCHUK)
|
|
{
|
|
Tmp += "\n";
|
|
Tmp += StringFromFormat("Nunchuck accel x, y, z: %03i %03i %03i\n", nc->accel.x, nc->accel.y, nc->accel.z);
|
|
}
|
|
|
|
//Tmp += "\n";
|
|
//std::string TmpData = ArrayToString(g_EventBuffer, ReportSize, 0, 30);
|
|
//Tmp += "Data: " + TmpData;
|
|
|
|
//Console::ClearScreen();
|
|
//Console::Print("%s\n\n", Tmp.c_str());
|
|
|
|
if(frame)
|
|
{
|
|
// Produce adjusted accelerometer values
|
|
u8 AccelX = 0, AccelY = 0, AccelZ = 0;
|
|
if((wm->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelX = wm->accel.x + g_Config.iAccNeutralX;
|
|
if((wm->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelY = wm->accel.y + g_Config.iAccNeutralY;
|
|
if((wm->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelZ = wm->accel.z + g_Config.iAccNeutralZ;
|
|
// And for the Nunchuck
|
|
u8 AccelNX = 0, AccelNY = 0, AccelNZ = 0;
|
|
if(wm->exp.type == EXP_NUNCHUK)
|
|
{
|
|
if((nc->accel.x + g_Config.iAccNunNeutralX) <= 255) AccelNX = nc->accel.x + g_Config.iAccNunNeutralX;
|
|
if((nc->accel.y + g_Config.iAccNunNeutralY) <= 255) AccelNY = nc->accel.y + g_Config.iAccNunNeutralY;
|
|
if((nc->accel.z + g_Config.iAccNunNeutralZ) <= 255) AccelNZ = nc->accel.z + g_Config.iAccNunNeutralZ;
|
|
}
|
|
|
|
if(g_Config.bUpdateRealWiimote)
|
|
{
|
|
// Update gauges
|
|
frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180);
|
|
frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180);
|
|
|
|
frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5));
|
|
frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5));
|
|
frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5));
|
|
|
|
frame->m_GaugeAccel[0]->SetValue(AccelX);
|
|
frame->m_GaugeAccel[1]->SetValue(AccelY);
|
|
frame->m_GaugeAccel[2]->SetValue(AccelZ);
|
|
|
|
frame->m_TextIR->SetLabel(wxString::Format(
|
|
wxT("Cursor: %03u %03u\nDistance:%4.0f"), wm->ir.x, wm->ir.y, wm->ir.z));
|
|
|
|
frame->m_TextAccNeutralCurrent->SetLabel(wxString::Format(
|
|
wxT("Current: %03u %03u %03u"), AccelX, AccelY, AccelZ));
|
|
|
|
if(frame->m_bRecording)
|
|
Console::Print("Wiiuse Recorded accel x, y, z: %03i %03i %03i\n", wm->accel.x, wm->accel.y, wm->accel.z);
|
|
}
|
|
|
|
// Send the data to be saved
|
|
//const u8* data = (const u8*)wm->event_buf;
|
|
frame->DoRecordMovement(AccelX, AccelY, AccelZ, (g_EventBuffer + 6),
|
|
(WIIUSE_USING_EXP(wm) ? 10 : 12));
|
|
|
|
// Turn recording on and off
|
|
if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true);
|
|
else frame->DoRecordA(false);
|
|
}
|
|
}
|
|
// Otherwise remove the values
|
|
else
|
|
{
|
|
if (frame)
|
|
{
|
|
|
|
frame->m_TextAccNeutralCurrent->SetLabel(wxT("Current: 000 000 000"));
|
|
|
|
frame->m_GaugeRoll[0]->SetValue(0);
|
|
frame->m_GaugeRoll[1]->SetValue(0);
|
|
|
|
frame->m_GaugeGForce[0]->SetValue(0);
|
|
frame->m_GaugeGForce[1]->SetValue(0);
|
|
frame->m_GaugeGForce[2]->SetValue(0);
|
|
|
|
frame->m_GaugeAccel[0]->SetValue(0);
|
|
frame->m_GaugeAccel[1]->SetValue(0);
|
|
frame->m_GaugeAccel[2]->SetValue(0);
|
|
|
|
frame->m_TextIR->SetLabel(wxT("Cursor:\nDistance:"));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ReadWiimote()
|
|
{
|
|
/* I place this outside wiiuse_poll() to produce a continous recording regardless of the status
|
|
change of the Wiimote, wiiuse_poll() is only true if the status has changed. However, this the
|
|
timing functions for recording playback that checks the time of the recording this should not
|
|
be needed. But I still use it becase it seemed like state_changed() or the threshold values or
|
|
something else might fail so that only huge status changed were reported. */
|
|
handle_event(g_WiiMotesFromWiiUse[0]);
|
|
|
|
// Declaration
|
|
std::string Temp;
|
|
|
|
/* Timeout for data reading. This is used in Initialize() to read the Eeprom, if we have not gotten
|
|
what we wanted in the WIIUSE_READ_DATA case we stop this loop and enable the regular
|
|
wiiuse_io_read() and wiiuse_io_write() loop again. */
|
|
if (g_RunTemporary)
|
|
{
|
|
// This holds if the update rate of wiiuse_poll() is kept at the default value of 10 ms
|
|
static const int SecondsToWait = 2;
|
|
g_RunTemporaryCountdown++;
|
|
if(g_RunTemporaryCountdown > (SecondsToWait * 100))
|
|
{
|
|
g_RunTemporaryCountdown = 0;
|
|
g_RunTemporary = false;
|
|
}
|
|
}
|
|
|
|
// Read formatted Wiimote data
|
|
if (wiiuse_poll(g_WiiMotesFromWiiUse, MAX_WIIMOTES))
|
|
{
|
|
/*
|
|
* This happens if something happened on any wiimote.
|
|
* So go through each one and check if anything happened.
|
|
*/
|
|
int i = 0;
|
|
for (; i < MAX_WIIMOTES; ++i)
|
|
{
|
|
switch (g_WiiMotesFromWiiUse[i]->event)
|
|
{
|
|
case WIIUSE_EVENT:
|
|
/* a generic event occured */
|
|
//handle_event(g_WiiMotesFromWiiUse[i]);
|
|
break;
|
|
|
|
case WIIUSE_STATUS:
|
|
/* a status event occured */
|
|
//handle_ctrl_status(g_WiiMotesFromWiiUse[i]);
|
|
break;
|
|
|
|
case WIIUSE_DISCONNECT:
|
|
case WIIUSE_UNEXPECTED_DISCONNECT:
|
|
/* the wiimote disconnected */
|
|
//handle_disconnect(wiimotes[i]);
|
|
break;
|
|
|
|
case WIIUSE_READ_DATA:
|
|
/*
|
|
* Data we requested to read was returned.
|
|
* Take a look at wiimotes[i]->read_req
|
|
* for the data.
|
|
*/
|
|
if(g_WiiMotesFromWiiUse[0]->read_req->size == sizeof(WiiMoteEmu::EepromData_0)
|
|
&& g_WiiMotesFromWiiUse[0]->read_req->addr == 0)
|
|
{
|
|
Temp = ArrayToString(g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0), 0, 30);
|
|
memcpy(WiiMoteEmu::g_Eeprom, g_WiiMotesFromWiiUse[0]->read_req->buf, sizeof(WiiMoteEmu::EepromData_0));
|
|
WiiMoteEmu::UpdateEeprom();
|
|
Console::Print("EEPROM: %s\n", Temp.c_str());
|
|
Console::Print("Got neutral values: %i %i %i\n",
|
|
WiiMoteEmu::g_Eeprom[22],WiiMoteEmu::g_Eeprom[23], WiiMoteEmu::g_Eeprom[27]);
|
|
g_RunTemporary = false;
|
|
}
|
|
break;
|
|
|
|
case WIIUSE_NUNCHUK_INSERTED:
|
|
/*
|
|
* a nunchuk was inserted
|
|
* This is a good place to set any nunchuk specific
|
|
* threshold values. By default they are the same
|
|
* as the wiimote.
|
|
*/
|
|
//wiiuse_set_nunchuk_orient_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 90.0f);
|
|
//wiiuse_set_nunchuk_accel_threshold((struct nunchuk_t*)&wiimotes[i]->exp.nunchuk, 100);
|
|
Console::Print("Nunchuk inserted.\n");
|
|
break;
|
|
|
|
case WIIUSE_CLASSIC_CTRL_INSERTED:
|
|
Console::Print("Classic controller inserted.\n");
|
|
break;
|
|
|
|
case WIIUSE_GUITAR_HERO_3_CTRL_INSERTED:
|
|
/* some expansion was inserted */
|
|
//handle_ctrl_status(wiimotes[i]);
|
|
Console::Print("Guitar Hero 3 controller inserted.\n");
|
|
break;
|
|
|
|
case WIIUSE_NUNCHUK_REMOVED:
|
|
case WIIUSE_CLASSIC_CTRL_REMOVED:
|
|
case WIIUSE_GUITAR_HERO_3_CTRL_REMOVED:
|
|
/* some expansion was removed */
|
|
//handle_ctrl_status(wiimotes[i]);
|
|
Console::Print("An expansion was removed.\n");
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}; // end of namespace
|
|
|
|
|