Merge pull request #7871 from jordan-woyak/wm-real-cleanup

WiimoteReal: Improve state changes and code cleanups.
This commit is contained in:
JMC47 2019-03-25 19:28:22 -04:00 committed by GitHub
commit e636b3e712
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 185 additions and 191 deletions

View File

@ -6,6 +6,7 @@
#include "Common/ChunkFile.h" #include "Common/ChunkFile.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
@ -137,21 +138,29 @@ void Pause()
// An L2CAP packet is passed from the Core to the Wiimote on the HID CONTROL channel. // An L2CAP packet is passed from the Core to the Wiimote on the HID CONTROL channel.
void ControlChannel(int number, u16 channel_id, const void* data, u32 size) void ControlChannel(int number, u16 channel_id, const void* data, u32 size)
{ {
if (g_wiimote_sources[number]) if (WIIMOTE_SRC_EMU == g_wiimote_sources[number])
{ {
static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number)) static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number))
->ControlChannel(channel_id, data, size); ->ControlChannel(channel_id, data, size);
} }
else
{
WiimoteReal::ControlChannel(number, channel_id, data, size);
}
} }
// An L2CAP packet is passed from the Core to the Wiimote on the HID INTERRUPT channel. // An L2CAP packet is passed from the Core to the Wiimote on the HID INTERRUPT channel.
void InterruptChannel(int number, u16 channel_id, const void* data, u32 size) void InterruptChannel(int number, u16 channel_id, const void* data, u32 size)
{ {
if (g_wiimote_sources[number]) if (WIIMOTE_SRC_EMU == g_wiimote_sources[number])
{ {
static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number)) static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(number))
->InterruptChannel(channel_id, data, size); ->InterruptChannel(channel_id, data, size);
} }
else
{
WiimoteReal::InterruptChannel(number, channel_id, data, size);
}
} }
bool ButtonPressed(int number) bool ButtonPressed(int number)
@ -215,6 +224,26 @@ unsigned int GetAttached()
void DoState(PointerWrap& p) void DoState(PointerWrap& p)
{ {
for (int i = 0; i < MAX_BBMOTES; ++i) for (int i = 0; i < MAX_BBMOTES; ++i)
{
auto state_wiimote_source = u8(g_wiimote_sources[i]);
p.Do(state_wiimote_source);
if (WIIMOTE_SRC_EMU == state_wiimote_source)
{
// Sync complete state of emulated wiimotes.
static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(i))->DoState(p); static_cast<WiimoteEmu::Wiimote*>(s_config.GetController(i))->DoState(p);
} }
if (p.GetMode() == PointerWrap::MODE_READ)
{
// If using a real wiimote or the save-state source does not match the current source,
// then force a reconnection on load.
if (WIIMOTE_SRC_REAL == g_wiimote_sources[i] || state_wiimote_source != g_wiimote_sources[i])
{
Connect(i, false);
Connect(i, true);
}
}
}
}
} // namespace Wiimote } // namespace Wiimote

View File

@ -4,6 +4,9 @@
#pragma once #pragma once
#include <array>
#include <atomic>
#include "Common/Common.h" #include "Common/Common.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -45,7 +48,7 @@ enum
WIIMOTE_SRC_REAL = 2, WIIMOTE_SRC_REAL = 2,
}; };
extern unsigned int g_wiimote_sources[MAX_BBMOTES]; extern std::array<std::atomic<u32>, MAX_BBMOTES> g_wiimote_sources;
namespace Wiimote namespace Wiimote
{ {

View File

@ -590,9 +590,6 @@ void Wiimote::DoState(PointerWrap& p)
p.Do(m_shake_step); p.Do(m_shake_step);
p.DoMarker("Wiimote"); p.DoMarker("Wiimote");
if (p.GetMode() == PointerWrap::MODE_READ)
RealState();
} }
ExtensionNumber Wiimote::GetActiveExtensionNumber() const ExtensionNumber Wiimote::GetActiveExtensionNumber() const
@ -600,14 +597,4 @@ ExtensionNumber Wiimote::GetActiveExtensionNumber() const
return m_active_extension; return m_active_extension;
} }
void Wiimote::RealState()
{
using namespace WiimoteReal;
if (g_wiimotes[m_index])
{
g_wiimotes[m_index]->SetChannel(m_reporting_channel);
}
}
} // namespace WiimoteEmu } // namespace WiimoteEmu

