一:介紹

L2CAP -全稱: Logical Link Control and Adaptation Protocol,L2CAP協(xié)議支持更高級(jí)別的協(xié)議復(fù)用和報(bào)文分片。它為RFCOMM和BNEP協(xié)議提供了基礎(chǔ)。對(duì)于BTstack官方支持的所有配置文件,不需要直接使用L2CAP。但是,對(duì)于自定義協(xié)議的測(cè)試或開發(fā),能夠訪問和提供L2CAP服務(wù)是很有幫助的。

二:訪問遠(yuǎn)端設(shè)備上的L2CAP服務(wù)要求 L2CAP基于通道的概念。

信道是在基帶連接之上的邏輯連接。每個(gè)通道以多對(duì)一的方式綁定到單個(gè)協(xié)議。一個(gè)通道可以綁定多個(gè)協(xié)議,但一個(gè)通道不能綁定多個(gè)協(xié)議。多個(gè)通道可以共享同一個(gè)基帶連接。 為了與遠(yuǎn)端設(shè)備上的L2CAP服務(wù)通信,本地藍(lán)牙設(shè)備上的應(yīng)用程序使用l2cap_init函數(shù)初始化L2CAP層,然后使用l2cap_create_channel函數(shù)創(chuàng)建一個(gè)到遠(yuǎn)端設(shè)備PSM的出站L2CAP通道。l2cap_create_channel函數(shù)將初始化一個(gè)新的基帶連接,如果它還不存在的話。作為L(zhǎng)2CAP創(chuàng)建通道函數(shù)的輸入?yún)?shù)給出的數(shù)據(jù)包處理程序?qū)⒈环峙浣o新的出站L2CAP通道。這個(gè)處理程序接收L2CAP_EVENT_CHANNEL_OPENED和L2CAP_EVENT_CHANNEL_CLOSED事件和L2CAP數(shù)據(jù)包,如下面的清單所示。

2402120001

三:提供L2CAP服務(wù)要求

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

2402120002

四:發(fā)送L2CAP數(shù)據(jù)要求

由于BTstack內(nèi)部出包緩沖區(qū)已滿,或者藍(lán)牙模塊中的ACL緩沖區(qū)已滿,也就是說,如果應(yīng)用程序發(fā)送的速度超過了可以通過空氣傳輸?shù)臄?shù)據(jù)包,則L2CAP數(shù)據(jù)包的發(fā)送可能會(huì)失敗。而不是直接調(diào)用l2cap_send,建議調(diào)用l2cap_request_can_send_now_event(cahnnel_id),它將盡快觸發(fā)L2CAP_EVENT_CAN_SEND_NOW。在l2cap_request_can_send_now_event函數(shù)返回之前,可能會(huì)通過包處理程序接收到事件。L2CAP_EVENT_CAN_SEND_NOW表示可以發(fā)送的通道ID。

請(qǐng)注意,數(shù)據(jù)包可以發(fā)送的保證只有在事件被接收時(shí)才有效。從包處理程序返回后,BTstack可能需要發(fā)送自己。

五:LE數(shù)據(jù)通道

LE數(shù)據(jù)通道的全稱實(shí)際上是具有LE基于信用的流量控制模式的面向連接的LE通道。在這種模式下,數(shù)據(jù)以sdu (Service data unit)的形式發(fā)送,sdu的大小可以大于單個(gè)HCI LE ACL報(bào)文。

LE數(shù)據(jù)通道類似于經(jīng)典L2CAP通道,但也提供了類似于RFCOMM通道的基于信用的流量控制。除非使用藍(lán)牙Core 4.2規(guī)范的LE數(shù)據(jù)包擴(kuò)展,否則LE ACL報(bào)文的最大數(shù)據(jù)包大小為27字節(jié)。為了發(fā)送更大的報(bào)文,每個(gè)報(bào)文將被分成多個(gè)ACL LE報(bào)文,在接收端重新組合。 由于多個(gè)sdu可以同時(shí)傳輸,并且各個(gè)ACL LE數(shù)據(jù)包可以交錯(cuò)發(fā)送,因此BTstack需要每個(gè)通道都有一個(gè)專用的接收緩沖區(qū),在創(chuàng)建或接受通道時(shí)必須通過該緩沖區(qū)。類似地,當(dāng)發(fā)送sdu時(shí),提供給l2cap_cbm_send_data的數(shù)據(jù)必須保持有效,直到收到L2CAP_EVENT_LE_PACKET_SENT。 在創(chuàng)建傳出連接或接受傳入連接時(shí),initial_credits允許向遠(yuǎn)程端提供固定數(shù)量的信用??梢噪S時(shí)使用l2cap_cbm_provide_credits提供更多的積分。

如果使用L2CAP_LE_AUTOMATIC_CREDITS, BTstack會(huì)根據(jù)需要自動(dòng)提供積分——為了方便,有效地交換了流量控制功能。 API的其余部分與L2CAP類似:

?L2cap_cbm_register_service和l2cap_cbm_unregister_service用于管理本地服務(wù)。

?L2cap_cbm_accept_connection和l2cap_cbm_decline_connection用于接受或拒絕傳入的連接請(qǐng)求。

