From 7d9c82f6042df4bfbc193c28f0b4274621cface9 Mon Sep 17 00:00:00 2001 From: Lysann Schlegel Date: Sat, 10 Nov 2012 18:31:00 +0100 Subject: [PATCH] implement wiiuse_os_connect for mac --- src/os_mac.m | 143 ++++++++++++++++++++++++++++++++++++++- src/os_mac/os_mac.h | 34 ++++++++++ src/os_mac/os_mac_find.m | 15 ++-- src/wiiuse.h | 5 +- 4 files changed, 188 insertions(+), 9 deletions(-) diff --git a/src/os_mac.m b/src/os_mac.m index 355f125..17c2662 100644 --- a/src/os_mac.m +++ b/src/os_mac.m @@ -39,8 +39,6 @@ #import "events.h" #import "os.h" - -#define BLUETOOTH_VERSION_USE_CURRENT #import #import #import @@ -51,8 +49,78 @@ #pragma mark - #pragma mark connect, disconnect +/** + * @brief Connect to a wiimote with a known address. + * + * @param wm Pointer to a wiimote_t structure. + * + * @see wiimote_os_connect() + * @see wiimote_os_find() + * + * @return 1 on success, 0 on failure + */ +static short wiiuse_os_connect_single(struct wiimote_t* wm) { + // Skip if already connected or device not found + if(!wm) { + WIIUSE_ERROR("No Wiimote given."); + return 0; + } else if(wm && (!WIIMOTE_IS_SET(wm, WIIMOTE_STATE_DEV_FOUND) || wm->device == NULL)) { + WIIUSE_ERROR("Tried to connect Wiimote without an address."); + return 0; + } else if(WIIMOTE_IS_CONNECTED(wm)) { + WIIUSE_WARNING("Wiimote [id %i] is already connected.", wm->unid); + return 1; + } + + WIIUSE_DEBUG("Connecting to Wiimote [id %i].", wm->unid); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + short result = 0; + + // connect + WiiuseWiimote* objc_wm = [[WiiuseWiimote alloc] initWithPtr: wm]; + if([objc_wm connect] == kIOReturnSuccess) { + WIIUSE_INFO("Connected to Wiimote [id %i].", wm->unid); + + // save the connect structure to retrieve data later on + wm->objc_wm = (void*)objc_wm; + + // save the connection status + WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_CONNECTED); + + // Do the handshake + wiiuse_handshake(wm, NULL, 0); + wiiuse_set_report_type(wm); + + result = 1; + } else { + [objc_wm release]; + } + + [pool drain]; + return result; +} + int wiiuse_os_connect(struct wiimote_t** wm, int wiimotes) { - return 0; + int connected = 0; + + int i; + for (i = 0; i < wiimotes; ++i) { + if(wm[i] == NULL) { + WIIUSE_ERROR("Trying to connect to non-initialized Wiimote."); + break; + } + + if (!WIIMOTE_IS_SET(wm[i], WIIMOTE_STATE_DEV_FOUND) || !wm[i]->device) { + // If the device is not set, skip it + continue; + } + + if (wiiuse_os_connect_single(wm[i])) + ++connected; + } + + return connected; } void wiiuse_os_disconnect(struct wiimote_t* wm) { @@ -87,11 +155,80 @@ int wiiuse_os_write(struct wiimote_t* wm, byte* buf, int len) { void wiiuse_init_platform_fields(struct wiimote_t* wm) { wm->device = NULL; + wm->objc_wm = NULL; + wm->controlChannel = NULL; + wm->interruptChannel = NULL; } void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) { [WIIUSE_IOBluetoothDeviceRef_to_IOBluetoothDevice(wm->device) release]; wm->device = NULL; + + [((WiiuseWiimote*) wm->objc_wm) release]; + wm->objc_wm = NULL; } +#pragma mark - +#pragma mark WiiuseWiimote + +@implementation WiiuseWiimote + +- (id) initWithPtr: (wiimote*) wm_ { + self = [super init]; + if(self) { + wm = wm_; + disconnectNotification = nil; + } + return self; +} + +- (void) dealloc { + wm = NULL; + + [disconnectNotification release]; + disconnectNotification = nil; + + [super dealloc]; +} + +- (IOReturn) connect { + IOBluetoothDevice* device = WIIUSE_IOBluetoothDeviceRef_to_IOBluetoothDevice(wm->device); + if(!device) { + WIIUSE_ERROR("Missing device."); + return kIOReturnBadArgument; + } + + // open channels + IOBluetoothL2CAPChannel* controlChannel = nil, *interruptChannel = nil; + if ([device openL2CAPChannelSync:&controlChannel withPSM:WM_OUTPUT_CHANNEL delegate:self] != kIOReturnSuccess) { + WIIUSE_ERROR("Unable to open L2CAP control channel [id %i].", wm->unid); + [device closeConnection]; + return kIOReturnNotOpen; + } else if([device openL2CAPChannelSync:&interruptChannel withPSM:WM_INPUT_CHANNEL delegate:self] != kIOReturnSuccess) { + WIIUSE_ERROR("Unable to open L2CAP interrupt channel [id %i].", wm->unid); + [controlChannel closeChannel]; + [device closeConnection]; + return kIOReturnNotOpen; + } + + // register for device disconnection + disconnectNotification = [device registerForDisconnectNotification:self selector:@selector(disconnected:fromDevice:)]; + if(!disconnectNotification) { + WIIUSE_ERROR("Unable to register disconnection handler [id %i].", wm->unid); + [interruptChannel closeChannel]; + [controlChannel closeChannel]; + [device closeConnection]; + return kIOReturnNotOpen; + } + + // retain channels, and save them to the C struct + [controlChannel retain]; [interruptChannel retain]; + wm->controlChannel = WIIUSE_IOBluetoothL2CAPChannel_to_IOBluetoothL2CAPChannelRef(controlChannel); + wm->interruptChannel = WIIUSE_IOBluetoothL2CAPChannel_to_IOBluetoothL2CAPChannelRef(interruptChannel); + + return kIOReturnSuccess; +} + +@end + #endif // __APPLE__ diff --git a/src/os_mac/os_mac.h b/src/os_mac/os_mac.h index abe875c..667f4ce 100644 --- a/src/os_mac/os_mac.h +++ b/src/os_mac/os_mac.h @@ -34,7 +34,12 @@ #ifdef __APPLE__ +#define BLUETOOTH_VERSION_USE_CURRENT + #import +#import + +#import "../wiiuse_internal.h" #if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 @@ -62,5 +67,34 @@ [IOBluetoothDevice withDeviceRef: (ref)] #endif +// WIIUSE_IOBluetoothL2CAPChannel_to_IOBluetoothL2CAPChannelRef +#if WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE +#define WIIUSE_IOBluetoothL2CAPChannel_to_IOBluetoothL2CAPChannelRef(channel) \ + ((IOBluetoothL2CAPChannelRef) (channel)) +#else +#define WIIUSE_IOBluetoothL2CAPChannel_to_IOBluetoothL2CAPChannelRef(channel) \ + [(channel) getL2CAPChannelRef] +#endif + +// WIIUSE_IOBluetoothL2CAPChannelRef_to_IOBluetoothL2CAPChannel +#if WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE +#define WIIUSE_IOBluetoothL2CAPChannelRef_to_IOBluetoothL2CAPChannel(ref) \ + ((IOBluetoothL2CAPChannel*) (ref)) +#else +#define WIIUSE_IOBluetoothL2CAPChannelRef_to_IOBluetoothL2CAPChannel(ref) \ + [IOBluetoothL2CAPChannel withChanneleRef: (ref)] +#endif + + +@interface WiiuseWiimote : NSObject { + wiimote* wm; // reference to the C wiimote struct + IOBluetoothUserNotification* disconnectNotification; +} + +- (id) initWithPtr: (wiimote*) wm; +- (IOReturn) connect; + +@end + #endif // __APPLE__ diff --git a/src/os_mac/os_mac_find.m b/src/os_mac/os_mac_find.m index 200fb64..032d262 100644 --- a/src/os_mac/os_mac_find.m +++ b/src/os_mac/os_mac_find.m @@ -39,8 +39,6 @@ #import "../events.h" #import "../os.h" - -#define BLUETOOTH_VERSION_USE_CURRENT #import #import #import @@ -48,7 +46,7 @@ #pragma mark - -#pragma mark find +#pragma mark WiiuseDeviceInquiry @interface WiiuseDeviceInquiry : NSObject { wiimote** wiimotes; @@ -122,6 +120,10 @@ } - (NSUInteger) collectResultsOf: (IOBluetoothDeviceInquiry*) inquiry { + // stop the inquiry + if(![inquiry stop]) + WIIUSE_ERROR("Unable to stop bluetooth device inquiry."); + // read found device information NSArray* devices = [inquiry foundDevices]; for(NSUInteger i = 0; i < [devices count]; i++) { @@ -168,6 +170,8 @@ return result; } +#pragma mark IOBluetoothDeviceInquiryDelegate + - (void) deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry *) inquiry device:(IOBluetoothDevice *) device { WIIUSE_DEBUG("Found a wiimote"); @@ -175,8 +179,6 @@ _foundDevices++; if(_foundDevices >= maxDevices) { // reached maximum number of devices - if(![inquiry stop]) - WIIUSE_ERROR("Unable to stop bluetooth device inquiry."); _inquiryComplete = YES; } } @@ -196,6 +198,9 @@ @end +#pragma mark - +#pragma mark public interface + int wiiuse_os_find(struct wiimote_t** wm, int max_wiimotes, int timeout) { int result; diff --git a/src/wiiuse.h b/src/wiiuse.h index 48297c3..f88e793 100644 --- a/src/wiiuse.h +++ b/src/wiiuse.h @@ -723,7 +723,10 @@ typedef struct wiimote_t { #ifdef WIIUSE_MAC /** @name Mac OS X-specific members */ /** @{ */ - WCONST IOBluetoothDeviceRef device; /** Device reference object */ + WCONST IOBluetoothDeviceRef device; /** Device reference */ + WCONST void* objc_wm; /** WiiuseWiimote* as opaque pointer */ + WCONST IOBluetoothL2CAPChannelRef controlChannel; /** control channel reference */ + WCONST IOBluetoothL2CAPChannelRef interruptChannel; /** interrupt channel reference */ /** @} */ #endif