iPhone • 52:51
iPhone OS 3.0 applications can now communicate with accessories, through either the 30-pin dock connector or wirelessly using Bluetooth. Your applications can now retrieve data from external sensors or even control accessories with a sophisticated, Multi-Touch interface. This session covers how to use the new External Accessory framework: a standard interface for sending and receiving data and instructions between your app and an external accessory.
Speakers: Paul Holden, John Ananny
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
All right, good afternoon everybody. My name is Paul Holden. I'm an iPhone Application engineer at Apple. And I am really, really excited to be here to talk to you folks today about creating iPhone applications that communicate with accessories. So why am I excited about it? Well, this was a really, really highly requested feature. A lot of people asked for it even around the office, people stopping by thinking you know telling me what if third party people could do this and developers could actually come through and make these great applications for their custom accessories? Wouldn't that be great? Well, it would.
Next, the second reason I'm really excited to be here today is because personally I can't wait to see what you guys come up with. So, with iPod, iPod Touches and iPhones, a lot of accessory manufacturers have come up with great, fantastic, thousands of accessories that work great with our products and customers love them, great experience.
And I think this will really let you guys come up to the next level and really make the next level of accessories and applications that work with them really great. So as with all the other presentations you guys have hopefully gone to, there's a, there's a demo here, you guys can go to the attendee site and pick up the EA Framework demo project.
You can follow along as we go through. So I just like to take a minute and talk about you, the developers, and what I hope to help you guys out with. So, with there's probably three groups of you here that I think this presentation will really, really be good for. So one is the MFi and the WWi people that are in the crowd.
So, MFi made for iPod and WWi works with iPhone, so if you go into any electronic stores, you're seeing the thousands of great iPod accessories, iPhone accessories and iPod Touch accessories out there today. So we really want to go through and show you guys exactly what we've added to the iPhone 3.0 SDK. And what you can do to make great applications that work with either those types of accessories or even the new types of accessories that this will unlock and let you develop.
Next, I'd like to talk about iPhone, iPhone application engineers. So iPhone application designers. So people who have already used the SDK, possibly already have an application on the store, and have this great idea for this piece of hardware that they want to develop and are not really sure what steps to take or you know where to go about doing that to actually get something to market. So, we'll help you guys out, we'll talk about that as well.
Next, I envision that there's also people in the crowd that are hardware people. So perhaps you guys have just played with the SDK, maybe you've, you've never even used it at all. So, in our demos and as we go through, I hope to give you guys the ground works of what you need to actually go through, take your hardware concept and make a great application for it.
So let's get started. So very, very high level, this is what we're talking about right? You have an accessory, a piece of hardware that's external to your phone. And you've got, and you've got an application that you've developed for your iPhone. In the 3.0 SDK, what we've done is we've let you communicate from your accessory and to your application using one of three transports.
So the first one is Bluetooth. So you can communicate with your application wirelessly using Bluetooth, which is great. The second is, well the second and third, you use through the dot connector. So USB and you are through an actual connector that will connect to the physical 30 pin on the bottom.
So let's take a closer look at this. So the goal of this feature is to take raw bytes that you've got in your application or in your accessory and transfer them back and forth, right? So you've got raw bytes that you want to send from your accessory to your application and vice versa.
How we allow you to do that on your application side is we provide you with an extra framework called the ExternalAccessory Framework. So your application with link against this and you'll be able to at runtime find out what accessories are connected to your iPhone or your iPod Touch and also how to communicate with them. From the hardware side when you've got an actual accessory, what'll happen is this will be presented to your accessory as an IAP accessory.
So IAP stands for the iPod Accessory Protocol that we have here. So what is this? What is this protocol? The IAP has been around for a long time. All of you have owned or played with in the stores with accessories that today communicate with iPods or iPod Touches or iPhones they use this protocol to send low-level information back and forth.
Well we use it as a wrapper for the raw bytes that'll go through from your accessory to your iPhone and in your application, you see those bytes in the ExternalAccessory Framework. Specifically though today, we'll spend most of the presentation talking about the ExternalAccessory Framework and how you'll use it to communicate to your accessories. So you've probably seen this diagram a few times in the last, in the last couple of days. But like all the other frameworks, like Core Location, UIKit, it sits on the Cocoa Touch layer.
Ok, so specifically, what we'll talk about today is the EA Architecture. So throughout the presentation I'll use that as a short form for ExternalAccessory. We'll look at how we set it up to make it very, very easy for you to go through and at runtime discover and communicate with your accessories.
So while providing you with a flexible architecture that you can you know that wasn't limiting, you could actually go out and make the applications that you want. Next we'll also talk to you about how you're going to associate your, you accessories with your applications. So when someone plugs in an accessory, you want to make sure that the application that goes with that accessory that they can go get it from the App Store.
So we'll show you how, how to set that up. Next, we spent a lot of time over the years working with accessory manufacturers. And we'll try to give you a few design guideline, a few design guidelines that we feel will really help you guys make the most out of using the ExternalAccessory Framework. So just to take a quick second to talk about hardware.
So when you're developing hardware, what's required? Well, first we talk about these programs a few slides ago, the Made for iPod and Works With iPhone. It's a requirement that your accessory is part of this, is part of this program. So there's already thousands and thousands of accessories that are out there that are part of it.
It because there's hardware involved, obviously you, you're going to need hardware connectors to actually go through and connect to an iPhone. That's part of the program as well. Documentation support. It's a very, very good program, a lot of great experience that we had with people working with them. It's been great. So, you'll want to go check out the developer.apple.com/iPod and you'll get most of the information from there. Alright, so we've gone high level.
[ Background noise ]
So the diagram we showed a few minutes ago, you've got an accessory, you've got your iPhone application and if you link against the ExternalAccessory Framework, what will happen is essentially, when you, before you've connected an accessory you won't see anything, right? You'll ask the ExternalAccessory Framework, alright what's connected to my system. And obviously, it'll say nothing is connected right away.
When you do connect, you're accessory will be responsible using the IP Protocol to send all of the EA protocols that it supports. So EA Protocol will go through, will dive into the terms in a few slides, but basically it's a logical communication path for you guys to package your information and send it to the iPhone or the iPod Touch.
So once that happens, the EA Protocol, the EA Framework will show your accessory as an EAAccessory object. So you can go through, you can query it, you can ask it what protocols it supports and you can open, you can open sessions to communicate with it. So when you have a protocol, that's not enough to actually go through and communicate through it.
In the architecture that we've come up with, once you've, once your accessory is enumerated the protocol, it's the responsibility of the application to say alright, I want to speak to this protocol, I'm going to form an EASession to it. Once you do that, you're able to freely communicate to and from your accessory. So we went through a lot of terminology in that, in that last slide. Let's take every single piece of it and dissect it and examine every one.
So the first one we discussed was this concept of EAAccessory. So what is that? It's an accessory that conforms to the Made for iPod, so it's part of the MFi licensing program. So again, throughout the website there you definitely want to go check that out. Next, it has to be either a Bluetooth accessory or connect through USB or UR through the doc connector.
[ Period of silence ]
Next, we also threw out this term EA Protocol. So what does that mean? If someone was to ask me what EA Protocol is, that would be difficult for me to do.
Because essentially all it is is a logical communication path. And you will decide what this EA Protocol does So we just wanted to give you a flexible architecture so you guys could decide how you'll actually package up your data, how you'll split it up, and how you'll set it to your accessory.
So you'll use these EA Protocols to send your, to define what communication you want to send back and forth. Next, obviously it's not related to the App Protocol for those of you who have worked with Objective-C a bunch and not only does your accessory have to enumerate the protocols that it supports, but your application must as well.
And we'll talk about that in a few slides. So as I mentioned, we really didn't want to put a lot of restrictions on this right? You really wanted to give you guys the freedom to develop applications and accessories that you want and get them to communicate in the fashion that you guys want to do that.
So the only two rules we have, one is all communication must happen on an EA protocol. So if you just want to send bytes to your accessory or receive bytes from your accessory, you can't do that until you've formed a session with an EA protocol. Next, we ask that the name of your protocol be in reverse DNS format.
So something that most of you are already pretty familiar with, shouldn't be a big problem. Next, let's dive into something a little bit more, more interesting which is kind of the visibility of how your EA protocol will be seen by developers. So again, we didn't want to put a lot of limitations on this, so let's say you have an accessory that supports a certain number of EA protocols. When you connect it to your iPhone, another developer who also connects it to your iPhone will be able to see your EA protocols.
Now, obviously they won't have the specs for them, but if it's something that can either be easily reverse engineered or it's something that for you having someone else or having another developer be able to communicate using your accessories is a problem, you'll want to bring in your own security, right? So you're going to be responsible for enforcing the security of your EA protocols that you have for you accessories. Alright, now EASessions. So this is where most of you will spend 95 you know percent of your time when developing for EAAccessories is you'll spend your time with EASessions.
So again, if we look at it high level, it's a container object for all of the streaming objects that are going to be used for your accessories. So the input streams and the output streams. And now this is obviously if you look at the architecture of the phone, but only apps can create EASessions. So at runtime you can't have your, your accessories go and form a session.
It has to be your app that does that. Alright, so we discussed having your accessory enumerate the protocol, the EA protocols that it supports. Let's talk about your application enumerating the EA protocols that it supports. So that'll happen through the info.plist which if any of you have created an iPhone application or even a desktop application are pretty familiar with, right? It's the plist that goes with inside the bundle of all your applications.
So we've added a key. UI supported ExternalAccessory Protocol, kind of a mouthful, but when you use that in an array, you add a string that enumerates every single protocol that your application supports. Now this was pretty long key so the folks at in XCode hooked us up and you can just add it through the UI and when you do that, every item you add will show up as, as an array item in your info.plist.
Alright, why would you want to associate your applications with EA Protocols? So the reason for that is we wanted to give you guys a method to help the user that for the first time connects an EAAccessory to their iPhone or their iPod Touch. So how we've done that is if you have an accessory that connects to your iPhone or your iPod Touch and it supports EA Protocols for which there is not a single application on your phone that also supports one of those EA Protocols, then this alert will go out.
So kind of a mouthful but basically if there's no apps for your accessory we'll throw this up. If the user presses yes, then they'll be sent to the App Store and we'll use the information in those protocols to go through and say alright, these are the applications that you probably want to download to use your accessory.
[ Period of silence ]
So the second way that we try to help you guys and help you out when actually associating your applications with, with accessories is if you navigate through settings and you go through, you go to the About table view, you'll see that we've added an extra field there for the accessory that you've connected.
So if you go here and you press the find app for accessory, you'll get the same query on the App store that happens if you press yes in that alert that we saw just a minute ago.
[ Period of silence ]
Alright, so we dove in, we defined all the terms that are important when working with the ExternalAccessory Framework.
Now let's actually look at the framework and its API in detail. So it's really simple. There's only three classes and one protocol that you'll use when communicating with your accessories. The first one is the EAAccessoryManager, which will be responsible for managing the connections of all the accessories that are connected to your iPhone or your iPod Touch. Next is the EA Accessory Class, which you'll use to represent a single ExternalAccessory in the framework.
Finally that has also got a protocol, which is the EAAccessoryDelegate protocol which you'll use to see disconnects of a single ExternalAccessory. And finally, the really important one that you'll spend most of your time with is the EASession. So what you'll use to communicate to and from your accessory.
So let's look at the API a little bit. So in the EAAccessoryManager API, you've got two notifications, connect, and disconnect, pretty normal. Anyone who's familiar with Cocoa Notifications knows that when you receive these you'll have a user info dictionary and in your user info dictionary, we'll actually give you a reference to the EA, the EAAccessory for which that event was triggered. Next, it's a singleton so there's only one per application.
So you'll use the shared accessory manager to get a hold of it. So also to receive the did disconnect and did connect notifications, we ask that, that you register for them. So when you want to start receiving them, you'll register. When you don't want to start receiving them, you'll use the unregister for local notifications to do that.
Finally, the connected accessories property is what you'll use at runtime to get a list of the currently connected accessories to your iPhone or your iPod Touch. So when your application launches, we won't send you a notification for every accessory that's already connected. All we'll send, all we'll send you is notifications for when new accessories are connected. So when you start up, you use the connected accessories so you'll get an array of everything that's connected.
Now, I want to mention that in the 3.0 SDK, only one EAAccessory is permitted on your iPhone or your iPod Touch at a time. So when you go and use the connected accessories NSArray, you'll only, you'll always receive one accessory, that'll be the maximum. So you'll get no accessories and nothing is connected. Or you'll get one if something is there. But obviously, this is something we hope to perhaps enhance in the future. So we ask that you treat this as an array. So don't go using index at object 0.
You know actually go through it and make sure that the EAAccessory that's in there is the one that you're looking for. Alright, so we talked about the manager. Now let's talk about EAAccessory, which is the object that'll represent a single accessory connected to your iPhone or iPod Touch. So again, a few properties that aren't listed here are things like name, serial number, version, sorry hardware version, firmware version.
So there's a few strings to help you identify it, but the real, the real property that you want to look at is the second one in the list here, which is protocol strings. So we talked before that an EAAccessory on connect has to enumerate all of the EA protocols that it supports. Well this is where you'll go get them. So you'll read this and it'll hold every single EA protocol that your accessory supported.
So you can take those and you can form sessions to them so you can start communicating with them. Next you'll use the connection ID, so just we assign a, a new number to every single connection when an accessory gets connected to the system And finally the delegate method. So, finally, sorry the delegate.
So while you use the delegate, what you'll use it for is the EAAccessoryDelegate. So as we mentioned a few minutes ago, accessory did disconnect you'll want to set that if all you care about is the disconnect of one single accessory. So the notification in the EAAccessoryManager is for when any EAAccessory is connected or disconnected from your system.
But if there's only one that you really care about or if there's only a few that you've got connections, that you've got references to and you care about them, then you want to use this delegate to make sure that you only get the notification, you only get delegate callbacks for when that one disconnects.
Alright, now again the one we're going to spend the most time is this EAsession. And if you look at little bit at the API, again it's very, very straightforward. So you have init with accessory for protocol. So how session works is when you know that you want to communicate to an EAAccessory, over a certain EA protocol, you form an EASession with that accessory for that protocol.
Now if your accessory supports 20 EAProtocols, then to communicate over all of them, you'll actually have to form 20 EASessions. OK? So it's basically one session per protocol per accessory. So as you can see by the init method here. Next, how are you going to transfer them? So those of you who may have used NSStream on the desktop or on the phone will be very familiar with this API. So we give you two objects, two properties here which is InputStream and OutputStream that are NSInputStream and NSOutputStream classes. So let's look into those in a little bit more detail. So NSInputStream and NSOutputStream aren't new. They've been around in foundation for a long time.
They're both subclasses of NSStream. And if you haven't looked at it before, I definitely, even if you have looked at it before, I definitely suggest that you go check out the Introduction to Stream Programming Guide for Cocoa. It's on ADC, it's fantastic. It definitely gives you the you know from one end the entire view of how you'll want to use NSStream Objects and how they behave.
So but of course, we want to give you demos and we want to dive into them right now. So if I had to explain to a, if I had to show one method which will explain how these work, how NSStreams work, it would be this one. So NSStream works very heavily using delegates.
So when you've got a stream anyone who's communicated to or from some kind of object or streamed stuff over the Internet, you can, you can definitely use poling right? So you can say are there bytes available now? Or can I send bytes to my, to my output? But NSStream definitely encourages you and we definitely encourage people when doing this to work asynchronously and to use a delegate callbacks. So here the handle event.
Types of events that you'll get back for you InputStream and your OutputStream are things like open completed. So did my stream open? And you'll also get end encountered. So was the end of my stream encountered? So in this case you'll get that when you unplug your accessory. So when you disconnect it, you'll get an endstream notification. Next for the inputstream, you'll get a has bytes available.
So the delegate will get called with that when bytes are available for your system to use. And finally, if you're using your outputstream, you want to wait for the event that's called has space available. So just like most streams, you can't just assume that you can write to it. You know you have to make sure that the stream has space available for you to send data to it. And once that, once that happens, you can go ahead and you can send your data to it.
And we'll go through that in a little bit more detail in the demo. So I have an application and I guess for you guys it's in the top right corner, which is EADemo. So if we click on that, this is the demo that you can go pick up from the attendee site. We have a simple table view.
And every time I connect an accessory, so I've got a very, very simple board here which is just a test accessory that, that we've created for this. When I plug it in, our Test App will go through and it'll list it. So it's listening to the didconnect notification through the EAAccessoryManager and putting up every single accessory that, that it sees come in.
If you press the.
[ Period of silence ]
There you go. If you press the, the information button, what you'll get, this is a little bit fuzzy, but basically we override the NSObject Description Method, so when you press that, if ever you decide just to print out your object, you'll get all of the important properties that are there.
So that's kind of interesting. And if we press on it, what we do is I go through and I actually read the protocol strings object that's connected to your, that is part of your EAAccessory Object. So here, I'm showing a UI alert sheet that posts every single EA protocol that this accessory has enumerated.
[ Period of silence ]
That looks pretty good. OK, so we've got three buttons. Again, this is just a basic custom view that has LED on, LED off, and send 10K of data. So if I press the on, I press the off, it'll just send a very small packet to that accessory to light and unlight the LED. So very, very simple demo. Let's go through and step by step look at the code and show you guys how you can add the same functionality to your application.
Perfect. So, we've got, actually, before I do that. I want to show you guys a slide first. So before I go through and actually look at this code, I'll bring up, I'll show you guys the flow of this application and the different files that were involved in creating it. And then we'll focus in on one of those files that, that's an accessory controller that does all of the communication with the EA Framework.
So first of all, we saw had, we have a root controller object that's just responsible for bringing up the table view. And once you press on an object, bring up the UI alert sheet that lists all of the EA protocols that your accessory enumerated, that it supports. Next, when you press on one, you bring up our custom view. That just has three buttons, LED on, LED off.
And we also create this object called the EADAccessory Controller. Now the EADAccessoryController came from when we were first developing this, we kind of wanted something to inspire everyone who was actually going to try to use the ExternalAccessory Protocol who maybe hadn't use NSStream before, NSInputStream or NSOutputStream. So NSController which we'll look at very, very precisely when we look at the code, it holds all the logic to use the streams for those EAAccessories. So what happens when you press a button? We go and we call right data with an NSData Object and there you go. It's the controller handles everything and it goes right to your accessory.
[ Period of silence ]
So we saw two view controllers, so the, the root view controller which was just the table view that brought up every single accessory that was currently connected. And then also watched for did connect and disconnect notifications. Next, we had the EAAccessory details view controller which had those three buttons, the LED on, LED off and send 10K of data. Finally, we had the EADAccessoryController. So this is what the views communicate with whenever they actually want to use the inputstream and outputstream that are associated to your EAAccessory.
[ Period of silence ]
So the API for this is very, very basic. The first thing you do is when you have this controller, you set it up with an accessory and a protocol string. So, obviously this looks like we're going to set up a session with it, right? So we're getting an accessory, we're getting a protocol that we want this to handle. And next, we have two methods, open session and close session.
So we'll use those methods to actually open up the input stream and the output stream of this EAAccessory.
[ Period of silence ]
Finally, here we've got the write data which is what we'll use to actually use those streams and take that data and asynchronously send it to your accessory.
[ Period of silence ]
[ Period of silence ]
So if I go here and I pick up the setup controller, all we're doing is just keeping a reference to the accessory and the protocol. So pretty basic.
[ Period of silence ]
We'll use the open session method. So what does this do? First thing is it sets the delegate of the accessory. So we want this object to receive disconnect notification or disconnect delegate methods for this accessory. So we go and we set that up. Next, we set up, we set up a session for that accessory.
So we call the InitAccessoryForProtocol. Now, the next line right here, we actually check to see if it's nil. So why do we do that? Well in the 3.0 SDK, you're permitted only one session per protocol per EA protocol per accessory. So let's say you tried to do that twice.
Let's say you tried to open two sessions for the same EAProtocol for one EAAccessory. This would come back as nil and you wouldn't, it wouldn't permit you to do that. So let's say your application did everything right. It, it set up a session. You're ready to go. The next thing you do is we set up the inputstream.
So again, those who are familiar with NSStream on a desktop or on, or on the phone will be really familiar with this. We set the delegate. So we talked about NSInputStream and NSOutputStream are very delegate driven, right? So they get events for when data comes in and when you have space available to write data to your accessory. So here, we set the delegate to receive those call, those, those delegate methods.
Next, we want to make sure that we're getting those delegates in the right, in the right run loop, right? So obviously if we're working in the main run loop and we have of UI, happening and we set this up to happen in another thread in another run loop, then we want to schedule it there. So what happens here, we schedule it in the run loop that called this, this method. So we just use the current run loop. And finally we go ahead and we open the stream.
We do the same thing for the input and for the output. Next, we look at the close session. This one again very simple. We just basically do what we did in the open session but in the reverse order. So we go, we close the session, we unregister its delegate events from the run loop and then we go ahead and we set the delegate to nil.
So very straightforward. Now where things get very interesting is here in the write data. So in write data, what do we do? We have a buffer called _writedata. And if that buffer wasn't created, we go ahead and we create it. We take the data that you wanted to put onto it and we add it to the buffer. So let's say you called write data with a 1K buffer. We go ahead and we add that to our NSMuteableData data and then which is right here where we append.
And finally, we call this write_data. So someone external to this controller will call a writedata and we have an internal method that'll actually be responsible for writing that data onto the stream. So before I look at _writedata, I want to take a little bit of time to have a look at this switch statement that I've put in the stream handle event.
So stream handle event comes from NSStream delegate event extensions. So this is the delegate that'll get called whenever an event happens on an inputstream or an outputstream. Because remember we set up the same class to be the delegate for both those streams. So we've got open completed, you'll get that both for the inputstream and for the outputstream. And at the bottom we've got error occurred and end encountered.
So you'll get this and the error occurred and end encountered. You could get that for both streams, both the input and the output. So you should handle those accordingly. Obviously, we just print them out here for the demo. But the really, really interesting ones come in the has bytes available and has space available.
So in our write data example, when it's very important that you don't just assume that you can take your data and you can write it to the stream. Because NSStream works like any stream and so does this, so does the EAAccessory. You've got a piece of hardware that can accept data.
So it's important that you can't just say hey, here's my 1K of data, right? You can't just send it to it. You have to do a little bit more work. So what you want to do is you want to ask it and say are you able to accept data.
So you want to ask it are you able to accept data. If it can, you say alright, try, try to write my 1K of data and it'll come back and tell you how much data it actually wrote. So let's say it says you can write to me, you try to write a K, it could come back and tell you OK look, I was only able to write 256 bytes so later on when this delegate gets called, you can go through and you can write the rest of the three quarters of the K. So let's look at this writedata here.
So this goes through, this goes through what we talked about a little bit. The first thing is we go through and we make sure that the stream has space available. Also, we make sure that the buffer that we want to write the data from also has, also has data in it. Obviously, you don't want to write just nothing to the buffer.
And when that happens, next loop here, we call the outputstream for our writedata. So here we sent it the bytes and the max length we're saying, OK let's say someone put a K or something, put 10K, we say write the whole thing. Now, as a return value, it'll return the bytes available. So that'll be the number of bytes that were actually written.
Now obviously when you get the callback that says that you have space available, it's not saying like we talked about, it's not saying how much space you have available. So and also, as you progress through your program, that will change right, so this will just return how much data was actually able to get written. So if you get - 1, just like most strings for people who have used the, the NSStream API before.
If you get - 1, an error occurred. But you know when you're using this in normal operation, you'll get either bytes written was 0, so it was, it was full it couldn't write anything to it. Or your bytes was greater than 0 and it was actually able to write a chunk of your data. And then this will just loop through until you've got no space available.
And once that's finished all you have to do is in your delegate you just wait for that has space available and you call the exact same method. So this is definitely, what we hope that you guys will use to get inspired to find out how to actually use the outputstream when working with the ExternalAccessory framework. Now when you want to read data from your stream, it's very, very similar.
So obviously you can work in a poling fashion but what the, what the specs recommend, definitely what we recommend is working asynchronously. So you'll want to have your system just wait for this has bytes available which is right here. Until your delegate gets called with that. That'll only get called for your NSInputStream object in your EASession. And when that happens then you'll call a function, here we call _readdata.
So let's go have a look at that.
[ Period of silence ]
So NSReadData goes to make sure that there is data available in your input stream. And then goes through and, and reads them. So we have a buffer here, 128 bytes and we read it and then we just print out the number of bytes that were read. Obviously, this will tell you what's there.
You'll probably want to do something more interesting such as post a notification locally to your system saying, OK I put these bytes in the buffer, whoever wants them, go through, and use them. Now it's important to notice that we don't make any assumptions here about the size of the buffer or of the data that was sent. And definitely, you shouldn't either.
If you have an accessory that for example is trying to send a K of data and it does so by sending four packets of 256 bytes of data, right? From your application layer, you can't assume that you'll get four delegate callbacks, each of them indicating that you have one quarter of K data or they have 256 bytes. You can't do that because you have to treat it just like a stream.
So when you get it, you just read, it'll tell you how much data is there. And you'll just want to keep reading from it until it's empty. OK? So definitely, definitely it works like a normal stream. Anyone that's used NSStream before, very, very similar. Don't make any assumptions about it.
Just read the data and you could get for example if you were sending a K of data, you could get one callback for when you've gotten this 512 bytes in it. And then you can get it again with 256 bytes and then another one with 256, right? Or they could even be broken up further depending on when the data was put in the stream, what the load on the system is, right? So that, that could change. So definitely don't make any assumptions about it.
[ Period of silence ]
[ Period of silence ]
Did that already. OK, OK. So now, when you guys go to use this in the simulator, you'll notice something. You'll notice that the simulator actually, it actually indicates that two accessories are already connected to your iPhone simulator.
Now this is because it's a simulator we can't take real accessories and we can't show them. But we do, we do bring up two and if you do try to form a session with one, you won't be able to because they don't have protocols. So we just put, we tried to put as much information there as we could to try and help you guys out and give you examples. But it does have, they do contain name and fake serial numbers and all this.
So you guys can have fun with that. Did, perfect. OK, now, I'll switch back to my demo. Now when debugging with external accessories, you're going to run into this very unique sort of situation that most of you haven't run into before. Which is it'll become difficult to debug with XCode unless you take a few measures.
So if you're developing a Bluetooth accessory you're fine, right? Because you can use that cable that came with your iPhone or your iPod Touch to connect your iPhone to your Mac and you'll be able to run XCode and you'll be able to run GDB and you'll be able to connect and set break points and set through your code and debug, right? You'll be fine.
But the accessory that I'm using here is just a very simple UART accessory. And unfortunately, it's connected to the 30 pin. So I can no longer connect that cable that came with my iPhone and my iPod Touch. So what you'll want to do is if possible in your hardware design, definitely have something near the 30 pin where you can fly out USB wires and that you can connect them to your PC.
So if you've got some pads that are laid down on your PCB that you can use and in some debug hardware you'll fly out a cable. You'll find that'll be a lot easier. And while your accessory is connected, you'll actually be able to run GDB and debug fix code.
[ Applause ]
We had talked about the Bluetooth case. Next, if you're developing a USB accessory then this will be a little bit more complicated. So when we use, when we communicate over USB, we use a different USB configuration than when you're you know synched to your machine or when you're connected through XCode. So you'll no longer be able to use XCode directly with your, with your, with your application.
So again, there's other techniques you can use. You can do logging through WiFi or you can go through and actually you know save data to disk or you can check out syslog there. There's a few things that you can do to get around this. But if you are developing a USB accessory and you're not sure how to go about it or really not sure how you're going to debug, we suggest that you come to the lab and we can help you out and give you a few tricks that, that we use internally to do that.
Alright. So that's debugging your hardware when using real EAAccessories. So finally at the start we, we promised that we would talk a little bit about designing your own EA protocol just based on our experience working with accessory manufacturers and accessory developers. So one is data integrity. This is a very, very important concept. Obviously you're working with hardware you can, you can lose bytes and also in an application it does happen that you, there's some kind of erase condition. And like we talked about, you won't get the bytes necessarily formed in the same way that you expect them.
So for example if someone is sending a K of data as four separate 256 you know packets of, four 256 byte of data packets, you might get those in two 512s, right? So it's important that on your application you actually check. So either through a CRC or a checksum or some type of you know data integrity method, that you make sure that when you form your packet, when you reform your information in your application, that it's what you expected.
That the bytes are what your actual hardware accessory expected to send. Next is security. So we put up that slide where we said the EA protocols any developer that connects your accessory to it is going to see that you've got an accessory connected to the system and it'll be able to see the protocols that that accessory supports.
So it's important that if that is a concern to you that you go through and you build in some security, so identification authorization, authentication, some kind of way so that you can make sure that if you don't want people using your accessory that they won't be able to. Next is this concept of framing. So this, these all kind of tie together. So when you work with data integrity let's say something on the wire does disappear. And you end up with the bytes that you don't expect.
Well all of a sudden, your stream can go completely out of synch, right? And your application layer you're looking at it and you don't know you know where the start of your data is again because some of it was lost. Well when that happens, we definitely suggest that you use some kind of framing.
So we'll go through, we'll have another example in a few minutes that'll give you a good example of this, but people that are familiar with Bluetooth and USB, they have their own synchronization methods. We definitely suggest that you implement something similar to that in your own protocols just to make sure that if something does happen, you can go, and you can recover from it.
You can, your application can just continue seamlessly. Finally, the last design protocol we'd like to talk about is this kind of hand waving idea of future proofing right? This is kind of difficult because it's so specific to what you guys are trying to do. But basically, we want you to think about how EA Protocols are going to be seen in, when you actually say OK, my accessory is going to work with these applications and the App Store is going to connect some of these protocols to the application that's there to query them for me.
Also, in my protocols I might know where my product line is going in a few years, so I want to make sure to leave room for expansion so that I can keep the same queries going and you know not have them break down depending on what my business model is. So we definitely encourage people to take this into account and think about this when designing this and it'll hopefully save you any haste that'll be in the future. So now performance.
This is a question that we get quite a bit and it's, it's very difficult to go through and characterize performance because it depends so much on how your accessory is using the EA Framework and also how your accessory responds to commands, right? So there's, there's a whole part of the stack that is in your control. And we need to work together right to find out how this protocol is going to work. So on our side, we've done everything we can to ensure speedy transfer across the, the different transports.
So but obviously, because of this, it's difficult for us to go through and actually guarantee something. But we can give you the, the specs on some of the transports that we use. So on UART, we permit you to do 19.2 or 57.6 Kbps, so very, very standard rates, so people out there using [inaudible] controllers can probably very easily find something that'll be able to divide to these clocks.
And next over USB, you're free to use full speed or high speed USB. And over BT, we use RFCOMM. So that's should give you an idea of what the, what the performance you should be able to go. And goals, another thing that we are asked quite a bit is you know Paul, what are the goals? Can I do this with EA Framework? Can I do that? Again, it really depends on what you guys are trying to do.
But I'd like to give you three of the goals that we really wanted to make sure that this framework could accomplish with everything we could think of for external accessories. So one is command and control. So this idea of handheld devices that will go through and send and you know human time information to and from your accessory. Next is some kind of real time data exchange. We definitely wanted to make sure that continuous real time data exchange was definitely possible with this framework.
And that's just file transfer, so that you know, reasonable sized files could definitely go through and easily be transferred to and from your accessories and your applications. So as a little bit of a treat, the, John Ananny, good friend of mine from the iPod and iPhone accessory team that'll come up and show you an example of what he did with the ExternalAccessory framework. John?
[ Applause ]
Thanks Paul.
So as mentioned my name is John Ananny, I'm one of the engineers on the iPod and iPhone accessories team. So Paul has gone through some specific examples of the code on the app side and he's also talked about some of the general principles on how and why you design a protocol. And we thought the next logical step would be to go through a specific example of what one particular protocol looks like in the hopes that this would inspire you to design your own.
So actually have a dark secret, I'm a diehard Pong fan. And it's not always possible to find a local Pong game, so one of the first things I did with the ExternalAccessory framework after it became available was to make a simple one person Pong practice game called Wall Ball. And that's it up there on the right.
There's not a whole heck of a lot going on, but there's a paddle down at the bottom that you control and the game of course as anybody that's played Pong knows is to keep the ball from falling through the bottom of the screen. Turns out there's a protocol underpinning this and the, the amount of data moving back and forth is pretty simple and it seemed like we could go through that example in its entirety for you. So Wall Ball, a couple things going on.
We've got a physical accessory and I'm going to show that in a moment. The physical accessory moves the paddle. There's a push button on the accessory, I have days when I feel like playing with an orange paddle and days that I feel like playing with a blue paddle, so we can use the push button to change the paddle color.
And every single the time the ball this the LED, we send a command down to the physical hardware to say flash the LED when the ball hits the paddle. So the data that's actually moving from the EAAccessory down to the physical, sorry from the EAAccessory up to the application we have regular updates on the position of the controler that drives the paddle.
And every single time the push button gets pressed, we have those events that make it up to the app as well. And the other direction, the app needs to tell the accessory what the state of the LED should be. So enough talking, let's look at it. So what I have is a physical accessory connected to.
[ Period of silence ]
[ Applause ]
So for the hardware hackers in the room, that is in fact a one turn potentiometer, there's nothing too fancy going on here.
[ Laughter ]
And the same simple demo board that Paul used for his example, we have little expansion header here that's monitoring the position of that potentiometer. And we have our app. So let's see if I can play looking over my shoulder here.
Alright so this feels like, this doesn't really feel like a green paddle day, so let's blue, yes. This definitely is a blue paddle day. So it looks like my Pong skills are about as mediocre as they've ever been. So I'm going to need a little bit more practice. But maybe not just now. So this is a UART accessory. There's not a whole heck of a lot of data going back and forth. But there's certainly some structure to how we send the bytes back and forth between app and accessory.
So the protocol itself. It's fundamentally a protocol is just what's the structure to this stream of bytes that's going back and forth between the two end points. And Wall Ball is organized around the notion of frames. So frames are always 4 bytes in length and any one particular frame is a self contained object that contains some particular piece of information either from the app to the accessory or vice versa.
So column 7 there, bit 7 frames are identified on the wire by the presence of a high bit on the 0 byte of the 4 byte frame. So if you think about it from the receiver's point of view, it just sees bytes going by and it needs to somehow achieve frame synchronization to the byte stream and figure out, you know what, what to make of this stream of bytes that's going by. Every single time the receiver sees a byte with its bit 7 set, it can say ah, OK, regardless of where I think I am, I now know for sure that I'm at the start of a, the reception of a frame.
And that tells the receiver to receive three more bytes, now you have four bytes and you can parse and use that information. The actual fields in a frame I've got a 5 bit command field and 16 bits of arbitrary payload and then a 7 bit CRC. We won't talk about the details of the CRC but you can imagine there's plenty of algorithms for detecting whether a byte or multiple bits has been corrupted somewhere in that frame. So if we have a CRC mismatch, we'll just throw the frame away and move on.
So the interesting parts of the frame are the command and the payload. So right now, we just have three commands to find. Two of them that are sent by the accessory and one of them which is sent by the app. The first so command, command value 0 would, would mean OK the payload contains an absolute controller position. So anything from fully counterclockwise to fully clockwise for the rotary controller. Command 1 would mean a bitmask of the states of a the push buttons.
Right now, we just have one push button, so we just use the 0th bit. Those are sent on a frequent schedule so that as the push button is pressed and released, the app is able to see that. And the command value 2 is sent down from the app to the accessory and this would be a bit mask of the desired state of the various LEDs on the board and again in this case we only use the 0th bit for the one particular LED.
And those again can be sent down on a regular schedule or they can be sent on change only. Those are, those are details and you can do a little bit of tuning and optimization is you care to. But the simplest scheme would just be to send updates on a regular, on a regular clock.
So commands 3 and above I haven't defined. They're reserved for future use. I'm not sure, when Wall Ball 2.0 will be, but there has to be one so we'll, we'll keep, we'll keep room for future growth. So the protocol name itself, probably not that many Wall Ball engineers within Apple, but I've tried to keep the namespace fairly tight.
So com.Apple.WallBallletpaddle. If someone else is using this, we'll have to figure out how to resolve the contention. But you'll want to within your organization figure out how to use reverse DNS to manage you know different product lines, different business units. You've got sort of the arbitrary depth of reverse DNS at your disposal here.
So what have we actually achieved? Well frame syncs, so via that bit 7 mechanism, we're very confident that at start up, in response to you know whatever conditions may arise, we're always going to be able to very quickly reachieve frame sync to the byte stream. Data integrity as I said you know 7, 7 bit CRC is plenty powerful to detect. You know you won't do much correction, but you'll certainly detect that there's something wrong with any particular frame and you can discard it.
Future expansion, as mentioned, I don't know what Wall Ball 2.0 looks like, but we've got room for more commands as needs. And this 4 byte frame is pretty low overhead. You could, you could get fancy and you could imagine variable frame lengths as a function of the command and other complications.
But those are, those are details. One thing that we haven't achieved here. In this particular case, the built in security I'm pretty comfortable if someone wants to watch the bytes go by and reverse engineer the Wall Ball control protocol in this particular case, I don't care. But you know you should, you shouldn't, you shouldn't, you shouldn't accidentally forget about issues of security. You should decide whether you do or don't care and engineer accordingly. So, at this point, I'm going to hand back to Paul and he'll talk about how you can get more information and what the next steps would be.
[ Applause ]
Alright, thanks John. So we have obviously tried to put together everything we could in this presentation to help you guys out to get you started and have a great experience with the ExternalAccessory framework. But if you do need more information associated with this feature are few evangelists so send them an email, they somehow seem to know everything which is great. And I've put up a few documentations, a few pieces of documentation there that you'll definitely want to check out.
So the second one again is the Introduction to Stream Programming Guide which I definitely suggest that you look at. I think we tried to give you a good introduction to it. So for people who haven't used it before, but you'll definitely want to go and have a look at that. Next is the iPhone OS Accessories Page. So if you go to developer.apple.com/iPhone/program/accessories, check it out, a lot of good information there.