With the more aggressive polling by the per-wiimote threads,

additional input queueing in IOdarwin appears to be unnecessary.

IOBluetoothDeviceInquiry does not find already connected devices,
so no need to filter those out.


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6710 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Soren Jorvang 2011-01-01 16:46:41 +00:00
parent 0732c337c5
commit 8b55eff33d
5 changed files with 46 additions and 377 deletions

View File

@ -36,9 +36,9 @@ void Wiimote::RealDisconnect()
return;
}
u8 *Wiimote::IORead()
int Wiimote::IORead(unsigned char* buf)
{
return NULL;
return 0;
}
int Wiimote::IOWrite(unsigned char* buf, int len)

View File

@ -1,298 +0,0 @@
#import <CoreServices/CoreServices.h>
extern "C" OSErr UpdateSystemActivity(UInt8 activity);
#define BLUETOOTH_VERSION_USE_CURRENT
#import <IOBluetooth/IOBluetooth.h>
#include "Common.h"
#include "../Wiimote.h"
#include "WiimoteReal.h"
@interface SearchBT: NSObject
{
@public
unsigned int maxDevices;
}
@end
@implementation SearchBT
- (void) deviceInquiryComplete: (IOBluetoothDeviceInquiry *) sender
error: (IOReturn) error
aborted: (BOOL) aborted
{
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void) deviceInquiryDeviceFound: (IOBluetoothDeviceInquiry *) sender
device: (IOBluetoothDevice *) device
{
NOTICE_LOG(WIIMOTE, "Discovered bluetooth device at %s: %s",
[[device getAddressString] UTF8String],
[[device getName] UTF8String]);
if ([[sender foundDevices] count] == maxDevices)
[sender stop];
}
@end
@interface ConnectBT: NSObject {}
@end
@implementation ConnectBT
- (void) l2capChannelData: (IOBluetoothL2CAPChannel *) l2capChannel
data: (unsigned char *) data
length: (NSUInteger) length
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
for (int i = 0; i < MAX_WIIMOTES; i++)
{
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
wm = WiimoteReal::g_wiimotes[i];
}
if (wm == NULL)
{
WARN_LOG(WIIMOTE, "Received packet for unknown wiimote");
return;
}
if (length > MAX_PAYLOAD)
{
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, too large",
wm->index + 1);
return;
}
if (wm->queue[wm->writer].len != 0)
{
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full",
wm->index + 1);
return;
}
memcpy(wm->queue[wm->writer].data, data, length);
wm->queue[wm->writer].len = length;
wm->writer++;
wm->outstanding++;
if (wm->writer == QUEUE_SIZE)
wm->writer = 0;
if (wm->outstanding > wm->watermark)
{
wm->watermark = wm->outstanding;
WARN_LOG(WIIMOTE, "New queue watermark %i for wiimote %i",
wm->watermark, wm->index + 1);
}
CFRunLoopStop(CFRunLoopGetCurrent());
(void)UpdateSystemActivity(1);
}
- (void) l2capChannelClosed: (IOBluetoothL2CAPChannel *) l2capChannel
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
for (int i = 0; i < MAX_WIIMOTES; i++)
{
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
wm = WiimoteReal::g_wiimotes[i];
}
if (wm == NULL)
{
WARN_LOG(WIIMOTE, "Received packet for unknown wiimote");
return;
}
WARN_LOG(WIIMOTE, "L2CAP channel was closed for wiimote %i", wm->index + 1);
if (l2capChannel == wm->cchan)
wm->cchan = nil;
if (l2capChannel == wm->ichan)
wm->ichan = nil;
}
@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)
{
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)
{
WARN_LOG(WIIMOTE, "No bluetooth host controller");
[bth release];
return found_wiimotes;
}
sbt = [[SearchBT alloc] init];
sbt->maxDevices = max_wiimotes;
bti = [[IOBluetoothDeviceInquiry alloc] init];
[bti setDelegate: sbt];
[bti setInquiryLength: 5];
[bti setSearchCriteria: kBluetoothServiceClassMajorAny
majorDeviceClass: kBluetoothDeviceClassMajorPeripheral
minorDeviceClass: kBluetoothDeviceClassMinorPeripheral2Joystick
];
[bti setUpdateNewDeviceNames: FALSE];
if ([bti start] == kIOReturnSuccess)
[bti retain];
else
ERROR_LOG(WIIMOTE, "Unable to do bluetooth discovery");
CFRunLoopRun();
[bti stop];
found_devices = [[bti foundDevices] count];
NOTICE_LOG(WIIMOTE, "Found %i bluetooth device%c", found_devices,
found_devices == 1 ? '\0' : 's');
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); i++)
{
IOBluetoothDevice *tmp_btd = [en nextObject];
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] && [tmp_btd isEqual: wm[j]->btd] == TRUE)
new_wiimote = false;
}
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);
wm[k]->btd = tmp_btd;
found_wiimotes++;
}
}
[bth release];
[bti release];
[sbt release];
return found_wiimotes;
}
// Connect to a wiimote with a known address.
bool Wiimote::Connect()
{
ConnectBT *cbt = [[ConnectBT alloc] init];
if (IsConnected()) return false;
[btd openL2CAPChannelSync: &cchan
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
[btd openL2CAPChannelSync: &ichan
withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
if (ichan == NULL || cchan == NULL)
{
ERROR_LOG(WIIMOTE, "Unable to open L2CAP channels for wiimote %i",
index + 1);
RealDisconnect();
return false;
}
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s",
index + 1, [[btd getAddressString] UTF8String]);
m_connected = true;
Handshake();
SetLEDs(WIIMOTE_LED_1 << index);
[cbt release];
return true;
}
// Disconnect a wiimote.
void Wiimote::RealDisconnect()
{
if (!IsConnected())
return;
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", index + 1);
m_connected = false;
[cchan closeChannel];
[ichan closeChannel];
[btd closeConnection];
}
unsigned char *Wiimote::IORead()
{
int bytes;
if (!IsConnected())
return NULL;
if (outstanding == 0)
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, true);
if (queue[reader].len == 0)
return 0;
bytes = queue[reader].len;
unsigned char *buffer = new unsigned char[MAX_PAYLOAD];
memcpy(buffer, queue[reader].data, bytes);
queue[reader].len = 0;
reader++;
outstanding--;
if (reader == QUEUE_SIZE)
reader = 0;
if (buffer[0] == '\0')
bytes = 0;
return buffer;
}
int Wiimote::IOWrite(unsigned char* buf, int len)
{
IOReturn ret;
ret = [cchan writeAsync: buf length: len refcon: nil];
if (ret == kIOReturnSuccess)
return len;
else
return 0;
}
};

