Try to improve real wiimotes on Windows.

This commit is contained in:
Jordan Woyak 2013-02-11 15:21:58 -06:00
parent b8fd5c0c30
commit c2d2fb8c7c
3 changed files with 112 additions and 72 deletions

View File

@ -270,10 +270,22 @@ bool Wiimote::Connect()
return false;
}
hid_overlap = OVERLAPPED();
hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T(""));
hid_overlap.Offset = 0;
hid_overlap.OffsetHigh = 0;
#if 0
HIDD_ATTRIBUTES attr;
attr.Size = sizeof(attr);
if (!HidD_GetAttributes(dev_handle, &attr))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
#endif
hid_overlap_read = OVERLAPPED();
hid_overlap_read.hEvent = CreateEvent(NULL, true, false, NULL);
hid_overlap_write = OVERLAPPED();
hid_overlap_write.hEvent = CreateEvent(NULL, true, false, NULL);
// TODO: thread isn't started here now, do this elsewhere
// This isn't as drastic as it sounds, since the process in which the threads
@ -296,7 +308,8 @@ void Wiimote::Disconnect()
CloseHandle(dev_handle);
dev_handle = 0;
CloseHandle(hid_overlap.hEvent);
CloseHandle(hid_overlap_read.hEvent);
CloseHandle(hid_overlap_write.hEvent);
}
bool Wiimote::IsConnected() const
@ -307,20 +320,20 @@ bool Wiimote::IsConnected() const
// positive = read packet
// negative = didn't read packet
// zero = error
int Wiimote::IORead(unsigned char* buf)
int Wiimote::IORead(u8* buf)
{
// used below for a warning
*buf = 0;
DWORD bytes;
ResetEvent(hid_overlap.hEvent);
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap))
ResetEvent(hid_overlap_read.hEvent);
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
{
auto const err = GetLastError();
if (ERROR_IO_PENDING == err)
{
auto const r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
auto const r = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
if (WAIT_TIMEOUT == r)
{
// Timeout - cancel and continue
@ -338,7 +351,7 @@ int Wiimote::IORead(unsigned char* buf)
}
else if (WAIT_OBJECT_0 == r)
{
if (!GetOverlappedResult(dev_handle, &hid_overlap, &bytes, TRUE))
if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE))
{
WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1);
bytes = 0;
@ -380,70 +393,76 @@ int Wiimote::IORead(unsigned char* buf)
int Wiimote::IOWrite(const u8* buf, int len)
{
u8 big_buf[MAX_PAYLOAD];
if (len < MAX_PAYLOAD)
{
std::copy(buf, buf + len, big_buf);
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
buf = big_buf;
}
DWORD bytes = 0;
switch (stack)
{
case MSBT_STACK_UNKNOWN:
{
// Try to auto-detect the stack type
auto i = WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap);
if (i)
stack = MSBT_STACK_BLUESOLEIL;
if (IOWrite(buf, len))
return 1;
stack = MSBT_STACK_MS;
if (IOWrite(buf, len))
{
// Bluesoleil will always return 1 here, even if it's not connected
stack = MSBT_STACK_BLUESOLEIL;
return i;
// Don't mind me, just a random sleep to fix stuff on Windows
SLEEP(1000);
return 1;
}
i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1);
if (i)
{
stack = MSBT_STACK_MS;
return i;
}
auto const dw = GetLastError();
// Checking for 121 = timeout on semaphore/device off/disconnected to
// avoid trouble with other stacks toshiba/widcomm
if (dw == 121)
{
NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: Timeout");
return 0;
}
else
{
ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw);
return 0;
}
stack = MSBT_STACK_UNKNOWN;
break;
}
case MSBT_STACK_MS:
{
auto i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1);
auto dw = GetLastError();
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
//FlushFileBuffers(dev_handle);
if (dw == 121)
if (!result)
{
// Semaphore timeout
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
return 0;
auto err = GetLastError();
if (err == 121)
{
// Semaphore timeout
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
}
else
{
ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
}
}
return i;
return result;
break;
}
case MSBT_STACK_BLUESOLEIL:
return WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap);
{
u8 big_buf[MAX_PAYLOAD];
if (len < MAX_PAYLOAD)
{
std::copy(buf, buf + len, big_buf);
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
buf = big_buf;
}
ResetEvent(hid_overlap_write.hEvent);
DWORD bytes = 0;
if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write))
{
// WriteFile always returns true with bluesoleil.
return 1;
}
else
{
auto const err = GetLastError();
if (ERROR_IO_PENDING == err)
{
CancelIo(dev_handle);
}
}
break;
}
}
return 0;
}
@ -555,6 +574,7 @@ bool ForgetWiimote(HANDLE, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
// We don't want "remembered" devices.
// SetServiceState seems to just fail with them.
// Make Windows forget about them.
// This is also required to detect a disconnect for some reason..
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
Bth_BluetoothRemoveDevice(&btdi.Address);

View File

@ -232,6 +232,12 @@ Report Wiimote::ProcessReadQueue()
void Wiimote::Update()
{
if (!IsConnected())
{
HandleWiimoteDisconnect(index);
return;
}
// Pop through the queued reports
Report const rpt = ProcessReadQueue();
@ -252,18 +258,17 @@ bool Wiimote::Prepare(int _index)
// core buttons, no continuous reporting
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30};
// Set the active LEDs.
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index)};
// Set the active LEDs and turn on rumble.
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index) | 0x1};
// Rumble briefly
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 1};
// Turn off rumble
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0};
// TODO: request status and check for sane response?
return (IOWrite(mode_report, sizeof(mode_report))
&& IOWrite(led_report, sizeof(led_report))
&& IOWrite(rumble_report, sizeof(rumble_report))
&& (rumble_report[2] = 0, SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))));
&& (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))));
}
void Wiimote::EmuStart()
@ -375,6 +380,8 @@ void Wiimote::ThreadFunc()
{
Common::SetCurrentThreadName("Wiimote Device Thread");
Host_ConnectWiimote(index, true);
// main loop
while (m_run_thread && IsConnected())
{
@ -408,13 +415,13 @@ void LoadSettings()
void Initialize()
{
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_real_wiimotes_initialized)
return;
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
g_wiimote_scanner.StartScanning();
@ -423,9 +430,7 @@ void Initialize()
}
void Shutdown(void)
{
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
{
g_wiimote_scanner.StopScanning();
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
@ -433,6 +438,8 @@ void Shutdown(void)
if (!g_real_wiimotes_initialized)
return;
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
g_real_wiimotes_initialized = false;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
@ -466,8 +473,6 @@ void TryToConnectWiimote(Wiimote* wm)
g_wiimotes[i] = wm;
wm->StartThread();
Host_ConnectWiimote(i, true);
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1);
@ -485,8 +490,6 @@ void HandleWiimoteDisconnect(int index)
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
Host_ConnectWiimote(index, false);
if (g_wiimotes[index])
{
delete g_wiimotes[index];
@ -511,12 +514,24 @@ void Refresh()
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
CheckForDisconnectedWiimotes();
std::vector<Wiimote*> found_wiimotes;
if (0 != CalculateWantedWiimotes())
{
HandleFoundWiimotes(g_wiimote_scanner.FindWiimotes());
found_wiimotes = g_wiimote_scanner.FindWiimotes();
}
CheckForDisconnectedWiimotes();
// Brief rumble for already connected wiimotes.
for (int i = 0; i != MAX_WIIMOTES; ++i)
{
// kinda sloppy
if (g_wiimotes[i])
g_wiimotes[i]->Prepare(i);
}
HandleFoundWiimotes(found_wiimotes);
}
g_wiimote_scanner.StartScanning();
@ -546,8 +561,13 @@ void Update(int _WiimoteNumber)
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->Update();
else
// Wiimote::Update() may remove the wiimote if it was disconnected.
if (!g_wiimotes[_WiimoteNumber])
{
NOTICE_LOG(WIIMOTE, "Emulating disconnect of wiimote %d.", _WiimoteNumber + 1);
Host_ConnectWiimote(_WiimoteNumber, false);
}
}
void StateChange(EMUSTATE_CHANGE newState)

View File

@ -96,7 +96,7 @@ public:
std::string devicepath; // Unique wiimote reference
//ULONGLONG btaddr; // Bluetooth address
HANDLE dev_handle; // HID handle
OVERLAPPED hid_overlap; // Overlap handle
OVERLAPPED hid_overlap_read, hid_overlap_write; // Overlap handle
enum win_bt_stack_t stack; // Type of bluetooth stack to use
#endif