mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-08 21:53:31 +01:00
Merge branch 'comex-wiimote-fixes'
Should fix issue 6574.
This commit is contained in:
commit
2fb0147967
@ -43,12 +43,12 @@ bool WiimoteScanner::IsReady() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wiimote::Connect()
|
bool Wiimote::ConnectInternal()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::Disconnect()
|
void Wiimote::DisconnectInternal()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -58,6 +58,9 @@ bool Wiimote::IsConnected() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wiimote::IOWakeup()
|
||||||
|
{}
|
||||||
|
|
||||||
int Wiimote::IORead(u8* buf)
|
int Wiimote::IORead(u8* buf)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -27,8 +27,7 @@ namespace WiimoteReal
|
|||||||
{
|
{
|
||||||
|
|
||||||
WiimoteScanner::WiimoteScanner()
|
WiimoteScanner::WiimoteScanner()
|
||||||
: m_run_thread()
|
: m_want_wiimotes()
|
||||||
, m_want_wiimotes()
|
|
||||||
, device_id(-1)
|
, device_id(-1)
|
||||||
, device_sock(-1)
|
, device_sock(-1)
|
||||||
{
|
{
|
||||||
@ -135,7 +134,7 @@ void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connect to a wiimote with a known address.
|
// Connect to a wiimote with a known address.
|
||||||
bool Wiimote::Connect()
|
bool Wiimote::ConnectInternal()
|
||||||
{
|
{
|
||||||
sockaddr_l2 addr;
|
sockaddr_l2 addr;
|
||||||
addr.l2_family = AF_BLUETOOTH;
|
addr.l2_family = AF_BLUETOOTH;
|
||||||
@ -168,7 +167,7 @@ bool Wiimote::Connect()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::Disconnect()
|
void Wiimote::DisconnectInternal()
|
||||||
{
|
{
|
||||||
close(cmd_sock);
|
close(cmd_sock);
|
||||||
close(int_sock);
|
close(int_sock);
|
||||||
@ -182,26 +181,43 @@ bool Wiimote::IsConnected() const
|
|||||||
return cmd_sock != -1;// && int_sock != -1;
|
return cmd_sock != -1;// && int_sock != -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wiimote::IOWakeup()
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
if (write(wakeup_pipe_w, &c, 1) != 1)
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "Unable to write to wakeup pipe.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// positive = read packet
|
// positive = read packet
|
||||||
// negative = didn't read packet
|
// negative = didn't read packet
|
||||||
// zero = error
|
// zero = error
|
||||||
int Wiimote::IORead(u8* buf)
|
int Wiimote::IORead(u8* buf)
|
||||||
{
|
{
|
||||||
// Block select for 1/2000th of a second
|
// Block select for 1/2000th of a second
|
||||||
timeval tv;
|
|
||||||
tv.tv_sec = 0;
|
|
||||||
tv.tv_usec = WIIMOTE_DEFAULT_TIMEOUT * 1000;
|
|
||||||
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(int_sock, &fds);
|
FD_SET(int_sock, &fds);
|
||||||
|
FD_SET(wakeup_pipe_r, &fds);
|
||||||
|
|
||||||
if (select(int_sock + 1, &fds, NULL, NULL, &tv) == -1)
|
if (select(int_sock + 1, &fds, NULL, NULL, NULL) == -1)
|
||||||
{
|
{
|
||||||
ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1);
|
ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FD_ISSET(wakeup_pipe_r, &fds))
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
if (read(wakeup_pipe_r, &c, 1) != 1)
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "Unable to read from wakeup pipe.");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FD_ISSET(int_sock, &fds))
|
if (!FD_ISSET(int_sock, &fds))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -142,6 +142,7 @@ namespace WiimoteReal
|
|||||||
|
|
||||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, int len);
|
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, int len);
|
||||||
int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index);
|
int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index);
|
||||||
|
void _IOWakeup(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ProcessWiimotes(bool new_scan, T& callback);
|
void ProcessWiimotes(bool new_scan, T& callback);
|
||||||
@ -459,7 +460,7 @@ bool WiimoteScanner::IsReady() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connect to a wiimote with a known device path.
|
// Connect to a wiimote with a known device path.
|
||||||
bool Wiimote::Connect()
|
bool Wiimote::ConnectInternal()
|
||||||
{
|
{
|
||||||
if (IsConnected())
|
if (IsConnected())
|
||||||
return false;
|
return false;
|
||||||
@ -535,7 +536,7 @@ bool Wiimote::Connect()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::Disconnect()
|
void Wiimote::DisconnectInternal()
|
||||||
{
|
{
|
||||||
if (!IsConnected())
|
if (!IsConnected())
|
||||||
return;
|
return;
|
||||||
@ -557,6 +558,11 @@ bool Wiimote::IsConnected() const
|
|||||||
return dev_handle != 0;
|
return dev_handle != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _IOWakeup(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read)
|
||||||
|
{
|
||||||
|
CancelIoEx(dev_handle, &hid_overlap_read);
|
||||||
|
}
|
||||||
|
|
||||||
// positive = read packet
|
// positive = read packet
|
||||||
// negative = didn't read packet
|
// negative = didn't read packet
|
||||||
// zero = error
|
// zero = error
|
||||||
@ -575,7 +581,7 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index
|
|||||||
|
|
||||||
if (ERROR_IO_PENDING == read_err)
|
if (ERROR_IO_PENDING == read_err)
|
||||||
{
|
{
|
||||||
auto const wait_result = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
auto const wait_result = WaitForSingleObject(hid_overlap_read.hEvent, INFINITE);
|
||||||
if (WAIT_TIMEOUT == wait_result)
|
if (WAIT_TIMEOUT == wait_result)
|
||||||
{
|
{
|
||||||
CancelIo(dev_handle);
|
CancelIo(dev_handle);
|
||||||
@ -592,10 +598,10 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index
|
|||||||
|
|
||||||
if (ERROR_OPERATION_ABORTED == overlapped_err)
|
if (ERROR_OPERATION_ABORTED == overlapped_err)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
if (buf[1] != 0)
|
if (buf[1] != 0)
|
||||||
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).",
|
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem.");
|
||||||
WIIMOTE_DEFAULT_TIMEOUT);
|
*/
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +621,12 @@ int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index
|
|||||||
return bytes + 1;
|
return bytes + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wiimote::IOWakeup()
|
||||||
|
{
|
||||||
|
_IOWakeup(dev_handle, hid_overlap_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// positive = read packet
|
// positive = read packet
|
||||||
// negative = didn't read packet
|
// negative = didn't read packet
|
||||||
// zero = error
|
// zero = error
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
@interface SearchBT: NSObject {
|
@interface SearchBT: NSObject {
|
||||||
@public
|
@public
|
||||||
unsigned int maxDevices;
|
unsigned int maxDevices;
|
||||||
|
bool done;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -15,6 +16,7 @@
|
|||||||
error: (IOReturn) error
|
error: (IOReturn) error
|
||||||
aborted: (BOOL) aborted
|
aborted: (BOOL) aborted
|
||||||
{
|
{
|
||||||
|
done = true;
|
||||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +64,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wm->inputlen != 0) {
|
if (wm->inputlen != -1) {
|
||||||
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full",
|
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full",
|
||||||
wm->index + 1);
|
wm->index + 1);
|
||||||
return;
|
return;
|
||||||
@ -71,9 +73,8 @@
|
|||||||
memcpy(wm->input, data, length);
|
memcpy(wm->input, data, length);
|
||||||
wm->inputlen = length;
|
wm->inputlen = length;
|
||||||
|
|
||||||
(void)wm->Read();
|
|
||||||
|
|
||||||
(void)UpdateSystemActivity(UsrActivity);
|
(void)UpdateSystemActivity(UsrActivity);
|
||||||
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel
|
- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel
|
||||||
@ -98,7 +99,7 @@
|
|||||||
|
|
||||||
WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->index + 1);
|
WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->index + 1);
|
||||||
|
|
||||||
wm->Disconnect();
|
wm->DisconnectInternal();
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -139,14 +140,18 @@ void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimot
|
|||||||
[bti setDelegate: sbt];
|
[bti setDelegate: sbt];
|
||||||
[bti setInquiryLength: 2];
|
[bti setInquiryLength: 2];
|
||||||
|
|
||||||
if ([bti start] == kIOReturnSuccess)
|
if ([bti start] != kIOReturnSuccess)
|
||||||
[bti retain];
|
{
|
||||||
else
|
|
||||||
ERROR_LOG(WIIMOTE, "Unable to do bluetooth discovery");
|
ERROR_LOG(WIIMOTE, "Unable to do bluetooth discovery");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
CFRunLoopRun();
|
CFRunLoopRun();
|
||||||
|
}
|
||||||
|
while(!sbt->done);
|
||||||
|
|
||||||
[bti stop];
|
|
||||||
int found_devices = [[bti foundDevices] count];
|
int found_devices = [[bti foundDevices] count];
|
||||||
|
|
||||||
if (found_devices)
|
if (found_devices)
|
||||||
@ -160,7 +165,7 @@ void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimot
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Wiimote *wm = new Wiimote();
|
Wiimote *wm = new Wiimote();
|
||||||
wm->btd = dev;
|
wm->btd = [dev retain];
|
||||||
|
|
||||||
if(IsBalanceBoardName([[dev name] UTF8String]))
|
if(IsBalanceBoardName([[dev name] UTF8String]))
|
||||||
{
|
{
|
||||||
@ -184,32 +189,37 @@ bool WiimoteScanner::IsReady() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connect to a wiimote with a known address.
|
// Connect to a wiimote with a known address.
|
||||||
bool Wiimote::Connect()
|
bool Wiimote::ConnectInternal()
|
||||||
{
|
{
|
||||||
if (IsConnected())
|
if (IsConnected())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ConnectBT *cbt = [[ConnectBT alloc] init];
|
ConnectBT *cbt = [[ConnectBT alloc] init];
|
||||||
|
|
||||||
|
cchan = ichan = nil;
|
||||||
|
|
||||||
[btd openL2CAPChannelSync: &cchan
|
[btd openL2CAPChannelSync: &cchan
|
||||||
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
|
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
|
||||||
[btd openL2CAPChannelSync: &ichan
|
[btd openL2CAPChannelSync: &ichan
|
||||||
withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
|
withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
|
||||||
if (ichan == NULL || cchan == NULL)
|
// Apple docs claim:
|
||||||
|
// "The L2CAP channel object is already retained when this function returns
|
||||||
|
// success; the channel must be released when the caller is done with it."
|
||||||
|
// But without this, the channels get over-autoreleased, even though the
|
||||||
|
// refcounting behavior here is clearly correct.
|
||||||
|
[ichan retain];
|
||||||
|
[cchan retain];
|
||||||
|
if (ichan == nil || cchan == nil)
|
||||||
{
|
{
|
||||||
ERROR_LOG(WIIMOTE, "Unable to open L2CAP channels "
|
ERROR_LOG(WIIMOTE, "Unable to open L2CAP channels "
|
||||||
"for wiimote %i", index + 1);
|
"for wiimote %i", index + 1);
|
||||||
Disconnect();
|
DisconnectInternal();
|
||||||
|
|
||||||
[cbt release];
|
[cbt release];
|
||||||
|
[ichan release];
|
||||||
|
[cchan release];
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// As of 10.8 these need explicit retaining or writing to the wiimote has a very high
|
|
||||||
// chance of crashing and burning.
|
|
||||||
[ichan retain];
|
|
||||||
[cchan retain];
|
|
||||||
|
|
||||||
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s",
|
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s",
|
||||||
index + 1, [[btd addressString] UTF8String]);
|
index + 1, [[btd addressString] UTF8String]);
|
||||||
|
|
||||||
@ -220,21 +230,20 @@ bool Wiimote::Connect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect a wiimote.
|
// Disconnect a wiimote.
|
||||||
void Wiimote::Disconnect()
|
void Wiimote::DisconnectInternal()
|
||||||
{
|
{
|
||||||
if (btd != NULL)
|
[ichan closeChannel];
|
||||||
[btd closeConnection];
|
|
||||||
|
|
||||||
if (ichan != NULL)
|
|
||||||
[ichan release];
|
[ichan release];
|
||||||
|
|
||||||
if (cchan != NULL)
|
|
||||||
[cchan release];
|
|
||||||
|
|
||||||
btd = NULL;
|
|
||||||
cchan = NULL;
|
|
||||||
ichan = NULL;
|
ichan = NULL;
|
||||||
|
|
||||||
|
[cchan closeChannel];
|
||||||
|
[cchan release];
|
||||||
|
cchan = NULL;
|
||||||
|
|
||||||
|
[btd closeConnection];
|
||||||
|
[btd release];
|
||||||
|
btd = NULL;
|
||||||
|
|
||||||
if (!IsConnected())
|
if (!IsConnected())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -248,18 +257,19 @@ bool Wiimote::IsConnected() const
|
|||||||
return m_connected;
|
return m_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wiimote::IOWakeup()
|
||||||
|
{
|
||||||
|
CFRunLoopStop(m_wiimote_thread_run_loop);
|
||||||
|
}
|
||||||
|
|
||||||
int Wiimote::IORead(unsigned char *buf)
|
int Wiimote::IORead(unsigned char *buf)
|
||||||
{
|
{
|
||||||
int bytes;
|
input = buf;
|
||||||
|
inputlen = -1;
|
||||||
|
|
||||||
if (!IsConnected())
|
CFRunLoopRun();
|
||||||
return 0;
|
|
||||||
|
|
||||||
bytes = inputlen;
|
return inputlen;
|
||||||
memcpy(buf, input, bytes);
|
|
||||||
inputlen = 0;
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Wiimote::IOWrite(const unsigned char *buf, int len)
|
int Wiimote::IOWrite(const unsigned char *buf, int len)
|
||||||
|
@ -40,7 +40,7 @@ WiimoteScanner g_wiimote_scanner;
|
|||||||
Wiimote::Wiimote()
|
Wiimote::Wiimote()
|
||||||
: index()
|
: index()
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
, btd(), ichan(), cchan(), inputlen(), m_connected()
|
, btd(), ichan(), cchan(), input(), inputlen(), m_connected()
|
||||||
#elif defined(__linux__) && HAVE_BLUEZ
|
#elif defined(__linux__) && HAVE_BLUEZ
|
||||||
, cmd_sock(-1), int_sock(-1)
|
, cmd_sock(-1), int_sock(-1)
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
@ -49,9 +49,17 @@ Wiimote::Wiimote()
|
|||||||
, m_last_input_report()
|
, m_last_input_report()
|
||||||
, m_channel(0)
|
, m_channel(0)
|
||||||
, m_rumble_state()
|
, m_rumble_state()
|
||||||
, m_run_thread(false)
|
, m_need_prepare()
|
||||||
{
|
{
|
||||||
#if defined(__linux__) && HAVE_BLUEZ
|
#if defined(__linux__) && HAVE_BLUEZ
|
||||||
|
int fds[2];
|
||||||
|
if (pipe(fds))
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "pipe failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
wakeup_pipe_w = fds[1];
|
||||||
|
wakeup_pipe_r = fds[0];
|
||||||
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
|
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -59,12 +67,12 @@ Wiimote::Wiimote()
|
|||||||
Wiimote::~Wiimote()
|
Wiimote::~Wiimote()
|
||||||
{
|
{
|
||||||
StopThread();
|
StopThread();
|
||||||
|
|
||||||
if (IsConnected())
|
|
||||||
Disconnect();
|
|
||||||
|
|
||||||
ClearReadQueue();
|
ClearReadQueue();
|
||||||
m_write_reports.Clear();
|
m_write_reports.Clear();
|
||||||
|
#if defined(__linux__) && HAVE_BLUEZ
|
||||||
|
close(wakeup_pipe_w);
|
||||||
|
close(wakeup_pipe_r);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// to be called from CPU thread
|
// to be called from CPU thread
|
||||||
@ -85,6 +93,7 @@ void Wiimote::WriteReport(Report rpt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_write_reports.Push(std::move(rpt));
|
m_write_reports.Push(std::move(rpt));
|
||||||
|
IOWakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
// to be called from CPU thread
|
// to be called from CPU thread
|
||||||
@ -225,8 +234,8 @@ bool Wiimote::Read()
|
|||||||
}
|
}
|
||||||
else if (0 == result)
|
else if (0 == result)
|
||||||
{
|
{
|
||||||
WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", index + 1);
|
ERROR_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting Wiimote %d.", index + 1);
|
||||||
Disconnect();
|
DisconnectInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -308,21 +317,25 @@ void Wiimote::Update()
|
|||||||
rpt.data(), rpt.size());
|
rpt.data(), rpt.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wiimote::Prepare(int _index)
|
void Wiimote::Prepare(int _index)
|
||||||
{
|
{
|
||||||
index = _index;
|
index = _index;
|
||||||
|
m_need_prepare = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Wiimote::PrepareOnThread()
|
||||||
|
{
|
||||||
// core buttons, no continuous reporting
|
// core buttons, no continuous reporting
|
||||||
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE};
|
u8 static const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REPORT_MODE, 0, WM_REPORT_CORE};
|
||||||
|
|
||||||
// Set the active LEDs and turn on rumble.
|
// Set the active LEDs and turn on rumble.
|
||||||
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << (index%WIIMOTE_BALANCE_BOARD) | 0x1)};
|
u8 static const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_LEDS, u8(WIIMOTE_LED_1 << (index%WIIMOTE_BALANCE_BOARD) | 0x1)};
|
||||||
|
|
||||||
// Turn off rumble
|
// Turn off rumble
|
||||||
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0};
|
u8 static const rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_RUMBLE, 0};
|
||||||
|
|
||||||
// Request status report
|
// Request status report
|
||||||
u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
|
u8 static const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
|
||||||
// TODO: check for sane response?
|
// TODO: check for sane response?
|
||||||
|
|
||||||
return (IOWrite(mode_report, sizeof(mode_report))
|
return (IOWrite(mode_report, sizeof(mode_report))
|
||||||
@ -480,6 +493,14 @@ void WiimoteScanner::ThreadFunc()
|
|||||||
NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped.");
|
NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Wiimote::Connect()
|
||||||
|
{
|
||||||
|
m_thread_ready = false;
|
||||||
|
StartThread();
|
||||||
|
WaitReady();
|
||||||
|
return IsConnected();
|
||||||
|
}
|
||||||
|
|
||||||
void Wiimote::StartThread()
|
void Wiimote::StartThread()
|
||||||
{
|
{
|
||||||
m_run_thread = true;
|
m_run_thread = true;
|
||||||
@ -489,26 +510,69 @@ void Wiimote::StartThread()
|
|||||||
void Wiimote::StopThread()
|
void Wiimote::StopThread()
|
||||||
{
|
{
|
||||||
m_run_thread = false;
|
m_run_thread = false;
|
||||||
|
IOWakeup();
|
||||||
if (m_wiimote_thread.joinable())
|
if (m_wiimote_thread.joinable())
|
||||||
m_wiimote_thread.join();
|
m_wiimote_thread.join();
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
CFRelease(m_wiimote_thread_run_loop);
|
||||||
|
m_wiimote_thread_run_loop = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::SetReady()
|
||||||
|
{
|
||||||
|
if (!m_thread_ready)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> Guard(m_thread_ready_mutex);
|
||||||
|
m_thread_ready = true;
|
||||||
|
}
|
||||||
|
m_thread_ready_cond.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::WaitReady()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_thread_ready_mutex);
|
||||||
|
while (!m_thread_ready)
|
||||||
|
{
|
||||||
|
m_thread_ready_cond.wait(lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::ThreadFunc()
|
void Wiimote::ThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("Wiimote Device Thread");
|
Common::SetCurrentThreadName("Wiimote Device Thread");
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
m_wiimote_thread_run_loop = (CFRunLoopRef) CFRetain(CFRunLoopGetCurrent());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool ok = ConnectInternal();
|
||||||
|
|
||||||
|
SetReady();
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
while (m_run_thread && IsConnected())
|
while (IsConnected() && m_run_thread)
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
if (m_need_prepare)
|
||||||
// Reading happens elsewhere on OSX
|
{
|
||||||
bool const did_something = Write();
|
m_need_prepare = false;
|
||||||
#else
|
if (!PrepareOnThread())
|
||||||
bool const did_something = Write() || Read();
|
{
|
||||||
#endif
|
ERROR_LOG(WIIMOTE, "Wiimote::PrepareOnThread failed. Disconnecting Wiimote %d.", index + 1);
|
||||||
if (!did_something)
|
DisconnectInternal();
|
||||||
Common::SleepCurrentThread(1);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Write();
|
||||||
|
Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
DisconnectInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadSettings()
|
void LoadSettings()
|
||||||
@ -629,24 +693,32 @@ void ChangeWiimoteSource(unsigned int index, int source)
|
|||||||
Host_ConnectWiimote(index, true);
|
Host_ConnectWiimote(index, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool TryToConnectWiimoteN(Wiimote* wm, unsigned int i)
|
||||||
|
{
|
||||||
|
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]
|
||||||
|
&& !g_wiimotes[i])
|
||||||
|
{
|
||||||
|
if (wm->Connect())
|
||||||
|
{
|
||||||
|
wm->Prepare(i);
|
||||||
|
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1);
|
||||||
|
g_wiimotes[i] = wm;
|
||||||
|
Host_ConnectWiimote(i, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void TryToConnectWiimote(Wiimote* wm)
|
void TryToConnectWiimote(Wiimote* wm)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
|
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||||
{
|
{
|
||||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]
|
if (TryToConnectWiimoteN(wm, i))
|
||||||
&& !g_wiimotes[i])
|
|
||||||
{
|
{
|
||||||
if (wm->Connect() && wm->Prepare(i))
|
wm = NULL;
|
||||||
{
|
|
||||||
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i.", i + 1);
|
|
||||||
|
|
||||||
std::swap(g_wiimotes[i], wm);
|
|
||||||
g_wiimotes[i]->StartThread();
|
|
||||||
|
|
||||||
Host_ConnectWiimote(i, true);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -662,18 +734,9 @@ void TryToConnectBalanceBoard(Wiimote* wm)
|
|||||||
{
|
{
|
||||||
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
|
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
|
||||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[WIIMOTE_BALANCE_BOARD]
|
if (TryToConnectWiimoteN(wm, WIIMOTE_BALANCE_BOARD))
|
||||||
&& !g_wiimotes[WIIMOTE_BALANCE_BOARD])
|
|
||||||
{
|
{
|
||||||
if (wm->Connect() && wm->Prepare(WIIMOTE_BALANCE_BOARD))
|
wm = NULL;
|
||||||
{
|
|
||||||
NOTICE_LOG(WIIMOTE, "Connected to Balance Board %i.", WIIMOTE_BALANCE_BOARD + 1);
|
|
||||||
|
|
||||||
std::swap(g_wiimotes[WIIMOTE_BALANCE_BOARD], wm);
|
|
||||||
g_wiimotes[WIIMOTE_BALANCE_BOARD]->StartThread();
|
|
||||||
|
|
||||||
Host_ConnectWiimote(WIIMOTE_BALANCE_BOARD, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_wiimote_scanner.WantBB(0 != CalculateWantedBB());
|
g_wiimote_scanner.WantBB(0 != CalculateWantedBB());
|
||||||
@ -687,26 +750,13 @@ void DoneWithWiimote(int index)
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
|
||||||
if (g_wiimotes[index])
|
Wiimote* wm = g_wiimotes[index];
|
||||||
{
|
|
||||||
g_wiimotes[index]->StopThread();
|
|
||||||
|
|
||||||
|
if (wm)
|
||||||
|
{
|
||||||
|
g_wiimotes[index] = NULL;
|
||||||
// First see if we can use this real Wiimote in another slot.
|
// First see if we can use this real Wiimote in another slot.
|
||||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
TryToConnectWiimote(wm);
|
||||||
{
|
|
||||||
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
|
// else, just disconnect the Wiimote
|
||||||
@ -763,9 +813,7 @@ void Refresh()
|
|||||||
{
|
{
|
||||||
if (g_wiimotes[i])
|
if (g_wiimotes[i])
|
||||||
{
|
{
|
||||||
g_wiimotes[i]->StopThread();
|
|
||||||
g_wiimotes[i]->Prepare(i);
|
g_wiimotes[i]->Prepare(i);
|
||||||
g_wiimotes[i]->StartThread();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,13 +52,17 @@ public:
|
|||||||
|
|
||||||
// connecting and disconnecting from physical devices
|
// connecting and disconnecting from physical devices
|
||||||
// (using address inserted by FindWiimotes)
|
// (using address inserted by FindWiimotes)
|
||||||
|
// these are called from the wiimote's thread.
|
||||||
|
bool ConnectInternal();
|
||||||
|
void DisconnectInternal();
|
||||||
|
|
||||||
bool Connect();
|
bool Connect();
|
||||||
void Disconnect();
|
|
||||||
|
|
||||||
// TODO: change to something like IsRelevant
|
// TODO: change to something like IsRelevant
|
||||||
bool IsConnected() const;
|
bool IsConnected() const;
|
||||||
|
|
||||||
bool Prepare(int index);
|
void Prepare(int index);
|
||||||
|
bool PrepareOnThread();
|
||||||
|
|
||||||
void DisableDataReporting();
|
void DisableDataReporting();
|
||||||
void EnableDataReporting(u8 mode);
|
void EnableDataReporting(u8 mode);
|
||||||
@ -72,13 +76,15 @@ public:
|
|||||||
IOBluetoothDevice *btd;
|
IOBluetoothDevice *btd;
|
||||||
IOBluetoothL2CAPChannel *ichan;
|
IOBluetoothL2CAPChannel *ichan;
|
||||||
IOBluetoothL2CAPChannel *cchan;
|
IOBluetoothL2CAPChannel *cchan;
|
||||||
char input[MAX_PAYLOAD];
|
unsigned char* input;
|
||||||
int inputlen;
|
int inputlen;
|
||||||
bool m_connected;
|
bool m_connected;
|
||||||
|
CFRunLoopRef m_wiimote_thread_run_loop;
|
||||||
#elif defined(__linux__) && HAVE_BLUEZ
|
#elif defined(__linux__) && HAVE_BLUEZ
|
||||||
bdaddr_t bdaddr; // Bluetooth address
|
bdaddr_t bdaddr; // Bluetooth address
|
||||||
int cmd_sock; // Command socket
|
int cmd_sock; // Command socket
|
||||||
int int_sock; // Interrupt socket
|
int int_sock; // Interrupt socket
|
||||||
|
int wakeup_pipe_w, wakeup_pipe_r;
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
std::basic_string<TCHAR> devicepath; // Unique wiimote reference
|
std::basic_string<TCHAR> devicepath; // Unique wiimote reference
|
||||||
@ -98,13 +104,23 @@ private:
|
|||||||
|
|
||||||
int IORead(u8* buf);
|
int IORead(u8* buf);
|
||||||
int IOWrite(u8 const* buf, int len);
|
int IOWrite(u8 const* buf, int len);
|
||||||
|
void IOWakeup();
|
||||||
|
|
||||||
void ThreadFunc();
|
void ThreadFunc();
|
||||||
|
void SetReady();
|
||||||
|
void WaitReady();
|
||||||
|
|
||||||
bool m_rumble_state;
|
bool m_rumble_state;
|
||||||
|
|
||||||
bool m_run_thread;
|
|
||||||
std::thread m_wiimote_thread;
|
std::thread m_wiimote_thread;
|
||||||
|
// Whether to keep running the thread.
|
||||||
|
volatile bool m_run_thread;
|
||||||
|
// Whether to call PrepareOnThread.
|
||||||
|
volatile bool m_need_prepare;
|
||||||
|
// Whether the thread has finished ConnectInternal.
|
||||||
|
volatile bool m_thread_ready;
|
||||||
|
std::mutex m_thread_ready_mutex;
|
||||||
|
std::condition_variable m_thread_ready_cond;
|
||||||
|
|
||||||
Common::FifoQueue<Report> m_read_reports;
|
Common::FifoQueue<Report> m_read_reports;
|
||||||
Common::FifoQueue<Report> m_write_reports;
|
Common::FifoQueue<Report> m_write_reports;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user