Merge branch 'real-wiimote-scanning'

This commit is contained in:
Jordan Woyak 2013-02-25 17:33:34 -06:00
commit 46adbfa9ed
21 changed files with 960 additions and 847 deletions

View File

@ -155,7 +155,6 @@ enum HOST_COMM
WM_USER_CREATE,
WM_USER_SETCURSOR,
WM_USER_KEYDOWN,
WIIMOTE_DISCONNECT // Disconnect Wiimote
};
// Used for notification on emulation state

View File

@ -100,9 +100,6 @@ SConfig::SConfig()
{
// Make sure we have log manager
LoadSettings();
//Make sure we load any extra settings
LoadSettingsWii();
}
void SConfig::Init()
@ -244,6 +241,8 @@ void SConfig::SaveSettings()
ini.Set("Core", "WiiSDCard", m_WiiSDCard);
ini.Set("Core", "WiiKeyboard", m_WiiKeyboard);
ini.Set("Core", "WiimoteReconnectOnLoad", m_WiimoteReconnectOnLoad);
ini.Set("Core", "WiimoteContinuousScanning", m_WiimoteContinuousScanning);
ini.Set("Core", "WiimoteEnableSpeaker", m_WiimoteEnableSpeaker);
ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer);
ini.Set("Core", "RunCompareClient", m_LocalCoreStartupParameter.bRunCompareClient);
ini.Set("Core", "FrameLimit", m_Framelimit);
@ -393,7 +392,9 @@ void SConfig::LoadSettings()
ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false);
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
ini.Get("Core", "WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false);
ini.Get("Core", "WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, true);
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
@ -428,18 +429,3 @@ void SConfig::LoadSettings()
m_SYSCONF = new SysConf();
}
void SConfig::LoadSettingsWii()
{
IniFile ini;
//Wiimote configs
ini.Load((File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"));
for (int i = 0; i < 4; i++)
{
char SectionName[32];
sprintf(SectionName, "Wiimote%i", i + 1);
ini.Get(SectionName, "AutoReconnectRealWiimote", &m_WiiAutoReconnect[i], false);
}
ini.Load((File::GetUserPath(D_CONFIG_IDX) + "wiimote.ini"));
ini.Get("Real", "Unpair", &m_WiiAutoUnpair, false);
}

View File

@ -41,9 +41,9 @@ struct SConfig : NonCopyable
// Wii Devices
bool m_WiiSDCard;
bool m_WiiKeyboard;
bool m_WiiAutoReconnect[4];
bool m_WiiAutoUnpair;
bool m_WiimoteReconnectOnLoad;
bool m_WiimoteContinuousScanning;
bool m_WiimoteEnableSpeaker;
// name of the last used filename
std::string m_LastFilename;
@ -107,9 +107,6 @@ struct SConfig : NonCopyable
// load settings
void LoadSettings();
//Special load settings
void LoadSettingsWii();
// Return the permanent and somewhat globally used instance of this struct
static SConfig& GetInstance() {return(*m_Instance);}

View File

@ -38,17 +38,12 @@ void Update(int _number);
namespace WiimoteReal
{
unsigned int Initialize();
void Initialize();
void Shutdown();
void Refresh();
void LoadSettings();
#ifdef _WIN32
int PairUp(bool unpair = false);
int UnPair();
#endif
}
#endif

View File

@ -248,13 +248,12 @@ void Wiimote::RequestStatus(const wm_request_status* const rs)
{
using namespace WiimoteReal;
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[m_index])
{
wm_request_status rpt;
rpt.rumble = 0;
g_wiimotes[m_index]->SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
wm_request_status rpt = {};
g_wiimotes[m_index]->QueueReport(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
}
return;

View File

@ -704,7 +704,7 @@ void Wiimote::Update()
{
using namespace WiimoteReal;
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[m_index])
{
Report rpt = g_wiimotes[m_index]->ProcessReadQueue();

View File

@ -201,6 +201,7 @@ struct wm_report
#define WM_LEDS 0x11
struct wm_leds {
u8 rumble : 1;
// real wii also sets bit 0x2 (unknown purpose)
u8 : 3;
u8 leds : 4;
};
@ -208,8 +209,9 @@ struct wm_leds {
#define WM_REPORT_MODE 0x12
struct wm_report_mode {
u8 rumble : 1;
u8 continuous : 1; // these 2 seem to be named wrong
// unsure what "all_the_time" actually is, the real wii does set it (bit 0x2)
u8 all_the_time : 1;
u8 continuous : 1;
u8 : 5;
u8 mode;
};

View File

@ -21,9 +21,25 @@
namespace WiimoteReal
{
int FindWiimotes(Wiimote **wm, int max_wiimotes)
WiimoteScanner::WiimoteScanner()
{
return 0;
return;
}
WiimoteScanner::~WiimoteScanner()
{}
void WiimoteScanner::Update()
{}
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
return std::vector<Wiimote*>();
}
bool WiimoteScanner::IsReady() const
{
return false;
}
bool Wiimote::Connect()
@ -31,22 +47,22 @@ bool Wiimote::Connect()
return 0;
}
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
return;
}
bool Wiimote::IsOpen() const
bool Wiimote::IsConnected() const
{
return IsConnected();
return false;
}
int Wiimote::IORead(unsigned char* buf)
int Wiimote::IORead(u8* buf)
{
return 0;
}
int Wiimote::IOWrite(unsigned char* buf, int len)
int Wiimote::IOWrite(const u8* buf, int len)
{
return 0;
}

View File

@ -15,16 +15,6 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <sys/time.h>
#include <errno.h>
#include <sys/types.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
@ -32,114 +22,116 @@
#include "Common.h"
#include "WiimoteReal.h"
#include "Host.h"
namespace WiimoteReal
{
// 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)
WiimoteScanner::WiimoteScanner()
: m_run_thread()
, m_want_wiimotes()
, device_id(-1)
, device_sock(-1)
{
int device_id;
int device_sock;
int found_devices;
int found_wiimotes = 0;
int i;
// Count the number of already found wiimotes
for (i = 0; i < MAX_WIIMOTES; ++i)
{
if (wm[i])
found_wiimotes++;
}
// Get the id of the first bluetooth device.
if ((device_id = hci_get_route(NULL)) < 0)
device_id = hci_get_route(NULL);
if (device_id < 0)
{
NOTICE_LOG(WIIMOTE, "Bluetooth not found.");
return found_wiimotes;
return;
}
// Create a socket to the device
if ((device_sock = hci_open_dev(device_id)) < 0)
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);
}
void WiimoteScanner::Update()
{}
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
std::vector<Wiimote*> found_wiimotes;
// supposedly 1.28 seconds
int const wait_len = 1;
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)
{
ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices.");
return found_wiimotes;
}
int try_num = 0;
while ((try_num < 5) && (found_wiimotes < max_wiimotes))
DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices);
// Display discovered devices
for (int i = 0; i < found_devices; ++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()
{
if (IsConnected())
return false;
sockaddr_l2 addr;
addr.l2_family = AF_BLUETOOTH;
addr.l2_bdaddr = bdaddr;
@ -148,7 +140,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 +151,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 +160,27 @@ 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::Disconnect()
{
if (!IsConnected())
return;
close(cmd_sock);
close(int_sock);
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i.", index + 1);
m_connected = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
Close();
cmd_sock = -1;
int_sock = -1;
}
void Wiimote::Close()
bool Wiimote::IsConnected() const
{
if (IsOpen())
{
Host_ConnectWiimote(index, false);
close(cmd_sock);
close(int_sock);
cmd_sock = -1;
int_sock = -1;
}
return cmd_sock != -1;// && int_sock != -1;
}
bool Wiimote::IsOpen() const
{
return IsConnected() && cmd_sock != -1 && int_sock != -1;
}
int Wiimote::IORead(unsigned char *buf)
// positive = read packet
// negative = didn't read packet
// zero = error
int Wiimote::IORead(u8* buf)
{
// Block select for 1/2000th of a second
timeval tv;
@ -232,11 +194,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 +212,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);
}

View File

@ -18,6 +18,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <regex>
#include <algorithm>
#include <unordered_map>
#include <ctime>
#include <windows.h>
#include <dbt.h>
@ -73,6 +76,8 @@ HINSTANCE bthprops_lib = NULL;
static int initialized = 0;
std::unordered_map<BTH_ADDR, std::time_t> g_connect_times;
inline void init_lib()
{
if (!initialized)
@ -127,311 +132,332 @@ inline void init_lib()
namespace WiimoteReal
{
template <typename T>
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()
: m_run_thread()
, m_want_wiimotes()
{
init_lib();
}
WiimoteScanner::~WiimoteScanner()
{
// TODO: what do we want here?
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.
int FindWiimotes(Wiimote** wm, int max_wiimotes)
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
GUID device_id;
HANDLE dev;
HDEVINFO device_info;
int found_wiimotes = 0;
DWORD len;
SP_DEVICE_INTERFACE_DATA device_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
HIDD_ATTRIBUTES attr;
init_lib();
// Count the number of already found wiimotes
for (int i = 0; i < MAX_WIIMOTES; ++i)
ProcessWiimotes(true, [](HANDLE hRadio, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
if (wm[i])
found_wiimotes++;
}
device_data.cbSize = sizeof(device_data);
ForgetWiimote(hRadio, btdi);
AttachWiimote(hRadio, btdi);
});
// Get the device id
GUID device_id;
HidD_GetHidGuid(&device_id);
// Get all hid devices connected
device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
HDEVINFO const device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
for (int index = 0; found_wiimotes < max_wiimotes; ++index)
std::vector<Wiimote*> wiimotes;
SP_DEVICE_INTERFACE_DATA device_data;
device_data.cbSize = sizeof(device_data);
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
for (int index = 0; SetupDiEnumDeviceInterfaces(device_info, NULL, &device_id, index, &device_data); ++index)
{
if (detail_data)
{
free(detail_data);
detail_data = NULL;
}
// Query the next hid device info
if (!SetupDiEnumDeviceInterfaces(device_info, NULL, &device_id, index, &device_data))
break;
// Get the size of the data block required
DWORD len;
SetupDiGetDeviceInterfaceDetail(device_info, &device_data, NULL, 0, &len, NULL);
detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(len);
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Query the data for this device
if (!SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL))
continue;
// Determine if this wiimote has already been found.
bool found = false;
for(int i = 0; i < MAX_WIIMOTES; i++)
if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL))
{
if(wm[i] && (wm[i]->devicepath == detail_data->DevicePath))
{
found = true;
break;
}
auto const wm = new Wiimote;
wm->devicepath = detail_data->DevicePath;
wiimotes.push_back(wm);
}
if (found)
continue;
// Open new device
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);
// 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);
wm[k]->dev_handle = dev;
wm[k]->devicepath = detail_data->DevicePath;
if (!wm[k]->Connect())
{
ERROR_LOG(WIIMOTE, "Unable to connect to wiimote %i.", wm[k]->index + 1);
delete wm[k];
wm[k] = NULL;
CloseHandle(dev);
}
else
{
++found_wiimotes;
}
}
if (detail_data)
free(detail_data);
}
SetupDiDestroyDeviceInfoList(device_info);
return found_wiimotes;
// Don't mind me, just a random sleep to fix stuff on Windows
//if (!wiimotes.empty())
// SLEEP(2000);
return wiimotes;
}
bool WiimoteScanner::IsReady() const
{
// TODO: don't search for a radio each time
BLUETOOTH_FIND_RADIO_PARAMS radioParam;
radioParam.dwSize = sizeof(radioParam);
HANDLE hRadio;
HBLUETOOTH_RADIO_FIND hFindRadio = Bth_BluetoothFindFirstRadio(&radioParam, &hRadio);
if (NULL != hFindRadio)
{
Bth_BluetoothFindRadioClose(hFindRadio);
return true;
}
else
{
return false;
}
}
// Connect to a wiimote with a known device path.
bool Wiimote::Connect()
{
if (IsConnected()) return false;
if (IsConnected())
return false;
if (!dev_handle)
dev_handle = CreateFile(devicepath.c_str(),
GENERIC_READ | GENERIC_WRITE,
// Having no FILE_SHARE_WRITE disallows us from connecting to the same wiimote twice.
// This is what "WiiYourself" does.
FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (dev_handle == INVALID_HANDLE_VALUE)
{
dev_handle = CreateFile(devicepath.c_str(),
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (dev_handle == INVALID_HANDLE_VALUE)
return false;
}
hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T(""));
hid_overlap.Offset = 0;
hid_overlap.OffsetHigh = 0;
m_connected = true;
// Try a handshake to see if the device is actually connected
if (!Handshake())
{
m_connected = false;
dev_handle = 0;
return false;
}
// Set LEDs
SetLEDs(WIIMOTE_LED_1 << index);
#if 0
HIDD_ATTRIBUTES attr;
attr.Size = sizeof(attr);
if (!HidD_GetAttributes(dev_handle, &attr))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
#endif
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
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
// reside is normal priority. Needed for keeping audio reports at a decent rate
/*
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
{
ERROR_LOG(WIIMOTE, "Failed to set wiimote thread priority");
}
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", index + 1);
*/
return true;
}
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
if (!IsConnected())
return;
m_connected = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
CloseHandle(dev_handle);
dev_handle = 0;
ResetEvent(&hid_overlap);
CloseHandle(hid_overlap_read.hEvent);
CloseHandle(hid_overlap_write.hEvent);
}
bool Wiimote::IsOpen() const
bool Wiimote::IsConnected() const
{
return IsConnected();
return dev_handle != 0;
}
int Wiimote::IORead(unsigned char* buf)
// positive = read packet
// negative = didn't read packet
// zero = error
int Wiimote::IORead(u8* buf)
{
DWORD b, r;
init_lib();
if (!IsConnected())
return 0;
// used below for a warning
*buf = 0;
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD, &b, &hid_overlap))
DWORD bytes;
ResetEvent(hid_overlap_read.hEvent);
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
{
// Partial read
b = GetLastError();
auto const err = GetLastError();
if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED))
if (ERROR_IO_PENDING == err)
{
auto const r = WaitForSingleObject(hid_overlap_read.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_read, &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
RealDisconnect();
return 0;
bytes = 0;
}
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 0;
// 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 0;
}
if (!GetOverlappedResult(dev_handle, &hid_overlap, &b, 0))
{
return 0;
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)
std::copy_n(buf, MAX_PAYLOAD - 1, buf + 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(unsigned char* buf, int len)
int Wiimote::IOWrite(const u8* buf, int len)
{
DWORD bytes, dw;
int i;
init_lib();
if (!IsConnected())
return 0;
switch (stack)
{
case MSBT_STACK_UNKNOWN:
{
// Try to auto-detect the stack type
if (i = WriteFile(dev_handle, buf + 1, 22, &bytes, &hid_overlap))
{
// Bluesoleil will always return 1 here, even if it's not connected
stack = MSBT_STACK_BLUESOLEIL;
return i;
}
case MSBT_STACK_UNKNOWN:
{
// Try to auto-detect the stack type
stack = MSBT_STACK_BLUESOLEIL;
if (IOWrite(buf, len))
return 1;
if (i = HidD_SetOutputReport(dev_handle, buf + 1, len - 1))
{
stack = MSBT_STACK_MS;
return i;
}
stack = MSBT_STACK_MS;
if (IOWrite(buf, len))
return 1;
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");
RealDisconnect();
}
else ERROR_LOG(WIIMOTE,
"IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw);
return 0;
}
stack = MSBT_STACK_UNKNOWN;
break;
}
case MSBT_STACK_MS:
{
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
//FlushFileBuffers(dev_handle);
case MSBT_STACK_MS:
i = HidD_SetOutputReport(dev_handle, buf + 1, len - 1);
dw = GetLastError();
if (dw == 121)
if (!result)
{
auto err = GetLastError();
if (err == 121)
{
// Semaphore timeout
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
RealDisconnect();
return 0;
}
return i;
else
{
WARN_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
}
}
case MSBT_STACK_BLUESOLEIL:
return WriteFile(dev_handle, buf + 1, 22, &bytes, &hid_overlap);
return result;
break;
}
case MSBT_STACK_BLUESOLEIL:
{
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;
}
int UnPair()
// invokes callback for each found wiimote bluetooth device
template <typename T>
void ProcessWiimotes(bool new_scan, T& callback)
{
// TODO:
return 0;
}
// WiiMote Pair-Up, function will return amount of either new paired or unpaired devices
// negative number on failure
int PairUp(bool unpair)
{
init_lib();
// 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);
@ -441,20 +467,19 @@ int PairUp(bool unpair)
// fConnected BT Devices
srch.fReturnConnected = true;
srch.fReturnUnknown = true;
srch.fIssueInquiry = true;
srch.cTimeoutMultiplier = 2; // == (2 * 1.28) seconds
srch.fIssueInquiry = new_scan;
// multiple of 1.28 seconds
srch.cTimeoutMultiplier = 2;
BLUETOOTH_FIND_RADIO_PARAMS radioParam;
radioParam.dwSize = sizeof(radioParam);
HANDLE hRadio;
// 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;
@ -478,40 +503,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))
@ -527,8 +519,64 @@ 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)
{
// We don't want "remembered" devices.
// SetServiceState will just fail with them..
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);
g_connect_times[btdi.Address.ullLong] = std::time(nullptr);
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)
{
// Time to avoid RemoveDevice after SetServiceState.
// Sometimes SetServiceState takes a while..
auto const avoid_forget_seconds = 5.0;
auto pair_time = g_connect_times.find(btdi.Address.ullLong);
if (pair_time == g_connect_times.end()
|| std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds)
{
// Make Windows forget about device so it will re-find it if visible.
// This is also required to detect a disconnect for some reason..
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
Bth_BluetoothRemoveDevice(&btdi.Address);
return true;
}
}
return false;
}
};

