1 藍牙簡介
藍牙是一種近距離無線通信技術,運作在2.4GHz免費頻段,目前已大量應用于各種移動終端,物聯網,健康醫療,智能家居等行業。藍牙4.0以後的版本分為兩種模式,單模藍牙和雙模藍牙。
- 單模藍牙,即低功耗藍牙模式,是藍牙4.0中的重點技術,低功耗,快連接配接,長距離。
- 雙模藍牙,支援低功耗藍牙的同時還相容經典藍牙,經典藍牙的特點是大資料高速率,例如音頻、視訊等資料傳輸。
如下圖所示,雙模藍牙具有下圖所有的特點,而單模藍牙僅如圖右側所示。
經典藍牙支援音頻(HFP/HSP, A2DP)和資料(SPP, HID等)兩大類協定,在音箱,耳機,汽車電子及傳統數傳行業,由于蘋果對經典藍牙資料傳輸接口有限制(需要過MFI認證),加上功耗偏大,是以在目前移動互聯應用中慢慢地被邊緣化。是以低功耗藍牙順勢而出,由于可支援蘋果4S以上及安卓4.3系統以上的資料傳輸,且功耗極低,目前正在被越來越多的移動互聯裝置所采用,但低功耗藍牙不支援音頻協定,并且受資料傳輸速度限制,其應用也被限制在小資料傳輸行業。而藍牙雙模則是綜合了兩者的優缺點,既可以支援音頻傳輸,同樣可支援資料傳輸,并且相容性也是兩者之和,在對功耗要求不苛刻的情況下,是比較理想的選擇。
2 BLE特點
低功耗藍牙瞄準多個市場,特别是移動智能終端,智能家居,互聯裝置等領域,主要特點包括:
- 低功耗,使用紐扣電池就可以運作數月至數年。
- 快連接配接,毫秒級的連接配接速度,傳統藍牙甚至長達數分鐘。
- 遠距離,長達數百米的通信距離,而傳統藍牙通常10米左右。
藍牙聯盟沿用經典藍牙的規範内容,為低功耗藍牙定義了一些标準
Profile
,Profile了解為資料規範,隻要遵守該規範,任意廠家的藍牙裝置,均可以互相連接配接與通信,例如無線藍牙鍵盤滑鼠,無論是安卓或是iOS還是Windows,均是即插即用,這便是“标準”的力量。低功耗藍牙支援的标準Profile有:
- HID,用于無線滑鼠,鍵盤或其他遙控裝置。
- BatteryServices,電池狀态服務,用于告知電池電量狀态。
- HRP,心率計Profile,用于心率采集。等等。
另外,低功耗藍牙還可以自定義Profile,伴随着智能手機的發展和普及,低功耗藍牙的這個特性得到了發揚光大,同時也拓寬了低功耗藍牙的應用領域。例如,可以自定義一個開關量的Profile,資料01表示開燈,資料00表示關燈,然後手機發送資料01和00就可以控制燈的亮和滅。類似的應用案例有很多,下面總結應用特點
- 支援自定義Profile,可以收發任意格式的資料,如01和00
- 支援自定義裝置,支援任意裝置的連接配接和通信,例如智能藍牙插座等。
提示:低功耗藍牙的Profile均基于GATT(通用屬性規範,後面會詳解)之上,如HID over GATT。也就是說,經典藍牙中的HID規範與低功耗藍牙中的HID規範用的是兩個不同的通道。 |
3 BLE工作流程
本節我們介紹低功耗藍牙的基本行為狀态和主從機互動過程,為後面的低功耗藍牙協定的學習準備基礎。
3.1 角色
BLE裝置角色主要分為兩種角色,
主機(Master或Central)
和
從機(Peripheral)
,當主機和從機建立連接配接之後才能互相收發資料
- 主機,主機可以發起對從機的掃描連接配接。例如手機,通常作為BLE的主機裝置
- 從機,從機隻能廣播并等待主機的連接配接。例如智能手環,是作為BLE的從機裝置
另外還有
觀察者(Observer)
和
廣播者(Broadcaster)
,這兩種角色不常使用,但也十分有用,例如iBeacon,就可以使用廣播者角色來做,隻需要廣播特定内容即可。
- 觀察者,觀察者角色監聽空中的廣播事件,和主機唯一的差別是不能發起連接配接,隻能持續掃描從機。
- 廣播者,廣播者可以持續廣播資訊,和從機的唯一差別是不能被主機連接配接,隻能廣播資料
藍牙協定棧沒有限制裝置的角色範圍,同一個BLE裝置,可以作為主機,也可以作為從機,我們稱之為主從一體,主從一體的好處是,每個BLE裝置都是對等的,可以發起連接配接,也可以被别人連接配接,更加實用。
3.2 廣播
廣播是指從機每經過一個時間間隔發送一次
廣播資料包
,這個時間間隔稱為
廣播間隔
,這個廣播動作叫做
廣播事件
,隻有當從機處于廣播狀态時,主機才能發現該從機。
在每個廣播事件中,廣播包會分别在37,38和39三個信道上依次廣播,如下圖所示。
廣播時間間隔的範圍是從20ms到10.24s,廣播間隔影響建立連接配接的時間。廣播間隔越大,連接配接的時間越長。
另外BLE鍊路層會在兩個廣播事件之間添加一個0~10ms的随機延時,保證多個裝置廣播時,不會一直碰撞廣播。也就是說,設定100ms的廣播間隔,實際上兩次廣播事件的時間間隔可能是100~110ms之間的任意時間。
廣播資料包最多能攜帶31個位元組的資料,一般包含可讀的裝置名稱,裝置是否可連接配接等資訊。
當主機收到從機廣播的資料包後,它可以再發送擷取更多資料包的請求,這個時候從機将廣播
掃描回應
資料包,掃描回應資料包和廣播包一樣,可以攜帶31個位元組的資料。
提示:藍牙4.x,廣播有效載荷最多是31個位元組。而在藍牙5.0中,通過添加額外的廣播信道和新的廣播PDU,将有效載荷增加到了255個位元組 |
3.3 掃描
掃描是主機監聽從機廣播資料包和發送掃描請求的過程,主機通過掃描,可以擷取到從機的廣播包以及掃描回應資料包,主機可以對已掃描到的從機裝置發起連接配接請求,進而連接配接從機裝置并通信。
掃描動作有兩個比較重要的時間參數:
掃描視窗
和
掃描間隔
,如果掃描視窗等于掃描間隔,那麼主機将一直處于掃描狀态之中,持續監聽從機廣播包。
- 被動掃描,主機監聽廣播信道的資料,當接收到廣播包時,協定棧将向上層(也就是應用層,使用者可程式設計)傳遞廣播包。
- 主動掃描,主動掃描除了完成被動掃描的動作外,還會向從機發送一個掃描請求,從機收到該請求時,會再次發送一個稱作
的廣播包。掃描回應
是以,主動掃描比被動掃描,可以多收到掃描回應資料包。
3.4 連接配接
在BLE連接配接中,使用跳頻方案,兩個裝置在特定時間、特定頻道上彼此發送和接收資料。這些裝置稍後在新的通道(協定棧的鍊路層處理通道切換)上通過這個約定的時間相遇。這次用于收發資料的相遇稱為
連接配接事件
。如果沒有要發送或接收的應用資料,則交換鍊路層資料來維護連接配接。兩個連接配接事件之間的時間跨度稱為
連接配接間隔
,是以1.25 ms為機關,範圍從最小值7.5 ms到最大值4.0 s
3.4.1 連接配接參數
Connection Interval連接配接間隔,兩次連接配接事件之間的時間間隔稱為連接配接間隔。1.25 ms為機關,範圍從最小值7.5 ms到最大值4.0 s
Slave Latency從機延遲,如果從機沒有要發送的資料,則可以跳過連接配接事件,繼續保持睡眠節省電量。
Supervision Time-out監控逾時,是兩次成功連接配接事件之間的最長時間。如果在此時間内沒有成功的連接配接事件,裝置将終止連接配接并傳回到未連接配接狀态。該參數值以10 ms為機關,監控逾時值可以從最小值10(100 ms)到3200(32.0 s)。逾時必須大于有效的連接配接間隔。
3.4.2 連接配接參數更新請求
連接配接參數由主機發起連接配接的時候提供,如果從機對連接配接參數有自己的要求,例如要求更低的功耗,或者更高的通信速率等,從機可以向主機發送連接配接參數更新請求。
從機可以在連接配接後的任何時候發起連接配接參數更新請求,但最好不要在主從建立連接配接後立刻發起,建議延遲5s左右再發送請求。
連接配接參數更新請求可以修改:Connection Interval連接配接間隔,Slave Latency從機延遲,Supervision Time-out監控逾時。
3.4.3 有效連接配接間隔
Effective Connection Interval有效連接配接間隔等于兩個連接配接事件之間的時間跨度,假設從機跳過最大數量的連接配接事件,且允許從機延遲(如果從機延遲設定為0,則有效連接配接間隔等于實際連接配接間隔,)。
從機延遲表示可以跳過的最大事件數。該數字的範圍可以從最小值0(意味着不能跳過連接配接事件)到最大值499。最大值不能使有效連接配接間隔(見下列公式)大于16秒。間隔可以使用以下公式計算:
Effective Connection Interval = (Connection Interval) × (1 + [Slave Latency])
Consider the following example:
- Connection Interval: 80 (100 ms)
- Slave Latency: 4
- Effective Connection Interval: (100 ms) × (1 + 4) = 500 ms
當沒有資料從從機發送到主機時,從機每500ms一個連接配接事件互動一次。
3.4.4 連接配接參數的優化考量
在許多應用中,從機跳過最大連接配接事件數。選擇正确的連接配接參數組在低功耗藍牙裝置的功率優化中起重要作用。以下清單給出了連接配接參數設定中權衡的總體概述。
減少連接配接間隔如下:
- 增加兩個裝置的功耗
- 增加雙向吞吐量
- 減少任一方向發送資料的時間
增加連接配接間隔如下:
- 降低兩個裝置的功耗
- 降低雙向吞吐量
- 增加任一方向發送資料的時間
減少從機延遲(或将其設定為零)如下:
- 增加外圍裝置的功耗
- 減少外圍裝置接收從中央裝置發送的資料的時間
增加從機延遲如下:
- 在周邊沒有資料發送期間,可以降低外設的功耗到主機裝置
- 增加外設裝置接收從主機裝置發送的資料的時間
3.5 通信
通俗的說,我們将從機具有的資料或者屬性特征,稱之為Profile,Profile可翻譯為:配置檔案。
從機中添加Profile配置檔案(定義和存儲Profile),作為GATT的Server端,主機作為GATT的Client端。
Profile包含一個或者多個Service,每個Service又包含一個或者多個Characteristic。主機可以發現和擷取從機的Service和Characteristic,然後與之通信。Characteristic是主從通信的最小單元。
- 主機可主動向從機Write寫入或Read讀取資料。
- 從機可主動向主機Notify通知資料。
注意,這裡引用了
服務 Service
和
特征值 Characteristic
的概念。每個服務和特征值都有自己的唯一辨別
UUID
,标準UUID為128位,藍牙協定棧中一般采用16位,也就是兩個位元組的UUID格式。
一個從機裝置包括一個或者多個服務;一個服務中又可以包括一條或者多條特征值,每個特征值都有自己的
屬性 Property
,屬性的取值有:
可讀 Read
,
可寫 Write
以及
通知 Notify
。
- 可讀可寫的字面意思容易了解,表示該特征值可以被主機讀取和寫入資料,
- 而通知則表示從機可以主動向主機發送通知資料。這便是主從機之間兩個典型的通信方式。
下圖是一個典型的從機裝置,該從機包含有一個Profile,兩個個Service和五個Characteristic。我們先來介紹這些特征值的作用,然後介紹如何通過特征值通信。
服務0x180A
180A是藍牙協定裡标準的服務UUID,用來描述
裝置資訊 Device Information
,可以通過該服務,來提供從機裝置的相關說明,例如硬體版本,軟體版本,序列号等資訊。這樣,主機就可以擷取從機的裝置資訊。上圖中我們添加了三個提供具體裝置資訊的特征值,他們分别是:
- 特征值0x2A24,描述産品型号
,例如某智能鎖的産品型号為:“DSL-C07”。Model Number String
- 特征值0x2A25,描述産品序列号
,例如某智能鎖的産品序列号為:“lkjl0016190502500269”Serial Number String
- 特征值0x2A26,描述産品固件版本号 Firmaware Revision String,例如某智能鎖的固件号為:“2.7.2.0”
上述特征值僅有Read屬性,是以主機隻能讀,不能執行寫操作。
服務0xFFF0
FFF0是我們自定義的服務UUID,它包含兩個特征值,用來發送和接收資料。
- 特征值0xFFF1,自定義的資料發送通道,具有Read和Write屬性,主機可以通過該特征值,向從機發送資料,至于發送的資料最大長度,可以在Profile中配置。
- 特征值0xFFF2,自定義的資料接收通道,具有Notify屬性,從機可以通過該特征值,主動向主機發送資料。
假設主機寫特征值的協定棧函數原型為
int GATT_WriteCharValue(uuid_t UUID, uint8 *pValue, uint8 len)
假設從機發送通知的協定棧函數原型為
int GATT_Notification(uuid_t UUID, uint8 *pValue, uint8 len)
那麼主機向從機發送Hello,可以這樣調用協定棧的函數:
GATT_WriteCharValue(0xFFF1,"Hello",5)
那麼從機向主機發送1234,可以這樣調用協定棧的函數:
GATT_Notification(0xFFF2,"1234",4)
3.6 斷開
主機或從機都可以發起斷開連接配接請求,對方會收到該請求,然後斷開連接配接恢複連接配接前的狀态。
3.7 過程示範
現在我們總結一下BLE的工作流程,使用兩個虛拟的BLE硬體來模拟主從機的互動過程。
假設有兩個BLE裝置,使用的是BLE261低功耗藍牙子產品(假設已經下載下傳了用于互動示範的功能固件),一個是主機,名稱為:BleCentral,另一個是從機,名稱為:BlePeripheral,如下圖所示。
3.7.1 步驟1:上電初始化
主機、從機上電後(不分先後順序),首先進行協定棧初始化和相關功能調用,如下圖所示。
- 主機裝置,主機初始化時,需要設定裝置類型,設定用于掃描的相關參數,初始化GATT等協定相關的參數。(下一章節詳細介紹何為GATT)
- 從機裝置,從機初始化時,需要設定裝置名稱,廣播相關參數,從機Profile等。從機一般會立即開啟廣播,也可以等待一個事件來觸發廣播,例如按鍵觸發。
3.7.2 步驟2:主機掃描從機
按鍵按下,觸發主機掃描從機,此時,主機顯示屏列印Scanning正在掃描。此刻的從機仍然處于廣播狀态。
3.7.3 步驟3:發現從機裝置
當主機掃描到從機時,可以傳回已掃描到的從機相關資訊,例如可以提取到下圖中的從機裝置名稱,從機MAC位址,從機的RSSI信号值等資料。
是以,有些應用在從機的廣播包或者掃描回應包中添加自定義字段,這樣就可以被主機通過掃描的方式拿到資料。
3.7.4 步驟4:發送連接配接請求
當主機掃描到從機後,通過MAC位址向從機發送連接配接請求。低功耗藍牙的連接配接速度非常快,100ms左右即可成功連接配接上。如果從機的廣播比較大,則會影響連接配接的速度。
從機在未收到連接配接請求之前仍然處于自由的廣播狀态。
3.7.5 步驟5:成功連接配接從機
當從機收到連接配接請求後,雙方成功建立連接配接,此時雙方的狀态均變為已連接配接狀态。
然後主機可以調用協定棧提供的接口函數來擷取從機的服務。
3.7.6 步驟6:擷取從機服務
擷取從機服務通常是在連接配接成功後就立即執行的,因為隻有擷取從機的服務後,才能與其通信。下圖是主機向從機發送擷取服務的請求。
此刻,從機處于已連接配接狀态。響應服務擷取請求是在底層自動完成,上層無需理會。
3.7.7 步驟7:成功擷取服務
如下圖所示,主機成功擷取到從機的服務,例如擷取到UUID為0xFFF0的Services,該Service有兩個特征值,分别是具有讀寫屬性的0xFFF1,以及具有通知屬性的0xFFF2。
讀寫屬性是指主機可以讀寫該特征值的内容。而通知屬性是指從機可以通過該特征值向主機發送資料。
3.7.8 步驟8:主機向從機發送資料
主機通過特征值0xFFF1,主動向從機發送自定義資料Hello,當資料成功發送後,主機狀态變為:資料已發送。從機将收到主機發來的資料,從機狀态變為收到資料。
3.7.9 步驟9:從機向主機發送資料
從機可以通過Norify的方式主動向主機發送資料,例如下圖,從機通過特征值0xFFF2發送了一條Notify通知,資料内容為:1234
3.7.10 步驟10:發送斷開請求
主機和從機任何一方均可以發起斷開連接配接的請求,對方收到後,狀态将變為已斷開。
3.7.11 步驟11:成功斷開連接配接
從機收到主機發來的斷開請求,此刻狀态變為已斷開。
4 BLE協定棧
BLE協定棧一般是指晶片廠家,依據 Bluetooth SIG 釋出的
Bluetooth Core Specification
核心協定的實作的代碼固件,并提供函數接口,由晶片内部程式調用,可實作上節BLE工作流程等相關功能。
常見的協定棧有德州儀器 TI 的
ble-stack
和 Nordic 的
SoftDevice
。
4.1 功能框圖
在本節中,我們列舉兩家典型的藍牙晶片廠家:TI和Noridc,來深入了解低功耗藍牙協定棧。
下圖是TI的CC26系列晶片協定棧結構圖,
下圖是Nordic的nRF52系列晶片的協定棧結構圖。
4.2 協定棧結構
從上節的兩張協定棧功能框圖中可以看出,無論是哪個晶片廠商實作的BLE協定棧,其結構都非常的相似,均三個部分:
- 底層:Controller
- 中層:Host
- 頂層:Application
然後每一層又分成若幹個子子產品。我們現在由下而上,逐層介紹。
提示:我們将位于頂層的應用層Application也歸到協定棧中描述,其實,應用層Application不屬于協定棧,它是用來調用協定棧提供的接口,然後實作藍牙的功能。 |
4.2.1 控制器Controller
-
,簡稱:Physical Layer
,實體層。PHY層用來指定BLE所用的無線頻段,調制解調方式和方法等。PHY層做得好不好,直接決定整個BLE晶片的功耗,靈敏度以及selectivity等射頻名額。PHY
-
,簡稱:Link Layer
,鍊路層。LL層是整個BLE協定棧的核心,也是BLE協定棧的難點和重點。像Nordic的BLE協定棧能同時支援20個link(連接配接),就是LL層的功勞。LL層要做的事情非常多,比如具體選擇哪個射頻通道進行通信,怎麼識别空中資料包,具體在哪個時間點把資料包發送出去,怎麼保證資料的完整性,ACK如何接收,如何進行重傳,以及如何對鍊路進行管理和控制等等。LL層隻負責把資料發出去或者收回來,對資料進行怎樣的解析則交給上面的GAP或者ATTLL
-
,簡稱:Host Controller Interface
。協定棧應用開發中,我們會經常看到HCI的身影,它對上Host提供Controller的功能接口, 主要用于 2 顆晶片實作 BLE 協定棧 的場合,用來規範兩者之間的通信協定和通信指令等, 是以稱作Host Controller Interface。HCI
4.2.2 主要Host
-
,簡稱:Logical Link Control Adaptation Protocol
。L2CAP對LL進行了一次簡單封裝,LL隻關心傳輸的資料本身,L2CAP就要區分是加密通道還是普通通道,同時還要對連接配接間隔進行管理。L2CAP
-
,簡稱:Attribute Protocol
。ATT層用來定義使用者指令及指令操作的資料,比如讀取某個資料或者寫某個資料。BLE協定棧中,開發者接觸最多的就是ATT。BLE引入了attribute概念,用來描述一條一條的資料。Attribute除了定義資料,同時定義該資料可以使用的ATT指令,是以這一層被稱為ATT層。ATT
-
,簡稱:Security Manager
。SMP用來管理BLE連接配接的加密和安全的,如何保證連接配接的安全性,同時不影響使用者的體驗,這些都是SMP要考慮的工作。SM
-
,簡稱:Generic Access Profile
。GAP是對LL層payload(有效資料包)如何進行解析的兩種方式中的一種,而且是最簡單的那一種。GAP簡單的對LL payload進行一些規範和定義,是以GAP能實作的功能極其有限。GAP目前主要用來進行廣播,掃描和發起連接配接等。GAP
-
,簡稱:Generic Attribute Profile
。GATT用來規範attribute中的資料内容,并運用group(分組)的概念對attribute進行分類管理。沒有GATT,BLE協定棧也能跑,但互聯互通就會出問題,也正是因為有了GATT和各種各樣的應用profile,BLE擺脫了ZigBee等無線協定的相容性困境,成了出貨量最大的2.4G無線通信産品。GATT
4.2.3 應用Application
應用層是使用者開發實際藍牙應用的地方,包含必要的協定棧參數設定,以及各種功能函數的調用。我們分别從藍牙從機和藍牙主機兩種裝置來分析。
- 藍牙從機
- 相關硬體和基礎服務初始化
- 設定廣播參數:廣播資料,廣播間隔,掃描回應等參數或者資料。
- 設定Profile:添加從機服務、特征是,還有設定回調函數用于接收主機資料等。
- 設定綁定管理參數(可選)
- 啟動廣播,開始運作。
- 等待相關事件,及事件處理,例如收到主機發來的資料,被連結等等。
- 藍牙主機
- 相關硬體和基礎服務初始化
- 設定掃描參數。
- 設定連接配接參數。
- 設定綁定管理參數(可選)
- 啟動協定棧,開始運作。
- 等待相關事件,及事件處理,例如掃描事件,從機的Notify事件等等。
5 GAP和GATT
藍牙協定棧分為兩類結構:控制器(Controller)和主機(Host)。每個類别都有子類别,這些子類别執行特定的角色。我們将要研究的兩個子類别是 通用通路配置檔案 (GAP)和 通用屬性配置檔案 (GATT)。
- GAP是Generic Access Profile的縮寫,中文含義是:通用通路配置檔案。
- GATT是Generic Attribute Profile的縮寫,中文含義是:通用屬性配置檔案。
5.1 GAP和GATT差別
區分GAP和GATT很重要。
- GAP 定義了 BLE網絡堆棧的一般拓撲。
- GATT 較長的描述了一旦裝置建立連接配接後如何傳輸屬性(資料)。
GATT特别關注如何根據其描述的規則格式化打包和發送資料。在BLE網絡堆棧中,屬性協定(ATT)與GATT緊密對齊,GATT直接位于ATT的頂部。GATT實際上使用ATT來描述如何從兩個連接配接的裝置交換資料。
5.2 通用通路配置檔案(GAP)
GAP 定義了裝置如何彼此發現、建立連接配接、以及如何實作綁定,同時描述了裝置如何成為廣播者和觀察者,并且實作無需連接配接的資料傳輸,最後,其定義了如何用不同類新的位址來實作隐私性和可解析性。BLE裝置可以使用兩種機制與外界通信:廣播或連接配接。這些機制受通用通路配置檔案(GAP)準則的限制。GAP定義了啟用BLE的裝置如何使其自身可用,以及兩個裝置如何直接互相通信。
通用通路規範GAP(Generic Access Profile)是BLE裝置内部功能對外的接口層,它規定了三個方面:GAP角色、模式和規程、安全問題。
GAP層将裝置分為四種角色,分别是外圍裝置,中央裝置,播報裝置和觀察裝置。這些裝置圍繞着廣播和連接配接的差異性而區分,外圍裝置和播報裝置對外發出廣播資料,中央裝置和觀察裝置掃描外部廣播資料,播報裝置和觀察裝置通常不建立連接配接,而外圍裝置和中央裝置可以建立連接配接。
圍繞着廣播和連接配接,GAP層定義了許多不同的模式(主要是從裝置所處的狀态),在不同模式下的操作稱為“規程”(主要是主裝置所做的操作)。
對于安全問題,GAP層提供了BLE安全管理器的一些列參數設定接口,包括:裝置的安全模式、IO能力、安全級别和密鑰長度等參數。裝置需要根據實際能力設定GAP的安全管理器參數,進而使用合适的配對方法。
GAP層可以與L2CAP建立聯系,設定自定義的MTU值。
1. GAP角色
GAP層定義了四種角色:
- 外圍裝置(Peripheral)
- 中央裝置(Central)
- 播報裝置(Broadcaster)
- 觀察裝置(Observer)
A、廣播(Broadcasting):這些角色不必顯式地互相連接配接即可傳輸資料。
- 廣播者(Broadcaster):發送廣播和接收掃描請求,通常不建立連接配接,對應着鍊路層的廣播狀态,例如可以廣播按下按鈕的時間。
- 觀察者(Observer):偵聽(掃描)廣播者發送的廣告包中資料廣播和發起掃描請求,通常不建立連接配接,對應着鍊路層的掃描狀态,廣播者和觀察者之間沒有任何連接配接。
B、連接配接(Connecting):這些角色必須顯式連接配接和握手才能傳輸資料。這些角色比廣播角色更常用。
- 從機裝置(Peripheral): 通過廣播資料,告知其他裝置自己的存在,以便主機裝置可以發送連接配接請求,繼而建立連接配接。連接配接後,從機裝置不再向其他主機裝置廣播資料,而是保持與主機裝置的連接配接,同一時間外圍裝置隻能被一個中央裝置連接配接。
- 從機裝置功耗低,因為它們隻需要定期發送信标即可。主機裝置負責開始與從機裝置的通信。
- 手環是BLE外設的一個示例。
- 主機裝置(Central):一種通過偵聽(掃描 )廣播包來啟動與從機裝置的連接配接的裝置。主機裝置可以連接配接到許多其他從機裝置。
- 當主機裝置要連接配接時,它将請求連接配接資料包發送到從機裝置。如果從機裝置接受來自主機裝置的請求,則建立連接配接。
- 當您的手機連接配接到手環時,手機就是BLE Central裝置的一個示例。
由于鍊路層支援同時擁有多個狀态機,GAP層也支援一個裝置同時具有多個GAP角色,比如在一個連接配接中充當中央裝置,同時對外發出廣播充當外圍裝置。
2.使用者接口
GAP定義了幾個與使用者操作密切相關的參數:裝置位址,裝置名,PIN碼和裝置外觀。
2.1 裝置位址
裝置位址在協定棧内部指BD_ADDR,在使用者界面顯示為“Bluetooth Device Address”。
裝置位址為一個6位元組的整形數組成,可以用冒号作為分隔符,比如00:0C:3E:3A:4B:69。
在使用者界面,裝置位址以自然順序顯示,而内部的BD_ADDR則以逆序儲存,對于上述位址,BD_ADDR[0]等于0x69而不是0x00。
裝置位址分為共有位址和随機位址,随機位址分為靜态随機位址和私有位址,私有位址進一步分為可解析的私有位址和不可解析的私有位址。常用的位址為共有位址和可解析的私有位址兩種類型。
關于裝置位址類型分析,參見鍊路層的文章介紹。
2.2 裝置名
裝置名稱僅起識别裝置的作用,在使用者界面顯示為“Bluetooth Device Name”。
裝置名最長可達248個位元組,但是對端裝置可能并不能顯示這麼長的名稱。
裝置名支援UTF-8編碼,是以裝置名可以使用中文。
2.3 PIN碼
PIN碼指兩個裝置配對時使用的passkey密碼,在使用者界面顯示為“Bluetooth Passkey”。
PIN碼為6位十進制整形數,是以它的有效範圍為000000-999999(0x00000000 – 0x000F423F)。使用時必須顯示全部6位數字,包括前導0。
2.4 裝置外觀
裝置外觀僅起識輔助别裝置的作用,在使用者界面顯示為一個圖示或一個字元串。
裝置外觀為一個2位元組數,掃描裝置可以通過裝置外觀值為裝置配置設定一個合适的圖示或描述。
3. 模式和規程
模式表示一種工作狀态,規程是針對模式實作的一套操作方法。模式和規程成對出現,GAP規定了五種模式和規程,如下:
模式 | 規程 |
---|---|
Broadcast Mode | Observer Procedure |
Discovery Mode | Discovery Procedure |
Connection Mode | Connection Procedure |
Bonding Mode | Bonding Procedure |
Periodic Advertising Mode | Periodic Advertising Procedure |
3.1 播報模式和觀察規程
播報模式并不等同于普通的廣播狀态。
在播報模式下,裝置在廣播事件中發送不可連接配接的廣播資料,播報裝置可以響應外部的掃描請求。
播報裝置的廣播資料格式與普通的廣播資料相同,但是它不設定LE Limited Discoverable Mode和LE General Discoverable Mode這兩個标志位,即播報裝置是Non-discovery裝置,這意味着中央裝置掃描到該廣播資料,應該選擇忽略。
觀察規程用于監聽播報裝置的廣播資料和掃描響應資料,也可以監聽普通廣播裝置。
3.2 可發現模式和發現規程
可發現模式分為三種,如下:
可發現模式 | 描述 |
---|---|
Non-Discoverable mode | 不可發現模式,掃描裝置應該選擇忽略這類廣播資料。 |
Limited Discoverable mode | 有限發現模式,廣播資料僅工作有限時間内是可被發現的。 |
General Discoverable mode | 普通發現模式,沒有額外限制。 |
有限發現模式将廣播資料的LE Limited Discoverable Mode位置為1,普通發現模式将廣播資料的LE General Discoverable Mode位置為1,如果這兩個标志位均不設定,就是不可發現模式。
不可發現模式的廣播資料與其他兩種模式相同,是以其廣播資料仍然能夠被掃描裝置正确讀取,但由于沒有設定相應的标志位,掃描裝置在解析廣播資料時應該尊重其不願意被發現的意圖,主動忽略該廣播資料。
使用觀察規程的觀察裝置,則不會忽略不可發現模式的廣播資料。
有限發現模式通常用于使用者指定的行為讓裝置臨時進入可發現狀态,可發現狀态持續時間為T_GAP[lim_adv_timeout]。
普通發現模式是預設模式,它沒有時間限制。
發現規程分為兩種,如下:
發現規程 | 描述 |
---|---|
Limited Discovery Procedure | 有限發現規程,僅能發現有限發現模式的廣播資料。 |
General Discovery Procedure | 普通發現規程,沒有額外限制。 |
有限發現規程,僅處理有限發現模式下的廣播資料,包括裝置位址和廣播資料,忽略其他發現模式下的廣播裝置。
正常發現規程,能普通發現模式和有限發現模式下的廣播資料。
此外還有一種發現規程,專用于發現裝置名稱,如下:
發現規程 | 描述 |
---|---|
Name Discovery Procedure | 裝置名發現規程,用于發現廣播裝置的裝置名稱。 |
裝置名發現規程,可以發現普通發現模式和有限發現模式下的廣播裝置名稱。
發現裝置名稱的步驟如下:
- 建立連接配接
- 讀取GATT中的名字特征值
3.3 可連接配接模式和連接配接規程
可連接配接模式分三種,如下:
可連接配接模式 | 描述 |
---|---|
Non-Connectable Mode | 不可連接配接模式,無法與其他裝置建立連接配接。 |
Directed Connectable Mode | 定向可連接配接模式,可以與指定的中央裝置建立連接配接。 |
Undirected Connectable Mode | 非定向可連接配接模式,可以與任何中央裝置建立連接配接,這是預設的可連接配接模式。 |
而相關的連接配接規程則由四種,如下:
連接配接規程 | 描述 |
---|---|
Auto Connection Establishment Procedure | 自動連接配接建立規程,利用中央裝置的裝置位址白名單,一旦位址比對就自動建立連接配接。 |
General Connection Establishment Procedure | 普通連接配接建立規程,這是預設的連接配接規程,沒有額外條件。 |
Selective Connection Establishment Procedure | 可選連接配接建立規程,利用中央裝置的裝置位址白名單,隻有位址比對的裝置才能建立連接配接。 |
Direct Connection Establishment Procedure | 定向連接配接建立規程,與指定位址的外圍裝置建立連接配接。 |
此外,還有兩個與連接配接相關的規程,如下:
規程 | 描述 |
---|---|
Connection Parameter Update Procedure | 連接配接參數更新規程,更新連接配接參數資訊。 |
Terminate Connection Procedure | 終止連接配接規程,終止目前連接配接。 |
3.4 可綁定模式和綁定規程
可綁定模式分為:
可綁定模式 | 描述 |
---|---|
Non-Bondable mode | 不可綁定模式,裝置不支援配對操作,在配對請求指令中清除Bonding_Flags标志位。 |
Bondable mode | 可綁定模式,裝置将設定認證請求指令中的Bonding_Flags标志位,并且儲存綁定資訊。 |
兩個未綁定的裝置,在通路需要綁定權限的資料時,執行綁定規程。
3.5 周期廣播模式和周期廣播規程
周期廣播模式分為:
模式 | 描述 |
---|---|
Periodic Advertising Synchronizability mode | 周期廣播同步模式,發送周期廣播事件的同步資訊,适用于播報裝置, |
Periodic Advertising mode | 周期廣播模式,發送周期廣播資料,适用于播報裝置 |
周期廣播規程為:
規程 | 描述 |
---|---|
Periodic Advertising Synchronization Establishment procedure | 周期廣播同步建立規程,接收周期廣播事件的同步資訊并同步周期廣播事件,适用于觀察裝置。 |
3.6 安全模式和認證規程
共有兩種安全模式:
安全模式 | 描述 |
---|---|
LE Security mode 1 | 安全模式1,使用認證資訊保證安全。 |
LE Security mode 2 | 安全模式2,使用數字簽名保證安全。 |
安全模式1下有四種安全級别:
- No security (No authentication and no encryption)
- Unauthenticated pairing with encryption
- Authenticated pairing with encryption
- Authenticated LE Secure Connections
四種安全級别圍繞着認證和加密進行,安全級别依次增加,第1種安全級别沒有認證和加密, 第2種安全基本提供未認證的加密,第3、4種安全級别能夠提供認證和加密。
安全模式2下有兩種安全級别:
- Unauthenticated pairing with data signing
- Authenticated pairing with data signing
假如裝置同時要求加密和數字簽名,将視認證需求選擇合适的安全模式,比如需要認證則選擇模式1.3,不需要認證則選擇模式1.2,如果需要安全連接配接則選擇模式1.4。
共有四種安全規程,如下:
規程 | 描述 | 适用安全模式 |
---|---|---|
Authentication procedure | 認證規程,執行認證和加密操作。 | 安全模式1 |
Authorization procedure | 授權規程,使用者行為确認是否為某個操作提供授權。 | 安全模式1 |
Connection data signing procedure | 連接配接資料簽名規程,在未加密的連接配接中傳輸認證的資料。 | 安全模式2 |
Authenticate signed data procedure | 認證已簽名的資料規程,校驗帶有前面的資料是否有效。 | 安全模式2 |
Encryption procedure | 加密規程,對連接配接和資料進行加密。 | 安全模式1 |
3.7 隐私規程
隐私與私有位址有密切關系,跟私有位址相關的規程如下:
規程 | 描述 |
---|---|
Non-resolvable private address generation procedure | 不可解析私有位址生成規程 |
Resolvable private address generation procedure | 可解析私有位址生成規程 |
Resolvable private address resolution procedure | 可解析私有位址解析規程 |
4. 廣播包
廣播包和掃描響應使用相同的資料格式,如下:
一個廣播包由多個AD Structure組成,傳統廣播包的最大長度為31位元組,擴充廣播包的最大長度為255位元組,未占用的資料則補零。
一個AD Structure中包含三個元素:長度、廣播資料類型和廣播資料。
其中長度指廣播資料類型加上廣播資料的總長度,廣播資料類型決定了廣播資料的屬性,可以代表裝置名、裝置位址或服務的UUID。完整的廣播資料類型可以在官方網站檢索(連結)。
動态的廣播資料适合放在廣播包中發送,靜态的廣播資料适合放在掃描響應包中發送。
7. GAP特征項
每個BLE裝置的GATT均包含必要的GAP服務項,GAP服務項包含以下特征項:
特征項 | UUID | 描述 |
---|---|---|
Device Name | 0x2A00 | 讀取裝置名稱 |
Appearance | 0x2A01 | 讀取裝置外觀 |
Peripheral Preferred Connection Parameters | 0x2A04 | 讀取期望的連接配接參數 |
Central Address Resolution | 0x2AA6 | 中央裝置支援解析位址,供外圍裝置讀取以确定中央裝置能否使用位址解析,僅在使能了隐私功能時使用,否則應删除 |
Resolvable Private Address Only | 0x2AC9 | 裝置僅使用可解析的随機位址,供對端裝置讀取以确定該裝置在綁定後是否僅使用可解析的随機位址,僅在使能了隐私功能時使用,否則應删除 |
5.3 通用屬性配置檔案GATT(Generic Attribute Profile)
5.3.1 模型角色
GATT分為兩種類型,注意與從機或主機無關,即主機可能是用戶端也可能是服務端,從機可能是服務端也可能是用戶端,其重點主要是看誰提供資料,誰使用資料,提供資料一方為服務端,接收資料一端為用戶端。
用戶端(Client):用戶端可以發送請求給GATT服務端,用戶端可以讀(Read)/寫(Write)服務端的屬性(Attributes ),通過屬性可以通信資料。
服務端(Server):服務端是用來存儲屬性(Attributes )的,每當用戶端發送請求時,服務端會相應這些請求。
5.3.2 用戶端與服務端的關系
一個示例如下:手環采集了心跳資訊,希望計算機讀取該資訊。手環充當服務端并提供資訊。手機充當用戶端,讀取該資訊。
GAP和GATT模型角色基本上彼此獨立從機裝置或主機裝置都可以充當服務端或用戶端,這取決于資料的流動方式。
在一般的主從機通信時,主機可以通過讀寫從機的屬性,實作接收和發送資料給從機,從機可以通過發送通知的方式實作與主機的通信。是以,一般從機是作為GATT的服務端,主機作為GATT的用戶端。
5.3.3 BLE GATT(Generic Attribute Profile)規範
1. GATT是低功耗藍牙屬性應用規範,應用于主機和從裝置之間的資料傳輸。其與GAP并列為BLE兩大profile。
Attribute是屬性的意思。何為屬性?在各藍牙單晶片平台的SDK實際使用中,屬性是指一條帶有标簽的、可以被尋址的資料。在藍牙實際的規範中,尋址即用handle句柄來表示。每個屬性都對應一個唯一的handle。
2. 對屬性協定需求的思考
藍牙是無線通信,BLE利用屬性協定進行傳輸,其如此重要,如果我們不了解其需求,那麼我們也很難從真正去了解其規範。盡管在實際的藍牙單晶片SDK中很容易通過模仿的方法進行應用,但是如果想深入地了解其為什麼要設計呢?
1) 連接配接的參數是一個裝置的固有參數,一般會作為一個服務來提供,如GAP服務;而假設這個裝置是一個溫度采集器,那麼這個溫度采集明顯跟裝置的參數不屬于一類,是以可以再作為一個服務。是以屬性協定應該支援多個服務。如何來區分這些不同的服務?這即對應藍牙标準規範規定的UUID。我們可以認為不同的UUID對應不同的确定的服務。
2) 連接配接的參數可以有多個,如Connection Interval、Slave Latency等等,我們如何區分這是一個服務,又如何區分服務包含了這些特性參數。我們可以認為一個服務包含了多個特性(參數)。在藍牙标準裡面,同樣是用不同的UUID來區分服務類型、特性類型等等。
3) 對于每個特性characteristic,要讓對方擷取這個特性,就必須要分别告訴對方這個特性的長度是多少,值是多少,而不能隻給數值。除此之外,特性還可能有描述值(說明特性名稱或者作用等)、特性機關等(國際機關,如米是公裡/每小時還是米/秒)。後面這兩個是非必選的。
4) 屬性還應該有一個通路控制,如可讀可寫還是讀寫、或者是通知notify/indicate等等,這是資料通信必須具有的權限控制,不管是服務還是特性,它都具有通路控制屬性。
3. 屬性和屬性類型
屬性由屬性句柄、屬性類型、屬性值組成。如下圖:
1) 屬性句柄在實際的運用中可以認為是屬性在屬性數組中的下标。我們都知道在實際的程式設計中,下标并不需要專門存儲,而隻是通過元素的結構體來進行索引即可。是以可以認為屬性句柄是一個無形的東西,它隻能被所在的裝置程式所認識,而不能用于無線傳輸。
2) 屬性類型是真實存在的,其和屬性值都會被實際存儲。屬性類型是由藍牙标準組織所規範,其一般通過128位的UUID來表征一個具體的屬性。由于BLE的GATT可以認為是藍牙标準規範的精簡版,是以BLE被允許隻傳輸前面2位元組(16位)的UUID,所有的BLE的UUID的基數都是一樣的,如下,隻有前面兩位元組不同。
利用2位元組(16位)也可以定義65536種屬性了。事實上,藍牙标準組織對這些UUID進行了分類。如下:
屬性類型即是0x2800~0x28ff,在實際的應用中,屬性類型主要包括:我們主要使用服務和特性定義兩種,其他兩個很少用到。
3) 藍牙标準不僅通過UUID來進行屬性分類,而且還用UUID來确定各種具體的服務和特性。是以我們會看到UUID可能會出現在屬性的屬性類型和屬性值兩個地方。
4) 藍牙标準組織規定兩個ATT_DECL_PRIMARY_SERVICE服務之間的特性都隸屬于第一個服務。這樣可以了解在藍牙服務發現協定中先通過UUID找到目标服務,然後通過ATT_DECL_PRIMARY_SERVICE這個屬性類型找到下一個服務,接着即可以在這兩個服務中進行特性的周遊,周遊的結果即是目标服務的所有特性。
4. 屬性值
屬性值的長度可以最長到512位元組,但對于某些屬性,其長度是固定的。對于藍牙标準裡面規定的UUID所對應的屬性(包括服務、特性定義、特性值、特性描述等等),服務、特性定義的長度是确定的,而特性值則是不固定長度的。
是以,對于不同的屬性,其屬性值是不一樣的。也即對于以上五類(通用服務、機關、屬性類型、特性描述和區分特性類型)等屬性,其屬性值的規範是不一樣,具體到不同的特性類型,其屬性值也是不同的。
BLE藍牙的UUID清單(服務和特性):https://charmve.blog.csdn.net/article/details/109342125
1)通用服務類通過唯一的UUID(0x1800~0x26ff)來辨別一種明确的服務。好比,0x180f代表電池電量服務。
2)計量機關類通過唯一的UUID來辨別一種機關。
3)區分屬性類型類通過唯一的UUID來辨別該屬性是首要服務定義、次要服務、包含服務還是特性定義等。其好比程式中的變量的類型,是整型、位元組型、還是确定的結構體。
4)特性描述類除了描述特性的名稱、作用之外,還有一個非常重要的配置作用。例如如果提供的特性服務需要主動告知對方,那麼對方就必須在連接配接時進行訂閱配置。這樣在該特性的資料值發生變更時能夠主動地進行notify或者indicate。
5)區分特性類型用于使用者定義不同的特性,用于區分該裝置裡面所有的特性。
5. 特性
把特性了解為一個程式中的一個變量是最好了解的。變量有變量類型和值,變量類型有int整型、位元組型等等(其實就是變量的存儲長度),值即具體的數值。相應地,而特性則有值和存儲值的長度的概念。如同變量的聲明和定義,特性characteristic也有聲明和定義(指派)的概念。
一般地,在藍牙标準裡面,特性一般包括三個要素:聲明、數值和描述。前兩者都是必須的。作為通信互動,一個特性必須要告訴對方聲明(存儲長度和通路控制)、定義(具體指派)。在某些特性(如notify或者indicate)裡面,特性還需要告知對方附加的配置屬性(提供訂閱等)。
特性聲明必須作為服務屬性之後的第一條屬性,而數值必須緊随其後。
1) 特性聲明
性質為一個8位字段,訓示通路控制權限,包括讀、寫、notify或者indicate等。對于特性聲明而言,其一般是隻讀的(這裡隻針對聲明這條屬性本身,而不是針對對應的特性數值)。數值句柄即用于直接尋址接下來的特性數值。其對于通信的對方是很有好處的,因為對方隻需要記錄該句柄即可在後續的通路中直接尋址,否則每次通信都要周遊。在實際的程式設計應用中,我們往往在初始化時填入0,代表由底層邏輯來自動更新該handle。而屬性UUID和接下來的特性數值屬性的區分特性類型值是一緻的。
2)特性數值
特性數值也是一個屬性,其屬性類型填入特性聲明的屬性UUID。屬性值要填入特性數值的通路權限、長度和數值。
3)特性描述
其可以是字元串表示的特性名稱,或者是notify/indicate要求的配置等等。
5.3.4 屬性協定範例(說明)
例如一個電池服務包括一個特性(電池電量),那麼其至少包括以下屬性:首要服務定義(電池服務)、目前電量的特性定義(定義值長度)、目前電量的特性值。如果希望電池電量在低于某個水準時主動告知對方,那麼這個電量特性值不僅應該是可讀的,還應該是能夠notify的。由于有主動告知,是以該特性還需要包括配置要素,用于對方來訂閱。
1.對于電池服務這個屬性,其屬性類型是ATT_DECL_PRIMARY_SERVICE(0x2800),屬性值是通路可讀和藍牙标準組織規定的0x180f(位于0x1800到0x26ff之間);
2.電池目前電量的特性定義這個屬性,其屬性類型是ATT_DECL_CHARACTERISTIC(0x2803),屬性值是可讀、特性值句柄和特性值的UUID(0x2A19)。
3.對于目前電量的特性值這個屬性,其屬性類型是0x2A19(0x2A00~0x7fff之間,區分特性類型),其用于區分多種不同的特性(如一個溫度采集器可能要采集多個溫度,這裡就要使用者通過不同的UUID來區分不同的特性了),屬性值即通路控制(可讀/indicate)、長度(1位元組)、數值。
4.配置屬性,用于notify的訂閱配置。其屬性類型是0x2902,屬性值是可讀/可寫(要能寫入訂閱方的handle)、長度(2個位元組)、handle值。
根據以上分析,我們來重構這個藍牙的資料底層資料庫。
6 協定棧分層協作
下面以如何發送一個無線資料包的例子來簡單闡述協定棧中各分層的作用和必要性。實際上,協定棧的實作可能更加負責,它需要考慮方方面面的因素。
6.1 廣播态資料包
廣播(Advertising),之所謂稱之為廣播,最初的含義(BLE 4.2)是為了讓其他裝置發現自己的存在,也就是告訴空中的其他裝置:“我在這裡啊~~,這是我的位址 0xAABBCCDDEEFF ”(BD Address 我瞎寫的),其他的處于 Scanning 狀态的裝置,就能夠發現廣播者了。
廣播(後面稱為 ADV 或者 Adv)也分為,可連接配接/不可連接配接 ADV,可掃描/不可掃描 ADV,定向/不定向 ADV,等以及他們的各種組合。(唐僧給悟空啰嗦這些,肯定要被活活 K 死)。好了,現在不管那麼多,咱們先來介紹各種 ADV 包的格式以及用法(請看官耐心)。
6.1.1 ADV 廣播包組成
廣播包的組成呢,也遵循上一節講的資料包的基本組成方式(BLE(3)—— 空口資料包組成),隻不過 AA 變為了特定值(0x8E89BED6),PDU 賦予了它新的生命:
廣播的 PDU 組成主要由 Header 和 Payload 構成:
Header 由 16bits 構成,Payload 長度為 1~255 位元組。
我們一步一步來,先看看 Header 域。
6.1.2 ADV PDU Header
Header 包含的内容比較豐富:
1、PDU Type:辨別這種 ADV 是什麼類型的 ADV(後面詳細介紹)
2、RFU : Reserved For Further 暫時不用,為後續預留
3、ChSel:如果本機支援跳頻(Hopping)算法 #2,這設定成為 1
4、TxAdd:如果為 0 代表 ADV 是 public 類型的 Address,否則為 1,是 random 類型的 Address
5、RxAdd:如果為 0 代表期望的對端位址類型為 public,否則為1,代表期望對端的 Target Address 為 random(在指向性廣播中使用,因為指向性廣播,攜帶了對端位址,其他類型廣播,這個 bit 沒用)
6、Length:代表了後面的 Payload 的長度,以直接為機關,因為是 8bits,是以最大的長度為 255 個位元組
好了,這裡就剩下 PDU Type 沒用詳細介紹了,在介紹這個之前呢,需要給大家插播一條 BLE4.2 Vs BLE 5.x,這樣了解這個玩意會更加容易。
---------------------------------------------------- 插播内容開始 ---------------------------------------------------
在 BLE 4.2 時代,所有的 ADV 都在 37、38、39上進行發送和接收互動,這裡我們稱 37、38、39 為 Primary Advertising Physical Channel 并且呢,ADV 攜帶的資料最大是 31 個位元組。
到了 BLE 5.0 時代,SIG 說,ADV 你們幾爺子也可以在其他頻道上搞事情了,好了,這個時候,SIG 對 ADV 進行了擴充,Core Spec 管這些新來的 ADV 大爺叫做 Extended ADV,也就是擴充廣播(名字簡單粗暴吧)。擴充廣播是怎麼個擴充法子呢?就是在 Primary Advertising Physical Channel 上,還是會發一個叫 EXT_ADV 的包,這個包呢,攜帶了一些資訊,資訊中包含了下一個和他關聯的包的所在地(Secondary Advertising Physical Channel),這個所在地,就不是 37、38、39了,而是其他的 37 個通道中的一個,具體是哪個,由這個 EXT_ADV 的包來決定。
---------------------------------------------------- 插播内容結束 ---------------------------------------------------
好了,這裡主要插播的目的是引出,Extended ADV 的概念和 Secondary Advertising Physical Channel 的概念。OK,我們繼續包格式的分析之旅。
1、ADV PDU Header PDU Type
Alright,下圖表示了 PDU Type 不同,所對應的包的不同,以及他們的 Physical Channel,甚至于支援的 PHYs:
我覺得已經非常清楚了(可能是我已經知道了後面的内容的緣故),如果覺得不清楚呢,沒事,看完 ADV 的所有分析後,在回頭來看這個表,客官您一定會覺得豁然開朗。
遠古時代,就已經支援個一些種類的 ADV PDUs,咱們稱之為,Legcay ADV:
• ADV_IND
• ADV_DIRECT_IND
• ADV_NONCONN_IND
• ADV_SCAN_IND
接下來一個一個分析呗。
2.1.1、ADV_IND
這個比較經典和常用的 ADV PDU 了,它代表了咱們發出去的這個 ADV 包,是一個可連接配接的,并且可掃描的廣播包。什麼是可連接配接呢?意思是,我發出去這個包,别人想連接配接我,OK,沒問題。可掃描指的是,有人處于 Scanning 狀态,收到我的這個 ADV_IND 後,對端發起 SCAN_REQ,咱們回複他 SCAN_RSP。
ADV_IND 的 包體為:
AdvA:本機位址 48bits
AdvData:攜帶的資料 0 - 31 位元組
2.1.2、ADV_DIRECT_IND
顧名思義,咱們可以知道這種類型的資料包,是可連接配接的并且帶指向性的(不可掃描),什麼叫指向性呢,也就是,我指着對端的鼻子說,我這個包是專門給你準備的(來連接配接我啊)。是以這個包攜帶了本機位址和指着的那個位址。同時不允許攜帶資料:
AdvA:本機位址 48bits
TargetA:對端位址 48bit
2.1.3、ADV_NONCONN_IND
這種類型的 ADV PDU,屬于不可連接配接,不可掃描,不定向的 ADV 包,包含了本機位址和資料(類似于,在空中散布謠言類型)
AdvA:本機位址 48bits
AdvData:攜帶的資料 0 - 31 位元組
2.1.4、ADV_SCAN_IND
這種類型的 ADV PDU 是隻能掃描的不定向的,不連接配接的 ADV
AdvA:本機位址 48bits
AdvData:攜帶的資料 0 - 31 位元組
假設有裝置A和裝置B,裝置A要把自己的電量狀态83%(十六進制表示為0x53)發給裝置B,該怎麼做呢?作為一個開發者,他希望越簡單越好,對他而言,他希望調用一個簡單的API就能完成這件事,比如
send(0x53)
,實際上我們的BLE協定棧就是這樣設計的,開發者隻需調用
send(0x53)
就可以把資料發送出去了,其餘的事情BLE協定棧幫你搞定。很多人會想,BLE協定棧是不是直接在實體層就把0x53發出去,就如下圖所示:
這種方式初看起來挺美的,但由于很多細節沒有考慮到,實際是不可行的。首先,它沒有考慮用哪一個射頻信道來進行傳輸,在不更改API的情況下,我們隻能對協定棧進行分層,為此引入LL層,開發者還是調用
send(0x53)
,
send(0x53)
再調用
send_LL(0x53,2402M)
(注:2402M為信道頻率)。這裡還有一個問題,裝置B怎麼知道這個資料包是發給自己的還是其他人的,為此BLE引入access address概念,用來指明接收者身份,其中,
0x8E89BED6
這個access address比較特殊,它表示要發給周邊所有裝置,即廣播。如果你要一對一的進行通信(BLE協定将其稱為連接配接),即裝置A的資料包隻能裝置B接收,同樣裝置B的資料包隻能裝置A接收,那麼就必須生成一個獨特的随機access address以辨別裝置A和裝置B兩者之間的連接配接。
6.2 廣播方式
我們先來看一下簡單的廣播情況,這種情況下,我們把裝置A叫advertiser(廣播者),裝置B叫scanner或者observer(掃描者)。廣播狀态下裝置A的LL層API将變成
send_LL(0x53,2402M, 0x8E89BED6)
。由于裝置B可以同時接收到很多裝置的廣播,是以資料包還必須包含裝置A的device address(0xE1022AAB753B)以确認該廣播包來自裝置A,為此send_LL參數需要變成
send_LL(0x53,2402M, 0x8E89BED6, 0xE1022AAB753B)
。LL層還要檢查資料的完整性,即資料在傳輸過程中有沒有發生竄改,為此引入CRC24對資料包進行檢驗 (假設為0xB2C78E) 。同時為了調制解調電路工作更高效,每一個資料包的最前面會加上1個位元組的preamble(前導幀),preamble一般為0x55或者0xAA。這樣,整個空中包就變成(注:空中包用小端模式表示!):
上面這個資料包還有如下問題:
- 沒有對資料包進行分類組織,裝置B無法找到自己想要的資料0x53。為此我們需要在access address之後加入兩個字段:LL header和長度位元組。LL header用來表示資料包的LL類型,長度位元組用來指明payload的長度
- 裝置B什麼時候開啟射頻視窗以接收空中資料包?如上圖case1所示,當裝置A的資料包在空中傳輸的時候,裝置B把接收視窗關閉,此時通信将失敗;同樣對case2來說,當裝置A沒有在空中發送資料包時,裝置B把接收視窗打開,此時通信也将失敗。隻有case3的情況,通信才能成功,即裝置A的資料包在空中傳輸時,裝置B正好打開射頻接收視窗,此時通信才能成功,換句話說,LL層還必須定義通信時序。
- 當裝置B拿到資料0x53後,該如何解析這個資料呢?它到底表示濕度還是電量,還是别的意思?這個就是GAP層要做的工作,GAP層引入了LTV(Length-Type-Value)結構來定義資料,比如020105,02-長度,01-類型(強制字段,表示廣播flag,廣播包必須包含該字段),05-值。由于廣播包最大隻能為31個位元組,它能定義的資料類型極其有限,像這裡說的電量,GAP就沒有定義,是以要通過廣播方式把電量資料發出去,隻能使用供應商自定義資料類型0xFF,即04FF590053,其中04表示長度,FF表示資料類型(自定義資料),0x0059是供應商ID(自定義資料中的強制字段),0x53就是我們的資料(裝置雙方約定0x53就是表示電量,而不是其他意思)。
最終空中傳輸的資料包将變成:
AAD6BE898E600E3B75AB2A02E102010504FF5900538EC7B2
-
– 前導幀(preamble)AA
-
– 通路位址(access address)D6BE898E
-
– LL幀頭字段(LL header)60
-
– 有效資料包長度(payload length)0E
-
– 廣播者裝置位址(advertiser address)3B75AB2A02E1
-
– 廣播資料02010504FF590053
-
– CRC24值8EC7B2
有了PHY,LL和GAP,就可以發送廣播包了,但廣播包攜帶的資訊極其有限,而且還有如下幾大限制:
- 無法進行一對一雙向通信 (廣播是一對多通信,而且是單方向的通信)
- 由于不支援組包和拆包,是以無法傳輸大資料
- 通信不可靠及效率低下。廣播信道不能太多,否則将導緻掃描端效率低下。為此,BLE隻使用37(2402MHz) /38(2426MHz) /39(2480MHz)三個信道進行廣播和掃描,是以廣播不支援跳頻。由于廣播是一對多的,是以廣播也無法支援ACK。這些都使廣播通信變得不可靠。
- 掃描端功耗高。由于掃描端不知道裝置端何時廣播,也不知道裝置端選用哪個頻道進行廣播,掃描端隻能拉長掃描視窗時間,并同時對37/38/39三個通道進行掃描,這樣功耗就會比較高。
而連接配接則可以很好解決上述問題,下面我們就來看看連接配接是如何将0x53發送出去的。
6.3 連接配接方式
到底什麼叫連接配接(connection)?像有線UART,很容易了解,就是用線(Rx和Tx等)把裝置A和裝置B相連,即為連接配接。用“線”把兩個裝置相連,實際是讓2個裝置有共同的通信媒介,并讓兩者時鐘同步起來。藍牙連接配接有何嘗不是這個道理,所謂裝置A和裝置B建立藍牙連接配接,就是指裝置A和裝置B兩者一對一“同步”成功,其具體包含以下幾方面:
- 裝置A和裝置B對接下來要使用的實體信道達成一緻
- 裝置A和裝置B雙方建立一個共同的時間錨點,也就是說,把雙方的時間原點變成同一個點
- 裝置A和裝置B兩者時鐘同步成功,即雙方都知道對方什麼時候發送資料包什麼時候接收資料包
- 連接配接成功後,裝置A和裝置B通信流程如下所示:
如上圖所示,一旦裝置A和裝置B連接配接成功(此種情況下,我們把裝置A稱為Master或者Central,把裝置B稱為Slave或者Peripheral),裝置A将周期性以CI(connection interval)為間隔向裝置B發送資料包,而裝置B也周期性地以CI為間隔打開射頻接收視窗以接收裝置A的資料包。同時按照藍牙spec要求,裝置B收到裝置A資料包150us後,裝置B切換到發送狀态,把自己的資料發給裝置A;裝置A則切換到接收狀态,接收裝置B發過來的資料。由此可見,連接配接狀态下,裝置A和裝置B的射頻發送和接收視窗都是周期性地有計劃地開和關,而且開的時間非常短,進而大大降低系統功耗并大大提高系統效率。
現在我們看看連接配接狀态下是如何把資料0x53發送出去的,從中大家可以體會到藍牙協定棧分層的妙處。
- 對開發者來說,很簡單,他隻需要調用send(0x53)
- GATT層定義資料的類型和分組,友善起見,我們用0x0013表示電量這種資料類型,這樣GATT層把資料打包成130053(小端模式!)
- ATT層用來選擇具體的通信指令,比如讀/寫/notify/indicate等,這裡選擇notify指令0x1B,這樣資料包變成了:1B130053
- L2CAP用來指定connection interval(連接配接間隔),比如每10ms同步一次(CI不展現在資料包中),同時指定邏輯通道編号0004(表示ATT指令),最後把ATT資料長度0x0004加在標頭,這樣資料就變為:040004001B130053
- LL層要做的工作很多,首先LL層需要指定用哪個實體信道進行傳輸(實體信道不展現在資料包中),然後再給此連接配接配置設定一個Access address(0x50655DAB)以辨別此連接配接隻為裝置A和裝置B直連服務,然後加上LL header和payload length字段,LL header辨別此packet為資料packet,而不是control packet等,payload length為整個L2CAP字段的長度,最後加上CRC24字段,以保證整個packet的資料完整性,是以資料包最後變成:
- AAAB5D65501E08040004001B130053D550F6
-
– 前導幀(preamble)AA
-
– 通路位址(access address)0x50655DAB
-
– LL幀頭字段(LL header)1E
-
– 有效資料包長度(payload length)08
-
– ATT資料長度,以及L2CAP通道編号04000400
-
– notify command1B
-
– 電量資料handle0x0013
-
– 真正要發送的電量資料0x53
-
– CRC24值0xF650D5
-
- AAAB5D65501E08040004001B130053D550F6
雖然開發者隻調用了 send(0x53),但由于低功耗藍牙協定棧層層打包,最後空中實際傳輸的資料将變成下圖所示的模樣,這就既滿足了低功耗藍牙通信的需求,又讓使用者API變得簡單,可謂一箭雙雕!
希望通過這個例子,讓大家對協定棧的各層作用有個初步的印象。
文章轉賬自:BLE技術揭秘大全_鄭道鵬鵬鵬的部落格-CSDN部落格