diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 5a2d89d518..d194d8447c 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -256,12 +256,10 @@ elseif(APPLE) elseif(UNIX) set(SRCS ${SRCS} HW/BBA-TAP/TAP_Unix.cpp) if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND BLUEZ_FOUND) - set(SRCS ${SRCS} HW/WiimoteReal/IONix.cpp) + set(SRCS ${SRCS} HW/WiimoteReal/IOLinux.cpp) set(LIBS ${LIBS} bluetooth) elseif(ANDROID) set(SRCS ${SRCS} HW/WiimoteReal/IOAndroid.cpp) - else() - set(SRCS ${SRCS} HW/WiimoteReal/IODummy.cpp) endif() endif() diff --git a/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp b/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp index d69eef4e10..abc33c88a2 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp @@ -12,7 +12,7 @@ #include "Common/Thread.h" #include "Common/Timer.h" -#include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/HW/WiimoteReal/IOAndroid.h" // Global java_vm class extern JavaVM* g_java_vm; @@ -22,45 +22,8 @@ namespace WiimoteReal // Java classes static jclass s_adapter_class; -class WiimoteAndroid final : public Wiimote -{ -public: - WiimoteAndroid(int index); - ~WiimoteAndroid() override; - -protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() {} - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; - -private: - int m_mayflash_index; - bool is_connected = true; - - JNIEnv* m_env; - - jmethodID m_input_func; - jmethodID m_output_func; - - jbyteArray m_java_wiimote_payload; -}; - -WiimoteScanner::WiimoteScanner() -{ -} - -WiimoteScanner::~WiimoteScanner() -{ -} - -void WiimoteScanner::Update() -{ -} - -void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +void WiimoteScannerAndroid::FindWiimotes(std::vector& found_wiimotes, + Wiimote*& found_board) { found_wiimotes.clear(); found_board = nullptr; @@ -87,11 +50,6 @@ void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote g_java_vm->DetachCurrentThread(); } -bool WiimoteScanner::IsReady() const -{ - return true; -} - WiimoteAndroid::WiimoteAndroid(int index) : Wiimote(), m_mayflash_index(index) { } diff --git a/Source/Core/Core/HW/WiimoteReal/IOAndroid.h b/Source/Core/Core/HW/WiimoteReal/IOAndroid.h new file mode 100644 index 0000000000..988d8794ed --- /dev/null +++ b/Source/Core/Core/HW/WiimoteReal/IOAndroid.h @@ -0,0 +1,57 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#ifdef ANDROID +#include + +#include "Core/HW/WiimoteReal/WiimoteReal.h" + +namespace WiimoteReal +{ +class WiimoteAndroid final : public Wiimote +{ +public: + WiimoteAndroid(int index); + ~WiimoteAndroid() override; + +protected: + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override{}; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + +private: + int m_mayflash_index; + bool is_connected = true; + + JNIEnv* m_env; + + jmethodID m_input_func; + jmethodID m_output_func; + + jbyteArray m_java_wiimote_payload; +}; + +class WiimoteScannerAndroid final : public WiimoteScannerBackend +{ +public: + WiimoteScannerAndroid() = default; + ~WiimoteScannerAndroid() override = default; + bool IsReady() const override { return true; } + void FindWiimotes(std::vector&, Wiimote*&) override; + void Update() override {} +}; +} + +#else +#include "Core/HW/WiimoteReal/IODummy.h" +namespace WiimoteReal +{ +using WiimoteScannerAndroid = WiimoteScannerDummy; +} +#endif diff --git a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp b/Source/Core/Core/HW/WiimoteReal/IODummy.cpp deleted file mode 100644 index 9f0ed27f56..0000000000 --- a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2008 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Common/CommonTypes.h" -#include "Core/HW/WiimoteReal/WiimoteReal.h" - -namespace WiimoteReal -{ -WiimoteScanner::WiimoteScanner() -{ -} - -WiimoteScanner::~WiimoteScanner() -{ -} - -void WiimoteScanner::Update() -{ -} - -void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) -{ - found_wiimotes.clear(); - found_board = nullptr; -} - -bool WiimoteScanner::IsReady() const -{ - return false; -} -}; diff --git a/Source/Core/Core/HW/WiimoteReal/IODummy.h b/Source/Core/Core/HW/WiimoteReal/IODummy.h new file mode 100644 index 0000000000..97cd5b1e88 --- /dev/null +++ b/Source/Core/Core/HW/WiimoteReal/IODummy.h @@ -0,0 +1,20 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Core/HW/WiimoteReal/WiimoteReal.h" + +namespace WiimoteReal +{ +class WiimoteScannerDummy final : public WiimoteScannerBackend +{ +public: + WiimoteScannerDummy() = default; + ~WiimoteScannerDummy() override = default; + bool IsReady() const override { return false; } + void FindWiimotes(std::vector&, Wiimote*&) override {} + void Update() override {} +}; +} diff --git a/Source/Core/Core/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp similarity index 64% rename from Source/Core/Core/HW/WiimoteReal/IONix.cpp rename to Source/Core/Core/HW/WiimoteReal/IOLinux.cpp index 2313914a0f..287956137a 100644 --- a/Source/Core/Core/HW/WiimoteReal/IONix.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp @@ -2,78 +2,57 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#ifndef _WIN32 -#include -#endif #include #include #include #include +#include #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/HW/WiimoteReal/IOLinux.h" namespace WiimoteReal { -class WiimoteLinux final : public Wiimote +// This is used to store the Bluetooth address of connected Wiimotes, +// so we can ignore Wiimotes that are already connected. +static std::vector s_known_addrs; +static bool IsNewWiimote(const std::string& addr) { -public: - WiimoteLinux(bdaddr_t bdaddr); - ~WiimoteLinux() override; - const bdaddr_t& Address() const; + return std::find(s_known_addrs.begin(), s_known_addrs.end(), addr) == s_known_addrs.end(); +} -protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; - -private: - bdaddr_t m_bdaddr; // Bluetooth address - int m_cmd_sock; // Command socket - int m_int_sock; // Interrupt socket - int m_wakeup_pipe_w; - int m_wakeup_pipe_r; -}; - -WiimoteScanner::WiimoteScanner() : device_id(-1), device_sock(-1) +WiimoteScannerLinux::WiimoteScannerLinux() : m_device_id(-1), m_device_sock(-1) { // Get the id of the first Bluetooth device. - device_id = hci_get_route(nullptr); - if (device_id < 0) + m_device_id = hci_get_route(nullptr); + if (m_device_id < 0) { NOTICE_LOG(WIIMOTE, "Bluetooth not found."); return; } // Create a socket to the device - device_sock = hci_open_dev(device_id); - if (device_sock < 0) + m_device_sock = hci_open_dev(m_device_id); + if (m_device_sock < 0) { ERROR_LOG(WIIMOTE, "Unable to open Bluetooth."); return; } } -bool WiimoteScanner::IsReady() const -{ - return device_sock > 0; -} - -WiimoteScanner::~WiimoteScanner() +WiimoteScannerLinux::~WiimoteScannerLinux() { if (IsReady()) - close(device_sock); + close(m_device_sock); } -void WiimoteScanner::Update() +bool WiimoteScannerLinux::IsReady() const { + return m_device_sock > 0; } -void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +void WiimoteScannerLinux::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) { // supposedly 1.28 seconds int const wait_len = 1; @@ -88,7 +67,7 @@ void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote // Scan for Bluetooth devices int const found_devices = - hci_inquiry(device_id, wait_len, max_infos, lap, &scan_infos_ptr, IREQ_CACHE_FLUSH); + hci_inquiry(m_device_id, wait_len, max_infos, lap, &scan_infos_ptr, IREQ_CACHE_FLUSH); if (found_devices < 0) { ERROR_LOG(WIIMOTE, "Error searching for Bluetooth devices."); @@ -104,46 +83,34 @@ void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote // BT names are a maximum of 248 bytes apparently char name[255] = {}; - if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 1000) < 0) + if (hci_read_remote_name(m_device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 1000) < 0) { ERROR_LOG(WIIMOTE, "name request failed"); continue; } ERROR_LOG(WIIMOTE, "device name %s", name); - if (IsValidBluetoothName(name)) + if (!IsValidBluetoothName(name)) + continue; + + char bdaddr_str[18] = {}; + ba2str(&scan_infos[i].bdaddr, bdaddr_str); + + if (!IsNewWiimote(bdaddr_str)) + continue; + + // Found a new device + s_known_addrs.push_back(bdaddr_str); + Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr); + if (IsBalanceBoardName(name)) { - bool new_wiimote = true; - - // Determine if this Wiimote has already been found. - for (int j = 0; j < MAX_BBMOTES && new_wiimote; ++j) - { - // compare this address with the stored addresses in our global array - // static_cast is OK here, since we're only ever going to have this subclass in g_wiimotes - // on Linux (and likewise, only WiimoteWindows on Windows, etc) - auto connected_wiimote = static_cast(g_wiimotes[j]); - if (connected_wiimote && bacmp(&scan_infos[i].bdaddr, &connected_wiimote->Address()) == 0) - new_wiimote = false; - } - - if (new_wiimote) - { - // Found a new device - char bdaddr_str[18] = {}; - ba2str(&scan_infos[i].bdaddr, bdaddr_str); - - Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr); - if (IsBalanceBoardName(name)) - { - found_board = wm; - NOTICE_LOG(WIIMOTE, "Found balance board (%s).", bdaddr_str); - } - else - { - found_wiimotes.push_back(wm); - NOTICE_LOG(WIIMOTE, "Found Wiimote (%s).", bdaddr_str); - } - } + found_board = wm; + NOTICE_LOG(WIIMOTE, "Found balance board (%s).", bdaddr_str); + } + else + { + found_wiimotes.push_back(wm); + NOTICE_LOG(WIIMOTE, "Found Wiimote (%s).", bdaddr_str); } } } @@ -172,11 +139,6 @@ WiimoteLinux::~WiimoteLinux() close(m_wakeup_pipe_r); } -const bdaddr_t& WiimoteLinux::Address() const -{ - return m_bdaddr; -} - // Connect to a Wiimote with a known address. bool WiimoteLinux::ConnectInternal() { @@ -218,6 +180,10 @@ void WiimoteLinux::DisconnectInternal() m_cmd_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 diff --git a/Source/Core/Core/HW/WiimoteReal/IOLinux.h b/Source/Core/Core/HW/WiimoteReal/IOLinux.h new file mode 100644 index 0000000000..9f74e74a80 --- /dev/null +++ b/Source/Core/Core/HW/WiimoteReal/IOLinux.h @@ -0,0 +1,57 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#if defined(__linux__) && HAVE_BLUEZ +#include + +#include "Core/HW/WiimoteReal/WiimoteReal.h" + +namespace WiimoteReal +{ +class WiimoteLinux final : public Wiimote +{ +public: + WiimoteLinux(bdaddr_t bdaddr); + ~WiimoteLinux() override; + +protected: + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + +private: + bdaddr_t m_bdaddr; // Bluetooth address + int m_cmd_sock; // Command socket + int m_int_sock; // Interrupt socket + int m_wakeup_pipe_w; + int m_wakeup_pipe_r; +}; + +class WiimoteScannerLinux final : public WiimoteScannerBackend +{ +public: + WiimoteScannerLinux(); + ~WiimoteScannerLinux() override; + bool IsReady() const override; + void FindWiimotes(std::vector&, Wiimote*&) override; + void Update() override{}; // not needed on Linux + +private: + int m_device_id; + int m_device_sock; +}; +} + +#else +#include "Core/HW/WiimoteReal/IODummy.h" +namespace WiimoteReal +{ +using WiimoteScannerLinux = WiimoteScannerDummy; +} +#endif diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index e57d549d94..b0e6e4d4ef 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -27,8 +27,7 @@ #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "Common/Thread.h" -#include "Core/HW/WiimoteEmu/WiimoteHid.h" -#include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/HW/WiimoteReal/IOWin.h" //#define AUTHENTICATE_WIIMOTES #define SHARE_WRITE_WIIMOTES @@ -192,28 +191,6 @@ inline void init_lib() namespace WiimoteReal { -class WiimoteWindows final : public Wiimote -{ -public: - WiimoteWindows(const std::basic_string& path, WinWriteMethod initial_write_method); - ~WiimoteWindows() override; - -protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; - -private: - std::basic_string m_devicepath; // Unique Wiimote reference - HANDLE m_dev_handle; // HID handle - OVERLAPPED m_hid_overlap_read; // Overlap handles - OVERLAPPED m_hid_overlap_write; - WinWriteMethod m_write_method; // Type of Write Method to use -}; - int IOWrite(HANDLE& dev_handle, OVERLAPPED& hid_overlap_write, enum WinWriteMethod& stack, const u8* buf, size_t len, DWORD* written); int IORead(HANDLE& dev_handle, OVERLAPPED& hid_overlap_read, u8* buf, int index); @@ -225,12 +202,12 @@ bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_ void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&); bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&); -WiimoteScanner::WiimoteScanner() +WiimoteScannerWindows::WiimoteScannerWindows() { init_lib(); } -WiimoteScanner::~WiimoteScanner() +WiimoteScannerWindows::~WiimoteScannerWindows() { // TODO: what do we want here? #if 0 @@ -241,7 +218,7 @@ WiimoteScanner::~WiimoteScanner() #endif } -void WiimoteScanner::Update() +void WiimoteScannerWindows::Update() { if (!s_loaded_ok) return; @@ -371,7 +348,8 @@ static WinWriteMethod GetInitialWriteMethod(bool IsUsingToshibaStack) // Does not replace already found Wiimotes even if they are disconnected. // wm is an array of max_wiimotes Wiimotes // Returns the total number of found and connected Wiimotes. -void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +void WiimoteScannerWindows::FindWiimotes(std::vector& found_wiimotes, + Wiimote*& found_board) { if (!s_loaded_ok) return; @@ -480,8 +458,9 @@ int CheckDeviceType_Read(HANDLE& dev_handle, u8* buf, int attempts) // Wiimote. // Because nothing on Windows should be easy. // (We can't seem to easily identify the Bluetooth device an HID device belongs to...) -void WiimoteScanner::CheckDeviceType(std::basic_string& devicepath, - WinWriteMethod& write_method, bool& real_wiimote, bool& is_bb) +void WiimoteScannerWindows::CheckDeviceType(std::basic_string& devicepath, + WinWriteMethod& write_method, bool& real_wiimote, + bool& is_bb) { real_wiimote = false; is_bb = false; @@ -606,7 +585,7 @@ void WiimoteScanner::CheckDeviceType(std::basic_string& devicepath, CloseHandle(dev_handle); } -bool WiimoteScanner::IsReady() const +bool WiimoteScannerWindows::IsReady() const { if (!s_loaded_ok) { diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.h b/Source/Core/Core/HW/WiimoteReal/IOWin.h new file mode 100644 index 0000000000..b3561c7f0c --- /dev/null +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.h @@ -0,0 +1,66 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#ifdef _WIN32 +#include + +#include "Core/HW/WiimoteEmu/WiimoteHid.h" +#include "Core/HW/WiimoteReal/WiimoteReal.h" + +namespace WiimoteReal +{ +// Different methods to send data Wiimote on Windows depending on OS and Bluetooth Stack +enum WinWriteMethod +{ + WWM_WRITE_FILE_LARGEST_REPORT_SIZE, + WWM_WRITE_FILE_ACTUAL_REPORT_SIZE, + WWM_SET_OUTPUT_REPORT +}; + +class WiimoteWindows final : public Wiimote +{ +public: + WiimoteWindows(const std::basic_string& path, WinWriteMethod initial_write_method); + ~WiimoteWindows() override; + +protected: + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + +private: + std::basic_string m_devicepath; // Unique Wiimote reference + HANDLE m_dev_handle; // HID handle + OVERLAPPED m_hid_overlap_read; // Overlap handles + OVERLAPPED m_hid_overlap_write; + WinWriteMethod m_write_method; // Type of Write Method to use +}; + +class WiimoteScannerWindows final : public WiimoteScannerBackend +{ +public: + WiimoteScannerWindows(); + ~WiimoteScannerWindows() override; + bool IsReady() const override; + void FindWiimotes(std::vector&, Wiimote*&) override; + void Update() override; + +private: + void CheckDeviceType(std::basic_string& devicepath, WinWriteMethod& write_method, + bool& real_wiimote, bool& is_bb); +}; +} + +#else +#include "Core/HW/WiimoteReal/IODummy.h" +namespace WiimoteReal +{ +using WiimoteScannerWindows = WiimoteScannerDummy; +} +#endif diff --git a/Source/Core/Core/HW/WiimoteReal/IOdarwin.h b/Source/Core/Core/HW/WiimoteReal/IOdarwin.h new file mode 100644 index 0000000000..9d7a10bc6f --- /dev/null +++ b/Source/Core/Core/HW/WiimoteReal/IOdarwin.h @@ -0,0 +1,106 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#ifdef __APPLE__ +// Work around an Apple bug: for some reason, IOBluetooth.h errors on +// inclusion in Mavericks, but only in Objective-C++ C++11 mode. I filed +// this as ; in the meantime... +#import +#undef NS_ENUM_AVAILABLE +#define NS_ENUM_AVAILABLE(...) +// end hack +#import +#include +#include + +#include "Core/HW/WiimoteReal/WiimoteReal.h" + +namespace WiimoteReal +{ +class WiimoteDarwin final : public Wiimote +{ +public: + WiimoteDarwin(IOBluetoothDevice* device); + ~WiimoteDarwin() override; + + // These are not protected/private because ConnectBT needs them. + void DisconnectInternal() override; + IOBluetoothDevice* m_btd; + unsigned char* m_input; + int m_inputlen; + +protected: + bool ConnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + void EnablePowerAssertionInternal() override; + void DisablePowerAssertionInternal() override; + +private: + IOBluetoothL2CAPChannel* m_ichan; + IOBluetoothL2CAPChannel* m_cchan; + bool m_connected; + CFRunLoopRef m_wiimote_thread_run_loop; + IOPMAssertionID m_pm_assertion; +}; + +class WiimoteDarwinHid final : public Wiimote +{ +public: + WiimoteDarwinHid(IOHIDDeviceRef device); + ~WiimoteDarwinHid() override; + +protected: + bool ConnectInternal() override; + void DisconnectInternal() override; + bool IsConnected() const override; + void IOWakeup() override; + int IORead(u8* buf) override; + int IOWrite(u8 const* buf, size_t len) override; + +private: + static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, + u32 reportID, u8* report, CFIndex reportLength); + static void RemoveCallback(void* context, IOReturn result, void* sender); + void QueueBufferReport(int length); + IOHIDDeviceRef m_device; + bool m_connected; + std::atomic m_interrupted; + Report m_report_buffer; + Common::FifoQueue m_buffered_reports; +}; + +class WiimoteScannerDarwin final : public WiimoteScannerBackend +{ +public: + WiimoteScannerDarwin() = default; + ~WiimoteScannerDarwin() override = default; + bool IsReady() const override; + void FindWiimotes(std::vector&, Wiimote*&) override; + void Update() override{}; // not needed +}; + +class WiimoteScannerDarwinHID final : public WiimoteScannerBackend +{ +public: + WiimoteScannerDarwinHID() = default; + ~WiimoteScannerDarwinHID() override = default; + bool IsReady() const override; + void FindWiimotes(std::vector&, Wiimote*&) override; + void Update() override{}; // not needed +}; +} + +#else +#include "Core/HW/WiimoteReal/IODummy.h" +namespace WiimoteReal +{ +using WiimoteScannerDarwin = WiimoteScannerDummy; +using WiimoteScannerDarwinHID = WiimoteScannerDummy; +} +#endif diff --git a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm index afc066e326..0ce4b68dff 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm @@ -1,9 +1,9 @@ #define BLUETOOTH_VERSION_USE_CURRENT +#include "Core/HW/WiimoteReal/IOdarwin.h" #include "Common/Common.h" #include "Common/Logging/Log.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" -#include "Core/HW/WiimoteReal/WiimoteReal.h" @interface SearchBT : NSObject { @@ -20,188 +20,123 @@ namespace WiimoteReal { -class WiimoteDarwin final : public Wiimote -{ -public: - WiimoteDarwin(IOBluetoothDevice* device); - ~WiimoteDarwin() override; - - // These are not protected/private because ConnectBT needs them. - void DisconnectInternal() override; - IOBluetoothDevice* m_btd; - unsigned char* m_input; - int m_inputlen; - -protected: - bool ConnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; - void EnablePowerAssertionInternal() override; - void DisablePowerAssertionInternal() override; - -private: - IOBluetoothL2CAPChannel* m_ichan; - IOBluetoothL2CAPChannel* m_cchan; - bool m_connected; - CFRunLoopRef m_wiimote_thread_run_loop; - IOPMAssertionID m_pm_assertion; -}; - -class WiimoteDarwinHid final : public Wiimote -{ -public: - WiimoteDarwinHid(IOHIDDeviceRef device); - ~WiimoteDarwinHid() override; - -protected: - bool ConnectInternal() override; - void DisconnectInternal() override; - bool IsConnected() const override; - void IOWakeup() override; - int IORead(u8* buf) override; - int IOWrite(u8 const* buf, size_t len) override; - -private: - static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, - u32 reportID, u8* report, CFIndex reportLength); - static void RemoveCallback(void* context, IOReturn result, void* sender); - void QueueBufferReport(int length); - IOHIDDeviceRef m_device; - bool m_connected; - std::atomic m_interrupted; - Report m_report_buffer; - Common::FifoQueue m_buffered_reports; -}; - -WiimoteScanner::WiimoteScanner() -{ -} - -WiimoteScanner::~WiimoteScanner() -{ -} - -void WiimoteScanner::Update() -{ -} - -void WiimoteScanner::FindWiimotes(std::vector& found_wiimotes, Wiimote*& found_board) +void WiimoteScannerDarwin::FindWiimotes(std::vector& found_wiimotes, + Wiimote*& found_board) { // TODO: find the device in the constructor and save it for later IOBluetoothHostController* bth; IOBluetoothDeviceInquiry* bti; - IOHIDManagerRef hid; - SearchBT* sbt; - NSEnumerator* en; found_board = nullptr; - bool btFailed = false; - bool hidFailed = false; - bth = [[IOBluetoothHostController alloc] init]; - btFailed = [bth addressAsString] == nil; + bool btFailed = [bth addressAsString] == nil; if (btFailed) - WARN_LOG(WIIMOTE, "No Bluetooth host controller"); - - hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone); - hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID(); - if (hidFailed) - WARN_LOG(WIIMOTE, "No HID manager"); - - if (hidFailed && btFailed) { - CFRelease(hid); + WARN_LOG(WIIMOTE, "No Bluetooth host controller"); [bth release]; return; } - if (!btFailed) + SearchBT* sbt = [[SearchBT alloc] init]; + sbt->maxDevices = 32; + bti = [[IOBluetoothDeviceInquiry alloc] init]; + [bti setDelegate:sbt]; + [bti setInquiryLength:2]; + + if ([bti start] != kIOReturnSuccess) { - sbt = [[SearchBT alloc] init]; - sbt->maxDevices = 32; - bti = [[IOBluetoothDeviceInquiry alloc] init]; - [bti setDelegate:sbt]; - [bti setInquiryLength:2]; + ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery"); + [bth release]; + [sbt release]; + btFailed = true; + } - if ([bti start] != kIOReturnSuccess) + do + { + CFRunLoopRun(); + } while (!sbt->done); + + int found_devices = [[bti foundDevices] count]; + + if (found_devices) + NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices); + + NSEnumerator* en = [[bti foundDevices] objectEnumerator]; + for (int i = 0; i < found_devices; i++) + { + IOBluetoothDevice* dev = [en nextObject]; + if (!IsValidBluetoothName([[dev name] UTF8String])) + continue; + + Wiimote* wm = new WiimoteDarwin([dev retain]); + + if (IsBalanceBoardName([[dev name] UTF8String])) { - ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery"); - [bth release]; - [sbt release]; - btFailed = true; + found_board = wm; } - - do + else { - CFRunLoopRun(); - } while (!sbt->done); + found_wiimotes.push_back(wm); + } + } - int found_devices = [[bti foundDevices] count]; + [bth release]; + [bti release]; + [sbt release]; +} +bool WiimoteScannerDarwin::IsReady() const +{ + // TODO: only return true when a BT device is present + return true; +} + +void WiimoteScannerDarwinHID::FindWiimotes(std::vector& found_wiimotes, + Wiimote*& found_board) +{ + found_board = nullptr; + + IOHIDManagerRef hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone); + bool hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID(); + if (hidFailed) + { + CFRelease(hid); + WARN_LOG(WIIMOTE, "No HID manager"); + return; + } + + NSArray* criteria = @[ + @{ @kIOHIDVendorIDKey : @0x057e, + @kIOHIDProductIDKey : @0x0306 }, + @{ @kIOHIDVendorIDKey : @0x057e, + @kIOHIDProductIDKey : @0x0330 }, + ]; + IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria); + if (IOHIDManagerOpen(hid, kIOHIDOptionsTypeNone) != kIOReturnSuccess) + WARN_LOG(WIIMOTE, "Failed to open HID Manager"); + CFSetRef devices = IOHIDManagerCopyDevices(hid); + if (devices) + { + int found_devices = CFSetGetCount(devices); if (found_devices) - NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices); - - en = [[bti foundDevices] objectEnumerator]; - for (int i = 0; i < found_devices; i++) { - IOBluetoothDevice* dev = [en nextObject]; - if (!IsValidBluetoothName([[dev name] UTF8String])) - continue; + NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices); - Wiimote* wm = new WiimoteDarwin([dev retain]); - - if (IsBalanceBoardName([[dev name] UTF8String])) - { - found_board = wm; - } - else + IOHIDDeviceRef values[found_devices]; + CFSetGetValues(devices, reinterpret_cast(&values)); + for (int i = 0; i < found_devices; i++) { + Wiimote* wm = new WiimoteDarwinHid(values[i]); found_wiimotes.push_back(wm); } } - - [bth release]; - [bti release]; - [sbt release]; - } - - if (!hidFailed) - { - NSArray* criteria = @[ - @{ @kIOHIDVendorIDKey : @0x057e, - @kIOHIDProductIDKey : @0x0306 }, - @{ @kIOHIDVendorIDKey : @0x057e, - @kIOHIDProductIDKey : @0x0330 }, - ]; - IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria); - if (IOHIDManagerOpen(hid, kIOHIDOptionsTypeNone) != kIOReturnSuccess) - WARN_LOG(WIIMOTE, "Failed to open HID Manager"); - CFSetRef devices = IOHIDManagerCopyDevices(hid); - if (devices) - { - int found_devices = CFSetGetCount(devices); - if (found_devices) - { - NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices); - - IOHIDDeviceRef values[found_devices]; - CFSetGetValues(devices, reinterpret_cast(&values)); - for (int i = 0; i < found_devices; i++) - { - Wiimote* wm = new WiimoteDarwinHid(values[i]); - found_wiimotes.push_back(wm); - } - } - } - CFRelease(hid); } + CFRelease(hid); } -bool WiimoteScanner::IsReady() const +bool WiimoteScannerDarwinHID::IsReady() const { - // TODO: only return true when a BT device is present + // TODO: only return true when !hidFailed return true; } diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index af62ece6ba..4a56d1f2e7 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -6,6 +6,8 @@ #include #include +#include "Core/HW/WiimoteReal/WiimoteReal.h" + #include "Common/ChunkFile.h" #include "Common/CommonTypes.h" #include "Common/IniFile.h" @@ -15,7 +17,10 @@ #include "Core/Core.h" #include "Core/HW/WiimoteEmu/WiimoteEmu.h" #include "Core/HW/WiimoteEmu/WiimoteHid.h" -#include "Core/HW/WiimoteReal/WiimoteReal.h" +#include "Core/HW/WiimoteReal/IOAndroid.h" +#include "Core/HW/WiimoteReal/IOLinux.h" +#include "Core/HW/WiimoteReal/IOWin.h" +#include "Core/HW/WiimoteReal/IOdarwin.h" #include "Core/Host.h" #include "InputCommon/InputConfig.h" @@ -452,6 +457,17 @@ void WiimoteScanner::SetScanMode(WiimoteScanMode scan_mode) m_scan_mode_changed_event.Set(); } +bool WiimoteScanner::IsReady() const +{ + return std::any_of(m_scanner_backends.begin(), m_scanner_backends.end(), + [](const auto& backend) { return backend->IsReady(); }); +} + +void WiimoteScanner::AddScannerBackend(std::unique_ptr backend) +{ + m_scanner_backends.emplace_back(std::move(backend)); +} + static void CheckForDisconnectedWiimotes() { std::lock_guard lk(g_wiimotes_mutex); @@ -475,21 +491,24 @@ void WiimoteScanner::ThreadFunc() if (m_scan_mode.load() == WiimoteScanMode::DO_NOT_SCAN) continue; - if (CalculateWantedWiimotes() != 0 || CalculateWantedBB() != 0) + for (const auto& backend : m_scanner_backends) { - std::vector found_wiimotes; - Wiimote* found_board = nullptr; - FindWiimotes(found_wiimotes, found_board); + if (CalculateWantedWiimotes() != 0 || CalculateWantedBB() != 0) { - std::lock_guard lk(g_wiimotes_mutex); - std::for_each(found_wiimotes.begin(), found_wiimotes.end(), TryToConnectWiimote); - if (found_board) - TryToConnectBalanceBoard(found_board); + std::vector found_wiimotes; + Wiimote* found_board = nullptr; + backend->FindWiimotes(found_wiimotes, found_board); + { + std::lock_guard lk(g_wiimotes_mutex); + 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 } - } - else - { - Update(); // Does stuff needed to detect disconnects on Windows } if (m_scan_mode.load() == WiimoteScanMode::SCAN_ONCE) @@ -615,7 +634,14 @@ void LoadSettings() void Initialize(::Wiimote::InitializeMode init_mode) { if (!g_real_wiimotes_initialized) + { + g_wiimote_scanner.AddScannerBackend(std::make_unique()); + g_wiimote_scanner.AddScannerBackend(std::make_unique()); + g_wiimote_scanner.AddScannerBackend(std::make_unique()); + g_wiimote_scanner.AddScannerBackend(std::make_unique()); + g_wiimote_scanner.AddScannerBackend(std::make_unique()); g_wiimote_scanner.StartThread(); + } if (SConfig::GetInstance().m_WiimoteContinuousScanning) g_wiimote_scanner.SetScanMode(WiimoteScanMode::CONTINUOUSLY_SCAN); diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index b576788157..36ef8ca3c0 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -114,6 +114,16 @@ private: Common::FifoQueue m_write_reports; }; +class WiimoteScannerBackend +{ +public: + virtual ~WiimoteScannerBackend() = default; + virtual bool IsReady() const = 0; + virtual void FindWiimotes(std::vector&, Wiimote*&) = 0; + // function called when not looking for more Wiimotes + virtual void Update() = 0; +}; + enum class WiimoteScanMode { DO_NOT_SCAN, @@ -124,36 +134,23 @@ enum class WiimoteScanMode class WiimoteScanner { public: - WiimoteScanner(); - ~WiimoteScanner(); - - bool IsReady() const; - + WiimoteScanner() = default; void StartThread(); void StopThread(); void SetScanMode(WiimoteScanMode scan_mode); - void FindWiimotes(std::vector&, Wiimote*&); - - // function called when not looking for more Wiimotes - void Update(); + void AddScannerBackend(std::unique_ptr backend); + bool IsReady() const; private: void ThreadFunc(); - std::thread m_scan_thread; + Common::Flag m_scan_thread_running; Common::Event m_scan_mode_changed_event; - Common::Flag m_scan_thread_running; std::atomic m_scan_mode{WiimoteScanMode::DO_NOT_SCAN}; -#if defined(_WIN32) - void CheckDeviceType(std::basic_string& devicepath, WinWriteMethod& write_method, - bool& real_wiimote, bool& is_bb); -#elif defined(__linux__) && HAVE_BLUEZ - int device_id; - int device_sock; -#endif + std::vector> m_scanner_backends; }; extern std::mutex g_wiimotes_mutex; diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h index 092eda0504..1f34d36fe4 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteRealBase.h @@ -4,23 +4,6 @@ #pragma once -#ifdef _WIN32 -#include -#elif defined(__APPLE__) -// Work around an Apple bug: for some reason, IOBluetooth.h errors on -// inclusion in Mavericks, but only in Objective-C++ C++11 mode. I filed -// this as ; in the meantime... -#import -#undef NS_ENUM_AVAILABLE -#define NS_ENUM_AVAILABLE(...) -// end hack -#import -#include -#include -#elif defined(__linux__) && HAVE_BLUEZ -#include -#endif - // Wiimote internal codes // Communication channels @@ -51,13 +34,3 @@ // It's 23. NOT 32! #define MAX_PAYLOAD 23 #define WIIMOTE_DEFAULT_TIMEOUT 1000 - -#ifdef _WIN32 -// Different methods to send data Wiimote on Windows depending on OS and Bluetooth Stack -enum WinWriteMethod -{ - WWM_WRITE_FILE_LARGEST_REPORT_SIZE, - WWM_WRITE_FILE_ACTUAL_REPORT_SIZE, - WWM_SET_OUTPUT_REPORT -}; -#endif