View File

@ -49,8 +49,9 @@ extern "C" OSErr UpdateSystemActivity(UInt8 activity);
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
wm = WiimoteReal::g_wiimotes[i];
}
if (wm == NULL) {
WARN_LOG(WIIMOTE, "Received packet for unknown wiimote");
ERROR_LOG(WIIMOTE, "Received packet for unknown wiimote");
return;
}
@ -60,25 +61,14 @@ extern "C" OSErr UpdateSystemActivity(UInt8 activity);
return;
}
if (wm->queue[wm->writer].len != 0) {
if (wm->inputlen != 0) {
WARN_LOG(WIIMOTE, "Dropping packet for wiimote %i, queue full",
wm->index + 1);
return;
}
memcpy(wm->queue[wm->writer].data, data, length);
wm->queue[wm->writer].len = length;
wm->writer++;
wm->outstanding++;
if (wm->writer == QUEUE_SIZE)
wm->writer = 0;
if (wm->outstanding > wm->watermark) {
wm->watermark = wm->outstanding;
WARN_LOG(WIIMOTE, "New queue watermark %i for wiimote %i",
wm->watermark, wm->index + 1);
}
memcpy(wm->input, data, length);
wm->inputlen = length;
CFRunLoopStop(CFRunLoopGetCurrent());
@ -96,19 +86,20 @@ extern "C" OSErr UpdateSystemActivity(UInt8 activity);
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
wm = WiimoteReal::g_wiimotes[i];
}
if (wm == NULL) {
WARN_LOG(WIIMOTE, "Received packet for unknown wiimote");
ERROR_LOG(WIIMOTE, "Channel for unknown wiimote was closed");
return;
}
WARN_LOG(WIIMOTE, "L2CAP channel was closed for wiimote %i",
wm->index + 1);
WARN_LOG(WIIMOTE, "Connection to wiimote %i closed", wm->index + 1);
if (l2capChannel == wm->cchan)
wm->cchan = nil;
[wm->btd closeConnection];
if (l2capChannel == wm->ichan)
wm->ichan = nil;
wm->btd = NULL;
wm->cchan = NULL;
wm->ichan = NULL;
wm->m_connected = false;
}
@end
@ -163,25 +154,18 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
found_devices == 1 ? '\0' : 's');
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); i++) {
IOBluetoothDevice *tmp_btd = [en nextObject];
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] && [tmp_btd isEqual: wm[j]->btd] == TRUE)
new_wiimote = false;
}
if (new_wiimote) {
for (int i = 0; i < found_devices; i++)
{
// Find an unused slot
unsigned int k = 0;
for ( ; k < MAX_WIIMOTES &&
!(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k)
{};
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 = tmp_btd;
wm[k]->btd = [en nextObject];
found_wiimotes++;
break;
}
}
@ -232,11 +216,12 @@ void Wiimote::RealDisconnect()
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", index + 1);
m_connected = false;
[cchan closeChannel];
[ichan closeChannel];
[btd closeConnection];
btd = NULL;
cchan = NULL;
ichan = NULL;
m_connected = false;
}
int Wiimote::IORead(unsigned char *buf)
@ -246,23 +231,14 @@ int Wiimote::IORead(unsigned char *buf)
if (!IsConnected())
return 0;
if (outstanding == 0)
if (inputlen == 0) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, true);
if (queue[reader].len == 0)
return 0;
}
bytes = queue[reader].len;
memcpy(buf, queue[reader].data, bytes);
queue[reader].len = 0;
reader++;
outstanding--;
if (reader == QUEUE_SIZE)
reader = 0;
if (buf[0] == '\0')
bytes = 0;
bytes = inputlen;
memcpy(buf, input, bytes);
inputlen = 0;
return bytes;
}
@ -271,6 +247,9 @@ int Wiimote::IOWrite(unsigned char *buf, int len)
{
IOReturn ret;
if (!IsConnected())
return 0;
ret = [cchan writeAsync: buf length: len refcon: nil];
if (ret == kIOReturnSuccess)

View File

@ -50,24 +50,20 @@ Wiimote *g_wiimotes[MAX_WIIMOTES];
Wiimote::Wiimote(const unsigned int _index)
: index(_index)
#if defined(__linux__) && HAVE_BLUEZ
#ifdef __APPLE__
, inputlen(0)
#elif defined(__linux__) && HAVE_BLUEZ
, out_sock(-1), in_sock(-1)
#elif defined(_WIN32)
, dev_handle(0), stack(MSBT_STACK_UNKNOWN)
#endif
, leds(0), m_channel(0), m_connected(false)
, leds(0)
, m_connected(false), m_last_data_report(Report(NULL, 0)), m_channel(0)
{
#ifdef __APPLE__
memset(queue, 0, sizeof queue);
reader = 0;
writer = 0;
outstanding = 0;
watermark = 0;
#elif defined(__linux__) && HAVE_BLUEZ
#if defined(__linux__) && HAVE_BLUEZ
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
#endif
ClearReadQueue();
DisableDataReporting();
}

View File

@ -71,16 +71,8 @@ public:
IOBluetoothDevice *btd;
IOBluetoothL2CAPChannel *ichan;
IOBluetoothL2CAPChannel *cchan;
#define QUEUE_SIZE 64
struct qbuffer
{
char data[MAX_PAYLOAD];
int len;
} queue[QUEUE_SIZE];
int reader;
int writer;
int outstanding;
int watermark;
char input[MAX_PAYLOAD];
int inputlen;
#elif defined(__linux__) && HAVE_BLUEZ
bdaddr_t bdaddr; // Bluetooth address
int out_sock; // Output socket
@ -94,6 +86,7 @@ public:
#endif
unsigned char leds; // Currently lit leds
bool m_connected;
protected:
Report m_last_data_report;
u16 m_channel;
@ -107,7 +100,6 @@ private:
int IORead(unsigned char* buf);
int IOWrite(unsigned char* buf, int len);
bool m_connected;
Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
};