天天看點

iOS 裝置和外部配件的通訊

轉載自cocoachina http://www.cocoachina.com

首先,如果我們的應用程式想跟外設傳輸資料,先要透過iphone的作業系統,也就是iphoneOS,而最開始的認證過程也是在外設和iphoneOS之間發生的,蘋果為這個過程提供了一顆認證晶片(這顆晶片的作用是用來讓iphoneOS識别這個外設是經過蘋果公司承認的,他的通信方式是I2C總線,而且每出一個産品蘋果都會收幾美元的認證費用,蘋果用心何其毒也~~~)           IphoneOS承認外設分兩個步驟,識别和認證,我們先說說識别過程。           識别過程是使用純實體連接配接來實作的,在這個過程中iphone的30pin有三個引腳被用到,分别是Accessory Identify,Accessory Detect,Accessory Power,Accessory Identify接549k歐姆的電阻,告知iphoneOS使用序列槽通信,Accessory Detect直接接地,告知iphoneOS有外設插入,Accessory Power相當于iphoneOS的信号,待機時這個引腳沒有輸出,否則會有3.3V的電壓輸出。如果按照以上連接配接就完成了識别過程。          下面開始認證過程,認證過程也叫IDPS過程,這些就牽扯到蘋果指定的通信協定了,蘋果給自己的通信協定起了一個名字叫Lingo,Lingo分好多種有音頻的lingo還有顯示遙控的lingo,而我們認證使用的lingo叫做General Lingo。可能大家這時有點暈,那我就給大家看一個iphone的指令包。 StartIDPS packet Byte     Value    Comment 0            0XFF    Sync byte(required only for UART serial) 1            0X55    Start of packet(SOP) 2            0XNN    Length of packet payload 3            0X00    General Lingo 4            0X38    StartIDPS 5            0XNN    transID [bit 15:8] Transaction ID  6            0XNN    transID [bit 7:0] 7            0XNN    校驗 這是iphone的指令包,大家看到這個應該就明白了。開始IDPS過程首先要發送StartIDPS指令,這樣,外設與iphoneOS之間的認證過程就開始了。其中咱們應用中EAAccessory關于一些外設的屬性,都是在這個過程中外設發給作業系統的,具體還是大家加入蘋果的mfi(made for ipod),拿到資料後,才能更明白。稍後我會将iphone序列槽通信的源碼發出來。

MFI位址:http://developer.apple.com/programs/mfi/

以下部分轉載自<iphone應用程式設計指南>

和配件進行通訊

在iPhone OS 3.0及之後的系統上,External Accessory架構

(ExternalAccessory.framework

)提供了一種管道機制,使應用程式可以和iPhone或iPod touch裝置的配件進行通訊。通過這種管道,應用程式開發者可以将配件級别的功能內建到自己的程式中。

請注意:下面部分将向您展示iPhone應用程式如何連接配接配件。如果您有興趣成為iPhone或iPod touch配件的開發者,可以在http://developer.apple.com網站上找到相應的資訊。

為了使用External Accessory架構的接口,您必須将

ExternalAccessory.framework

加入到Xcode工程,并連接配接到相應的目标中。此外,還需要在相應的源代碼檔案的頂部包含一個

#import <ExternalAccessory/ExternalAccessory.h>

語句,才能通路該架構的類和頭檔案。有關如何為工程添加架構的更多資訊,請參見Xcode工程管理指南中的工程中的檔案部分;有關External Accessory架構中類的一般資訊,請參見External Accessory架構參考。

配件的基礎

在和配件進行通訊之前,需要與配件的制造商緊密合作,了解配件提供的服務。制造商必須在配件的硬體中加入顯式的支援,才能和iPhone OS進行通訊。作為這種支援的一部分,配件必須支援至少一種指令協定,也就是支援一種定制的通訊模式,使配件和應用程式之間可以進行資料傳輸。蘋果并不維護一個協定的系統資料庫,支援何種協定及是否使用其他制造商支援的定制或标準協定是由制造商自行決定的。

作為和配件制造商通訊的一部分,您必須找出給定的配件支援什麼協定。為了避免名字空間發生沖突,協定的名稱由反向的DNS字元串來指定,形式是

com.apple.myProtocol

。這使得每個配件制造商都可以根據自己的需要定義協定,以支援不同的配件産品線。

應用程式通過打開一個使用指定協定的會話來和配件進行通訊。打開會話的方法是建立一個

