From 7e502b66d648f2318ae0b4628fd0e5e02f151932 Mon Sep 17 00:00:00 2001 From: Lysann Schlegel Date: Sat, 10 Nov 2012 23:26:56 +0100 Subject: [PATCH] implemented wiiuse_os_read for mac --- src/os_mac.m | 143 +++++++++++++++++++++++++++++++++++++++++--- src/os_mac/os_mac.h | 13 ++-- 2 files changed, 140 insertions(+), 16 deletions(-) diff --git a/src/os_mac.m b/src/os_mac.m index 50da0b4..554a0b6 100644 --- a/src/os_mac.m +++ b/src/os_mac.m @@ -134,25 +134,46 @@ void wiiuse_os_disconnect(struct wiimote_t* wm) { #pragma mark poll, read, write int wiiuse_os_poll(struct wiimote_t** wm, int wiimotes) { - int i; + int i, evnt = 0; if (!wm) return 0; for (i = 0; i < wiimotes; ++i) { wm[i]->event = WIIUSE_NONE; - idle_cycle(wm[i]); + + if (wiiuse_os_read(wm[i])) { + /* propagate the event, messages should be read as in linux, starting from the second element */ + propagate_event(wm[i], wm[i]->event_buf[1], wm[i]->event_buf+2); + evnt += (wm[i]->event != WIIUSE_NONE); + + /* clear out the event buffer */ + memset(wm[i]->event_buf, 0, sizeof(wm[i]->event_buf)); + } else { + idle_cycle(wm[i]); + } } - return 0; + return evnt; } int wiiuse_os_read(struct wiimote_t* wm) { - return 0; + if(!wm || !wm->objc_wm || !WIIMOTE_IS_CONNECTED(wm)) { + WIIUSE_ERROR("Attempting to read from NULL or unconnected Wiimote"); + return 0; + } + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + WiiuseWiimote* objc_wm = (WiiuseWiimote*) wm->objc_wm; + int result = [objc_wm read]; + + [pool drain]; + return result; } int wiiuse_os_write(struct wiimote_t* wm, byte* buf, int len) { - if(!wm) { - WIIUSE_ERROR("Attempting to write to NULL Wiimote"); + if(!wm || !wm->objc_wm || !WIIMOTE_IS_CONNECTED(wm)) { + WIIUSE_ERROR("Attempting to write to NULL or unconnected Wiimote"); return 0; } @@ -197,10 +218,15 @@ void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) { self = [super init]; if(self) { wm = wm_; + device = device_; controlChannel = nil; interruptChannel = nil; + disconnectNotification = nil; + + receivedData = [[NSMutableArray alloc] initWithCapacity: 2]; + receivedDataLock = [[NSLock alloc] init]; } return self; } @@ -214,7 +240,8 @@ void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) { [disconnectNotification unregister]; [disconnectNotification release]; - disconnectNotification = nil; + + [receivedData release]; [super dealloc]; } @@ -286,6 +313,71 @@ void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) { #pragma mark read, write +- (int) checkForAvailableData { + unsigned int length = 0; + + [receivedDataLock lock]; + if([receivedData count]) { + // pop first item from queue + NSData* firstData = [receivedData objectAtIndex:0]; + [receivedData removeObjectAtIndex:0]; + + byte* data = (byte*) [firstData bytes]; + length = [firstData length]; + + // forward event data to C struct + memcpy(wm->event_buf, data, sizeof(wm->event_buf)); + + // clear local buffer + [firstData release]; + } + [receivedDataLock unlock]; + + return length; +} + +- (void) waitForInclomingData: (NSTimeInterval) duration { + NSDate* timeoutDate = [NSDate dateWithTimeIntervalSinceNow: duration]; + NSRunLoop *theRL = [NSRunLoop currentRunLoop]; + while (true) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // This is used for fast release of NSDate, otherwise it leaks + + if(![theRL runMode:NSDefaultRunLoopMode beforeDate:timeoutDate]) { + WIIUSE_ERROR("Could not start run loop while waiting for read [id %i].", wm->unid); + break; + } + + [receivedDataLock lock]; + NSUInteger count = [receivedData count]; + [receivedDataLock unlock]; + if(count) { + // received some data, stop waiting + break; + } + + if([timeoutDate isLessThanOrEqualTo:[NSDate date]]) { + // timeout + break; + } + + [pool drain]; + } +} + +- (int) read { + // is there already some data to read? + int result = [self checkForAvailableData]; + if(!result) { + // wait a short amount of time, until data becomes available + [self waitForInclomingData:1]; + + // check again + result = [self checkForAvailableData]; + } + + return result; +} + - (int) writeBuffer: (byte*) buffer length: (NSUInteger) length { if(controlChannel == nil) { WIIUSE_ERROR("Attempted to write to nil control channel [id %i].", wm->unid); @@ -313,6 +405,43 @@ void wiiuse_cleanup_platform_fields(struct wiimote_t* wm) { return (error == kIOReturnSuccess) ? length : 0; } +#pragma mark IOBluetoothL2CAPChannelDelegate + +- (void) l2capChannelData:(IOBluetoothL2CAPChannel*)channel data:(void*)data_ length:(NSUInteger)length { + + byte* data = (byte*) data_; + + // This is done in case the output channel woke up this handler + if(!data || ([channel PSM] == WM_OUTPUT_CHANNEL)) { + return; + } + + // log the received data +#ifdef WITH_WIIUSE_DEBUG + { + printf("[DEBUG] (id %i) RECV: (%x) ", wm->unid, data[0]); + int x; + for (x = 1; x < length; ++x) + printf("%.2x ", data[x]); + printf("\n"); + } +#endif + + /* + * This is called if we are receiving data before completing + * the handshaking, hence before calling wiiuse_poll + */ + if(WIIMOTE_IS_SET(wm, WIIMOTE_STATE_HANDSHAKE)) { + propagate_event(wm, data[1], data+2); + return; + } + + // copy the data into the buffer + [receivedDataLock lock]; + [receivedData addObject: [[NSData alloc] initWithBytes:data length:length]]; + [receivedDataLock unlock]; +} + @end #endif // __APPLE__ diff --git a/src/os_mac/os_mac.h b/src/os_mac/os_mac.h index 06db9da..15ceef1 100644 --- a/src/os_mac/os_mac.h +++ b/src/os_mac/os_mac.h @@ -42,15 +42,6 @@ #import "../wiiuse_internal.h" -#if 0 -#if defined(MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 -#define WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE 1 -#else -#define WIIUSE_MAC_OS_X_VERSION_10_7_OR_ABOVE 0 -#endif -#endif - - @interface WiiuseWiimote : NSObject { wiimote* wm; // reference to the C wiimote struct @@ -59,6 +50,9 @@ IOBluetoothL2CAPChannel* interruptChannel; IOBluetoothUserNotification* disconnectNotification; + + NSMutableArray* receivedData; // a queue os NSData* + NSLock* receivedDataLock; } - (id) initWithPtr: (wiimote*) wm device: (IOBluetoothDevice*) device; @@ -66,6 +60,7 @@ - (IOReturn) connect; - (void) disconnect; +- (int) read; - (int) writeBuffer: (byte*) buffer length: (NSUInteger) length; @end