mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 05:47:56 -07:00
Make real wiimotes not so crappy on Windows hopefully.
This commit is contained in:
parent
50c83d614c
commit
05ec90488b
@ -29,7 +29,10 @@ WiimoteScanner::WiimoteScanner()
|
||||
WiimoteScanner::~WiimoteScanner()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes(size_t max_wiimotes)
|
||||
void WiimoteScanner::Update()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
{
|
||||
return std::vector<Wiimote*>();
|
||||
}
|
||||
|
@ -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<Wiimote*> WiimoteScanner::FindWiimotes(size_t max_wiimotes)
|
||||
void WiimoteScanner::Update()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
{
|
||||
std::vector<Wiimote*> found_wiimotes;
|
||||
|
||||
@ -86,7 +85,7 @@ std::vector<Wiimote*> 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...");
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <regex>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbt.h>
|
||||
@ -73,6 +74,8 @@ HINSTANCE bthprops_lib = NULL;
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
static std::unordered_set<std::string> 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 <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()
|
||||
{
|
||||
@ -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<Wiimote*> WiimoteScanner::FindWiimotes(size_t max_wiimotes)
|
||||
std::vector<Wiimote*> 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<Wiimote*> WiimoteScanner::FindWiimotes(size_t max_wiimotes)
|
||||
device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
|
||||
|
||||
std::vector<Wiimote*> 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<Wiimote*> 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 <typename T>
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -111,7 +111,10 @@ WiimoteScanner::WiimoteScanner()
|
||||
WiimoteScanner::~WiimoteScanner()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes(size_t max_wiimotes)
|
||||
void WiimoteScanner::Update()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
{
|
||||
// TODO: find the device in the constructor and save it for later
|
||||
|
||||
@ -130,7 +133,7 @@ std::vector<Wiimote*> 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<Wiimote*> 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];
|
||||
|
@ -35,7 +35,7 @@ namespace WiimoteReal
|
||||
{
|
||||
|
||||
void HandleFoundWiimotes(const std::vector<Wiimote*>&);
|
||||
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<std::recursive_mutex> 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<Wiimote*> found_wiimotes;
|
||||
|
||||
//NOTICE_LOG(WIIMOTE, "in loop");
|
||||
|
||||
if (m_want_wiimotes)
|
||||
found_wiimotes = FindWiimotes();
|
||||
else
|
||||
{
|
||||
// TODO: this code here is ugly
|
||||
std::lock_guard<std::recursive_mutex> 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<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])
|
||||
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<std::recursive_mutex> lk(g_refresh_lock);
|
||||
std::lock_guard<std::recursive_mutex> 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<Wiimote*>& 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<std::recursive_mutex> 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();
|
||||
|
@ -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<Report> m_read_reports;
|
||||
Common::FifoQueue<Report> 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<Wiimote*> FindWiimotes(size_t max_wiimotes);
|
||||
std::vector<Wiimote*> 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)
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user