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 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 ) ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWindow* const parent, wxWindow* const eventsink )
: wxStaticBoxSizer(wxVERTICAL, parent, wxString::FromAscii(group->name)) : wxStaticBoxSizer(wxVERTICAL, parent, wxString::FromAscii(group->name))
, control_group(group)
{ {
control_group = group;
static_bitmap = NULL; static_bitmap = NULL;
wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); 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); ControlButton* const control_button = new ControlButton(parent, (*ci)->control_ref, 80);
control_button->SetFont(m_SmallFont); control_button->SetFont(m_SmallFont);
controls.push_back(control_button);
control_buttons.push_back(control_button); control_buttons.push_back(control_button);
if ((*ci)->control_ref->is_input) if ((*ci)->control_ref->is_input)

View File

@ -161,11 +161,12 @@ class ControlGroupBox : public wxStaticBoxSizer
{ {
public: public:
ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWindow* const parent, wxWindow* const eventsink ); 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; wxStaticBitmap* static_bitmap;
std::vector< PadSetting* > options;
std::vector< wxButton* > controls;
std::vector<ControlButton*> control_buttons; 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) if (false == m_reporting_auto)
PanicAlert("Wiimote: Reporting is set to OFF! Everything should be fine, but games never do this."); 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."); PanicAlert("Wiimote: Unsupported Reporting mode.");
else if (dr->mode < WM_REPORT_CORE) else if (dr->mode < WM_REPORT_CORE)
PanicAlert("Wiimote: Reporting mode < 0x30."); PanicAlert("Wiimote: Reporting mode < 0x30.");

View File

