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
- 支持自定義設備,支持任意設備的連接和通信,例如智能藍牙插座等。
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個字節的數據。
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,描述產品型號
Model Number String,例如某智能鎖的產品型號為:“DSL-C07”。 - 特征值0x2A25,描述產品序列號
Serial Number String,例如某智能鎖的產品序列號為:“lkjl0016190502500269” - 特征值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
然后每一層又分成若干個子模塊。我們現在由下而上,逐層介紹。
4.2.1 控制器Controller
Physical Layer,簡稱:PHY,物理層。PHY層用來指定BLE所用的無線頻段,調制解調方式和方法等。PHY層做得好不好,直接決定整個BLE芯片的功耗,靈敏度以及selectivity等射頻指標。Link Layer,簡稱:LL,鏈路層。LL層是整個BLE協議棧的核心,也是BLE協議棧的難點和重點。像Nordic的BLE協議棧能同時支持20個link(連接),就是LL層的功勞。LL層要做的事情非常多,比如具體選擇哪個射頻通道進行通信,怎么識別空中數據包,具體在哪個時間點把數據包發送出去,怎么保證數據的完整性,ACK如何接收,如何進行重傳,以及如何對鏈路進行管理和控制等等。LL層只負責把數據發出去或者收回來,對數據進行怎樣的解析則交給上面的GAP或者ATTHost Controller Interface,簡稱:HCI。協議棧應用開發中,我們會經常看到HCI的身影,它對上Host提供Controller的功能接口, 主要用於 2 顆芯片實現 BLE 協議棧 的場合,用來規范兩者之間的通信協議和通信命令等, 所以稱作Host Controller Interface。
4.2.2 主控Host
Logical Link Control Adaptation Protocol,簡稱:L2CAP。L2CAP對LL進行了一次簡單封裝,LL只關心傳輸的數據本身,L2CAP就要區分是加密通道還是普通通道,同時還要對連接間隔進行管理。Attribute Protocol,簡稱:ATT。ATT層用來定義用戶命令及命令操作的數據,比如讀取某個數據或者寫某個數據。BLE協議棧中,開發者接觸最多的就是ATT。BLE引入了attribute概念,用來描述一條一條的數據。Attribute除了定義數據,同時定義該數據可以使用的ATT命令,因此這一層被稱為ATT層。Security Manager,簡稱:SM。SMP用來管理BLE連接的加密和安全的,如何保證連接的安全性,同時不影響用戶的體驗,這些都是SMP要考慮的工作。Generic Access Profile,簡稱:GAP。GAP是對LL層payload(有效數據包)如何進行解析的兩種方式中的一種,而且是最簡單的那一種。GAP簡單的對LL payload進行一些規范和定義,因此GAP能實現的功能極其有限。GAP目前主要用來進行廣播,掃描和發起連接等。Generic Attribute Profile,簡稱:GATT。GATT用來規范attribute中的數據內容,並運用group(分組)的概念對attribute進行分類管理。沒有GATT,BLE協議棧也能跑,但互聯互通就會出問題,也正是因為有了GATT和各種各樣的應用profile,BLE擺脫了ZigBee等無線協議的兼容性困境,成了出貨量最大的2.4G無線通信產品。
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
AA– 前導幀(preamble)D6BE898E– 訪問地址(access address)60– LL幀頭字段(LL header)0E– 有效數據包長度(payload length)3B75AB2A02E1– 廣播者設備地址(advertiser address)02010504FF590053– 廣播數據8EC7B2– CRC24值
有了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
AA– 前導幀(preamble)0x50655DAB– 訪問地址(access address)1E– LL幀頭字段(LL header)08– 有效數據包長度(payload length)04000400– ATT數據長度,以及L2CAP通道編號1B– notify command0x0013– 電量數據handle0x53– 真正要發送的電量數據0xF650D5– CRC24值
- AAAB5D65501E08040004001B130053D550F6
雖然開發者只調用了 send(0x53),但由於低功耗藍牙協議棧層層打包,最后空中實際傳輸的數據將變成下圖所示的模樣,這就既滿足了低功耗藍牙通信的需求,又讓用戶API變得簡單,可謂一箭雙雕!
希望通過這個例子,讓大家對協議棧的各層作用有個初步的印象。



























