/* |
|
File: EADSessionController.m |
Abstract: n/a |
Version: 1.1 |
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Inc. ("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or redistribution of |
this Apple software constitutes acceptance of these terms. If you do |
not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
|
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. may |
be used to endorse or promote products derived from the Apple Software |
without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or |
implied, are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or by other |
works in which the Apple Software may be incorporated. |
|
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
|
Copyright (C) 2010 Apple Inc. All Rights Reserved. |
|
|
*/ |
|
#import "EADSessionController.h" |
|
NSString *EADSessionDataReceivedNotification = @"EADSessionDataReceivedNotification"; |
|
@implementation EADSessionController |
|
@synthesize accessory = _accessory; |
@synthesize protocolString = _protocolString; |
|
#pragma mark Internal |
|
// low level write method - write data to the accessory while there is space available and data to write |
- (void)_writeData { |
while (([[_session outputStream] hasSpaceAvailable]) && ([_writeData length] > 0)) |
{ |
NSInteger bytesWritten = [[_session outputStream] write:[_writeData bytes] maxLength:[_writeData length]]; |
if (bytesWritten == -1) |
{ |
NSLog(@"write error"); |
break; |
} |
else if (bytesWritten > 0) |
{ |
[_writeData replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0]; |
} |
} |
} |
|
// low level read method - read data while there is data and space available in the input buffer |
- (void)_readData { |
#define EAD_INPUT_BUFFER_SIZE 128 |
uint8_t buf[EAD_INPUT_BUFFER_SIZE]; |
while ([[_session inputStream] hasBytesAvailable]) |
{ |
NSInteger bytesRead = [[_session inputStream] read:buf maxLength:EAD_INPUT_BUFFER_SIZE]; |
if (_readData == nil) { |
_readData = [[NSMutableData alloc] init]; |
} |
[_readData appendBytes:(void *)buf length:bytesRead]; |
//NSLog(@"read %d bytes from input stream", bytesRead); |
} |
|
[[NSNotificationCenter defaultCenter] postNotificationName:EADSessionDataReceivedNotification object:self userInfo:nil]; |
} |
|
#pragma mark Public Methods |
|
+ (EADSessionController *)sharedController |
{ |
static EADSessionController *sessionController = nil; |
if (sessionController == nil) { |
sessionController = [[EADSessionController alloc] init]; |
} |
|
return sessionController; |
} |
|
- (void)dealloc |
{ |
[self closeSession]; |
[self setupControllerForAccessory:nil withProtocolString:nil]; |
|
[super dealloc]; |
} |
|
// initialize the accessory with the protocolString |
- (void)setupControllerForAccessory:(EAAccessory *)accessory withProtocolString:(NSString *)protocolString |
{ |
[_accessory release]; |
_accessory = [accessory retain]; |
[_protocolString release]; |
_protocolString = [protocolString copy]; |
} |
|
// open a session with the accessory and set up the input and output stream on the default run loop |
- (BOOL)openSession |
{ |
[_accessory setDelegate:self]; |
_session = [[EASession alloc] initWithAccessory:_accessory forProtocol:_protocolString]; |
|
if (_session) |
{ |
[[_session inputStream] setDelegate:self]; |
[[_session inputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; |
[[_session inputStream] open]; |
|
[[_session outputStream] setDelegate:self]; |
[[_session outputStream] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; |
[[_session outputStream] open]; |
} |
else |
{ |
NSLog(@"creating session failed"); |
} |
|
return (_session != nil); |
} |
|
// close the session with the accessory. |
- (void)closeSession |
{ |
[[_session inputStream] close]; |
[[_session inputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; |
[[_session inputStream] setDelegate:nil]; |
[[_session outputStream] close]; |
[[_session outputStream] removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; |
[[_session outputStream] setDelegate:nil]; |
|
[_session release]; |
_session = nil; |
|
[_writeData release]; |
_writeData = nil; |
[_readData release]; |
_readData = nil; |
} |
|
// high level write data method |
- (void)writeData:(NSData *)data |
{ |
if (_writeData == nil) { |
_writeData = [[NSMutableData alloc] init]; |
} |
|
[_writeData appendData:data]; |
[self _writeData]; |
} |
|
// high level read method |
- (NSData *)readData:(NSUInteger)bytesToRead |
{ |
NSData *data = nil; |
if ([_readData length] >= bytesToRead) { |
NSRange range = NSMakeRange(0, bytesToRead); |
data = [_readData subdataWithRange:range]; |
[_readData replaceBytesInRange:range withBytes:NULL length:0]; |
} |
return data; |
} |
|
// get number of bytes read into local buffer |
- (NSUInteger)readBytesAvailable |
{ |
return [_readData length]; |
} |
|
#pragma mark EAAccessoryDelegate |
- (void)accessoryDidDisconnect:(EAAccessory *)accessory |
{ |
// do something ... |
} |
|
#pragma mark NSStreamDelegateEventExtensions |
|
// asynchronous NSStream handleEvent method |
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode |
{ |
switch (eventCode) { |
case NSStreamEventNone: |
break; |
case NSStreamEventOpenCompleted: |
break; |
case NSStreamEventHasBytesAvailable: |
[self _readData]; |
break; |
case NSStreamEventHasSpaceAvailable: |
[self _writeData]; |
break; |
case NSStreamEventErrorOccurred: |
break; |
case NSStreamEventEndEncountered: |
break; |
default: |
break; |
} |
} |
|
@end |