@ -58,11 +58,6 @@ const ReportFeatures reporting_mode_features[] =
{ 2, 0, 4, 14, 23 }, { 2, 0, 4, 14, 23 },
//0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes //0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
{ 2, 4, 7, 17, 23 }, { 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 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 unsigned int g_wiimotes_lastfound = 0;
volatile bool g_run_wiimote_thread = false; volatile bool g_run_wiimote_thread = false;
Common::Thread *g_wiimote_thread = NULL; Common::Thread *g_wiimote_threads[MAX_WIIMOTES] = {};
Common::CriticalSection g_refresh_critsec, g_wiimote_critsec; Common::CriticalSection g_refresh_critsec;
THREAD_RETURN WiimoteThreadFunc(void* arg); 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) Wiimote::Wiimote(wiimote_t* const _wiimote, const unsigned int _index)
: m_last_data_report(NULL) : wiimote(_wiimote)
, index(_index)
, m_last_data_report(NULL)
, m_channel(0) , m_channel(0)
, m_wiimote(wm)
, m_index(index)
{ {
// disable reporting // disable reporting
DisableDataReporting(); 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 // 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 // TODO: make Dolphin connect wiimote, maybe
} }
Wiimote::~Wiimote() 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 // disable reporting / wiiuse might do this on shutdown anyway, o well, don't know for sure
DisableDataReporting(); 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 // 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)); 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) if (m_last_data_report)
{ {
delete[] m_last_data_report; delete[] m_last_data_report;
m_last_data_report = NULL; m_last_data_report = NULL;
} }
Report rpt;
while (m_write_reports.Pop(rpt)) u8 *rpt;
delete rpt.first; while (m_read_reports.Pop(rpt))
while (m_read_reports.Pop(rpt.first)) delete[] rpt;
delete rpt.first;
} }
void Wiimote::ControlChannel(const u16 channel, const void* const data, const u32 size) 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 if (0 == m_channel) // first interrupt/control channel sent
{ {
// clear all msgs, silly maybe ClearReadQueue();
while (wiiuse_io_read(m_wiimote)) {};
// request status // request status
wm_request_status rpt; wm_request_status rpt;
@ -182,29 +163,36 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
m_write_reports.Push(rpt); 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 (wiiuse_io_read(wiimote))
if (0 == m_channel) {
return; if (m_channel)
if (wiiuse_io_read(m_wiimote))
{ {
// add it to queue // add it to queue
u8* const rpt = new u8[MAX_PAYLOAD]; 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); m_read_reports.Push(rpt);
} }
return true;
}
return false;
} }
void Wiimote::Write() bool Wiimote::Write()
{ {
Report rpt; Report rpt;
if (m_write_reports.Pop(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; delete[] rpt.first;
return true;
} }
return false;
} }
// returns the next report that should be sent // returns the next report that should be sent
@ -232,8 +220,8 @@ void Wiimote::Update()
u8* const rpt = ProcessReadQueue(); u8* const rpt = ProcessReadQueue();
// send the report // send the report
if (rpt) if (rpt && m_channel)
g_WiimoteInitialize.pWiimoteInterruptChannel(m_index, m_channel, rpt, MAX_PAYLOAD); g_WiimoteInitialize.pWiimoteInterruptChannel(index, m_channel, rpt, MAX_PAYLOAD);
// delete the data if it isn't also the last data rpt // delete the data if it isn't also the last data rpt
if (rpt != m_last_data_report) if (rpt != m_last_data_report)
@ -246,14 +234,6 @@ void Wiimote::Disconnect()
// disable reporting // disable reporting
DisableDataReporting(); 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() void LoadSettings()
@ -297,7 +277,6 @@ unsigned int Initialize()
// initialized // initialized
g_real_wiimotes_initialized = true; g_real_wiimotes_initialized = true;
#ifdef WIN32 #ifdef WIN32
// Alloc memory for wiimote structure only if we're starting fresh // Alloc memory for wiimote structure only if we're starting fresh
if(!g_wiimotes_from_wiiuse) if(!g_wiimotes_from_wiiuse)
@ -310,15 +289,14 @@ unsigned int Initialize()
g_wiimotes_found = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5); g_wiimotes_found = wiiuse_find(g_wiimotes_from_wiiuse, wanted_wiimotes, 5);
#endif #endif
g_wiimotes_lastfound = g_wiimotes_found; 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 = g_wiimotes_found =
wiiuse_connect(g_wiimotes_from_wiiuse, g_wiimotes_found); wiiuse_connect(g_wiimotes_from_wiiuse, g_wiimotes_found);
DEBUG_LOG(WIIMOTE, "Connected to %i Real Wiimotes", 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 // create real wiimote class instances, assign wiimotes
for (unsigned int i = 0, w = 0; i<MAX_WIIMOTES && w<g_wiimotes_found; ++i) 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_wiimotes[i] = new Wiimote(g_wiimotes_from_wiiuse[w++], i);
} }
g_wiimote_critsec.Leave(); // leave StartWiimoteThreads();
// start wiimote thread
g_run_wiimote_thread = true;
g_wiimote_thread = new Common::Thread(WiimoteThreadFunc, 0);
return g_wiimotes_found; return g_wiimotes_found;
} }
@ -344,16 +318,7 @@ void Shutdown(void)
// Uninitialized // Uninitialized
g_real_wiimotes_initialized = false; g_real_wiimotes_initialized = false;
// stop wiimote thread StopWiimoteThreads();
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
// delete wiimotes // delete wiimotes
for (unsigned int i=0; i<MAX_WIIMOTES; ++i) for (unsigned int i=0; i<MAX_WIIMOTES; ++i)
@ -363,14 +328,6 @@ void Shutdown(void)
g_wiimotes[i] = NULL; 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 // 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 // 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 #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); DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
StopWiimoteThreads();
g_refresh_critsec.Enter(); g_refresh_critsec.Enter();
g_wiimote_critsec.Enter(); // enter
// create real wiimote class instances, and assign wiimotes for the new wiimotes // create real wiimote class instances, and assign wiimotes for the new wiimotes
for (unsigned int i = g_wiimotes_found, w = g_wiimotes_found; 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_wiimotes_found = num_wiimotes;
g_wiimote_critsec.Leave(); // leave
g_refresh_critsec.Leave(); g_refresh_critsec.Leave();
StartWiimoteThreads();
#else // windows/ OSX #else // windows/ OSX
g_refresh_critsec.Enter(); g_refresh_critsec.Enter();
@ -468,31 +427,54 @@ void Update(int _WiimoteNumber)
void StateChange(PLUGIN_EMUSTATE newState) void StateChange(PLUGIN_EMUSTATE newState)
{ {
g_wiimote_critsec.Enter(); // enter //g_refresh_critsec.Enter(); // enter
// TODO: disable/enable auto reporting, maybe // 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) THREAD_RETURN WiimoteThreadFunc(void* arg)
{ {
Common::SetCurrentThreadName("Wiimote Thread"); Wiimote* const wiimote = (Wiimote*)arg;
while (g_run_wiimote_thread)
{ {
g_wiimote_critsec.Enter(); // enter char thname[] = "Wiimote # Thread";
thname[8] = (char)('1' + wiimote->index);
for (unsigned int i=0; i<MAX_WIIMOTES; ++i) Common::SetCurrentThreadName(thname);
if (g_wiimotes[i])
{
g_wiimotes[i]->Read();
g_wiimotes[i]->Write();
} }
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; return 0;

View File

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