I have a project that connects to an external accessory and communicates a small amount of data to and from an iOS app. I am able to setup the session and streams like apple does in their EADemo reference code and everything seems to work fine.
The problem I have is that after a random amount of time using the app, the output stream stops working, but the input stream still operates fine. I check to make sure hasSpaceAvailable is true before each write attempt and when I read back the number of bytes written, everything looks correct. Also, looking at the run loop doesn't indicate any differences between working and non working, and the stream status still reads as open.
The only thing that I can see that causes this is that my accessory doesn't ACK a few of the app's write attempts in a row, and then it breaks.
How can I detect I am in this state and how can I fix it?
// low level write method - write data to the accessory while there is space available and data to write
- (void)_writeData {
while (([[_session outputStream] hasSpaceAvailable]) && ([_dataToWrite length] > 0))
{
NSInteger bytesWritten = [[_session outputStream] write:[_dataToWrite bytes] maxLength:[_dataToWrite length]];
if (bytesWritten == -1)
{
NSLog(@"write error");
break;
}
else if (bytesWritten > 0)
{
[_dataToWrite 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 {
NSLog(@"reading data to buffer");
#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 (_dataToRead == nil) {
_dataToRead = [[NSMutableData alloc] init];
}
[_dataToRead appendBytes:(void *)buf length:bytesRead];
}
[[NSNotificationCenter defaultCenter] postNotificationName:EASessionDataReceivedNotification object:self userInfo:nil];
}
// high level write data method
- (void)writeData:(NSData *)data
{
// NSLog(@"writing data to buffer");
if (_dataToWrite == nil) {
_dataToWrite = [[NSMutableData alloc] init];
}
[_dataToWrite appendData:data];
[self _writeData];
}
// high level read method
- (NSData *)readData:(NSUInteger)bytesToRead
{
NSLog(@"reading data");
NSData *data = nil;
if ([_dataToRead length] >= bytesToRead) {
NSRange range = NSMakeRange(0, bytesToRead);
data = [_dataToRead subdataWithRange:range];
[_dataToRead replaceBytesInRange:range withBytes:NULL length:0];
}
return data;
}
- (BOOL)openSession
{
NSLog(@"openSession");
[_accessory setDelegate:self];
if(_session){
[self closeSession];
}
_session = [[EASession alloc] initWithAccessory:_accessory forProtocol:_protocolString];
if (_session)
{
_runLoop = [NSRunLoop currentRunLoop];
[[_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];
NSLog(@"creating session succeeded!");
}
else
{
NSLog(@"creating session failed!");
}
return (_session != nil);
}