Accessories are not visible through the External Accessory framework until they have been connected by the system and made ready for use. When an accessory does become visible, your application can get the appropriate accessory object and open a session using one or more of the protocols supported by the accessory.
The shared EAAccessoryManager
object provides the main entry point for applications looking to communicate with accessories. This class contains an array of already connected accessory objects that you can enumerate to see if there is one your application supports. Most of the information in an EAAccessory
object (such as the name, manufacturer, and model information) is intended for display purposes only. To determine whether your application can connect to an accessory, you must look at the accessory’s protocols and see if there is one your application supports.
Note: It is possible for more than one accessory object to support the same protocol. If that happens, your code is responsible for choosing which accessory object to use.
For a given accessory object, only one session at a time is allowed for a specific protocol. The protocolStrings
property of each EAAccessory
object contains a dictionary whose keys are the supported protocols. If you attempt to create a session using a protocol that is already in use, the External Accessory framework generates an error.
Listing 1 shows a method that checks the list of connected accessories and grabs the first one that the application supports. It creates a session for the designated protocol and configures the input and output streams of the session. By the time this method returns the session object, it is connected to the accessory and ready to begin sending and receiving data.
Listing 1 Creating a communications session for an accessory
- (EASession *)openSessionForProtocol:(NSString *)protocolString |
{ |
NSArray *accessories = [[EAAccessoryManager sharedAccessoryManager] |
connectedAccessories]; |
EAAccessory *accessory = nil; |
EASession *session = nil; |
for (EAAccessory *obj in accessories) |
{ |
if ([[obj protocolStrings] containsObject:protocolString]) |
{ |
accessory = obj; |
break; |
} |
} |
if (accessory) |
{ |
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]; |
[session autorelease]; |
} |
} |
return session; |
} |
After the input and output streams are configured, the final step is to process the stream-related data. Listing 2 shows the fundamental structure of a delegate’s stream processing code. This method responds to events from both input and output streams of the accessory. As the accessory sends data to your application an event arrives indicating there are bytes available to be read. Similarly, when the accessory is ready to receive data from your application, events arrive indicating that fact. (Of course, your application does not always have to wait for an event to arrive before it can write bytes to the stream. It can also call the stream’s hasBytesAvailable
method to see if the accessory is still able to receive data.) For more information on streams and handling stream-related events, see Stream Programming Guide for Cocoa.
Listing 2 Processing stream events
// Handle communications from the streams. |
- (void)stream:(NSStream*)theStream handleEvent:(NSStreamEvent)streamEvent |
{ |
switch (streamEvent) |
{ |
case NSStreamHasBytesAvailable: |
// Process the incoming stream data. |
break; |
case NSStreamEventHasSpaceAvailable: |
// Send the next queued command. |
break; |
default: |
break; |
} |
} |
Last updated: 2010-05-26