View File

@ -40,8 +40,11 @@
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
std::lock_guard<std::recursive_mutex> lk(WiimoteReal::g_refresh_lock);
for (int i = 0; i < MAX_WIIMOTES; i++) {
for (int i = 0; i < MAX_WIIMOTES; i++)
{
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
@ -77,8 +80,11 @@
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
std::lock_guard<std::recursive_mutex> lk(WiimoteReal::g_refresh_lock);
for (int i = 0; i < MAX_WIIMOTES; i++) {
for (int i = 0; i < MAX_WIIMOTES; i++)
{
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
@ -92,41 +98,47 @@
WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->index + 1);
wm->RealDisconnect();
wm->Disconnect();
}
@end
namespace WiimoteReal
{
// Find wiimotes.
// wm is an array of max_wiimotes wiimotes
// Returns the total number of found wiimotes.
int FindWiimotes(Wiimote **wm, int max_wiimotes)
WiimoteScanner::WiimoteScanner()
: m_run_thread()
, m_want_wiimotes()
{}
WiimoteScanner::~WiimoteScanner()
{}
void WiimoteScanner::Update()
{}
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
// TODO: find the device in the constructor and save it for later
std::vector<Wiimote*> wiimotes;
IOBluetoothHostController *bth;
IOBluetoothDeviceInquiry *bti;
SearchBT *sbt;
NSEnumerator *en;
int found_devices = 0, found_wiimotes = 0;
// Count the number of already found wiimotes
for (int i = 0; i < MAX_WIIMOTES; ++i)
if (wm[i])
found_wiimotes++;
bth = [[IOBluetoothHostController alloc] init];
if ([bth addressAsString] == nil) {
if ([bth addressAsString] == nil)
{
WARN_LOG(WIIMOTE, "No bluetooth host controller");
[bth release];
return found_wiimotes;
return wiimotes;
}
sbt = [[SearchBT alloc] init];
sbt->maxDevices = max_wiimotes - found_wiimotes;
sbt->maxDevices = 32;
bti = [[IOBluetoothDeviceInquiry alloc] init];
[bti setDelegate: sbt];
[bti setInquiryLength: 5];
[bti setInquiryLength: 2];
if ([bti start] == kIOReturnSuccess)
[bti retain];
@ -136,10 +148,10 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
CFRunLoopRun();
[bti stop];
found_devices = [[bti foundDevices] count];
int found_devices = [[bti foundDevices] count];
NOTICE_LOG(WIIMOTE, "Found %i bluetooth device%c", found_devices,
found_devices == 1 ? '\0' : 's');
if (found_devices)
NOTICE_LOG(WIIMOTE, "Found %i bluetooth devices", found_devices);
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; i < found_devices; i++)
@ -147,42 +159,44 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
IOBluetoothDevice *dev = [en nextObject];
if (!IsValidBluetoothName([[dev name] UTF8String]))
continue;
// Find an unused slot
for (int k = 0; k < MAX_WIIMOTES; k++) {
if (wm[k] != NULL ||
!(g_wiimote_sources[k] & WIIMOTE_SRC_REAL))
continue;
wm[k] = new Wiimote(k);
wm[k]->btd = dev;
found_wiimotes++;
break;
}
Wiimote *wm = new Wiimote();
wm->btd = dev;
wiimotes.push_back(wm);
}
[bth release];
[bti release];
[sbt release];
return found_wiimotes;
return wiimotes;
}
bool WiimoteScanner::IsReady() const
{
// TODO: only return true when a BT device is present
return true;
}
// Connect to a wiimote with a known address.
bool Wiimote::Connect()
{
ConnectBT *cbt = [[ConnectBT alloc] init];
if (IsConnected())
return false;
ConnectBT *cbt = [[ConnectBT alloc] init];
[btd openL2CAPChannelSync: &cchan
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
[btd openL2CAPChannelSync: &ichan
withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
if (ichan == NULL || cchan == NULL) {
if (ichan == NULL || cchan == NULL)
{
ERROR_LOG(WIIMOTE, "Unable to open L2CAP channels "
"for wiimote %i", index + 1);
RealDisconnect();
Disconnect();
[cbt release];
return false;
}
@ -196,40 +210,37 @@ bool Wiimote::Connect()
m_connected = true;
Handshake();
SetLEDs(WIIMOTE_LED_1 << index);
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
[cbt release];
return true;
}
// Disconnect a wiimote.
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
if (btd != NULL)
[btd closeConnection];
if (ichan != NULL)
[ichan release];
if (cchan != NULL)
[cchan release];
btd = NULL;
cchan = NULL;
ichan = NULL;
if (!IsConnected())
return;
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", index + 1);
m_connected = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
[btd closeConnection];
[ichan release];
[cchan release];
btd = NULL;
cchan = NULL;
ichan = NULL;
}
bool Wiimote::IsOpen() const
bool Wiimote::IsConnected() const
{
return IsConnected();
return m_connected;
}
int Wiimote::IORead(unsigned char *buf)
@ -246,14 +257,14 @@ int Wiimote::IORead(unsigned char *buf)
return bytes;
}
int Wiimote::IOWrite(unsigned char *buf, int len)
int Wiimote::IOWrite(const unsigned char *buf, int len)
{
IOReturn ret;
if (!IsConnected())
return 0;
ret = [ichan writeAsync: buf length: len refcon: nil];
ret = [ichan writeAsync: const_cast<void*>((void *)buf) length: len refcon: nil];
if (ret == kIOReturnSuccess)
return len;

View File

@ -23,6 +23,8 @@
#include "IniFile.h"
#include "StringUtil.h"
#include "Timer.h"
#include "Host.h"
#include "ConfigManager.h"
#include "WiimoteReal.h"
@ -33,36 +35,43 @@ unsigned int g_wiimote_sources[MAX_WIIMOTES];
namespace WiimoteReal
{
void HandleFoundWiimotes(const std::vector<Wiimote*>&);
void TryToConnectWiimote(Wiimote*);
void HandleWiimoteDisconnect(int index);
void DoneWithWiimote(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)
, btd(), ichan(), cchan(), inputlen(), m_connected()
#elif defined(__linux__) && HAVE_BLUEZ
, cmd_sock(-1), int_sock(-1)
#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}};
#endif
DisableDataReporting();
}
Wiimote::~Wiimote()
{
RealDisconnect();
StopThread();
if (IsConnected())
Disconnect();
ClearReadQueue();
// clear write queue
@ -71,26 +80,28 @@ Wiimote::~Wiimote()
delete[] rpt.first;
}
// Silly, copying data n stuff, o well, don't use this too often
void Wiimote::SendPacket(const u8 rpt_id, const void* const data, const unsigned int size)
// to be called from CPU thread
void Wiimote::QueueReport(u8 rpt_id, const void* _data, unsigned int size)
{
auto const data = static_cast<const u8*>(_data);
Report rpt;
rpt.second = size + 2;
rpt.first = new u8[rpt.second];
rpt.first[0] = 0xA1;
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
rpt.first[1] = rpt_id;
memcpy(rpt.first + 2, data, size);
std::copy(data, data + size, rpt.first + 2);
m_write_reports.Push(rpt);
}
void Wiimote::DisableDataReporting()
{
wm_report_mode rpt;
wm_report_mode rpt = {};
rpt.mode = WM_REPORT_CORE;
rpt.all_the_time = 0;
rpt.continuous = 0;
rpt.rumble = 0;
SendPacket(WM_REPORT_MODE, &rpt, sizeof(rpt));
QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt));
}
void Wiimote::ClearReadQueue()
@ -111,7 +122,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);
@ -124,24 +135,24 @@ void Wiimote::ControlChannel(const u16 channel, const void* const data, const u3
}
}
void Wiimote::InterruptChannel(const u16 channel, const void* const data, const u32 size)
void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const u32 size)
{
if (0 == m_channel) // first interrupt/control channel sent
// first interrupt/control channel sent
if (channel != m_channel)
{
m_channel = channel;
ClearReadQueue();
// request status
wm_request_status rpt;
rpt.rumble = 0;
SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
EmuStart();
}
m_channel = channel; // this right?
auto const data = static_cast<const u8*>(_data);
Report rpt;
rpt.first = new u8[size];
rpt.second = (u8)size;
memcpy(rpt.first, (u8*)data, size);
std::copy(data, data + size, rpt.first);
// Convert output DATA packets to SET_REPORT packets.
// Nintendo Wiimotes work without this translation, but 3rd
@ -150,13 +161,27 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
{
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
}
if (rpt.first[0] == (WM_SET_REPORT | WM_BT_OUTPUT) &&
rpt.first[1] == 0x18 && rpt.second == 23)
// Disallow games from turning off all of the LEDs.
// It makes wiimote connection status confusing.
if (rpt.first[1] == WM_LEDS)
{
m_audio_reports.Push(rpt);
return;
}
auto& leds_rpt = *reinterpret_cast<wm_leds*>(&rpt.first[2]);
if (0 == leds_rpt.leds)
{
// Turn on ALL of the LEDs.
leds_rpt.leds = 0xf;
}
}
else if (rpt.first[1] == WM_WRITE_SPEAKER_DATA
&& !SConfig::GetInstance().m_WiimoteEnableSpeaker)
{
// Translate speaker data reports into rumble reports.
rpt.first[1] = WM_CMD_RUMBLE;
// Keep only the rumble bit.
rpt.first[2] &= 0x1;
rpt.second = 3;
}
m_write_reports.Push(rpt);
}
@ -168,7 +193,14 @@ bool Wiimote::Read()
rpt.first = new unsigned char[MAX_PAYLOAD];
rpt.second = IORead(rpt.first);
if (rpt.second > 0 && m_channel > 0) {
if (0 == rpt.second)
{
WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting wiimote %d.", index + 1);
Disconnect();
}
if (rpt.second > 0 && m_channel > 0)
{
// Add it to queue
m_read_reports.Push(rpt);
return true;
@ -180,23 +212,25 @@ bool Wiimote::Read()
bool Wiimote::Write()
{
Report rpt;
if (last_audio_report.GetTimeDifference() > 5 && m_audio_reports.Pop(rpt))
if (!m_write_reports.Empty())
{
IOWrite(rpt.first, rpt.second);
last_audio_report.Update();
Report const& rpt = m_write_reports.Front();
delete[] rpt.first;
return true;
bool const is_speaker_data = rpt.first[1] == WM_WRITE_SPEAKER_DATA;
if (!is_speaker_data || m_last_audio_report.GetTimeDifference() > 5)
{
IOWrite(rpt.first, rpt.second);
if (is_speaker_data)
m_last_audio_report.Update();
delete[] rpt.first;
m_write_reports.Pop();
return true;
}
}
else if (m_write_reports.Pop(rpt))
{
IOWrite(rpt.first, rpt.second);
delete[] rpt.first;
return true;
}
return false;
}
@ -221,6 +255,12 @@ Report Wiimote::ProcessReadQueue()
void Wiimote::Update()
{
if (!IsConnected())
{
HandleWiimoteDisconnect(index);
return;
}
// Pop through the queued reports
Report const rpt = ProcessReadQueue();
@ -234,123 +274,151 @@ void Wiimote::Update()
delete[] rpt.first;
}
void Wiimote::Disconnect()
bool Wiimote::Prepare(int _index)
{
index = _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 and turn on rumble.
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index | 0x1)};
// Turn off rumble
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0};
// Request status report
u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
// TODO: check for sane response?
return (IOWrite(mode_report, sizeof(mode_report))
&& IOWrite(led_report, sizeof(led_report))
&& (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report)))
&& IOWrite(req_status_report, sizeof(req_status_report)));
}
void Wiimote::EmuStart()
{
DisableDataReporting();
}
void Wiimote::EmuStop()
{
m_channel = 0;
DisableDataReporting();
NOTICE_LOG(WIIMOTE, "Stopping wiimote data reporting");
}
bool Wiimote::IsConnected() const
unsigned int CalculateWantedWiimotes()
{
return m_connected;
// 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;
}
// Rumble briefly
void Wiimote::Rumble()
void WiimoteScanner::WantWiimotes(bool do_want)
{
if (!IsConnected())
return;
unsigned char buffer = 0x01;
DEBUG_LOG(WIIMOTE, "Starting rumble...");
SendRequest(WM_CMD_RUMBLE, &buffer, 1);
SLEEP(200);
DEBUG_LOG(WIIMOTE, "Stopping rumble...");
buffer = 0x00;
SendRequest(WM_CMD_RUMBLE, &buffer, 1);
m_want_wiimotes = do_want;
}
// Set the active LEDs.
// leds is a bitwise or of WIIMOTE_LED_1 through WIIMOTE_LED_4.
void Wiimote::SetLEDs(int new_leds)
void WiimoteScanner::StartScanning()
{
unsigned char buffer;
if (!IsConnected())
return;
// Remove the lower 4 bits because they control rumble
buffer = leds = (new_leds & 0xF0);
SendRequest(WM_CMD_LED, &buffer, 1);
if (!m_run_thread && IsReady())
{
m_run_thread = true;
m_scan_thread = std::thread(std::mem_fun(&WiimoteScanner::ThreadFunc), this);
}
}
// Send a handshake
bool Wiimote::Handshake()
void WiimoteScanner::StopScanning()
{
// Set buffer[0] to 0x04 for continuous reporting
unsigned char buffer[2] = {0x04, 0x30};
if (!IsConnected())
return 0;
DEBUG_LOG(WIIMOTE, "Sending handshake to wiimote");
return SendRequest(WM_CMD_REPORT_TYPE, buffer, 2);
m_run_thread = false;
if (m_scan_thread.joinable())
{
m_scan_thread.join();
}
}
// 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)
void CheckForDisconnectedWiimotes()
{
unsigned char buffer[32] = {WM_SET_REPORT | WM_BT_OUTPUT, report_type};
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
memcpy(buffer + 2, data, length);
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected())
HandleWiimoteDisconnect(i);
}
return (IOWrite(buffer, length + 2) != 0);
void WiimoteScanner::ThreadFunc()
{
Common::SetCurrentThreadName("Wiimote Scanning Thread");
NOTICE_LOG(WIIMOTE, "Wiimote scanning has started");
while (m_run_thread)
{
std::vector<Wiimote*> found_wiimotes;
//NOTICE_LOG(WIIMOTE, "in loop");
if (m_want_wiimotes)
found_wiimotes = FindWiimotes();
else
{
// Does stuff needed to detect disconnects on Windows
Update();
}
//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);
}
NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped");
}
void Wiimote::StartThread()
{
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();
}
void Wiimote::ThreadFunc()
{
char thname[] = "Wiimote # Thread";
thname[8] = (char)('1' + index);
Common::SetCurrentThreadName(thname);
// rumble briefly
Rumble();
Common::SetCurrentThreadName("Wiimote Device Thread");
// main loop
while (IsOpen())
while (m_run_thread && IsConnected())
{
#ifdef __APPLE__
while (Write()) {}
Common::SleepCurrentThread(1);
// Reading happens elsewhere on OSX
bool const did_something = Write();
#else
bool const did_something = Write() || Read();
#endif
if (!did_something)
Common::SleepCurrentThread(1);
#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";
@ -368,116 +436,181 @@ void LoadSettings()
}
}
unsigned int Initialize()
// config dialog calls this when some settings change
void Initialize()
{
// Return if already initialized
if (SConfig::GetInstance().m_WiimoteContinuousScanning)
g_wiimote_scanner.StartScanning();
else
g_wiimote_scanner.StopScanning();
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
if (g_real_wiimotes_initialized)
return g_wiimotes_found;
return;
memset(g_wiimotes, 0, sizeof(g_wiimotes));
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
// 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;
// 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)
{
g_wiimote_scanner.StopScanning();
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (!g_real_wiimotes_initialized)
return;
// Uninitialized
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
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<std::recursive_mutex> lk(g_refresh_lock);
g_wiimote_sources[index] = source;
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
// kill real connection (or swap to different slot)
DoneWithWiimote(index);
}
// reconnect to emu
Host_ConnectWiimote(index, false);
if (WIIMOTE_SRC_EMU & source)
Host_ConnectWiimote(index, true);
}
void TryToConnectWiimote(Wiimote* wm)
{
std::unique_lock<std::recursive_mutex> 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;
if (wm->Connect() && wm->Prepare(i))
{
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1);
std::swap(g_wiimotes[i], wm);
g_wiimotes[i]->StartThread();
Host_ConnectWiimote(i, true);
}
break;
}
}
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
lk.unlock();
delete wm;
}
void DoneWithWiimote(int index)
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[index])
{
g_wiimotes[index]->StopThread();
// First see if we can use this real wiimote in another slot.
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
{
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]
&& !g_wiimotes[i])
{
if (g_wiimotes[index]->Prepare(i))
{
std::swap(g_wiimotes[i], g_wiimotes[index]);
g_wiimotes[i]->StartThread();
Host_ConnectWiimote(i, true);
}
break;
}
}
}
// else, just disconnect the wiimote
HandleWiimoteDisconnect(index);
}
void HandleWiimoteDisconnect(int index)
{
Wiimote* wm = NULL;
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
std::swap(wm, g_wiimotes[index]);
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
}
if (wm)
{
delete wm;
NOTICE_LOG(WIIMOTE, "Disconnected wiimote %i.", index + 1);
}
}
void HandleFoundWiimotes(const std::vector<Wiimote*>& wiimotes)
{
std::for_each(wiimotes.begin(), wiimotes.end(), TryToConnectWiimote);
}
// This is called from the GUI thread
void Refresh()
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
#ifdef _WIN32
Shutdown();
Initialize();
#else
// Make sure real wiimotes have been initialized
if (!g_real_wiimotes_initialized)
g_wiimote_scanner.StopScanning();
{
Initialize();
return;
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
std::vector<Wiimote*> found_wiimotes;
if (0 != CalculateWantedWiimotes())
{
// Don't hang dolphin when searching
lk.unlock();
found_wiimotes = g_wiimote_scanner.FindWiimotes();
lk.lock();
}
// Find 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;
CheckForDisconnectedWiimotes();
// Remove wiimotes that are paired with slots no longer configured for a
// real wiimote or that are disconnected
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (g_wiimotes[i] && (!(WIIMOTE_SRC_REAL & g_wiimote_sources[i]) ||
!g_wiimotes[i]->IsConnected()))
// Brief rumble for already connected wiimotes.
for (int i = 0; i != MAX_WIIMOTES; ++i)
{
if (g_wiimotes[i])
{
delete g_wiimotes[i];
g_wiimotes[i] = NULL;
--g_wiimotes_found;
g_wiimotes[i]->StopThread();
g_wiimotes[i]->Prepare(i);
g_wiimotes[i]->StartThread();
}
// Scan for wiimotes if we want more
if (wanted_wiimotes > g_wiimotes_found)
{
// Scan for wiimotes
unsigned int num_wiimotes = FindWiimotes(g_wiimotes, wanted_wiimotes);
DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted", num_wiimotes, wanted_wiimotes);
// Connect newly found wiimotes.
int num_new_wiimotes = ConnectWiimotes(g_wiimotes);
DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
g_wiimotes_found = num_wiimotes;
}
#endif
HandleFoundWiimotes(found_wiimotes);
}
Initialize();
}
void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size);
@ -485,7 +618,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<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->ControlChannel(_channelID, _pData, _Size);
@ -495,15 +628,21 @@ void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32
// Read the Wiimote once
void Update(int _WiimoteNumber)
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->Update();
// Wiimote::Update() may remove the wiimote if it was disconnected.
if (!g_wiimotes[_WiimoteNumber])
{
Host_ConnectWiimote(_WiimoteNumber, false);
}
}
void StateChange(EMUSTATE_CHANGE newState)
{
//std::lock_guard<std::mutex> lk(g_refresh_lock);
//std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
// TODO: disable/enable auto reporting, maybe
}

