diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IODummy.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IODummy.cpp index 6af169f5ee..3a017354eb 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IODummy.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IODummy.cpp @@ -29,7 +29,10 @@ WiimoteScanner::WiimoteScanner() WiimoteScanner::~WiimoteScanner() {} -std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) +void WiimoteScanner::Update() +{} + +std::vector WiimoteScanner::FindWiimotes() { return std::vector(); } diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp index e926d44ec0..62fd2e4ac5 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp @@ -60,11 +60,10 @@ WiimoteScanner::~WiimoteScanner() close(device_sock); } -// Find wiimotes. -// 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 wiimotes. -std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) +void WiimoteScanner::Update() +{} + +std::vector WiimoteScanner::FindWiimotes() { std::vector found_wiimotes; @@ -86,7 +85,7 @@ std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices); // Display discovered devices - for (int i = 0; (i < found_devices) && (found_wiimotes.size() < max_wiimotes); ++i) + for (int i = 0; i < found_devices; ++i) { ERROR_LOG(WIIMOTE, "found a device..."); diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp index 8226c784e8..c88cdebdbc 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOWin.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,8 @@ HINSTANCE bthprops_lib = NULL; static int initialized = 0; +static std::unordered_set g_connected_devices; + inline void init_lib() { if (!initialized) @@ -127,7 +130,12 @@ inline void init_lib() namespace WiimoteReal { -int PairUp(bool unpair = false); +template +void ProcessWiimotes(bool new_scan, T& callback); + +bool AttachWiimote(HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi); +void RemoveWiimote(HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi); +bool ForgetWiimote(HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi); WiimoteScanner::WiimoteScanner() { @@ -137,24 +145,47 @@ WiimoteScanner::WiimoteScanner() WiimoteScanner::~WiimoteScanner() { // TODO: what do we want here? - //PairUp(true); + ProcessWiimotes(false, RemoveWiimote); +} + +void WiimoteScanner::Update() +{ + bool forgot_some = false; + + ProcessWiimotes(false, [&](HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) + { + forgot_some |= ForgetWiimote(hRadio, btdi); + }); + + // Some hacks that allows disconnects to be detected before connections are handled + // workaround for wiimote 1 moving to slot 2 on temporary disconnect + if (forgot_some) + SLEEP(100); } // Find and connect wiimotes. // 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. -std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) +std::vector WiimoteScanner::FindWiimotes() { - PairUp(); + bool attached_some; + + ProcessWiimotes(true, [&](HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) + { + ForgetWiimote(hRadio, btdi); + attached_some |= AttachWiimote(hRadio, btdi); + }); + + // Hacks... + if (attached_some) + SLEEP(1000); GUID device_id; - HANDLE dev; HDEVINFO device_info; DWORD len; SP_DEVICE_INTERFACE_DATA device_data; PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL; - HIDD_ATTRIBUTES attr; device_data.cbSize = sizeof(device_data); @@ -165,7 +196,7 @@ std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)); std::vector wiimotes; - for (int index = 0; wiimotes.size() < max_wiimotes; ++index) + for (int index = 0; true; ++index) { free(detail_data); detail_data = NULL; @@ -184,24 +215,7 @@ std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) continue; auto const wm = new Wiimote; - - // Open new device -#if 0 - dev = CreateFile(detail_data->DevicePath, - (GENERIC_READ | GENERIC_WRITE), - (FILE_SHARE_READ | FILE_SHARE_WRITE), - NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); - if (dev == INVALID_HANDLE_VALUE) - continue; - - // Get device attributes - attr.Size = sizeof(attr); - HidD_GetAttributes(dev, &attr); - - wm->dev_handle = dev; -#endif wm->devicepath = detail_data->DevicePath; - wiimotes.push_back(wm); } @@ -236,9 +250,15 @@ bool WiimoteScanner::IsReady() const // Connect to a wiimote with a known device path. bool Wiimote::Connect() { + // This is where we disallow connecting to the same device twice + if (g_connected_devices.count(devicepath)) + return false; + dev_handle = CreateFile(devicepath.c_str(), (GENERIC_READ | GENERIC_WRITE), - /*(FILE_SHARE_READ | FILE_SHARE_WRITE)*/ 0, + // TODO: Just do FILE_SHARE_READ and remove "g_connected_devices"? + // That is what "WiiYourself" does. + (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (dev_handle == INVALID_HANDLE_VALUE) @@ -247,11 +267,12 @@ bool Wiimote::Connect() return false; } + hid_overlap = OVERLAPPED(); hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T("")); hid_overlap.Offset = 0; hid_overlap.OffsetHigh = 0; - // TODO: 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 // reside is normal priority. Needed for keeping audio reports at a decent rate /* @@ -261,15 +282,17 @@ bool Wiimote::Connect() } */ + g_connected_devices.insert(devicepath); return true; } void Wiimote::Disconnect() { + g_connected_devices.erase(devicepath); + CloseHandle(dev_handle); dev_handle = 0; - //ResetEvent(&hid_overlap); CloseHandle(hid_overlap.hEvent); } @@ -283,50 +306,73 @@ bool Wiimote::IsConnected() const // zero = error int Wiimote::IORead(unsigned char* buf) { + // used below for a warning *buf = 0; - DWORD b; - if (!ReadFile(dev_handle, buf, MAX_PAYLOAD, &b, &hid_overlap)) + DWORD bytes; + ResetEvent(hid_overlap.hEvent); + if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap)) { - // Partial read - b = GetLastError(); - if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED)) + auto const err = GetLastError(); + + if (ERROR_IO_PENDING == err) + { + auto const r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT); + if (WAIT_TIMEOUT == r) + { + // Timeout - cancel and continue + if (*buf) + WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).", + WIIMOTE_DEFAULT_TIMEOUT); + + CancelIo(dev_handle); + bytes = -1; + } + else if (WAIT_FAILED == r) + { + WARN_LOG(WIIMOTE, "A wait error occured on reading from wiimote %i.", index + 1); + bytes = 0; + } + else if (WAIT_OBJECT_0 == r) + { + if (!GetOverlappedResult(dev_handle, &hid_overlap, &bytes, TRUE)) + { + WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1); + bytes = 0; + } + } + else + { + bytes = 0; + } + } + else if (ERROR_HANDLE_EOF == err) { // Remote disconnect - return 0; + bytes = 0; } - - auto const r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT); - if (r == WAIT_TIMEOUT) + else if (ERROR_DEVICE_NOT_CONNECTED == err) { - // Timeout - cancel and continue - if (*buf) - WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).", - WIIMOTE_DEFAULT_TIMEOUT); - - CancelIo(dev_handle); - ResetEvent(hid_overlap.hEvent); - return -1; + // Remote disconnect + bytes = 0; } - else if (r == WAIT_FAILED) + else { - WARN_LOG(WIIMOTE, "A wait error occured on reading from wiimote %i.", index + 1); - return -1; - } - - if (!GetOverlappedResult(dev_handle, &hid_overlap, &b, 0)) - { - return -1; + bytes = 0; } } - // This needs to be done even if ReadFile fails, essential during init - // Move the data over one, so we can add back in data report indicator byte (here, 0xa1) - memmove(buf + 1, buf, MAX_PAYLOAD - 1); - buf[0] = 0xa1; + if (bytes > 0) + { + // Move the data over one, so we can add back in data report indicator byte (here, 0xa1) + memmove(buf + 1, buf, MAX_PAYLOAD - 1); + buf[0] = 0xa1; - ResetEvent(hid_overlap.hEvent); - return MAX_PAYLOAD; // XXX + // TODO: is this really needed? + bytes = MAX_PAYLOAD; + } + + return bytes; } int Wiimote::IOWrite(const u8* buf, int len) @@ -392,14 +438,12 @@ int Wiimote::IOWrite(const u8* buf, int len) return 0; } -// WiiMote Pair-Up, function will return amount of either new paired or unpaired devices -// negative number on failure -int PairUp(bool unpair) +// invokes callback for each found wiimote bluetooth device +template +void ProcessWiimotes(bool new_scan, T& callback) { // match strings like "Nintendo RVL-WBC-01", "Nintendo RVL-CNT-01", "Nintendo RVL-CNT-01-TR" - const std::wregex wiimote_device_name(L"Nintendo RVL-\\w{3}-\\d{2}(-\\w{2})?"); - - int nPaired = 0; + const std::wregex wiimote_device_name(L"Nintendo RVL-.*"); BLUETOOTH_DEVICE_SEARCH_PARAMS srch; srch.dwSize = sizeof(srch); @@ -409,7 +453,7 @@ int PairUp(bool unpair) // fConnected BT Devices srch.fReturnConnected = true; srch.fReturnUnknown = true; - srch.fIssueInquiry = true; + srch.fIssueInquiry = new_scan; // multiple of 1.28 seconds srch.cTimeoutMultiplier = 1; @@ -418,14 +462,10 @@ int PairUp(bool unpair) HANDLE hRadio; - // TODO: save radio(s) in the WiimoteScanner constructor + // TODO: save radio(s) in the WiimoteScanner constructor? // Enumerate BT radios HBLUETOOTH_RADIO_FIND hFindRadio = Bth_BluetoothFindFirstRadio(&radioParam, &hRadio); - - if (NULL == hFindRadio) - return -1; - while (hFindRadio) { BLUETOOTH_RADIO_INFO radioInfo; @@ -449,40 +489,7 @@ int PairUp(bool unpair) if (std::regex_match(btdi.szName, wiimote_device_name)) { - if (unpair) - { - if (SUCCEEDED(Bth_BluetoothRemoveDevice(&btdi.Address))) - { - NOTICE_LOG(WIIMOTE, - "Pair-Up: Automatically removed BT Device on shutdown: %08x", - GetLastError()); - ++nPaired; - } - } - else - { - if (false == btdi.fConnected) - { - // TODO: improve the read of the BT driver, esp. when batteries - // of the wiimote are removed while being fConnected - if (btdi.fRemembered) - { - // Make Windows forget old expired pairing. We can pretty - // much ignore the return value here. It either worked - // (ERROR_SUCCESS), or the device did not exist - // (ERROR_NOT_FOUND). In both cases, there is nothing left. - Bth_BluetoothRemoveDevice(&btdi.Address); - } - - // Activate service - const DWORD hr = Bth_BluetoothSetServiceState(hRadio, &btdi, - &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE); - if (SUCCEEDED(hr)) - ++nPaired; - else - ERROR_LOG(WIIMOTE, "Pair-Up: BluetoothSetServiceState() returned %08x", hr); - } - } + callback(hRadio, btdi); } if (false == Bth_BluetoothFindNextDevice(hFindDevice, &btdi)) @@ -498,8 +505,53 @@ int PairUp(bool unpair) hFindRadio = NULL; } } +} - return nPaired; +void RemoveWiimote(HANDLE, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) +{ + //if (btdi.fConnected) + { + if (SUCCEEDED(Bth_BluetoothRemoveDevice(&btdi.Address))) + { + NOTICE_LOG(WIIMOTE, "Removed BT Device", GetLastError()); + } + } +} + +bool AttachWiimote(HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) +{ + if (!btdi.fConnected && !btdi.fRemembered) + { + NOTICE_LOG(WIIMOTE, "Found wiimote. Enabling HID service."); + + // Activate service + const DWORD hr = Bth_BluetoothSetServiceState(hRadio, &btdi, + &HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE); + + if (FAILED(hr)) + ERROR_LOG(WIIMOTE, "Pair-Up: BluetoothSetServiceState() returned %08x", hr); + else + return true; + } + + return false; +} + +// Removes remembered non-connected devices +bool ForgetWiimote(HANDLE, BLUETOOTH_DEVICE_INFO_STRUCT& btdi) +{ + if (!btdi.fConnected && btdi.fRemembered) + { + // We don't want "remembered" devices. + // SetServiceState seems to just fail with them. + // Make Windows forget about them. + NOTICE_LOG(WIIMOTE, "Removing remembered wiimote."); + Bth_BluetoothRemoveDevice(&btdi.Address); + + return true; + } + + return false; } }; diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm index f3c90d810d..9ed78800cc 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm @@ -111,7 +111,10 @@ WiimoteScanner::WiimoteScanner() WiimoteScanner::~WiimoteScanner() {} -std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) +void WiimoteScanner::Update() +{} + +std::vector WiimoteScanner::FindWiimotes() { // TODO: find the device in the constructor and save it for later @@ -130,7 +133,7 @@ std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) } sbt = [[SearchBT alloc] init]; - sbt->maxDevices = max_wiimotes; + sbt->maxDevices = 32; bti = [[IOBluetoothDeviceInquiry alloc] init]; [bti setDelegate: sbt]; [bti setInquiryLength: 2]; @@ -157,9 +160,6 @@ std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) Wiimote *wm = new Wiimote(); wm->btd = dev; wiimotes.push_back(wm); - - if(wiimotes.size() >= max_wiimotes) - break; } [bth release]; diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index 7ae1a9a961..6a5d91fa00 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -35,7 +35,7 @@ namespace WiimoteReal { void HandleFoundWiimotes(const std::vector&); -void HandleWiimoteConnect(Wiimote*); +void TryToConnectWiimote(Wiimote*); void HandleWiimoteDisconnect(int index); bool g_real_wiimotes_initialized = false; @@ -171,7 +171,10 @@ bool Wiimote::Read() rpt.second = IORead(rpt.first); if (0 == rpt.second) + { + WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting wiimote %d.", index + 1); Disconnect(); + } if (rpt.second > 0 && m_channel > 0) { @@ -192,12 +195,12 @@ bool Wiimote::Write() bool const is_speaker_data = rpt.first[1] == WM_WRITE_SPEAKER_DATA; - if (!is_speaker_data || last_audio_report.GetTimeDifference() > 5) + if (!is_speaker_data || m_last_audio_report.GetTimeDifference() > 5) { IOWrite(rpt.first, rpt.second); if (is_speaker_data) - last_audio_report.Update(); + m_last_audio_report.Update(); delete[] rpt.first; m_write_reports.Pop(); @@ -242,27 +245,24 @@ void Wiimote::Update() delete[] rpt.first; } -// Rumble briefly -void Wiimote::RumbleBriefly() +bool Wiimote::Prepare(int _index) { - unsigned char buffer = 0x01; - DEBUG_LOG(WIIMOTE, "Starting rumble..."); - QueueReport(WM_CMD_RUMBLE, &buffer, sizeof(buffer)); + index = _index; - SLEEP(200); + // Set the active LEDs. + u8 const led_report[] = {HID_TYPE_SET_REPORT, WM_CMD_LED, WIIMOTE_LED_1 << index}; - DEBUG_LOG(WIIMOTE, "Stopping rumble..."); - buffer = 0x00; - QueueReport(WM_CMD_RUMBLE, &buffer, sizeof(buffer)); -} + // Rumble briefly + u8 rumble_report[] = {HID_TYPE_SET_REPORT, WM_CMD_RUMBLE, 1}; -// Set the active LEDs. -// leds is a bitwise OR of WIIMOTE_LED_1 through WIIMOTE_LED_4. -void Wiimote::SetLEDs(int new_leds) -{ - // Remove the lower 4 bits because they control rumble - u8 const buffer = (new_leds & 0xF0); - QueueReport(WM_CMD_LED, &buffer, sizeof(buffer)); + // don't really care what is read, just that reading works + u8 input_buf[MAX_PAYLOAD]; + + // TODO: request status and check for sane response? + + return (IOWrite(led_report, sizeof(led_report)) + && IOWrite(rumble_report, sizeof(rumble_report)) + && (rumble_report[2] = 0, SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report)))); } void Wiimote::EmuStart() @@ -290,48 +290,66 @@ unsigned int CalculateWantedWiimotes() return wanted_wiimotes; } -void WiimoteScanner::WantWiimotes(size_t count) +void WiimoteScanner::WantWiimotes(bool do_want) { - want_wiimotes = count; + m_want_wiimotes = do_want; } void WiimoteScanner::StartScanning() { - run_thread = true; + m_run_thread = true; if (IsReady()) { - scan_thread = std::thread(std::mem_fun(&WiimoteScanner::ThreadFunc), this); + m_scan_thread = std::thread(std::mem_fun(&WiimoteScanner::ThreadFunc), this); } } void WiimoteScanner::StopScanning() { - run_thread = false; - if (scan_thread.joinable()) + m_run_thread = false; + if (m_scan_thread.joinable()) { - scan_thread.join(); + m_scan_thread.join(); } } + +void CheckForDisconnectedWiimotes() +{ + std::lock_guard lk(g_refresh_lock); + + for (unsigned int i = 0; i != MAX_WIIMOTES; ++i) + if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected()) + HandleWiimoteDisconnect(i); +} + void WiimoteScanner::ThreadFunc() { Common::SetCurrentThreadName("Wiimote Scanning Thread"); NOTICE_LOG(WIIMOTE, "Wiimote scanning has started"); - while (run_thread) + while (m_run_thread) { - auto const found_wiimotes = FindWiimotes(want_wiimotes); - HandleFoundWiimotes(found_wiimotes); -#if 1 + std::vector found_wiimotes; + + //NOTICE_LOG(WIIMOTE, "in loop"); + + if (m_want_wiimotes) + found_wiimotes = FindWiimotes(); + else { - // TODO: this code here is ugly - std::lock_guard lk(g_refresh_lock); - for (unsigned int i = 0; i != MAX_WIIMOTES; ++i) - if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected()) - HandleWiimoteDisconnect(i); + // Does stuff needed to detect disconnects on Windows + Update(); } -#endif + + //NOTICE_LOG(WIIMOTE, "after update"); + + // TODO: this is a fairly lame place for this + CheckForDisconnectedWiimotes(); + + HandleFoundWiimotes(found_wiimotes); + //std::this_thread::yield(); Common::SleepCurrentThread(500); } @@ -396,8 +414,7 @@ void Initialize() if (g_real_wiimotes_initialized) return; - auto const wanted_wiimotes = CalculateWantedWiimotes(); - g_wiimote_scanner.WantWiimotes(wanted_wiimotes); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); g_wiimote_scanner.StartScanning(); @@ -431,26 +448,23 @@ void ChangeWiimoteSource(unsigned int index, int source) if (!(WIIMOTE_SRC_REAL & g_wiimote_sources[index])) HandleWiimoteDisconnect(index); - auto const wanted_wiimotes = CalculateWantedWiimotes(); - g_wiimote_scanner.WantWiimotes(wanted_wiimotes); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); } -void HandleWiimoteConnect(Wiimote* wm) +void TryToConnectWiimote(Wiimote* wm) { std::lock_guard lk(g_refresh_lock); for (unsigned int i = 0; i != MAX_WIIMOTES; ++i) { - if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) + if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] + && !g_wiimotes[i] + && wm->Connect() + && wm->Prepare(i)) { g_wiimotes[i] = wm; - wm->index = i; wm->StartThread(); - - wm->DisableDataReporting(); - wm->SetLEDs(WIIMOTE_LED_1 << i); - wm->RumbleBriefly(); Host_ConnectWiimote(i, true); @@ -463,14 +477,12 @@ void HandleWiimoteConnect(Wiimote* wm) delete wm; - auto const want_wiimotes = CalculateWantedWiimotes(); - g_wiimote_scanner.WantWiimotes(want_wiimotes); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); } void HandleWiimoteDisconnect(int index) { - // locked above - //std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); Host_ConnectWiimote(index, false); @@ -482,19 +494,12 @@ void HandleWiimoteDisconnect(int index) NOTICE_LOG(WIIMOTE, "Disconnected wiimote %i.", index + 1); } - auto const want_wiimotes = CalculateWantedWiimotes(); - g_wiimote_scanner.WantWiimotes(want_wiimotes); + g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes()); } void HandleFoundWiimotes(const std::vector& wiimotes) { - std::for_each(wiimotes.begin(), wiimotes.end(), [](Wiimote* const wm) - { - if (wm->Connect()) - HandleWiimoteConnect(wm); - else - delete wm; - }); + std::for_each(wiimotes.begin(), wiimotes.end(), TryToConnectWiimote); } // This is called from the GUI thread @@ -504,14 +509,13 @@ void Refresh() { std::lock_guard lk(g_refresh_lock); + + CheckForDisconnectedWiimotes(); - auto wanted_wiimotes = CalculateWantedWiimotes(); - auto const found_wiimotes = g_wiimote_scanner.FindWiimotes(wanted_wiimotes); - - HandleFoundWiimotes(found_wiimotes); - - wanted_wiimotes = CalculateWantedWiimotes(); - g_wiimote_scanner.WantWiimotes(wanted_wiimotes); + if (0 != CalculateWantedWiimotes()) + { + HandleFoundWiimotes(g_wiimote_scanner.FindWiimotes()); + } } g_wiimote_scanner.StartScanning(); diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h index 139d59ce99..4b8f4365d3 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h @@ -63,14 +63,16 @@ public: void EmuStop(); // connecting and disconnecting from physical devices + // (using address inserted by FindWiimotes) + + // FYI, Connect/Disconnect are not thread safe even between unique objects (on windows) bool Connect(); void Disconnect(); // TODO: change to something like IsRelevant bool IsConnected() const; - void SetLEDs(int leds); - void RumbleBriefly(); + bool Prepare(int index); void DisableDataReporting(); @@ -116,7 +118,7 @@ private: Common::FifoQueue m_read_reports; Common::FifoQueue m_write_reports; - Common::Timer last_audio_report; + Common::Timer m_last_audio_report; }; class WiimoteScanner @@ -127,22 +129,23 @@ public: bool IsReady() const; - void WantWiimotes(size_t count); + void WantWiimotes(bool do_want); void StartScanning(); void StopScanning(); - std::vector FindWiimotes(size_t max_wiimotes); + std::vector FindWiimotes(); + + // function called when not looking for more wiimotes + void Update(); private: void ThreadFunc(); - std::thread scan_thread; + std::thread m_scan_thread; - volatile bool run_thread; - - // TODO: this should probably be atomic - volatile size_t want_wiimotes; + volatile bool m_run_thread; + volatile bool m_want_wiimotes; #if defined(_WIN32) diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h index 75a6d3e6a3..15bbc2917f 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h @@ -66,8 +66,9 @@ // End Wiimote internal codes -#define MAX_PAYLOAD 32 -#define WIIMOTE_DEFAULT_TIMEOUT 30 +// It's 23. NOT 32! +#define MAX_PAYLOAD 23 +#define WIIMOTE_DEFAULT_TIMEOUT 1000 #ifdef _WIN32 // Available bluetooth stacks for Windows.