WiimoteReal: Make the connected Wiimote check common

This moves the unordered_map used to store connected Wiimotes IDs to
WiimoteReal, and makes the ID insert/erase logic common so we don't
have to duplicate this code in scanner backends.
This commit is contained in:
Léo Lam 2016-08-11 13:28:25 +02:00
parent 222f7e6fc3
commit 2511bfdb8a
10 changed files with 45 additions and 75 deletions

View File

@ -7,6 +7,7 @@
#ifdef ANDROID #ifdef ANDROID
#include <jni.h> #include <jni.h>
#include "Common/StringUtil.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/HW/WiimoteReal/WiimoteReal.h"
namespace WiimoteReal namespace WiimoteReal
@ -16,7 +17,7 @@ class WiimoteAndroid final : public Wiimote
public: public:
WiimoteAndroid(int index); WiimoteAndroid(int index);
~WiimoteAndroid() override; ~WiimoteAndroid() override;
std::string GetId() const override { return "Android " + StringFromInt(m_mayflash_index); }
protected: protected:
bool ConnectInternal() override; bool ConnectInternal() override;
void DisconnectInternal() override; void DisconnectInternal() override;

View File

@ -14,14 +14,6 @@
namespace WiimoteReal namespace WiimoteReal
{ {
// This is used to store the Bluetooth address of connected Wiimotes,
// so we can ignore Wiimotes that are already connected.
static std::vector<std::string> s_known_addrs;
static bool IsNewWiimote(const std::string& addr)
{
return std::find(s_known_addrs.begin(), s_known_addrs.end(), addr) == s_known_addrs.end();
}
WiimoteScannerLinux::WiimoteScannerLinux() : m_device_id(-1), m_device_sock(-1) WiimoteScannerLinux::WiimoteScannerLinux() : m_device_id(-1), m_device_sock(-1)
{ {
// Get the id of the first Bluetooth device. // Get the id of the first Bluetooth device.
@ -100,7 +92,6 @@ void WiimoteScannerLinux::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wi
continue; continue;
// Found a new device // Found a new device
s_known_addrs.push_back(bdaddr_str);
Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr); Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr);
if (IsBalanceBoardName(name)) if (IsBalanceBoardName(name))
{ {
@ -180,10 +171,6 @@ void WiimoteLinux::DisconnectInternal()
m_cmd_sock = -1; m_cmd_sock = -1;
m_int_sock = -1; m_int_sock = -1;
char bdaddr_str[18] = {};
ba2str(&m_bdaddr, bdaddr_str);
s_known_addrs.erase(std::remove(s_known_addrs.begin(), s_known_addrs.end(), bdaddr_str),
s_known_addrs.end());
} }
bool WiimoteLinux::IsConnected() const bool WiimoteLinux::IsConnected() const

View File

@ -16,6 +16,12 @@ class WiimoteLinux final : public Wiimote
public: public:
WiimoteLinux(bdaddr_t bdaddr); WiimoteLinux(bdaddr_t bdaddr);
~WiimoteLinux() override; ~WiimoteLinux() override;
std::string GetId() const override
{
char bdaddr_str[18] = {};
ba2str(&m_bdaddr, bdaddr_str);
return bdaddr_str;
}
protected: protected:
bool ConnectInternal() override; bool ConnectInternal() override;

View File

@ -25,13 +25,9 @@
#include "Common/CommonFuncs.h" #include "Common/CommonFuncs.h"
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h" #include "Common/Thread.h"
#include "Core/HW/WiimoteReal/IOWin.h" #include "Core/HW/WiimoteReal/IOWin.h"
//#define AUTHENTICATE_WIIMOTES
#define SHARE_WRITE_WIIMOTES
// Create func_t function pointer type and declare a nullptr-initialized static variable of that // Create func_t function pointer type and declare a nullptr-initialized static variable of that
// type named "pfunc". // type named "pfunc".
#define DYN_FUNC_DECLARE(func) \ #define DYN_FUNC_DECLARE(func) \
@ -64,11 +60,6 @@ static bool s_loaded_ok = false;
std::unordered_map<BTH_ADDR, std::time_t> g_connect_times; std::unordered_map<BTH_ADDR, std::time_t> g_connect_times;
#ifdef SHARE_WRITE_WIIMOTES
std::unordered_set<std::basic_string<TCHAR>> g_connected_wiimotes;
std::mutex g_connected_wiimotes_lock;
#endif
#define DYN_FUNC_UNLOAD(func) p##func = nullptr; #define DYN_FUNC_UNLOAD(func) p##func = nullptr;
// Attempt to load the function from the given module handle. // Attempt to load the function from the given module handle.
@ -448,18 +439,7 @@ void WiimoteScannerWindows::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
WinWriteMethod write_method = GetInitialWriteMethod(IsUsingToshibaStack); WinWriteMethod write_method = GetInitialWriteMethod(IsUsingToshibaStack);
#ifdef SHARE_WRITE_WIIMOTES if (!IsNewWiimote(UTF16ToUTF8(device_path)) || !IsWiimote(device_path, write_method))
{
std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock);
// This device is a Wiimote that is already connected. Skip it.
if (g_connected_wiimotes.count(device_path) != 0)
{
free(detail_data);
continue;
}
}
#endif
if (!IsWiimote(device_path, write_method))
{ {
free(detail_data); free(detail_data);
continue; continue;
@ -510,19 +490,10 @@ bool WiimoteWindows::ConnectInternal()
if (IsConnected()) if (IsConnected())
return true; return true;
#ifdef SHARE_WRITE_WIIMOTES if (!IsNewWiimote(UTF16ToUTF8(m_devicepath)))
std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock);
if (g_connected_wiimotes.count(m_devicepath) != 0)
return false; return false;
auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE; auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE;
#else
// Having no FILE_SHARE_WRITE disallows us from connecting to the same Wiimote twice.
// (And disallows using Wiimotes in use by other programs)
// This is what "WiiYourself" does.
// Apparently this doesn't work for everyone. It might be their fault.
auto const open_flags = FILE_SHARE_READ;
#endif
m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr, m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr,
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr);
@ -558,18 +529,15 @@ bool WiimoteWindows::ConnectInternal()
} }
#endif #endif
// TODO: thread isn't started here now, do this elsewhere // TODO: thread isn't started here now, do this elsewhere
// This isn't as drastic as it sounds, since the process in which the threads // This isn't as drastic as it sounds, since the process in which the threads
// reside is normal priority. Needed for keeping audio reports at a decent rate // reside is normal priority. Needed for keeping audio reports at a decent rate
/* /*
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL)) if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
{ {
ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority"); ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority");
} }
*/ */
#ifdef SHARE_WRITE_WIIMOTES
g_connected_wiimotes.insert(m_devicepath);
#endif
return true; return true;
} }
@ -581,11 +549,6 @@ void WiimoteWindows::DisconnectInternal()
CloseHandle(m_dev_handle); CloseHandle(m_dev_handle);
m_dev_handle = nullptr; m_dev_handle = nullptr;
#ifdef SHARE_WRITE_WIIMOTES
std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock);
g_connected_wiimotes.erase(m_devicepath);
#endif
} }
WiimoteWindows::WiimoteWindows(const std::basic_string<TCHAR>& path, WiimoteWindows::WiimoteWindows(const std::basic_string<TCHAR>& path,

View File

@ -7,6 +7,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#include "Common/StringUtil.h"
#include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/HW/WiimoteReal/WiimoteReal.h"
@ -25,7 +26,7 @@ class WiimoteWindows final : public Wiimote
public: public:
WiimoteWindows(const std::basic_string<TCHAR>& path, WinWriteMethod initial_write_method); WiimoteWindows(const std::basic_string<TCHAR>& path, WinWriteMethod initial_write_method);
~WiimoteWindows() override; ~WiimoteWindows() override;
std::string GetId() const override { return UTF16ToUTF8(m_devicepath); }
protected: protected:
bool ConnectInternal() override; bool ConnectInternal() override;
void DisconnectInternal() override; void DisconnectInternal() override;

View File

@ -23,7 +23,7 @@ class WiimoteDarwin final : public Wiimote
public: public:
WiimoteDarwin(IOBluetoothDevice* device); WiimoteDarwin(IOBluetoothDevice* device);
~WiimoteDarwin() override; ~WiimoteDarwin() override;
std::string GetId() const override { return [[m_btd addressString] UTF8String]; }
// These are not protected/private because ConnectBT needs them. // These are not protected/private because ConnectBT needs them.
void DisconnectInternal() override; void DisconnectInternal() override;
IOBluetoothDevice* m_btd; IOBluetoothDevice* m_btd;

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm> #include <algorithm>
#include <unordered_set>
#include "Common/Assert.h" #include "Common/Assert.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
@ -11,10 +10,6 @@
#include "Core/HW/WiimoteEmu/WiimoteHid.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h"
#include "Core/HW/WiimoteReal/IOhidapi.h" #include "Core/HW/WiimoteReal/IOhidapi.h"
// This is used to store connected Wiimotes' paths, so we don't connect
// more than once to the same device.
static std::unordered_set<std::string> s_known_paths;
static bool IsDeviceUsable(const std::string& device_path) static bool IsDeviceUsable(const std::string& device_path)
{ {
hid_device* handle = hid_open_path(device_path.c_str()); hid_device* handle = hid_open_path(device_path.c_str());
@ -42,7 +37,6 @@ namespace WiimoteReal
{ {
WiimoteScannerHidapi::WiimoteScannerHidapi() WiimoteScannerHidapi::WiimoteScannerHidapi()
{ {
s_known_paths.clear();
int ret = hid_init(); int ret = hid_init();
_assert_msg_(WIIMOTE, ret == 0, "Couldn't initialise hidapi."); _assert_msg_(WIIMOTE, ret == 0, "Couldn't initialise hidapi.");
} }
@ -67,7 +61,7 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote
const bool is_wiimote = const bool is_wiimote =
IsValidDeviceName(name) || (device->vendor_id == 0x057e && IsValidDeviceName(name) || (device->vendor_id == 0x057e &&
(device->product_id == 0x0306 || device->product_id == 0x0330)); (device->product_id == 0x0306 || device->product_id == 0x0330));
if (!is_wiimote || s_known_paths.count(device->path) != 0 || !IsDeviceUsable(device->path)) if (!is_wiimote || !IsNewWiimote(device->path) || !IsDeviceUsable(device->path))
continue; continue;
auto* wiimote = new WiimoteHidapi(device->path); auto* wiimote = new WiimoteHidapi(device->path);
@ -87,13 +81,11 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote
WiimoteHidapi::WiimoteHidapi(const std::string& device_path) : m_device_path(device_path) WiimoteHidapi::WiimoteHidapi(const std::string& device_path) : m_device_path(device_path)
{ {
s_known_paths.insert(m_device_path);
} }
WiimoteHidapi::~WiimoteHidapi() WiimoteHidapi::~WiimoteHidapi()
{ {
Shutdown(); Shutdown();
s_known_paths.erase(m_device_path);
} }
bool WiimoteHidapi::ConnectInternal() bool WiimoteHidapi::ConnectInternal()
@ -107,7 +99,6 @@ bool WiimoteHidapi::ConnectInternal()
ERROR_LOG(WIIMOTE, "Could not connect to Wiimote at \"%s\". " ERROR_LOG(WIIMOTE, "Could not connect to Wiimote at \"%s\". "
"Do you have permission to access the device?", "Do you have permission to access the device?",
m_device_path.c_str()); m_device_path.c_str());
s_known_paths.erase(m_device_path);
} }
return m_handle != nullptr; return m_handle != nullptr;
} }

View File

@ -16,7 +16,7 @@ class WiimoteHidapi final : public Wiimote
public: public:
explicit WiimoteHidapi(const std::string& device_path); explicit WiimoteHidapi(const std::string& device_path);
~WiimoteHidapi() override; ~WiimoteHidapi() override;
std::string GetId() const override { return m_device_path; }
protected: protected:
bool ConnectInternal() override; bool ConnectInternal() override;
void DisconnectInternal() override; void DisconnectInternal() override;

View File

@ -5,6 +5,7 @@
#include <algorithm> #include <algorithm>
#include <cstdlib> #include <cstdlib>
#include <queue> #include <queue>
#include <unordered_set>
#include "Core/HW/WiimoteReal/WiimoteReal.h" #include "Core/HW/WiimoteReal/WiimoteReal.h"
@ -37,6 +38,11 @@ void HandleWiimoteDisconnect(int index);
static bool g_real_wiimotes_initialized = false; static bool g_real_wiimotes_initialized = false;
// This is used to store connected Wiimotes' IDs, so we don't connect
// more than once to the same device.
static std::unordered_set<std::string> s_known_ids;
static std::mutex s_known_ids_mutex;
std::mutex g_wiimotes_mutex; std::mutex g_wiimotes_mutex;
Wiimote* g_wiimotes[MAX_BBMOTES]; Wiimote* g_wiimotes[MAX_BBMOTES];
@ -687,6 +693,7 @@ void Initialize(::Wiimote::InitializeMode init_mode)
{ {
if (!g_real_wiimotes_initialized) if (!g_real_wiimotes_initialized)
{ {
s_known_ids.clear();
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerLinux>()); g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerLinux>());
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerAndroid>()); g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerAndroid>());
g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerWindows>()); g_wiimote_scanner.AddScannerBackend(std::make_unique<WiimoteScannerWindows>());
@ -790,6 +797,8 @@ static bool TryToConnectWiimoteToSlot(Wiimote* wm, unsigned int i)
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1); NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1);
g_wiimotes[i] = wm; g_wiimotes[i] = wm;
Host_ConnectWiimote(i, true); Host_ConnectWiimote(i, true);
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.insert(wm->GetId());
} }
return true; return true;
} }
@ -824,6 +833,8 @@ void HandleWiimoteDisconnect(int index)
std::swap(wm, g_wiimotes[index]); std::swap(wm, g_wiimotes[index]);
if (wm) if (wm)
{ {
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
s_known_ids.erase(wm->GetId());
delete wm; delete wm;
NOTICE_LOG(WIIMOTE, "Disconnected Wiimote %i.", index + 1); NOTICE_LOG(WIIMOTE, "Disconnected Wiimote %i.", index + 1);
} }
@ -897,4 +908,11 @@ bool IsBalanceBoardName(const std::string& name)
return "Nintendo RVL-WBC-01" == name; return "Nintendo RVL-WBC-01" == name;
} }
// This is called from the scanner backends (currently on the scanner thread).
bool IsNewWiimote(const std::string& identifier)
{
std::lock_guard<std::mutex> lk(s_known_ids_mutex);
return s_known_ids.count(identifier) == 0;
}
}; // end of namespace }; // end of namespace

View File

@ -31,6 +31,8 @@ public:
// This needs to be called in derived destructors! // This needs to be called in derived destructors!
void Shutdown(); void Shutdown();
virtual std::string GetId() const = 0;
void ControlChannel(const u16 channel, const void* const data, const u32 size); void ControlChannel(const u16 channel, const void* const data, const u32 size);
void InterruptChannel(const u16 channel, const void* const data, const u32 size); void InterruptChannel(const u16 channel, const void* const data, const u32 size);
void Update(); void Update();
@ -164,6 +166,7 @@ void ChangeWiimoteSource(unsigned int index, int source);
bool IsValidDeviceName(const std::string& name); bool IsValidDeviceName(const std::string& name);
bool IsBalanceBoardName(const std::string& name); bool IsBalanceBoardName(const std::string& name);
bool IsNewWiimote(const std::string& identifier);
#ifdef ANDROID #ifdef ANDROID
void InitAdapterClass(); void InitAdapterClass();