View File

@ -20,6 +20,7 @@
#define WIIMOTE_REAL_H
#include <functional>
#include <vector>
#include "WiimoteRealBase.h"
#include "ChunkFile.h"
@ -42,7 +43,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);
@ -53,16 +54,29 @@ public:
bool Read();
bool Write();
bool Connect();
bool IsConnected() const;
bool IsOpen() const;
void Disconnect();
void DisableDataReporting();
void Rumble();
void SendPacket(const u8 rpt_id, const void* const data, const unsigned int size);
void RealDisconnect();
const unsigned int index;
void StartThread();
void StopThread();
// "handshake" / stop packets
void EmuStart();
void EmuStop();
// connecting and disconnecting from physical devices
// (using address inserted by FindWiimotes)
bool Connect();
void Disconnect();
// TODO: change to something like IsRelevant
bool IsConnected() const;
bool Prepare(int index);
void DisableDataReporting();
void QueueReport(u8 rpt_id, const void* data, unsigned int size);
int index;
#if defined(__APPLE__)
IOBluetoothDevice *btd;
@ -70,21 +84,19 @@ public:
IOBluetoothL2CAPChannel *cchan;
char input[MAX_PAYLOAD];
int inputlen;
bool m_connected;
#elif defined(__linux__) && HAVE_BLUEZ
bdaddr_t bdaddr; // Bluetooth address
int cmd_sock; // Command socket
int int_sock; // Interrupt socket
void Close();
#elif defined(_WIN32)
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
unsigned char leds; // Currently lit leds
protected:
Report m_last_data_report;
@ -92,23 +104,58 @@ 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);
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<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
Common::FifoQueue<Report> m_audio_reports;
Common::Timer last_audio_report;
Common::Timer m_last_audio_report;
};
extern std::mutex g_refresh_lock;
class WiimoteScanner
{
public:
WiimoteScanner();
~WiimoteScanner();
bool IsReady() const;
void WantWiimotes(bool do_want);
void StartScanning();
void StopScanning();
std::vector<Wiimote*> FindWiimotes();
// function called when not looking for more wiimotes
void Update();
private:
void ThreadFunc();
std::thread m_scan_thread;
volatile bool m_run_thread;
volatile bool m_want_wiimotes;
#if defined(_WIN32)
#elif defined(__linux__) && HAVE_BLUEZ
int device_id;
int device_sock;
#endif
};
extern std::recursive_mutex g_refresh_lock;
extern WiimoteScanner g_wiimote_scanner;
extern Wiimote *g_wiimotes[4];
void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size);
@ -119,6 +166,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);