EASession

類的執行個體,該類中包含

NSInputStream

NSOutputStream

對象,可以和配件進行通訊。通過這些流對象,應用程式可以向配件發送未經加工的資料包,以及接收來自配件的類似資料包。是以,您必須按照期望的協定來了解每個資料包的格式。

聲明應用程式支援的協定

能夠和配件通訊的應用程式應該在其

Info.plist

檔案中聲明支援的協定,使系統知道在相應的配件接入時,該應用程式可以被啟動。如果目前沒有應用程式可以支援接入的配件,系統可以選擇啟動App Store并指向支援該裝置的應用程式。

為了聲明支援的協定,您必須在應用程式的

Info.plist

檔案中包含

UISupportedExternalAccessoryProtocols

鍵。該鍵包含一個字元串數組,用于辨別應用程式支援的通訊協定。您的應用程式可以在這個清單中以任意順序包含任意數量的協定。系統并不使用這個清單來确定應用程式應該選擇哪個協定,而隻是用它來确定應用程式是否能夠和相應的配件進行通訊。您的代碼需要在開始和配件進行對話時選擇适當的通訊協定。

在運作時連接配接配件

在配件接入系統并做好通訊準備之前,通過External Accessory架構無法看到配件。當配件變為可見時,您的應用程式就可以擷取相應的配件對象,然後用其支援的一或多個協定打開會話。

共享的

EAAccessoryManager

對象為應用程式尋找與之通訊的配件提供主入口點。該類包含一個已經接入的配件對象的數組,您可以對其進行枚舉,看看是否存在應用程式支援的配件。

EAAccessory

對象中的絕大多數資訊(比如名稱、制造商、和型号資訊)都隻是用于顯示。如果您要确定應用程式是否可以連接配接一個配件,必須看配件的協定,确認應用程式是否支援其中的某個協定。

請注意:多個配件對象支援同一協定是可能的。如果發生這種情況,您的代碼必須負責選擇使用哪個配件對象。

對于給定的配件對象,每次隻能有一個指定協定的會話。

EAAccessory

對象的

protocolStrings

屬性包含一個字典,字典的鍵是配件支援的協定。如果您試圖用一個已經在使用的協定建立會話,External Accessory架構就會産生錯誤。

程式清單8-1展示了如何檢查接入配件的清單并從中取得應用程式支援的第一個配件。它為指定的協定建立一個會話,并對會話的輸入和輸出流進行配置。在這個方法傳回會話對象時,已經完成和配件的連接配接,并可以開始發送和接收資料了。

程式清單8-1  建立和配件的通訊會話

- (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; }

在配置好輸入輸出流之後,最好一步就是處理和流相關的資料了。程式清單8-2展示了在委托方法中處理流事件的基本代碼結構。清單中的方法可以響應來自配件輸入輸出流的事件。當配件向應用程式發送資料時,事件發生表示有資料可供讀取;類似地,當配件準備好接收應用程式資料時,也通過事件來表示(當然,您并不一定要等到這個事件發生才向流寫出資料,應用程式也可以調用流的

hasBytesAvailable

方法來确認配件是否還能夠接收資料)。有關流及如何處理流事件的更多資訊,請參見Cocoa流程式設計指南。

程式清單8-2  處理流事件

// 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;     } }

監控與配件有關的事件

當配件接入或斷開時,External Accessory架構都可以發送通告。但是這些通告并不自動發送,如果您的應用程式感興趣,必須調用EAAccessoryManager類的registerForLocalNotifications方法來顯式請求。當配件接入、認證、并準備好和應用程式進行互動時,架構可以發出一個

EAAccessoryDidConnectNotification

通告;而當配件斷開時,架構則可以發送一個

EAAccessoryDidDisconnectNotification

通告。您可以通過預設的

NSNotificationCenter

來注冊接收這些通告。兩種通告都包含受影響的配件的資訊。

除了通過預設的通告中心接收通告之外,目前正在和配件進行互動的應用程式可以為相應的

EAAccessory

對象配置設定一個委托,使它在發生變化的時候得到通知。委托對象必須遵循

EAAccessoryDelegate

協定,該協定目前包含名為

accessoryDidDisconnect:

的可選方法,您可以通過這個方法來接收配件斷開通告,而不需要事先配置通告觀察者。

有關如何注冊接收通告的更多資訊,請參見Cocoa通告程式設計主題。