New Wiimote Plugin: Give each real wiimote an individual thread.(eliminates multi-wiimote delay)(fixes issue 3037 for the new plugin) Fix a mem-leak in the input config dialog.(GCPad/NewWiimote)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6096 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak 2010-08-15 20:33:07 +00:00
parent 0a606d7356
commit 7c7257b825
6 changed files with 115 additions and 128 deletions

View File

@ -670,11 +670,20 @@ void GamepadPage::RefreshDevices( wxCommandEvent& event )
m_plugin.controls_crit.Leave(); // leave
}
ControlGroupBox::~ControlGroupBox()
{
std::vector<PadSetting*>::const_iterator
i = options.begin(),
e = options.end();
for (; i!=e; ++i)
delete *i;
}
ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWindow* const parent, wxWindow* const eventsink )
: wxStaticBoxSizer(wxVERTICAL, parent, wxString::FromAscii(group->name))
, control_group(group)
{
control_group = group;
static_bitmap = NULL;
wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
@ -689,7 +698,6 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
ControlButton* const control_button = new ControlButton(parent, (*ci)->control_ref, 80);
control_button->SetFont(m_SmallFont);
controls.push_back(control_button);
control_buttons.push_back(control_button);
if ((*ci)->control_ref->is_input)

View File

@ -161,11 +161,12 @@ class ControlGroupBox : public wxStaticBoxSizer
{
public:
ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWindow* const parent, wxWindow* const eventsink );
~ControlGroupBox();
ControllerEmu::ControlGroup* control_group;
std::vector<PadSetting*> options;
ControllerEmu::ControlGroup* const control_group;
wxStaticBitmap* static_bitmap;
std::vector< PadSetting* > options;
std::vector< wxButton* > controls;
std::vector<ControlButton*> control_buttons;
};

View File

@ -71,7 +71,7 @@ void Wiimote::ReportMode(const wm_report_mode* const dr)
if (false == m_reporting_auto)
PanicAlert("Wiimote: Reporting is set to OFF! Everything should be fine, but games never do this.");
if (dr->mode >= WM_REPORT_INTERLEAVE1)
if (dr->mode > 0x37)
PanicAlert("Wiimote: Unsupported Reporting mode.");
else if (dr->mode < WM_REPORT_CORE)
PanicAlert("Wiimote: Reporting mode < 0x30.");

View File