View File

@ -41,6 +41,7 @@
#define WM_SET_REPORT 0xA0
#endif
// TODO: duplicated in WiimoteHid.h
// Commands
#define WM_CMD_RUMBLE 0x10
#define WM_CMD_LED 0x11
@ -66,8 +67,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.

View File

@ -211,8 +211,7 @@ void CWII_IPC_HLE_WiiMote::EventConnectionAccepted()
void CWII_IPC_HLE_WiiMote::EventDisconnect()
{
// Send disconnect message to plugin
u8 Message = WIIMOTE_DISCONNECT;
Wiimote::ControlChannel(m_ConnectionHandle & 0xFF, 99, &Message, 0);
Wiimote::ControlChannel(m_ConnectionHandle & 0xFF, 99, NULL, 0);
m_ConnectionState = CONN_INACTIVE;
// Clear channel flags

View File

@ -100,37 +100,6 @@ CPanel::CPanel(
else
SetCursor(wxNullCursor);
break;
case WIIMOTE_DISCONNECT:
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
{
const int wiimote_idx = lParam;
const int wiimote_num = wiimote_idx + 1;
//Auto reconnect if option is turned on.
//TODO: Make this only auto reconnect wiimotes that have the option activated.
SConfig::GetInstance().LoadSettingsWii();//Make sure we are using the newest settings.
if (SConfig::GetInstance().m_WiiAutoReconnect[wiimote_idx])
{
GetUsbPointer()->AccessWiiMote(wiimote_idx | 0x100)->Activate(true);
NOTICE_LOG(WIIMOTE, "Wiimote %i has been auto-reconnected...", wiimote_num);
}
else
{
// The Wiimote has been disconnected, we offer reconnect here.
wxMessageDialog *dlg = new wxMessageDialog(
this,
wxString::Format(_("Wiimote %i has been disconnected by system.\nMaybe this game doesn't support multi-wiimote,\nor maybe it is due to idle time out or other reason.\nDo you want to reconnect immediately?"), wiimote_num),
_("Reconnect Wiimote Confirm"),
wxYES_NO | wxSTAY_ON_TOP | wxICON_INFORMATION, //wxICON_QUESTION,
wxDefaultPosition);
if (dlg->ShowModal() == wxID_YES)
GetUsbPointer()->AccessWiiMote(wiimote_idx | 0x100)->Activate(true);
dlg->Destroy();
}
}
}
break;

View File

@ -1355,10 +1355,6 @@ void CFrame::ConnectWiimote(int wm_idx, bool connect)
wxString msg(wxString::Format(wxT("Wiimote %i %s"), wm_idx + 1,
connect ? wxT("Connected") : wxT("Disconnected")));
Core::DisplayMessage(msg.ToAscii(), 3000);
// Wait for the wiimote to connect
while (GetUsbPointer()->AccessWiiMote(wm_idx | 0x100)->IsConnected() != connect)
{}
Host_UpdateMainFrame();
}
}