View File

@ -20,6 +20,7 @@
#include "Core/Config/WiimoteInputSettings.h" #include "Core/Config/WiimoteInputSettings.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/Wiimote.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayClient.h" #include "Core/NetPlayClient.h"
@ -30,7 +31,6 @@
#include "Core/HW/WiimoteEmu/Extension/Guitar.h" #include "Core/HW/WiimoteEmu/Extension/Guitar.h"
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h" #include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
#include "Core/HW/WiimoteEmu/Extension/Turntable.h" #include "Core/HW/WiimoteEmu/Extension/Turntable.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "InputCommon/ControllerEmu/Control/Input.h" #include "InputCommon/ControllerEmu/Control/Input.h"
#include "InputCommon/ControllerEmu/Control/Output.h" #include "InputCommon/ControllerEmu/Control/Output.h"
@ -503,14 +503,6 @@ void Wiimote::ControlChannel(const u16 channel_id, const void* data, u32 size)
m_reporting_channel = channel_id; m_reporting_channel = channel_id;
// FYI: ControlChannel is piped through WiimoteEmu before WiimoteReal just so we can sync the
// channel on state load. This is ugly.
if (WIIMOTE_SRC_REAL == g_wiimote_sources[m_index])
{
WiimoteReal::ControlChannel(m_index, channel_id, data, size);
return;
}
const auto& hidp = *reinterpret_cast<const HIDPacket*>(data); const auto& hidp = *reinterpret_cast<const HIDPacket*>(data);
DEBUG_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index, DEBUG_LOG(WIIMOTE, "Emu ControlChannel (page: %i, type: 0x%02x, param: 0x%02x)", m_index,
@ -559,14 +551,6 @@ void Wiimote::InterruptChannel(const u16 channel_id, const void* data, u32 size)
m_reporting_channel = channel_id; m_reporting_channel = channel_id;
// FYI: InterruptChannel is piped through WiimoteEmu before WiimoteReal just so we can sync the
// channel on state load. This is ugly.
if (WIIMOTE_SRC_REAL == g_wiimote_sources[m_index])
{
WiimoteReal::InterruptChannel(m_index, channel_id, data, size);
return;
}
const auto& hidp = *reinterpret_cast<const HIDPacket*>(data); const auto& hidp = *reinterpret_cast<const HIDPacket*>(data);
switch (hidp.type) switch (hidp.type)

View File

@ -35,12 +35,6 @@ class Output;
class Tilt; class Tilt;
} // namespace ControllerEmu } // namespace ControllerEmu
// Needed for friendship:
namespace WiimoteReal
{
class Wiimote;
} // namespace WiimoteReal
namespace WiimoteEmu namespace WiimoteEmu
{ {
enum class WiimoteGroup enum class WiimoteGroup
@ -87,8 +81,6 @@ void UpdateCalibrationDataChecksum(T& data, int cksum_bytes)
class Wiimote : public ControllerEmu::EmulatedController class Wiimote : public ControllerEmu::EmulatedController
{ {
friend class WiimoteReal::Wiimote;
public: public:
enum : u8 enum : u8
{ {
@ -173,8 +165,6 @@ private:
void SendDataReport(); void SendDataReport();
bool ProcessReadDataRequest(); bool ProcessReadDataRequest();
void RealState();
void SetRumble(bool on); void SetRumble(bool on);
void CallbackInterruptChannel(const u8* data, u32 size); void CallbackInterruptChannel(const u8* data, u32 size);

View File

@ -284,7 +284,7 @@ void WiimoteDarwin::DisablePowerAssertionInternal()
for (int i = 0; i < MAX_WIIMOTES; i++) for (int i = 0; i < MAX_WIIMOTES; i++)
{ {
wm = static_cast<WiimoteReal::WiimoteDarwin*>(WiimoteReal::g_wiimotes[i]); wm = static_cast<WiimoteReal::WiimoteDarwin*>(WiimoteReal::g_wiimotes[i].get());
if (!wm) if (!wm)
continue; continue;
if ([device isEqual:wm->m_btd]) if ([device isEqual:wm->m_btd])
@ -325,7 +325,7 @@ void WiimoteDarwin::DisablePowerAssertionInternal()
for (int i = 0; i < MAX_WIIMOTES; i++) for (int i = 0; i < MAX_WIIMOTES; i++)
{ {
wm = static_cast<WiimoteReal::WiimoteDarwin*>(WiimoteReal::g_wiimotes[i]); wm = static_cast<WiimoteReal::WiimoteDarwin*>(WiimoteReal::g_wiimotes[i].get());
if (!wm) if (!wm)
continue; continue;
if ([device isEqual:wm->m_btd]) if ([device isEqual:wm->m_btd])

View File

@ -19,8 +19,8 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/HW/Wiimote.h" #include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteCommon/DataReport.h"
#include "Core/HW/WiimoteCommon/WiimoteHid.h" #include "Core/HW/WiimoteCommon/WiimoteHid.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
#include "Core/HW/WiimoteReal/IOAndroid.h" #include "Core/HW/WiimoteReal/IOAndroid.h"
#include "Core/HW/WiimoteReal/IOLinux.h" #include "Core/HW/WiimoteReal/IOLinux.h"
#include "Core/HW/WiimoteReal/IOWin.h" #include "Core/HW/WiimoteReal/IOWin.h"
@ -30,14 +30,14 @@
#include "SFML/Network.hpp" #include "SFML/Network.hpp"
unsigned int g_wiimote_sources[MAX_BBMOTES]; std::array<std::atomic<u32>, MAX_BBMOTES> g_wiimote_sources;
namespace WiimoteReal namespace WiimoteReal
{ {
using namespace WiimoteCommon; using namespace WiimoteCommon;
static void TryToConnectBalanceBoard(Wiimote*); static void TryToConnectBalanceBoard(std::unique_ptr<Wiimote>);
static void TryToConnectWiimote(Wiimote*); static void TryToConnectWiimote(std::unique_ptr<Wiimote>);
static void HandleWiimoteDisconnect(int index); static void HandleWiimoteDisconnect(int index);
static bool g_real_wiimotes_initialized = false; static bool g_real_wiimotes_initialized = false;
@ -49,18 +49,19 @@ static std::mutex s_known_ids_mutex;
std::mutex g_wiimotes_mutex; std::mutex g_wiimotes_mutex;
Wiimote* g_wiimotes[MAX_BBMOTES]; std::unique_ptr<Wiimote> g_wiimotes[MAX_BBMOTES];
WiimoteScanner g_wiimote_scanner; WiimoteScanner g_wiimote_scanner;
Wiimote::Wiimote() : m_index(), m_last_input_report(), m_channel(0), m_rumble_state()
{
}
void Wiimote::Shutdown() void Wiimote::Shutdown()
{ {
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.erase(GetId());
StopThread(); StopThread();
ClearReadQueue(); ClearReadQueue();
m_write_reports.Clear(); m_write_reports.Clear();
NOTICE_LOG(WIIMOTE, "Disconnected real wiimote.");
} }
// to be called from CPU thread // to be called from CPU thread
@ -70,9 +71,31 @@ void Wiimote::WriteReport(Report rpt)
{ {
bool const new_rumble_state = (rpt[2] & 0x1) != 0; bool const new_rumble_state = (rpt[2] & 0x1) != 0;
// If this is a rumble report and the rumble state didn't change, ignore. switch (WiimoteCommon::OutputReportID(rpt[1]))
if (rpt[1] == u8(OutputReportID::Rumble) && new_rumble_state == m_rumble_state) {
case OutputReportID::Rumble:
// If this is a rumble report and the rumble state didn't change, we can drop this report.
if (new_rumble_state == m_rumble_state)
return; return;
break;
case OutputReportID::SpeakerEnable:
m_speaker_enable = (rpt[2] & 0x4) != 0;
break;
case OutputReportID::SpeakerMute:
m_speaker_mute = (rpt[2] & 0x4) != 0;
break;
case OutputReportID::ReportMode:
// Force non-continuous reporting for less BT traffic.
// We duplicate reports to maintain 200hz anyways.
rpt[2] &= ~0x4;
break;
default:
break;
}
m_rumble_state = new_rumble_state; m_rumble_state = new_rumble_state;
} }
@ -82,42 +105,27 @@ void Wiimote::WriteReport(Report rpt)
} }
// to be called from CPU thread // to be called from CPU thread
void Wiimote::QueueReport(u8 rpt_id, const void* data, unsigned int size) void Wiimote::QueueReport(WiimoteCommon::OutputReportID rpt_id, const void* data, unsigned int size)
{ {
auto const queue_data = static_cast<const u8*>(data); auto const queue_data = static_cast<const u8*>(data);
Report rpt(size + 2); Report rpt(size + 2);
rpt[0] = WR_SET_REPORT | BT_OUTPUT; rpt[0] = WR_SET_REPORT | BT_OUTPUT;
rpt[1] = rpt_id; rpt[1] = u8(rpt_id);
std::copy_n(queue_data, size, rpt.begin() + 2); std::copy_n(queue_data, size, rpt.begin() + 2);
WriteReport(std::move(rpt)); WriteReport(std::move(rpt));
} }
void Wiimote::DisableDataReporting() void Wiimote::ResetDataReporting()
{ {
m_last_input_report.clear(); m_last_input_report.clear();
// This accomplishes very little: // "core" reporting in non-continuous mode is a wiimote's initial state.
// FYI: This also disables rumble.
OutputReportMode rpt = {}; OutputReportMode rpt = {};
rpt.mode = InputReportID::ReportCore; rpt.mode = InputReportID::ReportCore;
rpt.continuous = 0; rpt.continuous = 0;
rpt.rumble = 0; QueueReport(OutputReportID::ReportMode, &rpt, sizeof(rpt));
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
}
void Wiimote::EnableDataReporting(u8 mode)
{
m_last_input_report.clear();
OutputReportMode rpt = {};
rpt.mode = InputReportID(mode);
rpt.continuous = 1;
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
}
void Wiimote::SetChannel(u16 channel)
{
m_channel = channel;
} }
void Wiimote::ClearReadQueue() void Wiimote::ClearReadQueue()
@ -136,9 +144,15 @@ void Wiimote::ControlChannel(const u16 channel, const void* const data, const u3
if (channel == 99) if (channel == 99)
{ {
if (m_really_disconnect) if (m_really_disconnect)
{
DisconnectInternal(); DisconnectInternal();
} }
else else
{
EmuStop();
}
}
else
{ {
InterruptChannel(channel, data, size); InterruptChannel(channel, data, size);
const auto& hidp = *static_cast<const HIDPacket*>(data); const auto& hidp = *static_cast<const HIDPacket*>(data);
@ -164,8 +178,6 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
auto const report_data = static_cast<const u8*>(data); auto const report_data = static_cast<const u8*>(data);
Report rpt(report_data, report_data + size); Report rpt(report_data, report_data + size);
WiimoteEmu::Wiimote* const wm =
static_cast<WiimoteEmu::Wiimote*>(::Wiimote::GetConfig()->GetController(m_index));
// Convert output DATA packets to SET_REPORT packets. // Convert output DATA packets to SET_REPORT packets.
// Nintendo Wiimotes work without this translation, but 3rd // Nintendo Wiimotes work without this translation, but 3rd
@ -187,10 +199,9 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
} }
} }
else if (rpt[1] == u8(OutputReportID::SpeakerData) && else if (rpt[1] == u8(OutputReportID::SpeakerData) &&
(!SConfig::GetInstance().m_WiimoteEnableSpeaker || (!SConfig::GetInstance().m_WiimoteEnableSpeaker || !m_speaker_enable || m_speaker_mute))
(!wm->m_status.speaker || wm->m_speaker_mute)))
{ {
// Translate speaker data reports into rumble reports. // Translate undesired speaker data reports into rumble reports.
rpt[1] = u8(OutputReportID::Rumble); rpt[1] = u8(OutputReportID::Rumble);
// Keep only the rumble bit. // Keep only the rumble bit.
rpt[2] &= 0x1; rpt[2] &= 0x1;
@ -379,6 +390,8 @@ bool Wiimote::CheckForButtonPress()
if (rpt.size() >= 4) if (rpt.size() >= 4)
{ {
const auto mode = InputReportID(rpt[1]); const auto mode = InputReportID(rpt[1]);
// TODO: Button data could also be pulled out of non-data reports if really wanted.
if (DataReportBuilder::IsValidMode(mode)) if (DataReportBuilder::IsValidMode(mode))
{ {
auto builder = MakeDataReportManipulator(mode, rpt.data() + 2); auto builder = MakeDataReportManipulator(mode, rpt.data() + 2);
@ -423,49 +436,26 @@ bool Wiimote::PrepareOnThread()
void Wiimote::EmuStart() void Wiimote::EmuStart()
{ {
DisableDataReporting(); ResetDataReporting();
EnablePowerAssertionInternal(); EnablePowerAssertionInternal();
} }
void Wiimote::EmuStop() void Wiimote::EmuStop()
{ {
m_channel = 0; m_channel = 0;
ResetDataReporting();
DisableDataReporting();
NOTICE_LOG(WIIMOTE, "Stopping Wiimote data reporting.");
DisablePowerAssertionInternal(); DisablePowerAssertionInternal();
} }
void Wiimote::EmuResume() void Wiimote::EmuResume()
{ {
WiimoteEmu::Wiimote* const wm =
static_cast<WiimoteEmu::Wiimote*>(::Wiimote::GetConfig()->GetController(m_index));
m_last_input_report.clear(); m_last_input_report.clear();
OutputReportMode rpt = {};
rpt.mode = wm->m_reporting_mode;
rpt.continuous = 1;
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
NOTICE_LOG(WIIMOTE, "Resuming Wiimote data reporting.");
EnablePowerAssertionInternal(); EnablePowerAssertionInternal();
} }
void Wiimote::EmuPause() void Wiimote::EmuPause()
{ {
m_last_input_report.clear();
OutputReportMode rpt = {};
rpt.mode = InputReportID::ReportCore;
rpt.continuous = 0;
QueueReport(u8(OutputReportID::ReportMode), &rpt, sizeof(rpt));
NOTICE_LOG(WIIMOTE, "Pausing Wiimote data reporting.");
DisablePowerAssertionInternal(); DisablePowerAssertionInternal();
} }
@ -569,25 +559,43 @@ void WiimoteScanner::ThreadFunc()
if (m_scan_mode.load() == WiimoteScanMode::DO_NOT_SCAN) if (m_scan_mode.load() == WiimoteScanMode::DO_NOT_SCAN)
continue; continue;
if (!g_real_wiimotes_initialized)
continue;
// Does stuff needed to detect disconnects on Windows
for (const auto& backend : m_backends)
backend->Update();
if (0 == CalculateWantedWiimotes() && 0 == CalculateWantedBB())
continue;
for (const auto& backend : m_backends) for (const auto& backend : m_backends)
{
if (CalculateWantedWiimotes() != 0 || CalculateWantedBB() != 0)
{ {
std::vector<Wiimote*> found_wiimotes; std::vector<Wiimote*> found_wiimotes;
Wiimote* found_board = nullptr; Wiimote* found_board = nullptr;
backend->FindWiimotes(found_wiimotes, found_board); backend->FindWiimotes(found_wiimotes, found_board);
{ {
if (!g_real_wiimotes_initialized) std::lock_guard<std::mutex> wm_lk(g_wiimotes_mutex);
continue;
std::lock_guard<std::mutex> lk(g_wiimotes_mutex); for (auto* wiimote : found_wiimotes)
std::for_each(found_wiimotes.begin(), found_wiimotes.end(), TryToConnectWiimote);
if (found_board)
TryToConnectBalanceBoard(found_board);
}
}
else
{ {
backend->Update(); // Does stuff needed to detect disconnects on Windows {
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.insert(wiimote->GetId());
}
TryToConnectWiimote(std::unique_ptr<Wiimote>(wiimote));
}
if (found_board)
{
{
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.insert(found_board->GetId());
}
TryToConnectBalanceBoard(std::unique_ptr<Wiimote>(found_board));
}
} }
} }
@ -687,12 +695,17 @@ void LoadSettings()
secname += static_cast<char>('1' + i); secname += static_cast<char>('1' + i);
IniFile::Section& sec = *inifile.GetOrCreateSection(secname); IniFile::Section& sec = *inifile.GetOrCreateSection(secname);
sec.Get("Source", &g_wiimote_sources[i], i ? WIIMOTE_SRC_NONE : WIIMOTE_SRC_EMU); unsigned int source = 0;
sec.Get("Source", &source, i ? WIIMOTE_SRC_NONE : WIIMOTE_SRC_EMU);
g_wiimote_sources[i] = source;
} }
std::string secname("BalanceBoard"); std::string secname("BalanceBoard");
IniFile::Section& sec = *inifile.GetOrCreateSection(secname); IniFile::Section& sec = *inifile.GetOrCreateSection(secname);
sec.Get("Source", &g_wiimote_sources[WIIMOTE_BALANCE_BOARD], WIIMOTE_SRC_NONE);
unsigned int bb_source = 0;
sec.Get("Source", &bb_source, WIIMOTE_SRC_NONE);
g_wiimote_sources[WIIMOTE_BALANCE_BOARD] = bb_source;
} }
// config dialog calls this when some settings change // config dialog calls this when some settings change
@ -700,7 +713,6 @@ void Initialize(::Wiimote::InitializeMode init_mode)
{ {
if (!g_real_wiimotes_initialized) if (!g_real_wiimotes_initialized)
{ {
s_known_ids.clear();
g_wiimote_scanner.StartThread(); g_wiimote_scanner.StartThread();
} }
@ -776,83 +788,70 @@ void ChangeWiimoteSource(unsigned int index, int source)
} }
g_wiimote_sources[index] = source; g_wiimote_sources[index] = source;
{ {
// kill real connection (or swap to different slot) // Kill real wiimote connection (if any) (or swap to different slot)
std::lock_guard<std::mutex> lk(g_wiimotes_mutex); std::lock_guard<std::mutex> lk(g_wiimotes_mutex);
if (auto removed_wiimote = std::move(g_wiimotes[index]))
Wiimote* wm = g_wiimotes[index];
if (wm)
{ {
g_wiimotes[index] = nullptr; // See if we can use this real Wiimote in another slot.
// First see if we can use this real Wiimote in another slot. // Otherwise it will be disconnected.
TryToConnectWiimote(wm); TryToConnectWiimote(std::move(removed_wiimote));
}
} }
// else, just disconnect the Wiimote // Reconnect to the emulator.
HandleWiimoteDisconnect(index);
}
// reconnect to the emulator
Core::RunAsCPUThread([index, previous_source, source] { Core::RunAsCPUThread([index, previous_source, source] {
if (previous_source != WIIMOTE_SRC_NONE) if (previous_source != WIIMOTE_SRC_NONE)
::Wiimote::Connect(index, false); ::Wiimote::Connect(index, false);
if (source & WIIMOTE_SRC_EMU)
if (source == WIIMOTE_SRC_EMU)
::Wiimote::Connect(index, true); ::Wiimote::Connect(index, true);
}); });
} }
// Called from the Wiimote scanner thread // Called from the Wiimote scanner thread (or UI thread on source change)
static bool TryToConnectWiimoteToSlot(Wiimote* wm, unsigned int i) static bool TryToConnectWiimoteToSlot(std::unique_ptr<Wiimote>& wm, unsigned int i)
{ {
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) if (WIIMOTE_SRC_REAL != g_wiimote_sources[i] || g_wiimotes[i])
return false;
if (!wm->Connect(i))
{ {
if (wm->Connect(i)) ERROR_LOG(WIIMOTE, "Failed to connect real wiimote.");
{
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1);
g_wiimotes[i] = wm;
Core::RunAsCPUThread([i] { ::Wiimote::Connect(i, true); });
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.insert(wm->GetId());
}
return true;
}
return false; return false;
} }
static void TryToConnectWiimote(Wiimote* wm) g_wiimotes[i] = std::move(wm);
Core::RunAsCPUThread([i] { ::Wiimote::Connect(i, true); });
NOTICE_LOG(WIIMOTE, "Connected real wiimote to slot %i.", i + 1);
return true;
}
static void TryToConnectWiimote(std::unique_ptr<Wiimote> wm)
{ {
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
{ {
if (TryToConnectWiimoteToSlot(wm, i)) if (TryToConnectWiimoteToSlot(wm, i))
{ return;
wm = nullptr;
break;
}
}
delete wm;
} }
static void TryToConnectBalanceBoard(Wiimote* wm) NOTICE_LOG(WIIMOTE, "No open slot for real wiimote.");
}
static void TryToConnectBalanceBoard(std::unique_ptr<Wiimote> wm)
{ {
if (TryToConnectWiimoteToSlot(wm, WIIMOTE_BALANCE_BOARD)) if (TryToConnectWiimoteToSlot(wm, WIIMOTE_BALANCE_BOARD))
{ return;
wm = nullptr;
} NOTICE_LOG(WIIMOTE, "No open slot for real balance board.");
delete wm;
} }
static void HandleWiimoteDisconnect(int index) static void HandleWiimoteDisconnect(int index)
{ {
Wiimote* wm = nullptr; g_wiimotes[index] = nullptr;
std::swap(wm, g_wiimotes[index]);
if (wm)
{
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.erase(wm->GetId());
delete wm;
NOTICE_LOG(WIIMOTE, "Disconnected Wiimote %i.", index + 1);
}
} }
// This is called from the GUI thread // This is called from the GUI thread

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <atomic> #include <atomic>
#include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
@ -105,19 +106,19 @@ public:
void Prepare(); void Prepare();
bool PrepareOnThread(); bool PrepareOnThread();
void DisableDataReporting(); void ResetDataReporting();
void EnableDataReporting(u8 mode);
void SetChannel(u16 channel);
void QueueReport(u8 rpt_id, const void* data, unsigned int size); void QueueReport(WiimoteCommon::OutputReportID rpt_id, const void* data, unsigned int size);
int GetIndex() const; int GetIndex() const;
protected: protected:
Wiimote(); Wiimote() = default;
int m_index;
Report m_last_input_report; int m_index = 0;
u16 m_channel; Report m_last_input_report = {};
u16 m_channel = 0;
// If true, the Wiimote will be really disconnected when it is disconnected by Dolphin. // If true, the Wiimote will be really disconnected when it is disconnected by Dolphin.
// In any other case, data reporting is not paused to allow reconnecting on any button press. // In any other case, data reporting is not paused to allow reconnecting on any button press.
// This is not enabled on all platforms as connecting a Wiimote can be a pain on some platforms. // This is not enabled on all platforms as connecting a Wiimote can be a pain on some platforms.
@ -133,7 +134,12 @@ private:
void ThreadFunc(); void ThreadFunc();
bool m_rumble_state; // We track the speaker state to convert unnecessary speaker data into rumble reports.
bool m_speaker_enable = false;
bool m_speaker_mute = false;
// And we track the rumble state to drop unnecessary rumble reports.
bool m_rumble_state = false;
std::thread m_wiimote_thread; std::thread m_wiimote_thread;
// Whether to keep running the thread. // Whether to keep running the thread.
@ -188,7 +194,7 @@ private:
extern std::mutex g_wiimotes_mutex; extern std::mutex g_wiimotes_mutex;
extern WiimoteScanner g_wiimote_scanner; extern WiimoteScanner g_wiimote_scanner;
extern Wiimote* g_wiimotes[MAX_BBMOTES]; extern std::unique_ptr<Wiimote> g_wiimotes[MAX_BBMOTES];
void InterruptChannel(int wiimote_number, u16 channel_id, const void* data, u32 size); void InterruptChannel(int wiimote_number, u16 channel_id, const void* data, u32 size);
void ControlChannel(int wiimote_number, u16 channel_id, const void* data, u32 size); void ControlChannel(int wiimote_number, u16 channel_id, const void* data, u32 size);

View File

@ -74,7 +74,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 104; // Last changed in PR 7806 static const u32 STATE_VERSION = 105; // Last changed in PR 7871
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,
@ -177,10 +177,6 @@ static void DoState(PointerWrap& p)
g_video_backend->DoState(p); g_video_backend->DoState(p);
p.DoMarker("video_backend"); p.DoMarker("video_backend");
if (SConfig::GetInstance().bWii)
Wiimote::DoState(p);
p.DoMarker("Wiimote");
PowerPC::DoState(p); PowerPC::DoState(p);
p.DoMarker("PowerPC"); p.DoMarker("PowerPC");
// CoreTiming needs to be restored before restoring Hardware because // CoreTiming needs to be restored before restoring Hardware because
@ -189,6 +185,9 @@ static void DoState(PointerWrap& p)
p.DoMarker("CoreTiming"); p.DoMarker("CoreTiming");
HW::DoState(p); HW::DoState(p);
p.DoMarker("HW"); p.DoMarker("HW");
if (SConfig::GetInstance().bWii)
Wiimote::DoState(p);
p.DoMarker("Wiimote");
Movie::DoState(p); Movie::DoState(p);
p.DoMarker("Movie"); p.DoMarker("Movie");
Gecko::DoState(p); Gecko::DoState(p);

View File

@ -496,10 +496,7 @@ void ControllersWindow::SaveSettings()
for (size_t i = 0; i < m_wiimote_groups.size(); i++) for (size_t i = 0; i < m_wiimote_groups.size(); i++)
{ {
const int index = m_wiimote_boxes[i]->currentIndex(); const int index = m_wiimote_boxes[i]->currentIndex();
g_wiimote_sources[i] = index;
m_wiimote_buttons[i]->setEnabled(index != 0 && index != 2); m_wiimote_buttons[i]->setEnabled(index != 0 && index != 2);
if (Core::IsRunning())
WiimoteReal::ChangeWiimoteSource(static_cast<u32>(i), index); WiimoteReal::ChangeWiimoteSource(static_cast<u32>(i), index);
} }