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:
parent
0a606d7356
commit
7c7257b825
|
@ -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)
|
||||
|
|
|
@ -161,12 +161,13 @@ 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;
|
||||
std::vector<ControlButton*> control_buttons;
|
||||
};
|
||||
|
||||
class ControlGroupsSizer : public wxBoxSizer
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
// add it to queue
|
||||
u8* const rpt = new u8[MAX_PAYLOAD];
|
||||
memcpy(rpt, m_wiimote->event_buf, MAX_PAYLOAD);
|
||||
m_read_reports.Push(rpt);
|
||||
if (m_channel)
|
||||
{
|
||||
// add it to queue
|
||||
u8* const rpt = new u8[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;
|
||||
|
||||
{
|
||||
char thname[] = "Wiimote # Thread";
|
||||
thname[8] = (char)('1' + wiimote->index);
|
||||
Common::SetCurrentThreadName(thname);
|
||||
}
|
||||
|
||||
// rumble briefly
|
||||
wiiuse_rumble(wiimote->wiimote, 1);
|
||||
SLEEP(200);
|
||||
wiiuse_rumble(wiimote->wiimote, 0);
|
||||
|
||||
// main loop
|
||||
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();
|
||||
}
|
||||
|
||||
g_wiimote_critsec.Leave(); // leave
|
||||
|
||||
Common::SleepCurrentThread(1);
|
||||
wiimote->Write();
|
||||
if (false == wiimote->Read())
|
||||
Common::SleepCurrentThread(1); // sleep if there was nothing to read
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue