L2CAP接口介紹&運用
一:介紹
L2CAP -全稱: Logical Link Control and Adaptation Protocol,L2CAP協(xié)議支持更高級別的協(xié)議復用和報文分片。它為RFCOMM和BNEP協(xié)議提供了基礎。對于BTstack官方支持的所有配置文件,不需要直接使用L2CAP。但是,對于自定義協(xié)議的測試或開發(fā),能夠訪問和提供L2CAP服務是很有幫助的。
二:訪問遠端設備上的L2CAP服務要求 L2CAP基于通道的概念。
信道是在基帶連接之上的邏輯連接。每個通道以多對一的方式綁定到單個協(xié)議。一個通道可以綁定多個協(xié)議,但一個通道不能綁定多個協(xié)議。多個通道可以共享同一個基帶連接。 為了與遠端設備上的L2CAP服務通信,本地藍牙設備上的應用程序使用l2cap_init函數(shù)初始化L2CAP層,然后使用l2cap_create_channel函數(shù)創(chuàng)建一個到遠端設備PSM的出站L2CAP通道。l2cap_create_channel函數(shù)將初始化一個新的基帶連接,如果它還不存在的話。作為L2CAP創(chuàng)建通道函數(shù)的輸入?yún)?shù)給出的數(shù)據(jù)包處理程序將被分配給新的出站L2CAP通道。這個處理程序接收L2CAP_EVENT_CHANNEL_OPENED和L2CAP_EVENT_CHANNEL_CLOSED事件和L2CAP數(shù)據(jù)包,如下面的清單所示。

三:提供L2CAP服務要求
為了提供L2CAP服務,本地藍牙設備上的應用程序必須初始化L2CAP層并通過l2cap_register_service注冊服務。從那里開始,它可以等待進入的L2CAP連接。應用程序可以通過分別調用l2cap_accept_connection和l2cap_deny_connection函數(shù)來接受或拒絕傳入的連接。 如果一個連接被接受并且進入的L2CAP通道成功打開,L2CAP服務可以使用l2cap_send向被連接的設備發(fā)送和接收L2CAP數(shù)據(jù)包。 下面的清單提供了L2CAP服務示例代碼。

四:發(fā)送L2CAP數(shù)據(jù)要求
由于BTstack內部出包緩沖區(qū)已滿,或者藍牙模塊中的ACL緩沖區(qū)已滿,也就是說,如果應用程序發(fā)送的速度超過了可以通過空氣傳輸?shù)臄?shù)據(jù)包,則L2CAP數(shù)據(jù)包的發(fā)送可能會失敗。而不是直接調用l2cap_send,建議調用l2cap_request_can_send_now_event(cahnnel_id),它將盡快觸發(fā)L2CAP_EVENT_CAN_SEND_NOW。在l2cap_request_can_send_now_event函數(shù)返回之前,可能會通過包處理程序接收到事件。L2CAP_EVENT_CAN_SEND_NOW表示可以發(fā)送的通道ID。
請注意,數(shù)據(jù)包可以發(fā)送的保證只有在事件被接收時才有效。從包處理程序返回后,BTstack可能需要發(fā)送自己。
五:LE數(shù)據(jù)通道
LE數(shù)據(jù)通道的全稱實際上是具有LE基于信用的流量控制模式的面向連接的LE通道。在這種模式下,數(shù)據(jù)以sdu (Service data unit)的形式發(fā)送,sdu的大小可以大于單個HCI LE ACL報文。
LE數(shù)據(jù)通道類似于經典L2CAP通道,但也提供了類似于RFCOMM通道的基于信用的流量控制。除非使用藍牙Core 4.2規(guī)范的LE數(shù)據(jù)包擴展,否則LE ACL報文的最大數(shù)據(jù)包大小為27字節(jié)。為了發(fā)送更大的報文,每個報文將被分成多個ACL LE報文,在接收端重新組合。 由于多個sdu可以同時傳輸,并且各個ACL LE數(shù)據(jù)包可以交錯發(fā)送,因此BTstack需要每個通道都有一個專用的接收緩沖區(qū),在創(chuàng)建或接受通道時必須通過該緩沖區(qū)。類似地,當發(fā)送sdu時,提供給l2cap_cbm_send_data的數(shù)據(jù)必須保持有效,直到收到L2CAP_EVENT_LE_PACKET_SENT。 在創(chuàng)建傳出連接或接受傳入連接時,initial_credits允許向遠程端提供固定數(shù)量的信用。可以隨時使用l2cap_cbm_provide_credits提供更多的積分。
如果使用L2CAP_LE_AUTOMATIC_CREDITS, BTstack會根據(jù)需要自動提供積分——為了方便,有效地交換了流量控制功能。 API的其余部分與L2CAP類似:
?L2cap_cbm_register_service和l2cap_cbm_unregister_service用于管理本地服務。
?L2cap_cbm_accept_connection和l2cap_cbm_decline_connection用于接受或拒絕傳入的連接請求。
?L2cap_cbm_create_channel創(chuàng)建一個outgoing連接。
?L2cap_cbm_can_send_now檢查一個數(shù)據(jù)包現(xiàn)在是否可以被調度傳輸。
?l2cap_cbm_request_can_send_now_event請求L2CAP_EVENT_LE_CAN_SEND_NOW事件。
?L2cap_cbm_disconnect關閉連接。
六:RFCOMM——無線電頻率通信協(xié)議
射頻通信(RFCOMM)協(xié)議通過L2CAP協(xié)議和重組提供了串行端口的仿真。它是串行端口配置文件和其他用于電信的配置文件的基礎,如耳機配置文件、免提配置文件、對象交換(OBEX)等。
七:無RFCOMM報文邊界
由于RFCOMM仿真了一個串行端口,它不保存包邊界。在大多數(shù)操作系統(tǒng)中,RFCOMM / SPP將被建模為允許編寫塊字節(jié)的管道。操作系統(tǒng)和藍牙堆棧可以自由地緩沖和屏蔽這些數(shù)據(jù),以任何方式看起來都是合適的。在BTstack應用程序中,因此您將按照同樣的順序接收這些數(shù)據(jù),但是沒有任何保證可以將其分割成多個塊。如果您需要保留發(fā)送一個特定大小的包的概念,最簡單的方法是用2或4字節(jié)長的字段來前綴數(shù)據(jù),然后在接收方上重建數(shù)據(jù)包。請注意,由于BTstack的“no buffer”策略,BTstack將立即發(fā)送退出的RFCOMM數(shù)據(jù),并隱式地保存包邊界,即。它將將數(shù)據(jù)作為單個RFCOMM包中的單個RFCOMM包發(fā)送到一個單一的L2CAP包中,它將會在一段時間內到達。雖然這將在兩個BTstack實例之間保持,但依賴實現(xiàn)細節(jié)并不像描述的數(shù)據(jù)一樣,這不是一個好想法。
八:RFCOMM流控制
RFCOMM具有強制性的基于信用的流量控制。這意味著建立RFCOMM連接的兩個設備使用積分來跟蹤可以向每個設備發(fā)送多少RFCOMM數(shù)據(jù)包。如果設備沒有剩余的(傳出)積分,則無法再發(fā)送RFCOMM報文,必須暫停傳輸。在建立連接期間,提供初始學分。BTstack跟蹤兩個方向的積分數(shù)量。如果沒有可用的信用額度,RFCOMM發(fā)送函數(shù)將返回一個錯誤,您可以稍后再嘗試。對于傳入數(shù)據(jù),BTstack通過不同的功能分別創(chuàng)建/注冊具有和不具有自動信用管理的通道和服務。如果信用管理是自動的,則在需要時根據(jù)ACL流控制提供新的信用——這只在傳輸?shù)臄?shù)據(jù)不多和/或只使用一個物理連接時才有用。如果積分管理是手動的,則由應用程序提供積分,以便它可以顯式地管理其接收緩沖區(qū)。
九:訪問遠端設備上的RFCOMM服務
為了與遠程設備上的RFCOMM服務通信,本地藍牙設備上的應用程序使用rfcomm_init函數(shù)初始化RFCOMM層,然后使用rfcomm_create_channel函數(shù)創(chuàng)建一個到遠程設備上給定服務器通道的出站RFCOMM通道。如果RFCOMM多路復用器不存在,rfcomm_create_channel函數(shù)將為RFCOMM多路復用器發(fā)起一個新的L2CAP連接。信道將自動向遠端提供足夠的信用。要手動提供信用,您必須通過調用rfcomm_create_channel_with_initial_credits創(chuàng)建RFCOMM連接——參見手動信用分配一節(jié)。 作為RFCOMM創(chuàng)建通道函數(shù)的輸入?yún)?shù)給出的數(shù)據(jù)包處理程序將被分配給新的傳出通道。這個處理程序接收RFCOMM_EVENT_CHANNEL_OPENED和RFCOMM_EVENT_CHANNEL_CLOSED事件,以及RFCOMM數(shù)據(jù)包,如下面的清單所示。

十:提供RFCOMM服務
為了提供RFCOMM服務,本地藍牙設備上的應用程序必須首先初始化L2CAP和RFCOMM層,然后在rfcomm_register_service中注冊服務。從那里開始,它可以等待傳入的RFCOMM連接。應用程序可以通過分別調用rfcomm_accept_connection和rfcomm_deny_connection函數(shù)來接受或拒絕傳入的連接。如果一個連接被接受并且傳入的RFCOMM通道成功打開,RFCOMM服務可以使用rfcomm_send向連接的設備發(fā)送RFCOMM數(shù)據(jù)包,并通過rfcomm_register_service調用提供的數(shù)據(jù)包處理程序接收數(shù)據(jù)包。 下面的清單提供了RFCOMM服務示例代碼。