@ -58,11 +58,6 @@ const ReportFeatures reporting_mode_features[] =
{ 2, 0, 4, 14, 23 },
//0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
{ 2, 4, 7, 17, 23 },
//0x3d: 21 Extension Bytes
{ 0, 0, 0, 2, 23 },
//0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
// UNSUPPORTED
{ 0, 0, 0, 0, 23 },
};
void EmulateShake( u8* const accel

View File

@ -39,62 +39,42 @@ unsigned int g_wiimotes_found = 0;
volatile unsigned int g_wiimotes_lastfound = 0;
volatile bool g_run_wiimote_thread = false;
Common::Thread *g_wiimote_thread = NULL;
Common::CriticalSection g_refresh_critsec, g_wiimote_critsec;
Common::Thread *g_wiimote_threads[MAX_WIIMOTES] = {};
Common::CriticalSection g_refresh_critsec;
THREAD_RETURN WiimoteThreadFunc(void* arg);
void StartWiimoteThreads();
void StopWiimoteThreads();
Wiimote *g_wiimotes[4];
Wiimote *g_wiimotes[MAX_WIIMOTES];
Wiimote::Wiimote(wiimote_t* const wm, const unsigned int index)
: m_last_data_report(NULL)
Wiimote::Wiimote(wiimote_t* const _wiimote, const unsigned int _index)
: wiimote(_wiimote)
, index(_index)
, m_last_data_report(NULL)
, m_channel(0)
, m_wiimote(wm)
, m_index(index)
{
// disable reporting
DisableDataReporting();
// clear all msgs, silly maybe
// - cleared on first InterruptChannel call
//while (wiiuse_io_read(m_wiimote));
//{
// LEDs test
//wm_leds rpt = wm_leds();
//rpt.leds = 1 << i;
//SendPacket(g_wiimotes_from_wiiuse[i], WM_LEDS, &rpt, sizeof(rpt));
//}
// Rumble briefly, this is a bad spot for the rumble
wiiuse_rumble(m_wiimote, 1);
SLEEP(200);
wiiuse_rumble(m_wiimote, 0);
// set LEDs
wiiuse_set_leds(m_wiimote, WIIMOTE_LED_1 << m_index);
wiiuse_set_leds(wiimote, WIIMOTE_LED_1 << index);
// TODO: make Dolphin connect wiimote, maybe
}
Wiimote::~Wiimote()
{
ClearReports();
ClearReadQueue();
// clear write queue
Report rpt;
while (m_write_reports.Pop(rpt))
delete[] rpt.first;
// disable reporting / wiiuse might do this on shutdown anyway, o well, don't know for sure
DisableDataReporting();
// send disconnect message to wii, maybe, i hope, naw shit messes up on emu-stop
//if (g_WiimoteInitialize.pWiimoteInterruptChannel)
//{
// //u8* const rpt = new u8[2];
// //rpt[0] = 0XA1; rpt[1] = 0x15;
// //m_read_reports.push(rpt);
// //Update();
// const u8 rpt[] = { 0xA1, 0x15 };
// g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, sizeof(rpt));
//}
}
// silly, copying data n stuff, o well, don't use this too often
@ -119,18 +99,20 @@ void Wiimote::DisableDataReporting()
SendPacket(WM_REPORT_MODE, &rpt, sizeof(rpt));
}
void Wiimote::ClearReports()
void Wiimote::ClearReadQueue()
{
// might be silly
while (wiiuse_io_read(wiimote)) {};
if (m_last_data_report)
{
delete[] m_last_data_report;
m_last_data_report = NULL;
}
Report rpt;
while (m_write_reports.Pop(rpt))
delete rpt.first;
while (m_read_reports.Pop(rpt.first))
delete rpt.first;
u8 *rpt;
while (m_read_reports.Pop(rpt))
delete[] rpt;
}
void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size)
@ -146,8 +128,7 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
{
if (0 == m_channel) // first interrupt/control channel sent
{
// clear all msgs, silly maybe
while (wiiuse_io_read(m_wiimote)) {};
ClearReadQueue();
// request status
wm_request_status rpt;
@ -182,29 +163,36 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
m_write_reports.Push(rpt);
}
void Wiimote::Read()
bool Wiimote::Read()
{
// if not connected to Dolphin, don't do anything, to keep sanchez happy :p
if (0 == m_channel)
return;
if (wiiuse_io_read(m_wiimote))
if (wiiuse_io_read(wiimote))
{
if (m_channel)
{
// add it to queue
u8* const rpt = new u8[MAX_PAYLOAD];
memcpy(rpt, m_wiimote->event_buf, MAX_PAYLOAD);
memcpy(rpt, wiimote->event_buf, MAX_PAYLOAD);
m_read_reports.Push(rpt);
}
return true;
}
return false;
}
void Wiimote::Write()
bool Wiimote::Write()
{
Report rpt;
if (m_write_reports.Pop(rpt))
{
wiiuse_io_write(m_wiimote, rpt.first, rpt.second);
wiiuse_io_write(wiimote, rpt.first, rpt.second);
delete[] rpt.first;
return true;
}
return false;
}
// returns the next report that should be sent
@ -232,8 +220,8 @@ void Wiimote::Update()
u8* const rpt = ProcessReadQueue();
// send the report
if (rpt)
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, MAX_PAYLOAD);
if (rpt && m_channel)
g_WiimoteInitialize.pWiimoteInterruptChannel(index, m_channel, rpt, MAX_PAYLOAD);
// delete the data if it isn't also the last data rpt
if (rpt != m_last_data_report)
@ -246,14 +234,6 @@ void Wiimote::Disconnect()
// disable reporting
DisableDataReporting();
// clear queue
u8 *rpt;
while (m_read_reports.Pop(rpt))
delete rpt;
// clear out wiiuse queue, or maybe not, silly? idk
while (wiiuse_io_read(m_wiimote)) {};
}
void LoadSettings()
@ -297,7 +277,6 @@ unsigned int Initialize()
// initialized
g_real_wiimotes_initialized = true;
#ifdef WIN32
// Alloc memory for wiimote structure only if we're starting fresh
if(!g_wiimotes_from_wiiuse)
@ -310,15 +289,14 @@ unsigned int Initialize()
g_wiimotes_found = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5);
#endif
g_wiimotes_lastfound = g_wiimotes_found;
DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted and %i previously found", g_wiimotes_found, wanted_wiimotes, g_wiimotes_lastfound);
DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted and %i previously found",
g_wiimotes_found, wanted_wiimotes, g_wiimotes_lastfound);
g_wiimotes_found =
wiiuse_connect(g_wiimotes_from_wiiuse, g_wiimotes_found);
DEBUG_LOG(WIIMOTE, "Connected to %i Real Wiimotes", g_wiimotes_found);
g_wiimote_critsec.Enter(); // enter
// create real wiimote class instances, assign wiimotes
for (unsigned int i = 0, w = 0; i<MAX_WIIMOTES && w<g_wiimotes_found; ++i)
{
@ -327,11 +305,7 @@ unsigned int Initialize()
g_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
}
g_wiimote_critsec.Leave(); // leave
// start wiimote thread
g_run_wiimote_thread = true;
g_wiimote_thread = new Common::Thread(WiimoteThreadFunc, 0);
StartWiimoteThreads();
return g_wiimotes_found;
}
@ -344,16 +318,7 @@ void Shutdown(void)
// Uninitialized
g_real_wiimotes_initialized = false;
// stop wiimote thread
if (g_wiimote_thread)
{
g_run_wiimote_thread = false;
g_wiimote_thread->WaitForDeath();
delete g_wiimote_thread;
g_wiimote_thread = NULL;
}
g_wiimote_critsec.Enter(); // enter
StopWiimoteThreads();
// delete wiimotes
for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
@ -363,14 +328,6 @@ void Shutdown(void)
g_wiimotes[i] = NULL;
}
g_wiimote_critsec.Leave(); // leave
// set all LEDs on, idk
//for (unsigned int i=0; i<g_wiimotes_found; ++i)
//{
// wiiuse_set_leds(g_wiimotes_from_wiiuse[i], 0xF0);
//}
// Clean up wiiuse, win32: we cant just delete the struct on win32, since wiiuse_find() maintains it and
// adds/removes wimotes directly to/from it to prevent problems, which would occur when using more than 1 wiimote if we create it from scratch everytime
#ifndef WIN32
@ -407,8 +364,9 @@ void Refresh() // this gets called from the GUI thread
DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
StopWiimoteThreads();
g_refresh_critsec.Enter();
g_wiimote_critsec.Enter(); // enter
// create real wiimote class instances, and assign wiimotes for the new wiimotes
for (unsigned int i = g_wiimotes_found, w = g_wiimotes_found;
@ -420,9 +378,10 @@ void Refresh() // this gets called from the GUI thread
}
g_wiimotes_found = num_wiimotes;
g_wiimote_critsec.Leave(); // leave
g_refresh_critsec.Leave();
StartWiimoteThreads();
#else // windows/ OSX
g_refresh_critsec.Enter();
@ -468,31 +427,54 @@ void Update(int _WiimoteNumber)
void StateChange(PLUGIN_EMUSTATE newState)
{
g_wiimote_critsec.Enter(); // enter
//g_refresh_critsec.Enter(); // enter
// TODO: disable/enable auto reporting, maybe
g_wiimote_critsec.Leave(); // leave
//g_refresh_critsec.Leave(); // leave
}
void StartWiimoteThreads()
{
g_run_wiimote_thread = true;
for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
if (g_wiimotes[i])
g_wiimote_threads[i] = new Common::Thread(WiimoteThreadFunc, g_wiimotes[i]);
}
void StopWiimoteThreads()
{
g_run_wiimote_thread = false;
for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
if (g_wiimote_threads[i])
{
g_wiimote_threads[i]->WaitForDeath();
delete g_wiimote_threads[i];
g_wiimote_threads[i] = NULL;
}
}
THREAD_RETURN WiimoteThreadFunc(void* arg)
{
Common::SetCurrentThreadName("Wiimote Thread");
Wiimote* const wiimote = (Wiimote*)arg;
while (g_run_wiimote_thread)
{
g_wiimote_critsec.Enter(); // enter
for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
if (g_wiimotes[i])
{
g_wiimotes[i]->Read();
g_wiimotes[i]->Write();
char thname[] = "Wiimote # Thread";
thname[8] = (char)('1' + wiimote->index);
Common::SetCurrentThreadName(thname);
}
g_wiimote_critsec.Leave(); // leave
// rumble briefly
wiiuse_rumble(wiimote->wiimote, 1);
SLEEP(200);
wiiuse_rumble(wiimote->wiimote, 0);
Common::SleepCurrentThread(1);
// main loop
while (g_run_wiimote_thread)
{
wiimote->Write();
if (false == wiimote->Read())
Common::SleepCurrentThread(1); // sleep if there was nothing to read
}
return 0;

View File

@ -57,8 +57,8 @@ public:
u8* ProcessReadQueue();
void Read();
void Write();
bool Read();
bool Write();
void Disconnect();
void DisableDataReporting();
@ -67,15 +67,16 @@ public:
// pointer to data, and size of data
typedef std::pair<u8*,u8> Report;
const unsigned int index;
wiimote_t* const wiimote;
protected:
u8 *m_last_data_report;
u16 m_channel;
private:
void ClearReports();
void ClearReadQueue();
wiimote_t* const m_wiimote;
const unsigned int m_index;
Common::FifoQueue<u8*> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
};