?L2cap_cbm_create_channel創(chuàng)建一個(gè)outgoing連接。

?L2cap_cbm_can_send_now檢查一個(gè)數(shù)據(jù)包現(xiàn)在是否可以被調(diào)度傳輸。

?l2cap_cbm_request_can_send_now_event請(qǐng)求L2CAP_EVENT_LE_CAN_SEND_NOW事件。

?L2cap_cbm_disconnect關(guān)閉連接。

六:RFCOMM——無線電頻率通信協(xié)議

射頻通信(RFCOMM)協(xié)議通過L2CAP協(xié)議和重組提供了串行端口的仿真。它是串行端口配置文件和其他用于電信的配置文件的基礎(chǔ),如耳機(jī)配置文件、免提配置文件、對(duì)象交換(OBEX)等。

七:無RFCOMM報(bào)文邊界

由于RFCOMM仿真了一個(gè)串行端口,它不保存包邊界。在大多數(shù)操作系統(tǒng)中,RFCOMM / SPP將被建模為允許編寫塊字節(jié)的管道。操作系統(tǒng)和藍(lán)牙堆??梢宰杂傻鼐彌_和屏蔽這些數(shù)據(jù),以任何方式看起來都是合適的。在BTstack應(yīng)用程序中,因此您將按照同樣的順序接收這些數(shù)據(jù),但是沒有任何保證可以將其分割成多個(gè)塊。如果您需要保留發(fā)送一個(gè)特定大小的包的概念,最簡(jiǎn)單的方法是用2或4字節(jié)長(zhǎng)的字段來前綴數(shù)據(jù),然后在接收方上重建數(shù)據(jù)包。請(qǐng)注意,由于BTstack的“no buffer”策略,BTstack將立即發(fā)送退出的RFCOMM數(shù)據(jù),并隱式地保存包邊界,即。它將將數(shù)據(jù)作為單個(gè)RFCOMM包中的單個(gè)RFCOMM包發(fā)送到一個(gè)單一的L2CAP包中,它將會(huì)在一段時(shí)間內(nèi)到達(dá)。雖然這將在兩個(gè)BTstack實(shí)例之間保持,但依賴實(shí)現(xiàn)細(xì)節(jié)并不像描述的數(shù)據(jù)一樣,這不是一個(gè)好想法。

八:RFCOMM流控制

RFCOMM具有強(qiáng)制性的基于信用的流量控制。這意味著建立RFCOMM連接的兩個(gè)設(shè)備使用積分來跟蹤可以向每個(gè)設(shè)備發(fā)送多少RFCOMM數(shù)據(jù)包。如果設(shè)備沒有剩余的(傳出)積分,則無法再發(fā)送RFCOMM報(bào)文,必須暫停傳輸。在建立連接期間,提供初始學(xué)分。BTstack跟蹤兩個(gè)方向的積分?jǐn)?shù)量。如果沒有可用的信用額度,RFCOMM發(fā)送函數(shù)將返回一個(gè)錯(cuò)誤,您可以稍后再嘗試。對(duì)于傳入數(shù)據(jù),BTstack通過不同的功能分別創(chuàng)建/注冊(cè)具有和不具有自動(dòng)信用管理的通道和服務(wù)。如果信用管理是自動(dòng)的,則在需要時(shí)根據(jù)ACL流控制提供新的信用——這只在傳輸?shù)臄?shù)據(jù)不多和/或只使用一個(gè)物理連接時(shí)才有用。如果積分管理是手動(dòng)的,則由應(yīng)用程序提供積分,以便它可以顯式地管理其接收緩沖區(qū)。

九:訪問遠(yuǎn)端設(shè)備上的RFCOMM服務(wù)

為了與遠(yuǎn)程設(shè)備上的RFCOMM服務(wù)通信,本地藍(lán)牙設(shè)備上的應(yīng)用程序使用rfcomm_init函數(shù)初始化RFCOMM層,然后使用rfcomm_create_channel函數(shù)創(chuàng)建一個(gè)到遠(yuǎn)程設(shè)備上給定服務(wù)器通道的出站RFCOMM通道。如果RFCOMM多路復(fù)用器不存在,rfcomm_create_channel函數(shù)將為RFCOMM多路復(fù)用器發(fā)起一個(gè)新的L2CAP連接。信道將自動(dòng)向遠(yuǎn)端提供足夠的信用。要手動(dòng)提供信用,您必須通過調(diào)用rfcomm_create_channel_with_initial_credits創(chuàng)建RFCOMM連接——參見手動(dòng)信用分配一節(jié)。 作為RFCOMM創(chuàng)建通道函數(shù)的輸入?yún)?shù)給出的數(shù)據(jù)包處理程序?qū)⒈环峙浣o新的傳出通道。這個(gè)處理程序接收RFCOMM_EVENT_CHANNEL_OPENED和RFCOMM_EVENT_CHANNEL_CLOSED事件,以及RFCOMM數(shù)據(jù)包,如下面的清單所示。

2402120003

十:提供RFCOMM服務(wù)

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

2402120004