diff --git a/Source/Core/Core/Src/HW/Wiimote.h b/Source/Core/Core/Src/HW/Wiimote.h index 5e0ab8d05e..d514cf9909 100644 --- a/Source/Core/Core/Src/HW/Wiimote.h +++ b/Source/Core/Core/Src/HW/Wiimote.h @@ -38,7 +38,7 @@ void Update(int _number); namespace WiimoteReal { -unsigned int Initialize(); +void Initialize(); void Shutdown(); void Refresh(); diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp index 5c34fff9ac..cfb81bb768 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp @@ -248,7 +248,7 @@ void Wiimote::RequestStatus(const wm_request_status* const rs) { using namespace WiimoteReal; - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); if (g_wiimotes[m_index]) { diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp index b7652e973a..30fad4b458 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp @@ -685,7 +685,7 @@ void Wiimote::Update() { using namespace WiimoteReal; - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); if (g_wiimotes[m_index]) { Report rpt = g_wiimotes[m_index]->ProcessReadQueue(); diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp b/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp index ec838d9313..82630aaebb 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/IONix.cpp @@ -15,16 +15,6 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include -#include - -#include -#include -#include -#include -#include -#include - #include #include #include @@ -32,114 +22,117 @@ #include "Common.h" #include "WiimoteReal.h" -#include "Host.h" namespace WiimoteReal { +WiimoteScanner::WiimoteScanner() + : run_thread() + , want_wiimotes() + , device_id(-1) + , device_sock(-1) +{ + // Get the id of the first bluetooth device. + device_id = hci_get_route(NULL); + if (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) + { + ERROR_LOG(WIIMOTE, "Unable to open bluetooth."); + return; + } +} + +bool WiimoteScanner::IsReady() const +{ + return device_sock > 0; +} + +WiimoteScanner::~WiimoteScanner() +{ + if (IsReady()) + 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. -int FindWiimotes(Wiimote** wm, int max_wiimotes) +std::vector WiimoteScanner::FindWiimotes(size_t max_wiimotes) { - int device_id; - int device_sock; - int found_devices; - int found_wiimotes = 0; - int i; + std::vector found_wiimotes; - // Count the number of already found wiimotes - for (i = 0; i < MAX_WIIMOTES; ++i) - { - if (wm[i]) - found_wiimotes++; - } + // supposedly 1.28 seconds + int const wait_len = 1; - // Get the id of the first bluetooth device. - if ((device_id = hci_get_route(NULL)) < 0) + int const max_infos = 255; + inquiry_info scan_infos[max_infos] = {}; + auto* scan_infos_ptr = scan_infos; + + // Scan for bluetooth devices + int const found_devices = hci_inquiry(device_id, wait_len, max_infos, NULL, &scan_infos_ptr, IREQ_CACHE_FLUSH); + if (found_devices < 0) { - NOTICE_LOG(WIIMOTE, "Bluetooth not found."); + ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices."); return found_wiimotes; } - // Create a socket to the device - if ((device_sock = hci_open_dev(device_id)) < 0) - { - ERROR_LOG(WIIMOTE, "Unable to open bluetooth."); - return found_wiimotes; - } + DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices); - int try_num = 0; - while ((try_num < 5) && (found_wiimotes < max_wiimotes)) + // Display discovered devices + for (int i = 0; (i < found_devices) && (found_wiimotes.size() < max_wiimotes); ++i) { - inquiry_info scan_info_arr[128]; - inquiry_info* scan_info = scan_info_arr; - memset(&scan_info_arr, 0, sizeof(scan_info_arr)); - - // Scan for bluetooth devices for approximately one second - found_devices = hci_inquiry(device_id, 1, 128, NULL, &scan_info, IREQ_CACHE_FLUSH); - if (found_devices < 0) + ERROR_LOG(WIIMOTE, "found a device..."); + + // 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, 0) < 0) { - ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices."); - return found_wiimotes; + ERROR_LOG(WIIMOTE, "name request failed"); + continue; } - DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices); - - // Display discovered devices - for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i) + ERROR_LOG(WIIMOTE, "device name %s", name); + if (IsValidBluetoothName(name)) { - char name[1000]; - memset(name, 0, sizeof(name)); - ERROR_LOG(WIIMOTE, "found a device..."); - if (hci_read_remote_name(device_sock, &scan_info[i].bdaddr, sizeof(name), name, 0) < 0) { - ERROR_LOG(WIIMOTE, "name request failed"); - continue; - } - ERROR_LOG(WIIMOTE, "device name %s", name); - if (IsValidBluetoothName(name)) + bool new_wiimote = true; + + // TODO: do this + + // Determine if this wiimote has already been found. + //for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j) + //{ + // if (wm[j] && bacmp(&scan_infos[i].bdaddr,&wm[j]->bdaddr) == 0) + // new_wiimote = false; + //} + + if (new_wiimote) { - bool new_wiimote = true; - // Determine if this wiimote has already been found. - for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j) - { - if (wm[j] && bacmp(&scan_info[i].bdaddr,&wm[j]->bdaddr) == 0) - new_wiimote = false; - } + // Found a new device + char bdaddr_str[18] = {}; + ba2str(&scan_infos[i].bdaddr, bdaddr_str); - if (new_wiimote) - { - // Find an unused slot - unsigned int k = 0; - for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k); - wm[k] = new Wiimote(k); - - // Found a new device - char bdaddr_str[18]; - ba2str(&scan_info[i].bdaddr, bdaddr_str); - - NOTICE_LOG(WIIMOTE, "Found wiimote %i, (%s).", - wm[k]->index + 1, bdaddr_str); - - wm[k]->bdaddr = scan_info[i].bdaddr; - ++found_wiimotes; - } + auto* const wm = new Wiimote; + wm->bdaddr = scan_infos[i].bdaddr; + found_wiimotes.push_back(wm); + + NOTICE_LOG(WIIMOTE, "Found wiimote (%s).", bdaddr_str); } } - try_num++; } - close(device_sock); return found_wiimotes; } // Connect to a wiimote with a known address. -bool Wiimote::Connect() +bool Wiimote::Open() { - if (IsConnected()) - return false; - sockaddr_l2 addr; addr.l2_family = AF_BLUETOOTH; addr.l2_bdaddr = bdaddr; @@ -148,7 +141,7 @@ bool Wiimote::Connect() // Output channel addr.l2_psm = htobs(WM_OUTPUT_CHANNEL); if ((cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(cmd_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) + connect(cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0) { DEBUG_LOG(WIIMOTE, "Unable to open output socket to wiimote."); close(cmd_sock); @@ -159,7 +152,7 @@ bool Wiimote::Connect() // Input channel addr.l2_psm = htobs(WM_INPUT_CHANNEL); if ((int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 || - connect(int_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) + connect(int_sock, (sockaddr*)&addr, sizeof(addr)) < 0) { DEBUG_LOG(WIIMOTE, "Unable to open input socket from wiimote."); close(int_sock); @@ -168,57 +161,37 @@ bool Wiimote::Connect() return false; } - NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", index + 1); - - m_connected = true; - - // Do the handshake - Handshake(); - - // Set LEDs - SetLEDs(WIIMOTE_LED_1 << index); - - m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this); - return true; } -// Disconnect a wiimote. -void Wiimote::RealDisconnect() +void Wiimote::StartThread() { - if (!IsConnected()) - return; - - NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i.", index + 1); - - m_connected = false; + m_run_thread = true; + m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this); +} +void Wiimote::StopThread() +{ + m_run_thread = false; if (m_wiimote_thread.joinable()) m_wiimote_thread.join(); - - Close(); } void Wiimote::Close() { - if (IsOpen()) - { - Host_ConnectWiimote(index, false); + close(cmd_sock); + close(int_sock); - close(cmd_sock); - close(int_sock); - - cmd_sock = -1; - int_sock = -1; - } + cmd_sock = -1; + int_sock = -1; } bool Wiimote::IsOpen() const { - return IsConnected() && cmd_sock != -1 && int_sock != -1; + return cmd_sock != -1;// && int_sock != -1; } -int Wiimote::IORead(unsigned char *buf) +int Wiimote::IORead(u8* buf) { // Block select for 1/2000th of a second timeval tv; @@ -232,11 +205,11 @@ int Wiimote::IORead(unsigned char *buf) if (select(int_sock + 1, &fds, NULL, NULL, &tv) == -1) { ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1); - return 0; + return -1; } if (!FD_ISSET(int_sock, &fds)) - return 0; + return -1; // Read the pending message into the buffer int r = read(int_sock, buf, MAX_PAYLOAD); @@ -250,21 +223,15 @@ int Wiimote::IORead(unsigned char *buf) // This can happen if the bluetooth dongle is disconnected ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. " "Wiimote %i will be disconnected.", index + 1); - Close(); } - return 0; - } - else if (!r) - { - // Disconnect - Close(); + r = 0; } return r; } -int Wiimote::IOWrite(unsigned char* buf, int len) +int Wiimote::IOWrite(u8 const* buf, int len) { return write(int_sock, buf, len); } diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index 2381793f30..2735c1a312 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -23,6 +23,7 @@ #include "IniFile.h" #include "StringUtil.h" #include "Timer.h" +#include "Host.h" #include "WiimoteReal.h" @@ -33,15 +34,20 @@ unsigned int g_wiimote_sources[MAX_WIIMOTES]; namespace WiimoteReal { +void HandleFoundWiimotes(const std::vector&); +void HandleWiimoteConnect(Wiimote*); +void HandleWiimoteDisconnect(int index); + bool g_real_wiimotes_initialized = false; -unsigned int g_wiimotes_found = 0; -std::mutex g_refresh_lock; +std::recursive_mutex g_refresh_lock; -Wiimote *g_wiimotes[MAX_WIIMOTES]; +Wiimote* g_wiimotes[MAX_WIIMOTES]; -Wiimote::Wiimote(const unsigned int _index) - : index(_index) +WiimoteScanner g_wiimote_scanner; + +Wiimote::Wiimote() + : index() #ifdef __APPLE__ , inputlen(0) #elif defined(__linux__) && HAVE_BLUEZ @@ -49,8 +55,8 @@ Wiimote::Wiimote(const unsigned int _index) #elif defined(_WIN32) , dev_handle(0), stack(MSBT_STACK_UNKNOWN) #endif - , leds(0), m_last_data_report(Report((u8 *)NULL, 0)) - , m_channel(0), m_connected(false) + , m_last_data_report(Report((u8 *)NULL, 0)) + , m_channel(0), m_run_thread(false) { #if defined(__linux__) && HAVE_BLUEZ bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}}; @@ -61,8 +67,11 @@ Wiimote::Wiimote(const unsigned int _index) Wiimote::~Wiimote() { - RealDisconnect(); + StopThread(); + if (IsOpen()) + Close(); + ClearReadQueue(); // clear write queue @@ -111,7 +120,7 @@ void Wiimote::ControlChannel(const u16 channel, const void* const data, const u3 { // Check for custom communication if (99 == channel) - Disconnect(); + EmuStop(); else { InterruptChannel(channel, data, size); @@ -168,6 +177,9 @@ bool Wiimote::Read() rpt.first = new unsigned char[MAX_PAYLOAD]; rpt.second = IORead(rpt.first); + if (0 == rpt.second) + Close(); + if (rpt.second > 0 && m_channel > 0) { // Add it to queue m_read_reports.Push(rpt); @@ -234,24 +246,18 @@ void Wiimote::Update() delete[] rpt.first; } -void Wiimote::Disconnect() +void Wiimote::EmuStop() { m_channel = 0; DisableDataReporting(); -} -bool Wiimote::IsConnected() const -{ - return m_connected; + NOTICE_LOG(WIIMOTE, "Stopping wiimote data reporting"); } // Rumble briefly void Wiimote::Rumble() { - if (!IsConnected()) - return; - unsigned char buffer = 0x01; DEBUG_LOG(WIIMOTE, "Starting rumble..."); SendRequest(WM_CMD_RUMBLE, &buffer, 1); @@ -264,37 +270,29 @@ void Wiimote::Rumble() } // Set the active LEDs. -// leds is a bitwise or of WIIMOTE_LED_1 through WIIMOTE_LED_4. +// leds is a bitwise OR of WIIMOTE_LED_1 through WIIMOTE_LED_4. void Wiimote::SetLEDs(int new_leds) { - unsigned char buffer; - - if (!IsConnected()) - return; - // Remove the lower 4 bits because they control rumble - buffer = leds = (new_leds & 0xF0); - + u8 const buffer = (new_leds & 0xF0); SendRequest(WM_CMD_LED, &buffer, 1); } -// Send a handshake -bool Wiimote::Handshake() +bool Wiimote::EmuStart() { + // Send a handshake + // Set buffer[0] to 0x04 for continuous reporting - unsigned char buffer[2] = {0x04, 0x30}; + u8 const buffer[2] = {0x04, 0x30}; - if (!IsConnected()) - return 0; - - DEBUG_LOG(WIIMOTE, "Sending handshake to wiimote"); + NOTICE_LOG(WIIMOTE, "Sending handshake to wiimote"); return SendRequest(WM_CMD_REPORT_TYPE, buffer, 2); } // Send a packet to the wiimote. // report_type should be one of WIIMOTE_CMD_LED, WIIMOTE_CMD_RUMBLE, etc. -bool Wiimote::SendRequest(unsigned char report_type, unsigned char* data, int length) +bool Wiimote::SendRequest(u8 report_type, u8 const* data, int length) { unsigned char buffer[32] = {WM_SET_REPORT | WM_BT_OUTPUT, report_type}; @@ -303,59 +301,99 @@ bool Wiimote::SendRequest(unsigned char report_type, unsigned char* data, int le return (IOWrite(buffer, length + 2) != 0); } +unsigned int CalculateWantedWiimotes() +{ + // Figure out how many real wiimotes are required + unsigned int wanted_wiimotes = 0; + for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) + if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i]) + ++wanted_wiimotes; + + return wanted_wiimotes; +} + +void WiimoteScanner::WantWiimotes(size_t count) +{ + want_wiimotes = count; +} + +void WiimoteScanner::StartScanning() +{ + run_thread = true; + scan_thread = std::thread(std::mem_fun(&WiimoteScanner::ThreadFunc), this); +} + +void WiimoteScanner::StopScanning() +{ + run_thread = false; + if (scan_thread.joinable()) + { + scan_thread.join(); + NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped"); + } +} + +void WiimoteScanner::ThreadFunc() +{ + Common::SetCurrentThreadName("Wiimote Scanning Thread"); + + NOTICE_LOG(WIIMOTE, "Wiimote scanning has started"); + + while (run_thread) + { + auto const found_wiimotes = FindWiimotes(want_wiimotes); + HandleFoundWiimotes(found_wiimotes); +#if 1 + { + // 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]->IsOpen()) + HandleWiimoteDisconnect(i); + } +#endif + //std::this_thread::yield(); + Common::SleepCurrentThread(500); + } +} + void Wiimote::ThreadFunc() { - char thname[] = "Wiimote # Thread"; - thname[8] = (char)('1' + index); - Common::SetCurrentThreadName(thname); + Common::SetCurrentThreadName("Wiimote Device Thread"); // rumble briefly Rumble(); // main loop - while (IsOpen()) + while (m_run_thread && IsOpen()) { #ifdef __APPLE__ while (Write()) {} Common::SleepCurrentThread(1); #else - bool read = false; - while (Write() || (read = true, IsOpen() && Read())) + // TODO: this is all a mess + while (m_run_thread && IsOpen()) { - if (m_audio_reports.Size() && !read) - Read(); - Common::SleepCurrentThread(m_audio_reports.Size() ? 5 : 2); - read = false; + bool const did_write = Write(); + + if (did_write) + break; + else + if (!Read()) + break; + + // TODO: what is this doing? + //if (m_audio_reports.Size() && did_write) + // Read(); + + // TODO: make work well + //Common::SleepCurrentThread(m_audio_reports.Size() ? 5 : 2); + Common::SleepCurrentThread(2); } #endif } } -#ifndef _WIN32 -// Connect all discovered wiimotes -// Return the number of wiimotes that successfully connected. -static int ConnectWiimotes(Wiimote** wm) -{ - int connected = 0; - - for (int i = 0; i < MAX_WIIMOTES; ++i) - { - if (!wm[i] || wm[i]->IsConnected()) - continue; - - if (wm[i]->Connect()) - ++connected; - else - { - delete wm[i]; - wm[i] = NULL; - } - } - - return connected; -} -#endif - void LoadSettings() { std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini"; @@ -373,71 +411,124 @@ void LoadSettings() } } -unsigned int Initialize() +void Initialize() { - // Return if already initialized + NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize"); + + std::lock_guard lk(g_refresh_lock); + if (g_real_wiimotes_initialized) - return g_wiimotes_found; + return; - memset(g_wiimotes, 0, sizeof(g_wiimotes)); + auto const wanted_wiimotes = CalculateWantedWiimotes(); + g_wiimote_scanner.WantWiimotes(wanted_wiimotes); - // Only call FindWiimotes with the number of slots configured for real wiimotes - unsigned int wanted_wiimotes = 0; - for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]) - ++wanted_wiimotes; + //if (wanted_wiimotes > 0) + g_wiimote_scanner.StartScanning(); - // Don't bother initializing if we don't want any real wiimotes - if (0 == wanted_wiimotes) - { - g_wiimotes_found = 0; - return 0; - } - - // Initialized g_real_wiimotes_initialized = true; - - g_wiimotes_found = FindWiimotes(g_wiimotes, wanted_wiimotes); - - DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted", - g_wiimotes_found, wanted_wiimotes); - -#ifndef _WIN32 - atexit(WiimoteReal::Shutdown); - g_wiimotes_found = ConnectWiimotes(g_wiimotes); -#endif - - DEBUG_LOG(WIIMOTE, "Connected to %i Real Wiimotes", g_wiimotes_found); - - return g_wiimotes_found; } void Shutdown(void) { - if (false == g_real_wiimotes_initialized) + NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown"); + + g_wiimote_scanner.StopScanning(); + + std::lock_guard lk(g_refresh_lock); + + if (!g_real_wiimotes_initialized) return; - // Uninitialized g_real_wiimotes_initialized = false; - // Delete wiimotes for (unsigned int i = 0; i < MAX_WIIMOTES; ++i) - if (g_wiimotes[i]) + HandleWiimoteDisconnect(i); +} + +void ChangeWiimoteSource(unsigned int index, int source) +{ + std::lock_guard lk(g_refresh_lock); + + g_wiimote_sources[index] = source; + + // source is emulated, kill any real connection + if (!(WIIMOTE_SRC_REAL & g_wiimote_sources[index])) + HandleWiimoteDisconnect(index); + + auto const wanted_wiimotes = CalculateWantedWiimotes(); + g_wiimote_scanner.WantWiimotes(wanted_wiimotes); +} + +void HandleWiimoteConnect(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]) { - delete g_wiimotes[i]; - g_wiimotes[i] = NULL; + g_wiimotes[i] = wm; + + wm->index = i; + wm->StartThread(); + wm->SetLEDs(WIIMOTE_LED_1 << i); + + Host_ConnectWiimote(i, true); + + NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1); + + wm = NULL; + break; } + } + + delete wm; + + auto const want_wiimotes = CalculateWantedWiimotes(); + g_wiimote_scanner.WantWiimotes(want_wiimotes); +} + +void HandleWiimoteDisconnect(int index) +{ + // locked above + //std::lock_guard lk(g_refresh_lock); + + Host_ConnectWiimote(index, false); + + if (g_wiimotes[index]) + { + delete g_wiimotes[index]; + g_wiimotes[index] = NULL; + + NOTICE_LOG(WIIMOTE, "Disconnected wiimote %i.", index + 1); + } + + auto const want_wiimotes = CalculateWantedWiimotes(); + g_wiimote_scanner.WantWiimotes(want_wiimotes); +} + +void HandleFoundWiimotes(const std::vector& wiimotes) +{ + std::for_each(wiimotes.begin(), wiimotes.end(), [](Wiimote* const wm) + { + if (wm->Open()) + HandleWiimoteConnect(wm); + else + delete wm; + }); } // This is called from the GUI thread void Refresh() { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); #ifdef _WIN32 Shutdown(); Initialize(); #else +/* // Make sure real wiimotes have been initialized if (!g_real_wiimotes_initialized) { @@ -477,12 +568,13 @@ void Refresh() g_wiimotes_found = num_wiimotes; } +*/ #endif } void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size) { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); if (g_wiimotes[_WiimoteNumber]) g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size); @@ -490,7 +582,7 @@ void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u3 void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size) { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); if (g_wiimotes[_WiimoteNumber]) g_wiimotes[_WiimoteNumber]->ControlChannel(_channelID, _pData, _Size); @@ -500,7 +592,7 @@ void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 // Read the Wiimote once void Update(int _WiimoteNumber) { - std::lock_guard lk(g_refresh_lock); + std::lock_guard lk(g_refresh_lock); if (g_wiimotes[_WiimoteNumber]) g_wiimotes[_WiimoteNumber]->Update(); @@ -508,7 +600,7 @@ void Update(int _WiimoteNumber) void StateChange(EMUSTATE_CHANGE newState) { - //std::lock_guard lk(g_refresh_lock); + //std::lock_guard lk(g_refresh_lock); // TODO: disable/enable auto reporting, maybe } diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h index 9fdb305a56..5f8206bf14 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h @@ -20,6 +20,7 @@ #define WIIMOTE_REAL_H #include +#include #include "WiimoteRealBase.h" #include "ChunkFile.h" @@ -41,7 +42,7 @@ class Wiimote : NonCopyable { friend class WiimoteEmu::Wiimote; public: - Wiimote(const unsigned int _index); + Wiimote(); ~Wiimote(); void ControlChannel(const u16 channel, const void* const data, const u32 size); @@ -52,16 +53,28 @@ public: bool Read(); bool Write(); - bool Connect(); - bool IsConnected() const; + + void StartThread(); + void StopThread(); + + // "handshake" / stop packets + bool EmuStart(); + void EmuStop(); + + // connecting and disconnecting from physical devices + bool Open(); + void Close(); + + // TODO: change to something like IsRelevant bool IsOpen() const; - void Disconnect(); + + void SetLEDs(int leds); + void DisableDataReporting(); void Rumble(); void SendPacket(const u8 rpt_id, const void* const data, const unsigned int size); - void RealDisconnect(); - const unsigned int index; + int index; #if defined(__APPLE__) IOBluetoothDevice *btd; @@ -74,8 +87,6 @@ public: int cmd_sock; // Command socket int int_sock; // Interrupt socket - void Close(); - #elif defined(_WIN32) char devicepath[255]; // Unique wiimote reference //ULONGLONG btaddr; // Bluetooth address @@ -83,7 +94,6 @@ public: OVERLAPPED hid_overlap; // Overlap handle enum win_bt_stack_t stack; // Type of bluetooth stack to use #endif - unsigned char leds; // Currently lit leds protected: Report m_last_data_report; @@ -91,21 +101,51 @@ protected: private: void ClearReadQueue(); - bool SendRequest(unsigned char report_type, unsigned char* data, int length); - bool Handshake(); - void SetLEDs(int leds); - int IORead(unsigned char* buf); - int IOWrite(unsigned char* buf, int len); + bool SendRequest(u8 report_type, u8 const* data, int length); + + int IORead(u8* buf); + int IOWrite(u8 const* buf, int len); + void ThreadFunc(); - bool m_connected; + bool m_run_thread; std::thread m_wiimote_thread; + Common::FifoQueue m_read_reports; Common::FifoQueue m_write_reports; Common::FifoQueue m_audio_reports; }; -extern std::mutex g_refresh_lock; +class WiimoteScanner +{ +public: + WiimoteScanner(); + ~WiimoteScanner(); + + bool IsReady() const; + + void WantWiimotes(size_t count); + + void StartScanning(); + void StopScanning(); + + std::vector FindWiimotes(size_t max_wiimotes); + +private: + void ThreadFunc(); + + std::thread scan_thread; + + volatile bool run_thread; + + // TODO: this should probably be atomic + volatile size_t want_wiimotes; + + int device_id; + int device_sock; +}; + +extern std::recursive_mutex g_refresh_lock; extern Wiimote *g_wiimotes[4]; void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size); @@ -116,6 +156,7 @@ void DoState(PointerWrap &p); void StateChange(EMUSTATE_CHANGE newState); int FindWiimotes(Wiimote** wm, int max_wiimotes); +void ChangeWiimoteSource(unsigned int index, int source); bool IsValidBluetoothName(const std::string& name); diff --git a/Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp b/Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp index ea23e532e7..ba2186d17a 100644 --- a/Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp +++ b/Source/Core/DolphinWX/Src/WiimoteConfigDiag.cpp @@ -4,11 +4,12 @@ #include "HW/WiimoteReal/WiimoteReal.h" #include "Frame.h" -const wxString& ConnectedWiimotesString() +wxString ConnectedWiimotesString() { - static wxString str; - str.Printf(_("%i connected"), WiimoteReal::Initialize()); - return str; + //static wxString str; + //str.Printf(_("%i connected"), WiimoteReal::Initialize()); + //return str; + return "TODO: this text"; } WiimoteConfigDiag::WiimoteConfigDiag(wxWindow* const parent, InputPlugin& plugin) @@ -222,13 +223,16 @@ void WiimoteConfigDiag::SelectSource(wxCommandEvent& event) // This needs to be changed now in order for refresh to work right. // Revert if the dialog is canceled. int index = m_wiimote_index_from_ctrl_id[event.GetId()]; - g_wiimote_sources[index] = event.GetInt(); + + WiimoteReal::ChangeWiimoteSource(index, event.GetInt()); + if (g_wiimote_sources[index] != WIIMOTE_SRC_EMU && g_wiimote_sources[index] != WIIMOTE_SRC_HYBRID) wiimote_configure_bt[index]->Disable(); else wiimote_configure_bt[index]->Enable(); } +// TODO: race conditiions void WiimoteConfigDiag::UpdateWiimoteStatus() { for (int index = 0; index < 4; ++index) @@ -241,7 +245,7 @@ void WiimoteConfigDiag::UpdateWiimoteStatus() if (WIIMOTE_SRC_EMU & g_wiimote_sources[index]) CFrame::ConnectWiimote(index, true); else if (WIIMOTE_SRC_REAL & g_wiimote_sources[index] && WiimoteReal::g_wiimotes[index]) - CFrame::ConnectWiimote(index, WiimoteReal::g_wiimotes[index]->IsConnected()); + CFrame::ConnectWiimote(index, WiimoteReal::g_wiimotes[index]->IsOpen()); } } }