View File

@ -390,10 +390,6 @@ void DolphinApp::InitLanguageSupport()
int DolphinApp::OnExit()
{
WiimoteReal::Shutdown();
#ifdef _WIN32
if (SConfig::GetInstance().m_WiiAutoUnpair)
WiimoteReal::UnPair();
#endif
VideoBackend::ClearList();
SConfig::Shutdown();
LogManager::Shutdown();

View File

@ -4,13 +4,6 @@
#include "HW/WiimoteReal/WiimoteReal.h"
#include "Frame.h"
const wxString& ConnectedWiimotesString()
{
static wxString str;
str.Printf(_("%i connected"), WiimoteReal::Initialize());
return str;
}
WiimoteConfigDiag::WiimoteConfigDiag(wxWindow* const parent, InputPlugin& plugin)
: wxDialog(parent, -1, _("Dolphin Wiimote Configuration"), wxDefaultPosition, wxDefaultSize)
, m_plugin(plugin)
@ -64,27 +57,31 @@ WiimoteConfigDiag::WiimoteConfigDiag(wxWindow* const parent, InputPlugin& plugin
// "Real wiimotes" controls
connected_wiimotes_txt = new wxStaticText(this, -1, ConnectedWiimotesString());
wxButton* const refresh_btn = new wxButton(this, -1, _("Refresh"), wxDefaultPosition);
refresh_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &WiimoteConfigDiag::RefreshRealWiimotes, this);
#ifdef _WIN32
wxButton* const pairup_btn = new wxButton(this, -1, _("Pair Up"), wxDefaultPosition);
pairup_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &WiimoteConfigDiag::PairUpRealWiimotes, this);
#endif
wxStaticBoxSizer* const real_wiimotes_group = new wxStaticBoxSizer(wxVERTICAL, this, _("Real Wiimotes"));
wxBoxSizer* const real_wiimotes_sizer = new wxBoxSizer(wxHORIZONTAL);
if (!WiimoteReal::g_wiimote_scanner.IsReady())
real_wiimotes_group->Add(new wxStaticText(this, -1, _("A supported bluetooth device could not be found.\n"
"You must manually connect your wiimotes.")), 0, wxALIGN_CENTER | wxALL, 5);
wxCheckBox* const continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning"));
continuous_scanning->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &WiimoteConfigDiag::OnContinuousScanning, this);
continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning);
auto wiimote_speaker = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data"));
wiimote_speaker->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &WiimoteConfigDiag::OnEnableSpeaker, this);
wiimote_speaker->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker);
real_wiimotes_sizer->Add(continuous_scanning, 0, wxALIGN_CENTER_VERTICAL);
real_wiimotes_sizer->AddStretchSpacer(1);
real_wiimotes_sizer->Add(refresh_btn, 0, wxALL | wxALIGN_CENTER, 5);
// "Real wiimotes" layout
wxStaticBoxSizer* const real_wiimotes_group = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Real Wiimotes"));
wxFlexGridSizer* const real_wiimotes_sizer = new wxFlexGridSizer(3, 5, 5);
real_wiimotes_sizer->Add(connected_wiimotes_txt, 0, wxALIGN_CENTER_VERTICAL);
#ifdef _WIN32
real_wiimotes_sizer->Add(pairup_btn);
#endif
real_wiimotes_sizer->Add(refresh_btn);
real_wiimotes_group->Add(real_wiimotes_sizer, 1, wxALL, 5);
real_wiimotes_group->Add(wiimote_speaker, 0);
real_wiimotes_group->Add(real_wiimotes_sizer, 0, wxEXPAND);
// "General Settings" controls
const wxString str[] = { _("Bottom"), _("Top") };
@ -188,33 +185,9 @@ void WiimoteConfigDiag::ConfigEmulatedWiimote(wxCommandEvent& ev)
m_emu_config_diag->Destroy();
}
void WiimoteConfigDiag::UpdateGUI()
{
connected_wiimotes_txt->SetLabel(ConnectedWiimotesString());
}
#ifdef _WIN32
void WiimoteConfigDiag::PairUpRealWiimotes(wxCommandEvent&)
{
const int paired = WiimoteReal::PairUp();
if (paired > 0)
{
// TODO: Maybe add a label of newly paired up wiimotes?
WiimoteReal::Refresh();
UpdateGUI();
}
else if (paired < 0)
PanicAlertT("A supported bluetooth device could not be found!\n"
"If you are not using Microsoft's bluetooth stack "
"you must manually pair your wiimotes and use only the \"Refresh\" button.");
}
#endif
void WiimoteConfigDiag::RefreshRealWiimotes(wxCommandEvent&)
{
WiimoteReal::Refresh();
UpdateGUI();
}
void WiimoteConfigDiag::SelectSource(wxCommandEvent& event)
@ -222,30 +195,15 @@ 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();
}
void WiimoteConfigDiag::UpdateWiimoteStatus()
{
for (int index = 0; index < 4; ++index)
{
if (m_orig_wiimote_sources[index] != g_wiimote_sources[index])
{
// Disconnect first, otherwise the new source doesn't seem to work
CFrame::ConnectWiimote(index, false);
// Connect wiimotes
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());
}
}
}
void WiimoteConfigDiag::RevertSource()
{
for (int i = 0; i < 4; ++i)
@ -267,7 +225,6 @@ void WiimoteConfigDiag::Save(wxCommandEvent& event)
sec.Set("Source", (int)g_wiimote_sources[i]);
}
UpdateWiimoteStatus();
inifile.Save(ini_filename);

