diff --git a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp b/Source/Core/Core/HW/WiimoteReal/IODummy.cpp index 5b14f9012b..090c7141e5 100644 --- a/Source/Core/Core/HW/WiimoteReal/IODummy.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IODummy.cpp @@ -9,9 +9,7 @@ namespace WiimoteReal { WiimoteScanner::WiimoteScanner() -{ - return; -} +{} WiimoteScanner::~WiimoteScanner() {} @@ -30,43 +28,4 @@ bool WiimoteScanner::IsReady() const return false; } -void Wiimote::InitInternal() -{} - -void Wiimote::TeardownInternal() -{} - -bool Wiimote::ConnectInternal() -{ - return 0; -} - -void Wiimote::DisconnectInternal() -{ - return; -} - -bool Wiimote::IsConnected() const -{ - return false; -} - -void Wiimote::IOWakeup() -{} - -int Wiimote::IORead(u8* buf) -{ - return 0; -} - -int Wiimote::IOWrite(const u8* buf, size_t len) -{ - return 0; -} - -void Wiimote::EnablePowerAssertionInternal() -{} -void Wiimote::DisablePowerAssertionInternal() -{} - }; diff --git a/Source/Core/Core/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/HW/WiimoteReal/IONix.cpp index b94ce5db9a..adcf9ab62b 100644 --- a/Source/Core/Core/HW/WiimoteReal/IONix.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IONix.cpp @@ -13,6 +13,28 @@ 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; +}; + WiimoteScanner::WiimoteScanner() : m_want_wiimotes() , device_id(-1) @@ -102,8 +124,7 @@ void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimot char bdaddr_str[18] = {}; ba2str(&scan_infos[i].bdaddr, bdaddr_str); - auto* const wm = new Wiimote; - wm->bdaddr = scan_infos[i].bdaddr; + Wiimote* wm = new WiimoteLinux(scan_infos[i].bdaddr); if (IsBalanceBoardName(name)) { found_board = wm; @@ -120,10 +141,10 @@ void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimot } -void Wiimote::InitInternal() +WiimoteLinux::WiimoteLinux(bdaddr_t bdaddr) : Wiimote(), m_bdaddr(bdaddr) { - cmd_sock = -1; - int_sock = -1; + m_cmd_sock = -1; + m_int_sock = -1; int fds[2]; if (pipe(fds)) @@ -131,69 +152,69 @@ void Wiimote::InitInternal() ERROR_LOG(WIIMOTE, "pipe failed"); abort(); } - wakeup_pipe_w = fds[1]; - wakeup_pipe_r = fds[0]; - bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}}; + m_wakeup_pipe_w = fds[1]; + m_wakeup_pipe_r = fds[0]; } -void Wiimote::TeardownInternal() +WiimoteLinux::~WiimoteLinux() { - close(wakeup_pipe_w); - close(wakeup_pipe_r); + Shutdown(); + close(m_wakeup_pipe_w); + close(m_wakeup_pipe_r); } // Connect to a wiimote with a known address. -bool Wiimote::ConnectInternal() +bool WiimoteLinux::ConnectInternal() { sockaddr_l2 addr; addr.l2_family = AF_BLUETOOTH; - addr.l2_bdaddr = bdaddr; + addr.l2_bdaddr = m_bdaddr; addr.l2_cid = 0; // Output channel addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); - if ((cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + if ((m_cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || + connect(m_cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) { DEBUG_LOG(WIIMOTE, "Unable to open output socket to wiimote."); - close(cmd_sock); - cmd_sock = -1; + close(m_cmd_sock); + m_cmd_sock = -1; return false; } // Input channel addr.l2_psm = htobs(WM_INPUT_CHANNEL); - if ((int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) + if ((m_int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || + connect(m_int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) { DEBUG_LOG(WIIMOTE, "Unable to open input socket from wiimote."); - close(int_sock); - close(cmd_sock); - int_sock = cmd_sock = -1; + close(m_int_sock); + close(m_cmd_sock); + m_int_sock = m_cmd_sock = -1; return false; } return true; } -void Wiimote::DisconnectInternal() +void WiimoteLinux::DisconnectInternal() { - close(cmd_sock); - close(int_sock); + close(m_cmd_sock); + close(m_int_sock); - cmd_sock = -1; - int_sock = -1; + m_cmd_sock = -1; + m_int_sock = -1; } -bool Wiimote::IsConnected() const +bool WiimoteLinux::IsConnected() const { - return cmd_sock != -1;// && int_sock != -1; + return m_cmd_sock != -1;// && int_sock != -1; } -void Wiimote::IOWakeup() +void WiimoteLinux::IOWakeup() { char c = 0; - if (write(wakeup_pipe_w, &c, 1) != 1) + if (write(m_wakeup_pipe_w, &c, 1) != 1) { ERROR_LOG(WIIMOTE, "Unable to write to wakeup pipe."); } @@ -202,46 +223,46 @@ void Wiimote::IOWakeup() // positive = read packet // negative = didn't read packet // zero = error -int Wiimote::IORead(u8* buf) +int WiimoteLinux::IORead(u8* buf) { // Block select for 1/2000th of a second fd_set fds; FD_ZERO(&fds); - FD_SET(int_sock, &fds); - FD_SET(wakeup_pipe_r, &fds); + FD_SET(m_int_sock, &fds); + FD_SET(m_wakeup_pipe_r, &fds); - if (select(int_sock + 1, &fds, nullptr, nullptr, nullptr) == -1) + if (select(m_int_sock + 1, &fds, nullptr, nullptr, nullptr) == -1) { - ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1); + ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", m_index + 1); return -1; } - if (FD_ISSET(wakeup_pipe_r, &fds)) + if (FD_ISSET(m_wakeup_pipe_r, &fds)) { char c; - if (read(wakeup_pipe_r, &c, 1) != 1) + if (read(m_wakeup_pipe_r, &c, 1) != 1) { ERROR_LOG(WIIMOTE, "Unable to read from wakeup pipe."); } return -1; } - if (!FD_ISSET(int_sock, &fds)) + if (!FD_ISSET(m_int_sock, &fds)) return -1; // Read the pending message into the buffer - int r = read(int_sock, buf, MAX_PAYLOAD); + int r = read(m_int_sock, buf, MAX_PAYLOAD); if (r == -1) { // Error reading data - ERROR_LOG(WIIMOTE, "Receiving data from wiimote %i.", index + 1); + ERROR_LOG(WIIMOTE, "Receiving data from wiimote %i.", m_index + 1); if (errno == ENOTCONN) { // This can happen if the bluetooth dongle is disconnected ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. " - "Wiimote %i will be disconnected.", index + 1); + "Wiimote %i will be disconnected.", m_index + 1); } r = 0; @@ -250,14 +271,9 @@ int Wiimote::IORead(u8* buf) return r; } -int Wiimote::IOWrite(u8 const* buf, size_t len) +int WiimoteLinux::IOWrite(u8 const* buf, size_t len) { - return write(int_sock, buf, (int)len); + return write(m_int_sock, buf, (int)len); } -void Wiimote::EnablePowerAssertionInternal() -{} -void Wiimote::DisablePowerAssertionInternal() -{} - }; // WiimoteReal diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index e08870d9c9..65edcc9326 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -187,10 +187,30 @@ inline void init_lib() namespace WiimoteReal { +class WiimoteWindows final : public Wiimote +{ +public: + WiimoteWindows(const std::basic_string& path); + ~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; + enum win_bt_stack_t m_stack; // Type of bluetooth stack to use +}; int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, size_t len, DWORD* written); int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index); -void _IOWakeup(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read); template void ProcessWiimotes(bool new_scan, T& callback); @@ -272,11 +292,11 @@ void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimot // Query the data for this device if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, nullptr, nullptr)) { - auto const wm = new Wiimote; - wm->devicepath = detail_data->DevicePath; + std::basic_string device_path(detail_data->DevicePath); + Wiimote* wm = new WiimoteWindows(device_path); bool real_wiimote = false, is_bb = false; - CheckDeviceType(wm->devicepath, real_wiimote, is_bb); + CheckDeviceType(device_path, real_wiimote, is_bb); if (is_bb) { found_board = wm; @@ -500,14 +520,14 @@ bool WiimoteScanner::IsReady() const } // Connect to a wiimote with a known device path. -bool Wiimote::ConnectInternal() +bool WiimoteWindows::ConnectInternal() { if (IsConnected()) return false; #ifdef SHARE_WRITE_WIIMOTES std::lock_guard lk(g_connected_wiimotes_lock); - if (g_connected_wiimotes.count(devicepath) != 0) + if (g_connected_wiimotes.count(m_devicepath) != 0) return false; auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE; @@ -519,13 +539,13 @@ bool Wiimote::ConnectInternal() auto const open_flags = FILE_SHARE_READ; #endif - dev_handle = CreateFile(devicepath.c_str(), + m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); - if (dev_handle == INVALID_HANDLE_VALUE) + if (m_dev_handle == INVALID_HANDLE_VALUE) { - dev_handle = 0; + m_dev_handle = 0; return false; } @@ -564,52 +584,48 @@ bool Wiimote::ConnectInternal() } */ #ifdef SHARE_WRITE_WIIMOTES - g_connected_wiimotes.insert(devicepath); + g_connected_wiimotes.insert(m_devicepath); #endif return true; } -void Wiimote::DisconnectInternal() +void WiimoteWindows::DisconnectInternal() { if (!IsConnected()) return; - CloseHandle(dev_handle); - dev_handle = 0; + CloseHandle(m_dev_handle); + m_dev_handle = 0; #ifdef SHARE_WRITE_WIIMOTES std::lock_guard lk(g_connected_wiimotes_lock); - g_connected_wiimotes.erase(devicepath); + g_connected_wiimotes.erase(m_devicepath); #endif } -void Wiimote::InitInternal() +WiimoteWindows::WiimoteWindows(const std::basic_string& path) : m_devicepath(path) { - dev_handle = 0; - stack = MSBT_STACK_UNKNOWN; + m_dev_handle = 0; + m_stack = MSBT_STACK_UNKNOWN; - hid_overlap_read = OVERLAPPED(); - hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr); + m_hid_overlap_read = OVERLAPPED(); + m_hid_overlap_read.hEvent = CreateEvent(nullptr, true, false, nullptr); - hid_overlap_write = OVERLAPPED(); - hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr); + m_hid_overlap_write = OVERLAPPED(); + m_hid_overlap_write.hEvent = CreateEvent(nullptr, true, false, nullptr); } -void Wiimote::TeardownInternal() +WiimoteWindows::~WiimoteWindows() { - CloseHandle(hid_overlap_read.hEvent); - CloseHandle(hid_overlap_write.hEvent); + Shutdown(); + CloseHandle(m_hid_overlap_read.hEvent); + CloseHandle(m_hid_overlap_write.hEvent); } -bool Wiimote::IsConnected() const +bool WiimoteWindows::IsConnected() const { - return dev_handle != 0; -} - -void _IOWakeup(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read) -{ - SetEvent(hid_overlap_read.hEvent); + return m_dev_handle != 0; } // positive = read packet @@ -632,7 +648,7 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index { auto const wait_result = WaitForSingleObject(hid_overlap_read.hEvent, INFINITE); - // In case the event was signalled by _IOWakeup before the read completed, cancel it. + // In case the event was signalled by IOWakeup before the read completed, cancel it. CancelIo(dev_handle); if (WAIT_FAILED == wait_result) @@ -666,18 +682,18 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index return bytes + 1; } -void Wiimote::IOWakeup() +void WiimoteWindows::IOWakeup() { - _IOWakeup(dev_handle, hid_overlap_read); + SetEvent(m_hid_overlap_read.hEvent); } // positive = read packet // negative = didn't read packet // zero = error -int Wiimote::IORead(u8* buf) +int WiimoteWindows::IORead(u8* buf) { - return _IORead(dev_handle, hid_overlap_read, buf, index); + return _IORead(m_dev_handle, m_hid_overlap_read, buf, m_index); } @@ -778,16 +794,11 @@ int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stac return 0; } -int Wiimote::IOWrite(const u8* buf, size_t len) +int WiimoteWindows::IOWrite(const u8* buf, size_t len) { - return _IOWrite(dev_handle, hid_overlap_write, stack, buf, len, nullptr); + return _IOWrite(m_dev_handle, m_hid_overlap_write, m_stack, buf, len, nullptr); } -void Wiimote::EnablePowerAssertionInternal() -{} -void Wiimote::DisablePowerAssertionInternal() -{} - // invokes callback for each found wiimote bluetooth device template void ProcessWiimotes(bool new_scan, T& callback) diff --git a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm index d2b450dc6b..9e00d946c8 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/HW/WiimoteReal/IOdarwin.mm @@ -10,100 +10,41 @@ } @end -@implementation SearchBT -- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender - error: (IOReturn) error - aborted: (BOOL) aborted -{ - done = true; - CFRunLoopStop(CFRunLoopGetCurrent()); -} - -- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry *) sender - device: (IOBluetoothDevice *) device -{ - NOTICE_LOG(WIIMOTE, "Discovered bluetooth device at %s: %s", - [[device addressString] UTF8String], - [[device name] UTF8String]); - - if ([[sender foundDevices] count] == maxDevices) - [sender stop]; -} -@end - @interface ConnectBT: NSObject {} @end -@implementation ConnectBT -- (void) l2capChannelData: (IOBluetoothL2CAPChannel *) l2capChannel - data: (unsigned char *) data - length: (NSUInteger) length -{ - IOBluetoothDevice *device = [l2capChannel device]; - WiimoteReal::Wiimote *wm = nullptr; - - std::lock_guard lk(WiimoteReal::g_refresh_lock); - - for (int i = 0; i < MAX_WIIMOTES; i++) - { - if (WiimoteReal::g_wiimotes[i] == nullptr) - continue; - if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE) - wm = WiimoteReal::g_wiimotes[i]; - } - - if (wm == nullptr) { - ERROR_LOG(WIIMOTE, "Received packet for unknown wiimote"); - return; - } - - if (length > MAX_PAYLOAD) { - WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, too large", - wm->index + 1); - return; - } - - if (wm->inputlen != -1) { - WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full", - wm->index + 1); - return; - } - - memcpy(wm->input, data, length); - wm->inputlen = length; - - CFRunLoopStop(CFRunLoopGetCurrent()); -} - -- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel -{ - IOBluetoothDevice *device = [l2capChannel device]; - WiimoteReal::Wiimote *wm = nullptr; - - std::lock_guard lk(WiimoteReal::g_refresh_lock); - - for (int i = 0; i < MAX_WIIMOTES; i++) - { - if (WiimoteReal::g_wiimotes[i] == nullptr) - continue; - if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE) - wm = WiimoteReal::g_wiimotes[i]; - } - - if (wm == nullptr) { - ERROR_LOG(WIIMOTE, "Channel for unknown wiimote was closed"); - return; - } - - WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->index + 1); - - wm->DisconnectInternal(); -} -@end - 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; +}; + WiimoteScanner::WiimoteScanner() : m_run_thread() , m_want_wiimotes() @@ -164,8 +105,7 @@ void WiimoteScanner::FindWiimotes(std::vector & found_wiimotes, Wiimot if (!IsValidBluetoothName([[dev name] UTF8String])) continue; - Wiimote *wm = new Wiimote(); - wm->btd = [dev retain]; + Wiimote* wm = new WiimoteDarwin([dev retain]); if (IsBalanceBoardName([[dev name] UTF8String])) { @@ -188,51 +128,52 @@ bool WiimoteScanner::IsReady() const return true; } -void Wiimote::InitInternal() +WiimoteDarwin::WiimoteDarwin(IOBluetoothDevice* device) : m_btd(device) { - inputlen = 0; + m_inputlen = 0; m_connected = false; m_wiimote_thread_run_loop = nullptr; - btd = nil; m_pm_assertion = kIOPMNullAssertionID; } -void Wiimote::TeardownInternal() +WiimoteDarwin::~WiimoteDarwin() { + Shutdown(); if (m_wiimote_thread_run_loop) { CFRelease(m_wiimote_thread_run_loop); m_wiimote_thread_run_loop = nullptr; } - [btd release]; - btd = nil; + [m_btd release]; + m_btd = nil; + DisablePowerAssertionInternal(); } // Connect to a wiimote with a known address. -bool Wiimote::ConnectInternal() +bool WiimoteDarwin::ConnectInternal() { if (IsConnected()) return false; ConnectBT *cbt = [[ConnectBT alloc] init]; - cchan = ichan = nil; + m_cchan = m_ichan = nil; - IOReturn ret = [btd openConnection]; + IOReturn ret = [m_btd openConnection]; if (ret) { ERROR_LOG(WIIMOTE, "Unable to open Bluetooth connection to wiimote %i: %x", - index + 1, ret); + m_index + 1, ret); [cbt release]; return false; } - ret = [btd openL2CAPChannelSync: &cchan + ret = [m_btd openL2CAPChannelSync: &m_cchan withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt]; if (ret) { ERROR_LOG(WIIMOTE, "Unable to open control channel for wiimote %i: %x", - index + 1, ret); + m_index + 1, ret); goto bad; } // Apple docs claim: @@ -240,20 +181,20 @@ bool Wiimote::ConnectInternal() // success; the channel must be released when the caller is done with it." // But without this, the channels get over-autoreleased, even though the // refcounting behavior here is clearly correct. - [cchan retain]; + [m_cchan retain]; - ret = [btd openL2CAPChannelSync: &ichan + ret = [m_btd openL2CAPChannelSync: &m_ichan withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt]; if (ret) { WARN_LOG(WIIMOTE, "Unable to open interrupt channel for wiimote %i: %x", - index + 1, ret); + m_index + 1, ret); goto bad; } - [ichan retain]; + [m_ichan retain]; NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s", - index + 1, [[btd addressString] UTF8String]); + m_index + 1, [[m_btd addressString] UTF8String]); m_connected = true; @@ -270,32 +211,32 @@ bad: } // Disconnect a wiimote. -void Wiimote::DisconnectInternal() +void WiimoteDarwin::DisconnectInternal() { - [ichan closeChannel]; - [ichan release]; - ichan = nil; + [m_ichan closeChannel]; + [m_ichan release]; + m_ichan = nil; - [cchan closeChannel]; - [cchan release]; - cchan = nil; + [m_cchan closeChannel]; + [m_cchan release]; + m_cchan = nil; - [btd closeConnection]; + [m_btd closeConnection]; if (!IsConnected()) return; - NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", index + 1); + NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", m_index + 1); m_connected = false; } -bool Wiimote::IsConnected() const +bool WiimoteDarwin::IsConnected() const { return m_connected; } -void Wiimote::IOWakeup() +void WiimoteDarwin::IOWakeup() { if (m_wiimote_thread_run_loop) { @@ -303,24 +244,24 @@ void Wiimote::IOWakeup() } } -int Wiimote::IORead(unsigned char *buf) +int WiimoteDarwin::IORead(unsigned char *buf) { - input = buf; - inputlen = -1; + m_input = buf; + m_inputlen = -1; CFRunLoopRun(); - return inputlen; + return m_inputlen; } -int Wiimote::IOWrite(const unsigned char *buf, size_t len) +int WiimoteDarwin::IOWrite(const unsigned char *buf, size_t len) { IOReturn ret; if (!IsConnected()) return 0; - ret = [ichan writeAsync: const_cast((void *)buf) length: (int)len refcon: nil]; + ret = [m_ichan writeAsync: const_cast((void *)buf) length: (int)len refcon: nil]; if (ret == kIOReturnSuccess) return len; @@ -328,7 +269,7 @@ int Wiimote::IOWrite(const unsigned char *buf, size_t len) return 0; } -void Wiimote::EnablePowerAssertionInternal() +void WiimoteDarwin::EnablePowerAssertionInternal() { if (m_pm_assertion == kIOPMNullAssertionID) { @@ -337,7 +278,7 @@ void Wiimote::EnablePowerAssertionInternal() } } -void Wiimote::DisablePowerAssertionInternal() +void WiimoteDarwin::DisablePowerAssertionInternal() { if (m_pm_assertion != kIOPMNullAssertionID) { @@ -346,4 +287,94 @@ void Wiimote::DisablePowerAssertionInternal() } } +} // namespace + +@implementation SearchBT +- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender + error: (IOReturn) error + aborted: (BOOL) aborted +{ + done = true; + CFRunLoopStop(CFRunLoopGetCurrent()); } + +- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry *) sender + device: (IOBluetoothDevice *) device +{ + NOTICE_LOG(WIIMOTE, "Discovered bluetooth device at %s: %s", + [[device addressString] UTF8String], + [[device name] UTF8String]); + + if ([[sender foundDevices] count] == maxDevices) + [sender stop]; +} +@end + +@implementation ConnectBT +- (void) l2capChannelData: (IOBluetoothL2CAPChannel *) l2capChannel + data: (unsigned char *) data + length: (NSUInteger) length +{ + IOBluetoothDevice *device = [l2capChannel device]; + WiimoteReal::WiimoteDarwin *wm = nullptr; + + std::lock_guard lk(WiimoteReal::g_refresh_lock); + + for (int i = 0; i < MAX_WIIMOTES; i++) + { + if (WiimoteReal::g_wiimotes[i] == nullptr) + continue; + wm = static_cast(WiimoteReal::g_wiimotes[i]); + if ([device isEqual: wm->m_btd] != TRUE) + wm = nullptr; + } + + if (wm == nullptr) { + ERROR_LOG(WIIMOTE, "Received packet for unknown wiimote"); + return; + } + + if (length > MAX_PAYLOAD) { + WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, too large", + wm->m_index + 1); + return; + } + + if (wm->m_inputlen != -1) { + WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full", + wm->m_index + 1); + return; + } + + memcpy(wm->m_input, data, length); + wm->m_inputlen = length; + + CFRunLoopStop(CFRunLoopGetCurrent()); +} + +- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel +{ + IOBluetoothDevice *device = [l2capChannel device]; + WiimoteReal::WiimoteDarwin *wm = nullptr; + + std::lock_guard lk(WiimoteReal::g_refresh_lock); + + for (int i = 0; i < MAX_WIIMOTES; i++) + { + if (WiimoteReal::g_wiimotes[i] == nullptr) + continue; + wm = static_cast(WiimoteReal::g_wiimotes[i]); + if ([device isEqual: wm->m_btd] != TRUE) + wm = nullptr; + } + + if (wm == nullptr) { + ERROR_LOG(WIIMOTE, "Channel for unknown wiimote was closed"); + return; + } + + WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->m_index + 1); + + wm->DisconnectInternal(); +} +@end diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 92e6c73c5b..36b797f697 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -37,22 +37,18 @@ Wiimote* g_wiimotes[MAX_BBMOTES]; WiimoteScanner g_wiimote_scanner; Wiimote::Wiimote() - : index() + : m_index() , m_last_input_report() , m_channel(0) , m_rumble_state() , m_need_prepare() -{ - InitInternal(); -} +{} -Wiimote::~Wiimote() +void Wiimote::Shutdown() { - DisablePowerAssertionInternal(); StopThread(); ClearReadQueue(); m_write_reports.Clear(); - TeardownInternal(); } // to be called from CPU thread @@ -62,12 +58,9 @@ void Wiimote::WriteReport(Report rpt) { bool const new_rumble_state = (rpt[2] & 0x1) != 0; + // If this is a rumble report and the rumble state didn't change, ignore. if (WM_RUMBLE == rpt[1] && new_rumble_state == m_rumble_state) - { - // If this is a rumble report and the rumble state didn't change, ignore - //ERROR_LOG(WIIMOTE, "Ignoring rumble report."); return; - } m_rumble_state = new_rumble_state; } @@ -140,7 +133,7 @@ void Wiimote::ControlChannel(const u16 channel, const void* const data, const u3 if (hidp->type == HID_TYPE_SET_REPORT) { u8 handshake_ok = HID_HANDSHAKE_SUCCESS; - Core::Callback_WiimoteInterruptChannel(index, channel, &handshake_ok, sizeof(handshake_ok)); + Core::Callback_WiimoteInterruptChannel(m_index, channel, &handshake_ok, sizeof(handshake_ok)); } } } @@ -159,7 +152,7 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const auto const data = static_cast(_data); Report rpt(data, data + size); - WiimoteEmu::Wiimote *const wm = (WiimoteEmu::Wiimote*)::Wiimote::GetConfig()->controllers[index]; + WiimoteEmu::Wiimote *const wm = (WiimoteEmu::Wiimote*)::Wiimote::GetConfig()->controllers[m_index]; // Convert output DATA packets to SET_REPORT packets. // Nintendo Wiimotes work without this translation, but 3rd @@ -202,7 +195,7 @@ bool Wiimote::Read() if (result > 0 && m_channel > 0) { if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 && - index == WIIMOTE_BALANCE_BOARD) + m_index == WIIMOTE_BALANCE_BOARD) { static sf::UdpSocket Socket; Socket.send((char*)rpt.data(), @@ -218,7 +211,7 @@ bool Wiimote::Read() } else if (0 == result) { - ERROR_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", index + 1); + ERROR_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", m_index + 1); DisconnectInternal(); } @@ -235,7 +228,7 @@ bool Wiimote::Write() if (!is_speaker_data || m_last_audio_report.GetTimeDifference() > 5) { - if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 && index == WIIMOTE_BALANCE_BOARD) + if (SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort > 0 && m_index == WIIMOTE_BALANCE_BOARD) { static sf::UdpSocket Socket; Socket.send((char*)rpt.data(), rpt.size(), sf::IpAddress::LocalHost, SConfig::GetInstance().m_LocalCoreStartupParameter.iBBDumpPort); @@ -290,7 +283,7 @@ void Wiimote::Update() { if (!IsConnected()) { - HandleWiimoteDisconnect(index); + HandleWiimoteDisconnect(m_index); return; } @@ -300,14 +293,14 @@ void Wiimote::Update() // Send the report if (!rpt.empty() && m_channel > 0) { - Core::Callback_WiimoteInterruptChannel(index, m_channel, + Core::Callback_WiimoteInterruptChannel(m_index, m_channel, rpt.data(), (u32)rpt.size()); } } void Wiimote::Prepare(int _index) { - index = _index; + m_index = _index; m_need_prepare = true; } @@ -317,7 +310,7 @@ bool Wiimote::PrepareOnThread() u8 static const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE}; // Set the active LEDs and turn on rumble. - u8 static const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << (index%WIIMOTE_BALANCE_BOARD) | 0x1)}; + u8 static const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << (m_index%WIIMOTE_BALANCE_BOARD) | 0x1)}; // Turn off rumble u8 static const rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0}; @@ -351,7 +344,7 @@ void Wiimote::EmuStop() void Wiimote::EmuResume() { - WiimoteEmu::Wiimote *const wm = (WiimoteEmu::Wiimote*)::Wiimote::GetConfig()->controllers[index]; + WiimoteEmu::Wiimote *const wm = (WiimoteEmu::Wiimote*)::Wiimote::GetConfig()->controllers[m_index]; m_last_input_report.clear(); @@ -508,8 +501,6 @@ void Wiimote::StopThread() IOWakeup(); if (m_wiimote_thread.joinable()) m_wiimote_thread.join(); -#if defined(__APPLE__) -#endif } void Wiimote::SetReady() @@ -554,7 +545,7 @@ void Wiimote::ThreadFunc() m_need_prepare = false; if (!PrepareOnThread()) { - ERROR_LOG(WIIMOTE, "Wiimote::PrepareOnThread failed. Disconnecting Wiimote %d.", index + 1); + ERROR_LOG(WIIMOTE, "Wiimote::PrepareOnThread failed. Disconnecting Wiimote %d.", m_index + 1); break; } } diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index fa167a81a2..b7edb53d72 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -26,8 +26,9 @@ class Wiimote : NonCopyable { friend class WiimoteEmu::Wiimote; public: - Wiimote(); - ~Wiimote(); + virtual ~Wiimote() {} + // This needs to be called in derived destructors! + void Shutdown(); void ControlChannel(const u16 channel, const void* const data, const u32 size); void InterruptChannel(const u16 channel, const void* const data, const u32 size); @@ -47,22 +48,19 @@ public: void EmuResume(); void EmuPause(); - void EnablePowerAssertionInternal(); - void DisablePowerAssertionInternal(); + virtual void EnablePowerAssertionInternal() {} + virtual void DisablePowerAssertionInternal() {} // connecting and disconnecting from physical devices // (using address inserted by FindWiimotes) // these are called from the wiimote's thread. - bool ConnectInternal(); - void DisconnectInternal(); - - void InitInternal(); - void TeardownInternal(); + virtual bool ConnectInternal() = 0; + virtual void DisconnectInternal() = 0; bool Connect(); // TODO: change to something like IsRelevant - bool IsConnected() const; + virtual bool IsConnected() const = 0; void Prepare(int index); bool PrepareOnThread(); @@ -73,32 +71,10 @@ public: void QueueReport(u8 rpt_id, const void* data, unsigned int size); - int index; - -#if defined(__APPLE__) - IOBluetoothDevice *btd; - IOBluetoothL2CAPChannel *ichan; - IOBluetoothL2CAPChannel *cchan; - unsigned char* input; - int inputlen; - bool m_connected; - CFRunLoopRef m_wiimote_thread_run_loop; - IOPMAssertionID m_pm_assertion; -#elif defined(__linux__) && HAVE_BLUEZ - bdaddr_t bdaddr; // Bluetooth address - int cmd_sock; // Command socket - int int_sock; // Interrupt socket - int wakeup_pipe_w, wakeup_pipe_r; - -#elif defined(_WIN32) - std::basic_string devicepath; // Unique wiimote reference - //ULONGLONG btaddr; // Bluetooth address - HANDLE dev_handle; // HID handle - OVERLAPPED hid_overlap_read, hid_overlap_write; // Overlap handle - enum win_bt_stack_t stack; // Type of bluetooth stack to use -#endif + int m_index; protected: + Wiimote(); Report m_last_input_report; u16 m_channel; @@ -106,9 +82,9 @@ private: void ClearReadQueue(); void WriteReport(Report rpt); - int IORead(u8* buf); - int IOWrite(u8 const* buf, size_t len); - void IOWakeup(); + virtual int IORead(u8* buf) = 0; + virtual int IOWrite(u8 const* buf, size_t len) = 0; + virtual void IOWakeup() = 0; void ThreadFunc(); void SetReady();