mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-16 04:09:39 +00:00
WiimoteReal: Send periodic writes to test for disconnect.
This commit is contained in:
parent
94ecf4df39
commit
e8d22923c6
@ -168,8 +168,6 @@ void Wiimote::Shutdown()
|
||||
|
||||
StopThread();
|
||||
ClearReadQueue();
|
||||
|
||||
NOTICE_LOG_FMT(WIIMOTE, "Disconnected real wiimote.");
|
||||
}
|
||||
|
||||
// to be called from CPU thread
|
||||
@ -209,8 +207,8 @@ void Wiimote::WriteReport(Report rpt)
|
||||
const auto report_time =
|
||||
Core::IsCPUThread() ? core_timing.GetTargetHostTime(core_timing.GetTicks()) : Clock::now();
|
||||
|
||||
m_write_thread.EmplaceItem(report_time, std::move(rpt));
|
||||
IOWakeup();
|
||||
m_write_reports.Emplace(report_time, std::move(rpt));
|
||||
m_write_event.Set();
|
||||
}
|
||||
|
||||
// to be called from CPU thread
|
||||
@ -512,11 +510,13 @@ void Wiimote::Prepare()
|
||||
// Set reporting mode to non-continuous core buttons and turn on rumble.
|
||||
Report mode_report = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::ReportMode), 1,
|
||||
u8(InputReportID::ReportCore)};
|
||||
m_write_thread.EmplaceItem(now, std::move(mode_report));
|
||||
m_write_reports.Emplace(now, std::move(mode_report));
|
||||
|
||||
// Request status and turn off rumble.
|
||||
Report req_status_report = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::RequestStatus), 0};
|
||||
m_write_thread.EmplaceItem(now + std::chrono::milliseconds{200}, std::move(req_status_report));
|
||||
m_write_reports.Emplace(now + std::chrono::milliseconds{200}, std::move(req_status_report));
|
||||
|
||||
m_write_event.Set();
|
||||
}
|
||||
|
||||
void Wiimote::EmuStop()
|
||||
@ -764,38 +764,54 @@ void WiimoteScanner::ThreadFunc()
|
||||
bool Wiimote::Connect(int index)
|
||||
{
|
||||
m_index = index;
|
||||
|
||||
if (!m_run_thread.IsSet())
|
||||
{
|
||||
m_run_thread.Set();
|
||||
StartThread();
|
||||
m_thread_ready_event.Wait();
|
||||
}
|
||||
|
||||
StartThread();
|
||||
return IsConnected();
|
||||
}
|
||||
|
||||
void Wiimote::StartThread()
|
||||
{
|
||||
// Note that the read thread starts the writing worker thread.
|
||||
m_read_thread = std::thread(&Wiimote::ReadThreadFunc, this);
|
||||
if (m_write_thread.joinable())
|
||||
return;
|
||||
|
||||
m_run_thread.Set();
|
||||
// Note that the write thread starts the read thread.
|
||||
m_write_thread = std::thread(&Wiimote::WriteThreadFunc, this);
|
||||
|
||||
m_thread_ready_event.Wait();
|
||||
}
|
||||
|
||||
void Wiimote::StopThread()
|
||||
{
|
||||
if (!m_run_thread.TestAndClear())
|
||||
if (!m_write_thread.joinable())
|
||||
return;
|
||||
|
||||
IOWakeup();
|
||||
m_run_thread.Clear();
|
||||
m_write_event.Set();
|
||||
|
||||
// Note that the read thread stops the writing worker thread.
|
||||
m_read_thread.join();
|
||||
// Note that the write thread stops the read thread.
|
||||
m_write_thread.join();
|
||||
}
|
||||
|
||||
void Wiimote::ReadThreadFunc()
|
||||
{
|
||||
Common::SetCurrentThreadName("Wiimote Read Thread");
|
||||
|
||||
while (m_run_thread.IsSet())
|
||||
{
|
||||
if (!Read())
|
||||
{
|
||||
WARN_LOG_FMT(WIIMOTE, "Wiimote::Read failed on Wiimote {}.", m_index + 1);
|
||||
m_run_thread.Clear();
|
||||
m_write_event.Set();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Wiimote::WriteThreadFunc()
|
||||
{
|
||||
Common::SetCurrentThreadName("Wiimote Write Thread");
|
||||
|
||||
bool ok = ConnectInternal();
|
||||
|
||||
if (!ok)
|
||||
@ -812,19 +828,55 @@ void Wiimote::ReadThreadFunc()
|
||||
return;
|
||||
}
|
||||
|
||||
m_write_thread.Reset("Wiimote Write Thread", std::bind_front(&Wiimote::Write, this));
|
||||
std::thread read_thread{&Wiimote::ReadThreadFunc, this};
|
||||
|
||||
// Windows and also the DolphinBar require performing a write
|
||||
// to detect disconnections in a timely manner
|
||||
// If we haven't written a report in some time, attempt a rumble-off report.
|
||||
// This also has a minor benefit of preventing rumble from being stuck on.
|
||||
constexpr auto WRITE_TEST_INTERVAL = std::chrono::milliseconds{1000};
|
||||
|
||||
TimePoint last_write_time = Clock::now();
|
||||
|
||||
while (m_run_thread.IsSet())
|
||||
{
|
||||
if (!Read())
|
||||
bool write_success = false;
|
||||
|
||||
if (!m_write_reports.Empty())
|
||||
{
|
||||
ERROR_LOG_FMT(WIIMOTE, "Wiimote::Read failed. Disconnecting Wiimote {}.", m_index + 1);
|
||||
// Send a normal report.
|
||||
write_success = Write(m_write_reports.Front());
|
||||
m_write_reports.Pop();
|
||||
}
|
||||
else if (Clock::now() - last_write_time >= WRITE_TEST_INTERVAL)
|
||||
{
|
||||
// We haven't written in a while, test a write so we can check for a disconnect.
|
||||
DEBUG_LOG_FMT(WIIMOTE, "Sending periodic write test for Wiimote {}.", m_index + 1);
|
||||
const u8 rumble_off[] = {WR_SET_REPORT | BT_OUTPUT, u8(OutputReportID::Rumble), 0x00};
|
||||
|
||||
write_success = IOWrite(std::data(rumble_off), std::size(rumble_off)) > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do. Wait a while for a kick.
|
||||
m_write_event.WaitFor(WRITE_TEST_INTERVAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
last_write_time = Clock::now();
|
||||
|
||||
if (!write_success)
|
||||
{
|
||||
WARN_LOG_FMT(WIIMOTE, "Wiimote::Write failed on Wiimote {}.", m_index + 1);
|
||||
m_run_thread.Clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_write_thread.StopAndCancel();
|
||||
IOWakeup();
|
||||
read_thread.join();
|
||||
|
||||
NOTICE_LOG_FMT(WIIMOTE, "Disconnecting Wiimote {}.", m_index + 1);
|
||||
DisconnectInternal();
|
||||
}
|
||||
|
||||
|
||||
@ -146,6 +146,7 @@ private:
|
||||
virtual void IOWakeup() = 0;
|
||||
|
||||
void ReadThreadFunc();
|
||||
void WriteThreadFunc();
|
||||
|
||||
void RefreshConfig();
|
||||
|
||||
@ -158,14 +159,16 @@ private:
|
||||
// And we track the rumble state to drop unnecessary rumble reports.
|
||||
bool m_rumble_state = false;
|
||||
|
||||
std::thread m_read_thread;
|
||||
std::thread m_write_thread;
|
||||
// Whether to keep running the thread.
|
||||
Common::Flag m_run_thread;
|
||||
// Triggered when the thread has finished ConnectInternal.
|
||||
Common::Event m_thread_ready_event;
|
||||
|
||||
Common::SPSCQueue<Report> m_read_reports;
|
||||
Common::WorkQueueThreadSP<TimedReport> m_write_thread;
|
||||
Common::SPSCQueue<TimedReport> m_write_reports;
|
||||
// Kick the write thread.
|
||||
Common::Event m_write_event;
|
||||
|
||||
bool m_speaker_enabled_in_dolphin_config = false;
|
||||
int m_balance_board_dump_port = 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user