View File

@ -24,20 +24,13 @@ class WiimoteConfigDiag : public wxDialog
public:
WiimoteConfigDiag(wxWindow* const parent, InputPlugin& plugin);
#ifdef _WIN32
void PairUpRealWiimotes(wxCommandEvent& event);
#endif
void RefreshRealWiimotes(wxCommandEvent& event);
void SelectSource(wxCommandEvent& event);
void UpdateWiimoteStatus();
void RevertSource();
void ConfigEmulatedWiimote(wxCommandEvent& event);
void Save(wxCommandEvent& event);
void UpdateGUI();
void OnSensorBarPos(wxCommandEvent& event)
{
@ -64,6 +57,17 @@ public:
SConfig::GetInstance().m_WiimoteReconnectOnLoad = event.IsChecked();
event.Skip();
}
void OnContinuousScanning(wxCommandEvent& event)
{
SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked();
WiimoteReal::Initialize();
event.Skip();
}
void OnEnableSpeaker(wxCommandEvent& event)
{
SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked();
event.Skip();
}
private:
void Cancel(wxCommandEvent& event);
@ -76,8 +80,6 @@ private:
wxButton* wiimote_configure_bt[4];
std::map<wxWindowID, unsigned int> m_wiimote_index_from_conf_bt_id;
wxStaticText* connected_wiimotes_txt;
};

View File

@ -205,10 +205,6 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
OnKeyDown(lParam);
FreeLookInput((u32)wParam, lParam);
}
else if (wParam == WIIMOTE_DISCONNECT)
{
PostMessage(m_hParent, WM_USER, wParam, lParam);
}
break;
// Called when a screensaver wants to show up while this window is active