1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
//
// SDLIAPSession.m
//
#import "SDLIAPSession.h"
#import "SDLLogMacros.h"
#import "SDLMutableDataQueue.h"
#import "SDLTimer.h"
NS_ASSUME_NONNULL_BEGIN
@interface SDLIAPSession ()
@property (nullable, strong, nonatomic, readwrite) EASession *eaSession;
@property (nullable, strong, nonatomic, readwrite) EAAccessory *accessory;
@property (nullable, strong, nonatomic, readwrite) NSString *protocolString;
@end
@implementation SDLIAPSession
#pragma mark - Lifecycle
- (instancetype)initWithAccessory:(nullable EAAccessory *)accessory forProtocol:(NSString *)protocol {
SDLLogD(@"SDLIAPSession init with accessory:%@ for protocol:%@", accessory.name, protocol);
self = [super init];
if (!self) { return nil; }
_accessory = accessory;
_protocolString = protocol;
_isInputStreamOpen = NO;
_isOutputStreamOpen = NO;
return self;
}
#pragma mark - Abstract Methods
- (void)startSession {}
- (void)destroySession {}
#pragma mark - Private Stream Lifecycle Helpers
- (BOOL)createSession {
SDLLogD(@"Opening EASession with accessory: %@", self.accessory.name);
self.eaSession = [[EASession alloc] initWithAccessory:self.accessory forProtocol:self.protocolString];
return (self.eaSession != nil);
}
- (void)startStream:(NSStream *)stream {
stream.delegate = self;
[stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[stream open];
}
- (void)stopStream:(NSStream *)stream {
// Verify stream is in a state that can be closed. Closing a stream that has not been opened has very bad effects.
NSUInteger status1 = stream.streamStatus;
if (status1 != NSStreamStatusNotOpen &&
status1 != NSStreamStatusClosed) {
[stream close];
}
// When the USB cable is disconnected, the app will will call this method after the `NSStreamEventEndEncountered` event. The stream will already be in the closed state but it still needs to be removed from the run loop.
[stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[stream setDelegate:nil];
NSUInteger status2 = stream.streamStatus;
if (status2 == NSStreamStatusClosed) {
if (stream == [self.eaSession inputStream]) {
SDLLogD(@"Input stream closed");
self.isInputStreamOpen = NO;
} else if (stream == [self.eaSession outputStream]) {
SDLLogD(@"Output stream closed");
self.isOutputStreamOpen = NO;
}
}
}
- (void)cleanupClosedSession {
if (self.eaSession == nil) {
SDLLogD(@"Attempting to close session with accessory: %@, but it is already closed", self.accessory.name);
return;
}
self.eaSession = nil;
SDLLogD(@"Session closed with: %@", self.accessory.name);
self.accessory.delegate = nil;
}
#pragma mark - Getters
- (BOOL)isStopped {
return !self.isOutputStreamOpen && !self.isInputStreamOpen;
}
- (NSUInteger)connectionID {
return self.eaSession.accessory.connectionID;
}
- (BOOL)isSessionInProgress {
return !self.isStopped;
}
@end
NS_ASSUME_NONNULL_END
|