From c2d2fb8c7c84ab2abf439f1ccdafd44d71b41b64 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 11 Feb 2013 15:21:58 -0600 Subject: [PATCH] Try to improve real wiimotes on Windows. --- Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp | 126 ++++++++++-------- .../Core/Src/HW/WiimoteReal/WiimoteReal.cpp | 56 +++++--- .../Core/Src/HW/WiimoteReal/WiimoteReal.h | 2 +- 3 files changed, 112 insertions(+), 72 deletions(-) diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp index d9b6a665ef..d6bc5dd28b 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp @@ -270,10 +270,22 @@ bool Wiimote::Connect() return false; } - hid_overlap = OVERLAPPED(); - hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T("")); - hid_overlap.Offset = 0; - hid_overlap.OffsetHigh = 0; +#if 0 + HIDD_ATTRIBUTES attr; + attr.Size = sizeof(attr); + if (!HidD_GetAttributes(dev_handle, &attr)) + { + CloseHandle(dev_handle); + dev_handle = 0; + return false; + } +#endif + + hid_overlap_read = OVERLAPPED(); + hid_overlap_read.hEvent = CreateEvent(NULL, true, false, NULL); + + hid_overlap_write = OVERLAPPED(); + hid_overlap_write.hEvent = CreateEvent(NULL, true, false, NULL); // 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 @@ -296,7 +308,8 @@ void Wiimote::Disconnect() CloseHandle(dev_handle); dev_handle = 0; - CloseHandle(hid_overlap.hEvent); + CloseHandle(hid_overlap_read.hEvent); + CloseHandle(hid_overlap_write.hEvent); } bool Wiimote::IsConnected() const @@ -307,20 +320,20 @@ bool Wiimote::IsConnected() const // positive = read packet // negative = didn't read packet // zero = error -int Wiimote::IORead(unsigned char* buf) +int Wiimote::IORead(u8* buf) { // used below for a warning *buf = 0; DWORD bytes; - ResetEvent(hid_overlap.hEvent); - if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap)) + ResetEvent(hid_overlap_read.hEvent); + if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read)) { auto const err = GetLastError(); if (ERROR_IO_PENDING == err) { - auto const r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT); + auto const r = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT); if (WAIT_TIMEOUT == r) { // Timeout - cancel and continue @@ -338,7 +351,7 @@ int Wiimote::IORead(unsigned char* buf) } else if (WAIT_OBJECT_0 == r) { - if (!GetOverlappedResult(dev_handle, &hid_overlap, &bytes, TRUE)) + if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE)) { WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1); bytes = 0; @@ -380,70 +393,76 @@ int Wiimote::IORead(unsigned char* buf) int Wiimote::IOWrite(const u8* buf, int len) { - u8 big_buf[MAX_PAYLOAD]; - if (len < MAX_PAYLOAD) - { - std::copy(buf, buf + len, big_buf); - std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0); - buf = big_buf; - } - - DWORD bytes = 0; switch (stack) { case MSBT_STACK_UNKNOWN: { // Try to auto-detect the stack type - - auto i = WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap); - if (i) + stack = MSBT_STACK_BLUESOLEIL; + if (IOWrite(buf, len)) + return 1; + + stack = MSBT_STACK_MS; + if (IOWrite(buf, len)) { - // Bluesoleil will always return 1 here, even if it's not connected - stack = MSBT_STACK_BLUESOLEIL; - return i; + // Don't mind me, just a random sleep to fix stuff on Windows + SLEEP(1000); + return 1; } - i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1); - if (i) - { - stack = MSBT_STACK_MS; - return i; - } - - auto const dw = GetLastError(); - // Checking for 121 = timeout on semaphore/device off/disconnected to - // avoid trouble with other stacks toshiba/widcomm - if (dw == 121) - { - NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: Timeout"); - return 0; - } - else - { - ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw); - return 0; - } + stack = MSBT_STACK_UNKNOWN; break; } case MSBT_STACK_MS: { - auto i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1); - auto dw = GetLastError(); + auto result = HidD_SetOutputReport(dev_handle, const_cast(buf) + 1, len - 1); + //FlushFileBuffers(dev_handle); - if (dw == 121) + if (!result) { - // Semaphore timeout - NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote"); - return 0; + auto err = GetLastError(); + if (err == 121) + { + // Semaphore timeout + NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote"); + } + else + { + ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err); + } } - return i; + return result; break; } case MSBT_STACK_BLUESOLEIL: - return WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap); + { + u8 big_buf[MAX_PAYLOAD]; + if (len < MAX_PAYLOAD) + { + std::copy(buf, buf + len, big_buf); + std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0); + buf = big_buf; + } + + ResetEvent(hid_overlap_write.hEvent); + DWORD bytes = 0; + if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write)) + { + // WriteFile always returns true with bluesoleil. + return 1; + } + else + { + auto const err = GetLastError(); + if (ERROR_IO_PENDING == err) + { + CancelIo(dev_handle); + } + } break; } + } return 0; } @@ -555,6 +574,7 @@ bool ForgetWiimote(HANDLE, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) // We don't want "remembered" devices. // SetServiceState seems to just fail with them. // Make Windows forget about them. + // This is also required to detect a disconnect for some reason.. NOTICE_LOG(WIIMOTE, "Removing remembered wiimote."); Bth_BluetoothRemoveDevice(&btdi.Address); diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index e006ec1f69..6e9a72eb00 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -232,6 +232,12 @@ Report Wiimote::ProcessReadQueue() void Wiimote::Update() { + if (!IsConnected()) + { + HandleWiimoteDisconnect(index); + return; + } + // Pop through the queued reports Report const rpt = ProcessReadQueue(); @@ -252,18 +258,17 @@ bool Wiimote::Prepare(int _index) // core buttons, no continuous reporting u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30}; - // Set the active LEDs. - u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index)}; + // Set the active LEDs and turn on rumble. + u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index) | 0x1}; - // Rumble briefly - u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 1}; + // Turn off rumble + u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0}; // TODO: request status and check for sane response? return (IOWrite(mode_report, sizeof(mode_report)) && IOWrite(led_report, sizeof(led_report)) - && IOWrite(rumble_report, sizeof(rumble_report)) - && (rumble_report[2] = 0, SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report)))); + && (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report)))); } void Wiimote::EmuStart() @@ -375,6 +380,8 @@ void Wiimote::ThreadFunc() { Common::SetCurrentThreadName("Wiimote Device Thread"); + Host_ConnectWiimote(index, true); + // main loop while (m_run_thread && IsConnected()) { @@ -408,13 +415,13 @@ void LoadSettings() void Initialize() { - NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize"); - std::lock_guard lk(g_refresh_lock); if (g_real_wiimotes_initialized) return; + NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize"); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); g_wiimote_scanner.StartScanning(); @@ -423,9 +430,7 @@ void Initialize() } void Shutdown(void) -{ - NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown"); - +{ g_wiimote_scanner.StopScanning(); std::lock_guard lk(g_refresh_lock); @@ -433,6 +438,8 @@ void Shutdown(void) if (!g_real_wiimotes_initialized) return; + NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown"); + g_real_wiimotes_initialized = false; for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) @@ -466,8 +473,6 @@ void TryToConnectWiimote(Wiimote* wm) g_wiimotes[i] = wm; wm->StartThread(); - - Host_ConnectWiimote(i, true); NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1); @@ -485,8 +490,6 @@ void HandleWiimoteDisconnect(int index) { std::lock_guard lk(g_refresh_lock); - Host_ConnectWiimote(index, false); - if (g_wiimotes[index]) { delete g_wiimotes[index]; @@ -511,12 +514,24 @@ void Refresh() { std::lock_guard lk(g_refresh_lock); - CheckForDisconnectedWiimotes(); + std::vector found_wiimotes; if (0 != CalculateWantedWiimotes()) { - HandleFoundWiimotes(g_wiimote_scanner.FindWiimotes()); + found_wiimotes = g_wiimote_scanner.FindWiimotes(); } + + CheckForDisconnectedWiimotes(); + + // Brief rumble for already connected wiimotes. + for (int i = 0; i != MAX_WIIMOTES; ++i) + { + // kinda sloppy + if (g_wiimotes[i]) + g_wiimotes[i]->Prepare(i); + } + + HandleFoundWiimotes(found_wiimotes); } g_wiimote_scanner.StartScanning(); @@ -546,8 +561,13 @@ void Update(int _WiimoteNumber) if (g_wiimotes[_WiimoteNumber]) g_wiimotes[_WiimoteNumber]->Update(); - else + + // Wiimote::Update() may remove the wiimote if it was disconnected. + if (!g_wiimotes[_WiimoteNumber]) + { + NOTICE_LOG(WIIMOTE, "Emulating disconnect of wiimote %d.", _WiimoteNumber + 1); Host_ConnectWiimote(_WiimoteNumber, false); + } } void StateChange(EMUSTATE_CHANGE newState) diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h index 4b8f4365d3..55fc552abd 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h @@ -96,7 +96,7 @@ public: std::string devicepath; // Unique wiimote reference //ULONGLONG btaddr; // Bluetooth address HANDLE dev_handle; // HID handle - OVERLAPPED hid_overlap; // Overlap handle + OVERLAPPED hid_overlap_read, hid_overlap_write; // Overlap handle enum win_bt_stack_t stack; // Type of bluetooth stack to use #endif