前言
藍牙作為一個龐大的知識體系,其學習和運用對于初學者來說顯得有些復雜且凌亂。我整理了這段時間的學習筆記,涵蓋了協議棧、工作流程、參數等內容。在實際應用中,我們主要使用 GAP 和 GATT,協議棧中的其他部分只需了解即可。因此,如果只是簡單使用藍牙,只要理清邏輯,學習難度其實并不高。
希望這篇筆記能夠幫助你快速入門藍牙技術。你可以結合 ESP-IDF 提供的 gatt_server_service_table
和 gatt_client
示例進行學習。同時,附件中還提供了協議棧和設備工作流程的思維導圖,或許通過圖示化的方式能更直觀地理解這些概念。
需要注意的是,筆記中的某些內容(如特征值擴展部分)可能在初級使用中用不到,可以暫時跳過。
如果發現任何錯誤或是提出改進建議,歡迎與我聯系。
AI 摘要
這篇筆記詳細介紹了藍牙技術的核心概念和實現,包括藍牙網絡的拓撲結構(如微微網、散射網和 Mesh 網絡)、藍牙連接流程(廣播、掃描、連接建立等)、以及藍牙協議棧的分層結構(GAP 和 GATT)。文中還深入解析了 BLE 的數據傳輸機制、MTU 配置、廣播數據格式和特性描述符等內容,并結合 ESP32 的實際開發,提供了豐富的技術細節。
參考資料:
ESP-IDF 編程指南
藍牙技術網站
Bluetooth - Wikipedia
Bilibili-Michael_ee
Assigned Numbers
BLE User Guide — Apache Mynewt latest documentation
附件鏈接:
Github_CodeFlashier
文章目錄
- 前言
- AI 摘要
- Brief
- The classification of Bluetooth
- Bluetooth terminology
- Core Architecture
- Bluetooth Roles
- Bluetooth Network Configuration
- Bluetooth Connection Process
- Bluetooth Stack
- GAP
- Roles when Operating over BR/EDR Physical Transport
- Roles when Operating over an LE Physical Transport
- Defines compliance requirements
- Device Connection Establishment Process
- GATT
- Configuration and Roles
- GATT Profile Hierarchy
- Service
- Service Declaration
- Service Include
- Include Declaration
- Characteristic
- Characteristic Declaration
- Characteristic Value Declaration
- Characteristic Descriptor Declarations
- Characteristic Extended Properties
- Characteristic User Description
- Client Characteristic Configuration
- Server Characteristic Configuration
- Characteristic Presentation Format
- Characteristic Aggregate Format
- GATT Profile Attribute Types
- GATT Send Command
- GATT Server
- GATT Server Work Flow
- Advertising
- MTU
- PDU
- Advertising Flow
- Advertising State
- Undirected Advertising
- Directed Advertising
- Scanning State
- Passive Scanning
- Active Scanning
- Callback Parameters
- Advertising And Scanning Response Data Format
- gatts_table_creat_demo
- GATT Client
- GATT Client Work Flow
- Connection
- Supervision Timeout
- Peripheral Latency
- MTU
- Data Exchange
- Write Data
- Notification for Server
- Notification for Client
Brief
藍牙是一種支持設備短距離通信的無線通信技術,能夠實現在短距離范圍內實現信息的自由分享和傳輸,具有安全性高、自由連接等特性,工作在 2.4GHz ISM(工業、科學、醫學) 頻段
藍牙可分為經典藍牙和低功耗藍牙
從整體結構上,藍?可分為控制器 (Controller) 和主機 (Host) 兩?部分:控制器包括了 PHY、Baseband、Link Controller、Link Manager、Device Manager、HCI 等模塊,?于硬件接?管理、鏈路管理等等;主機則包括了 L2CAP、SMP、SDP、ATT、GATT、GAP 以及各種規范,構建了向應?層提供接?的基礎,?便應?層對藍?系統的訪問。主機可以與控制器運?在同?個宿主上,也可以分布在不同的宿主上。
The classification of Bluetooth
Classic Bluetooth
經典藍牙(BR/EDR)泛指支持藍牙協議在 4.0 以下的模塊,一般用于大數據量的傳輸(如語音、音樂),其協議包含個人局域網的各種規范,如:
Advanced Audio Distribution Profile (A2DP)
?適用于音頻Hands-Free Profiles/Hand-Set Profiles (HFP/HSP)
? 適用于免提設備Serial Port Profiles (SPP)
? 適用于文本串口透傳(可用于藍牙調試)HFP/HSP
?、HID
? 等
Bluetooth Low Energy
一種超低功耗無線通信技術,主要針對低成本、低復雜度的無線體域網和無線各域網設計
來源:Bluetooth 技術概述 |Bluetooth? 技術網站
特性 | 低功耗藍牙 (LE) | 經典藍牙 (Bluetooth Classic) |
---|---|---|
頻段 | 2.4GHz ISM 頻段 (2.402 – 2.480 GHz 使用) | 2.4GHz ISM 頻段 (2.402 – 2.480 GHz 使用) |
頻道 | 40 個頻道,2 MHz 間隔(3 個廣播頻道/37 個數據頻道) | 79個頻道,1 MHz間隔 |
頻道使用 | 頻率跳變擴頻 (FHSS) | 頻率跳變擴頻 (FHSS) |
調制方式 | GFSK | GFSK,π/4 DQPSK,8DPSK |
數據速率 | LE 2M PHY:2 Mb/s LE 1M PHY:1 Mb/s LE Coded PHY (S=2):500 Kb/s LE Coded PHY (S=8):125 Kb/s | EDR PHY (8DPSK):3 Mb/s EDR PHY (π/4 DQPSK):2 Mb/s BR PHY (GFSK):1 Mb/s |
發射功率 | ≤ 100 mW (+20 dBm) | ≤ 100 mW (+20 dBm) |
接收靈敏度 | LE 2M PHY:≤-70 dBm LE 1M PHY:≤-70 dBm LE Coded PHY (S=2):≤-75 dBm LE Coded PHY (S=8):≤-82 dBm | ≤-70 dBm |
數據傳輸 | 異步面向連接 同步面向連接 異步無連接 同步無連接 等時無連接 | 異步面向連接 同步面向連接 |
通信拓撲 | 點對點(包括個人區域網絡(Piconet微微網)) 廣播 Mesh(網狀) | 點對點(包括個人區域網絡(Piconet 微微網)) |
定位功能 | 存在:廣告 方向:測向(AoA/AoD) 距離:RSSI,信道探測 | 無 |
Bluetooth terminology
Core Architecture
藍牙的核心系統
Host 主機
? 實現各種業務場景需求,大部分的開發工作基于此Controller 控制器
? 用于藍牙報文的收發、藍牙物理連接等功能,由芯片廠商負責實現Host Controller Interface(HCI) 主機控制接口
? Host 和 Controller 通過 HIC 進行通信
Bluetooth Roles
藍牙通信是指兩個或多個藍牙設備之間的通信,通信雙方必須一個是主機,另一個是從機,從機和從機之間不能直接通信
?Master
? 工作在 Master 模式的設備,可以與一個 Slave 進行連接,在此模式下可以對周圍的設備進行搜索并選擇需要的 Slave 進行連接
?Slave
? Slave 模式下的設備只能被 Master 搜索,不能主動搜索
?
Bluetooth Network Configuration
根據拓撲結構,藍牙網絡可分為
Piconet
?微微網Scatternet
?散射網Mesh
?
Piconet 微微網
?每次建立的藍牙無線鏈路,都處于微微網中,一個微微網由兩個或更多占用相同物理信道的設備組成(表示這些設備是按照共用時鐘和跳頻序列進行同步的),其拓撲結構如下:
從機3// //從機1 -------------------- 主機\\\\ \從機2
拓撲結構(Topology Structure)是指系統中各個節點及其連接關系的組織方式或布局。它廣泛應用于網絡、工程、數學等領域,用來描述元素之間的連接模式,而不關注實際的物理位置或距離
Scatternet 散射網
?如果多個網存在重疊的區域,就可以構成散射網,其中各個 Piconet仍然具有自己的主機,但一個 Piconet 的主機可以同時是另一個 Piconet 的從機,這樣該設備就具有雙重身份
如下圖,此時左側的主機同時也是右側的從機
從機1.3 從機2.1/ // // // /
從機1.1 ---------- 主機/從機 ---------- 主機\ \\ \\ \\ \從機1.2 從機2.2
Mesh
?藍牙 4.0 之后誕生了藍牙 Mesh,用于建立多對多設備通信的低能耗藍牙網絡,允許創建基于多個設備的大型網絡,可以包含數十臺、數百臺甚至數千臺藍牙 Mesh 設備,設備之間可以相互進行數據傳輸
Bluetooth Connection Process
藍牙首先需要通過廣播或掃描發現周圍設備,其次創建連接,最終組建網絡傳輸數據
- 從機端廣播
- 在大部分情況下,外圍設備 (Peripheral,從機) 通過廣播自己來讓中心設備 (Central,主機) 發現自己,并建立 GATT (通用屬性配置文件)連接,從而進行更多的消息交換
- 也有些情況是不需要連接的,只需要外圍設備(外設)廣播自己的信息即可,這種方式的主要目的是讓外設把自己的消息發送給多個中心設備
- Peripheral 在進行廣播時不斷發送廣播包,每發送一次廣播包稱為廣播事件;每一次發送之間有長度為 t 的廣播間隔,也稱為廣播事件間隔,每次廣播事件都會持續一段時間,只有在此期間藍牙芯片才會打開射頻模塊發送廣播包,功耗較高,其余時間都處于空閑待機狀態
- 當廣播事件時,每一個事件包含三個廣播包,分別在 37、38、39 三個信道同事廣播相同的消息
- 在大部分情況下,外圍設備 (Peripheral,從機) 通過廣播自己來讓中心設備 (Central,主機) 發現自己,并建立 GATT (通用屬性配置文件)連接,從而進行更多的消息交換
- 主機端掃描
- 掃描是在一定范圍內用來尋址其他 BLE 設備的過程,掃描者在掃描過程中會使用廣播信道,但掃描并沒有嚴格的時間定義和信道規則,其過程按照主機設定的掃描定時參數進行?
被動掃描
? 掃描者僅僅監聽廣播包,而不向廣播者發送任何數據- 在掃描過程中,如果控制器接收到符合過濾策略或其他規則的的廣播包, 則向主機發送一個報告時間,其中包括廣播者的設備地址、廣播包中的數據、信號接收強度?
主動掃描
? Central 在掃描捕獲廣播包的同時捕獲掃描響應包,并作出區分廣播包
?主要用于設備發現和提供基本信息,適合所有設備接收掃描響應包
?用于增強廣播包,滿足需要獲取更多信息的主動掃描設備需求
- 掃描是在一定范圍內用來尋址其他 BLE 設備的過程,掃描者在掃描過程中會使用廣播信道,但掃描并沒有嚴格的時間定義和信道規則,其過程按照主機設定的掃描定時參數進行?
- 主機端連接
- 連接過程如下
- Peripheral(外設,外圍設備)開始廣播,在發送完一個廣播包的T_IFS內,開啟射頻窗口接收來自中心設備的數據包
- Central 接收到廣播,在接收后的 T_IFS 內如果開啟了 Central 的掃描回復,則 Central 將向 Peripheral 發送回復
- Peripheral 收到中心設備的回復后,做好接收準備并返回 ACK 包
- 如果 Peripheral 發送的 ACK 沒有被中心設備接收到,則 Central 將一直發送回復知道超時為止,在此期間內只要外設返回過一次 ACK 就算連接成功
- 開始建立通信,Central 以接收到外設廣播的時間為原點,以連接間隔為周期向 Peripheral 數據包,數據包用于同步兩個設備的時鐘和建立主從模式的通信,其過程如下:?
同步兩個設備的時鐘
? Peripheral 每收到 Central 發送的一個數據包,就會重新設置自己的書序原點,以便于 Central 同步- BLE 通信在建立成功后變成主從模式,Central 變成主機模式,Peripheral 變成從機,從機只能在 Central 向它發送一個數據包后才能在規定時間內把自己的數據回傳給 Central
- 連接建立成功
- 外設自動停止廣播,其他設備無法再查找到此外設
- 在中心設備發送數據包的間隔內,外設可以發送多個數據包
- 連接過程如下
T_ISF 、 ACK 和同步時鐘
T_ISF(Inter Frame Space)
?同一信道上連續傳輸包之間的時間間隔
ACK
?ACK在通信中是接收方對發送方的反饋,用于確認數據包已成功接收;如果沒有ACK,發送方無法知道數據是否到達目標,從而無法保障通信的可靠性ACK機制還可檢測數據錯誤并觸發重傳,確保數據傳輸完整無誤 同步時鐘同步時鐘在通信中用來協調雙方的時間基準,確保數據的發送與接收按預期時序進行。如果沒有同步時鐘,數據可能因時序錯亂而丟失或解析錯誤。在 BLE 中,同步時鐘還能優化設備能耗,讓設備在需要時準確喚醒,保持高效運行
斷開連接
- 在需要斷開連接時,只要 Central 停止連接(停止發送數據包)即可
重新連接
- 中心設備可以將外設的 MAC 地址寫入 Flash 或是 SRAM 等存儲器件,并保持監聽此 MAC 地址,當再次收到 Peripheral 發送的廣播包時就可以建立通信
- 從機為了省電,當一段時間沒有數據要發送時,可以不在發送廣播包,雙方就會因為連接超時 (Connection Timeout) 而斷開,此時需要 Central 啟動監聽
MAC地址(Media Access Control Address)是一個設備的唯一硬件地址,用于標識藍牙設備。每個藍牙設備在出廠時都會分配一個全球唯一的MAC地址,一個48位(6字節)的數字,通常用16進制表示,格式為 XX:XX:XX:XX:XX:XX,例如 A1:B2:C3:D4:E5:F6
Bluetooth Stack
藍牙 API - ESP32 - — ESP-IDF 編程指南 latest 文檔
ESP-IDF 目前支持兩個主機堆棧(藍牙協議棧),基于 Bluedroid 的堆棧(默認)支持傳統藍牙和低功耗藍牙 (Bluetooth? LE),而基于 Apache NimBLE 的堆棧僅支持低功耗藍牙
- 對于同時涉及傳統藍牙和低功耗藍牙的用例,應該選用 Bluedroid
- 對于僅涉及低功耗藍牙的用例,建議選用 NimBLE,在代碼占用和運行時,NimBLE 對內存的要求較低,因此適用于此類場景
有關功能支持狀態,詳見 docs.espressif
Bluedroid 是 Android 平臺和 ESP32 上常用的藍牙協議棧。它提供了完整的藍牙主機和控制器功能,支持藍牙經典(BR/EDR)和藍牙低功耗(BLE);Bluedroid 已被廣泛應用于 Android 設備和 ESP32 系統,能夠通過提供標準的 HCI 接口與硬件控制器通信;Bluedroid 是一個穩定的協議棧,但由于它具有較大的代碼庫和相對較高的資源需求,可能不適合資源有限的嵌入式設備
Apache MyNewt NimBLE 是一個輕量級、靈活、高度可配置且符合 Bluetooth? SIG 認證的藍牙低功耗 (Bluetooth LE) 協議棧,提供主機和控制器功能,專注于低功耗藍牙設備的高效能實現,與 Bluedroid 不同,NimBLE 更加簡化,旨在提供更好的性能和更少的內存占用,適用于嵌入式應用和低功耗設備
ESP-IDF 支持專為 ESP32 平臺和 FreeRTOS 移植的 NimBLE 主機棧,底層控制器與 Bluedroid 中使用的相同,提供 VHCI 接口
ESP-IDF 支持大多數 NimBLE 特性,包括藍牙低功耗網狀網絡 (Bluetooth Low Energy Mesh),通過保留 NimBLE 所有現有 API 并提供一個統一的 ESP-NimBLE API 用于初始化,移植層變得更簡潔,從而簡化了應用開發者的工作
?
圖源:NimBLE-based Host APIs - ESP32 - — ESP-IDF 編程指南 latest 文檔
BLE User Guide — Apache Mynewt latest documentation
BLE 協議棧
-
應用層 (Application Layer)
-
主機層 (Host Layer)
-
控制器層 (Controller Layer)
? -
Controller
?用于硬件接口管理、鏈路管理等功能-
Physical Layer(PHY) 物理層
? 指定低功耗藍牙所用的無線頻段、調制解調方式等 -
Link Layer(LL) 鏈路層
? 負責數據發送和接收,但不負責數據解析,是藍牙協議棧的核心
-
-
Host Controller Interface(HCI) 主機控制接口
? Host 和 Controller 之間的通信接口,可以是物理形式的(UART、USB 等,常見于雙芯片架構),也可以用 API 實現(常見于單芯片架構) -
Host
?構建了向應用層提供接口的基礎,方便應用層對藍牙系統的訪問-
Logical Link Control and Adaptation Protocol(L2CAP) 邏輯鏈路控制和適配協議
? 向上層協議(協議復用、分段、重組操作)提供連接導向和無連接的數據服務,并按通道進行流量控制和重傳 -
Attribute Protocol(ATT) 屬性協議
? 用來定義用戶命令以及命令操作的數據(如讀取或寫入);BLE 協議棧引入了 Attribute 概念,用于描述一條條的數據;ATT 除了定義數據,也定義該數據可以使用的 ATT 命令 -
Security Manager Protocol(SMP) 安全管理器協議
? 負責管理 BLE 連接的加密和安全,在保證連接安全的同時不影響用戶的體驗 -
Generic Attribute Profile(GATT) 通用屬性配置文件
? 規范 Attribute 中的數據內容,并運用分組 (Group) 的概念對 Attribute 進行分類管理 -
Generic Access Profile(GAP) 通用訪問配置文件
? 對 LL 的有效數據包進行了一些規范和定義,是解析 LL 負載數據最簡單的一種方式,一次 GAP 的功能及其有限,主要用來進行廣播、掃描和發起連接等
-
作為應用開發者,在開發過程中主要使用主機層提供的 API 接口
BLUEDROID 內部?致分為 2 層:BTU 層和 BTC 層(除去 HCI ),每個層都有對應的任務來處理。BTU 層主要負責藍?主機底層協議棧的處理,包括 L2CAP、GATT/ATT、SMP、GAP 以及部分規范等,并向上提供以“bta”為前綴的接?; BTC 層主要負責向應?層提供接??持、處理基于 GATT 的規范、處理雜項等,并向應? 層提供以“esp”為前綴的接?。所有的 API 都在 ESP_API 層,開發者應當使?“esp”為前綴的藍? API(特殊的除外)。
藍牙核心規范 (Core Specification) 允許主機層和控制器層在物理上分離,此時 HCI 體現為物理接口,包括 SDIO、USB 以及 UART 等
?
?
圖源:esp32_bluetooth_architecture_cn
通過軟硬件分層的設計,底層不變,可以方便的切換上層程序(應用層軟件)
場景一(ESP-IDF 默認)
在 ESP32 的系統上,選擇 Bluedroid 為藍牙主機,并通過 VHCI(軟件實現的虛擬 HCI 接口)接口,訪問控制器。此場景下,Bluedroid 和控制器都運行在同一宿主上(即 ESP32 芯片),不需要額外連接運行藍牙主機的 PC 或其它主機設備
場景二
在 ESP32 上運行控制器(此時設備將單純作為藍牙控制器使用),外接一個運行藍牙主機的設備(如運行 BlueZ 的 Linux PC、運行 Bluedroid 的 Android 等)
此場景下,控制器和主機運行在不同宿主上,與手機、PAD、PC 的使用方式比較類似
場景三
此場景與場景二類似,特別之處在于,在 BQB(或其它認證)的控制器測試下,可以將 ESP32 作為 DUT(Device Under Test),用 UART 作為 IO 接口,接上認證測試的 PC 機,即可完成認證
IDF 中的 host、controller 目錄,其中存放有不同芯片型號相應的庫文件及接口等
路徑:
idf 安裝路徑\v5.3.1\esp-idf\components\bt
?
ESP-IDF 的 component/bt/host/bluedroid 目錄說明
子文件夾 | 說明 |
---|---|
api | API 目錄,所有的 API(除 Controller 相關)都在此目錄下 |
bta | 藍牙適配層,適配一些主機層底層協議的接口 |
btc | 藍牙控制層,控制主機上層協議(包括規范)以及雜項的處理 |
common | 協議棧的通用頭文件 |
config | 為協議棧配置一些參數 |
device | 與藍牙設備控制相關的,如控制器設備的配置的 HCI CMD 流程等 |
external | 與藍牙自身無關,但又要使用的代碼,如 SBC codec 設備程序等 |
hci | HCI 層協議 |
Kconfig.in | Menuconfig 文件 |
main | 主程序目錄(主要為啟動、關閉流程) |
stack | 主機底層協議棧(GAP/ATT/GATT/SDP/SMP 等) |
?
GAP
藍牙協議棧中 GAP 和 GATT 部分各知識點之間聯系
原圖較大,由于網站壓縮,圖像畫質可能較差,原圖見Github_CodeFlashier
本部分的全部內容詳見: Bluetooth Core Specification v5.0 Vol3 PartC,這里只做必要內容的介紹
通用訪問配置文件(Generic Access Profile,GAP)的目的如下:
- 引入與運輸和應用配置文件使用的模式和訪問程序相關的定義、建議和通用要求
- 描述設備在待機和連接狀態下的行為,以保證藍牙設備之間始終能夠建立連接和通道,并且支持多配置文件操作;特別關注設備發現、鏈路建立和安全程序
- 規定用戶界面方面的要求,主要是編碼方案和過程與參數的命名,以確保用戶體驗
該配置文件的目的是描述:
- 配置文件角色
- 可發現模式和程序
- 連接模式和程序
- 安全模式和程序
GAP 與藍牙底層架構的關系
圖源:Bluetooth Core Specification v5.0
Roles when Operating over BR/EDR Physical Transport
BR/EDR 是 Bluetooth Radio/Enhanced Data Rate 的縮寫,指的是藍牙技術中的兩種主要通信模式:
BR (Basic Rate)
?基本速率,是藍牙 1.x 版本中使用的傳輸速率,最高為 1 Mbps?EDR (Enhanced Data Rate)
?增強數據傳輸速率,是藍牙 2.x 版本及更高版本中引入的,提供更高的傳輸速率,最高為 3 Mbps
BR/EDR 是藍牙經典(Bluetooth Classic)模式的一部分,適用于需要較高數據傳輸速率的應用,如音頻傳輸(例如藍牙耳機)和文件傳輸
在 GAP 協議中,為了描述發生在 BR/EDR GAP 角色的兩個設備之間的藍牙通信,使用以下兩個通用符號描述設備:
A-party A 方
鏈路建立時的分頁設備(發起連接請求的設備)B-party B 方
?接收連接請求的設備
在藍牙的 GAP 協議中,“分頁設備”(paging device)是指在進行藍牙設備配對或連接時,發起連接請求的設備;分頁設備通過廣播其存在來尋找其他設備,并嘗試建立一個連接
具體而言,“分頁”(paging)指的是一種低功耗的搜索過程,設備會掃描特定的信道,并等待另一方設備響應以建立連接
?
該配置文件涵蓋了由一個設備(A)發起,針對另一個設備(B)的程序,后者可能已經建立了藍牙連接,也可能沒有
圖源:《Bluetooth Core Specification v5.0》
發起者和接受者通常根據此配置文件或引用此配置文件的其他配置文件執行通用程序;如果接受者同時根據多個配置文件操作,則此配置文件提供了處理這種情況的通用機制
Roles when Operating over an LE Physical Transport
LE 指的是 Bluetooth Low Energy(藍牙低功耗)技術
GAP 中共定義了三種設備的連接狀態以及五種不同的設備角色,如下
- 空閑 (Idle)
- 此時設備無角色,處于就緒狀態 (Standby)
- 設備發現 (Device Discovery)
- 廣播者 (Advertiser)
- 掃描者 (Scanner)
- 連接發起者 (Initiator)
- 連接 (Connection)
- 外圍設備 (Peripheral)
- 中央設備 (Central)
Bluetooth LE GAP 協議層采? API 調?和事件 (Event) 返回的設計模式,通過事件返回來獲取 API 在協議棧的處理結果。當對端設備主動發起請求時,也是通過事件返回獲取對端設備的狀態。Bluetooth LE 設備定義了四類 GAP ??:
? ?播者 (Broadcaster):處于這種??的設備通過發送?播 (Advertising) 讓接收者發現??。這種??只能發?播,不能被連接。
? 觀察者 (Observer):處于這種??的設備通過接收?播事件并發送掃描 (Scan) 請求。這種??只能發送掃描請求,不能被連接。
? 外圍設備 (Peripheral):當?播者接受了觀察者發來的連接請求后就會進?這種? ?。當設備進?了這種??之后,將會作為從設備 (Slave) 在鏈路中進?通信。
? 中央設備 (Central):當觀察者主動進?初始化,并建??個物理鏈路時就會進?這種??。這種??在鏈路中同樣被稱為主設備 (Master)。
?
同時在多個 GAP 角色下運行
如果控制器支持,設備可以同時在多個GAP角色下運行,主機應在使用任何程序或模式之前,先讀取控制器支持的鏈路層狀態和狀態組合
Defines compliance requirements
在 LE 物理傳輸上操作時,每個 GAP 角色的物理層和鏈路層功能的 GAP 遵從性要求
圖源:Bluetooth Core Specification v5.0
符號釋義
M
?強制支持的功能O
?可選支持的功能C
?條件支持的功能E
?在配置文件角色中排除的功能N/A
?不適用的功能C1
?如果支持被動掃描,則主動掃描是可選的,否則主動掃描是強制的C2
?如果支持連接參數請求過程,則必選,否則可選
?
Device Connection Establishment Process
設備連接過程
- 設備 A、B 進入空閑狀態
- 在上層軟件控制下,A 進入廣播狀態,向外界進入廣播狀態,B 進入掃描狀態
- 當 B 掃描到數據后,進入初始化狀態,發送請求連接的數據給 A
- 設備 A 返回數據給 B,進入連接狀態
- B 收到返回的數據后,進入連接狀態
- 兩個設備相互交換數據
對于部分設備,可能不需要連接(如 BLE Beacon、BLE Sniffer)
GATT
藍牙協議棧中 GAP 和 GATT 部分各知識點之間聯系
原圖較大由于網站壓縮,圖像畫質可能較差,原圖見Github_CodeFlashier
本部分的全部內容詳見: Bluetooth Core Specification v5.0 Vol3 PartD,這里只做必要內容的介紹
通用屬性配置文件(Generic Attribute Profile,GATT)通過使用屬性協議(Attribute Protocol)定義了一個服務框架,該框架定義了服務及其特性的程序和格式,所定義的程序包括發現、讀取、寫入、通知和指示特性,以及配置特性廣播
ATT 屬性協議規定了在 Bluetooth LE 中的最?數據存儲單位,? GATT 規范則定義了如何 ?特性值和描述符表示?個數據,如何把相似的數據聚合成服務 (Service),以及如何發現對端設備擁有哪些服務和數據。
ATT 與 GATT 的關系
ATT 提供了一個基礎的傳輸框架和操作機制(例如,讀取、寫入和通知),而 GATT 則是 ATT 的上層協議,定義了如何組織這些屬性,使得設備能夠通過結構化的方式進行通信
- GATT 提供了一套服務(services)和特征(characteristics)的規范,指導如何通過 ATT 協議進行數據交換
- GATT 使用 ATT 協議的讀、寫和通知操作來訪問設備的屬性
ATT 是 GATT 的數據傳輸載體,而 GATT 是 ATT 的應用框架,二者結合為藍牙低功耗設備的通信提供了完整的協議支持
Configuration and Roles
GATT 將藍牙設備分為兩種:
Client 客戶端
?發起命令和請求的設備,向服務器發送命令并接收服務器發送的響應、指示和通知Server 服務端
?接受來自客戶端的命令和請求的設備,并向客戶端發送響應、指示和通知- 這些角色不是固定分配給設備的,角色是在設備發起定義的程序時確定的,并在程序結束時釋放
此配置文件涵蓋以下場景:
- 配置交換
- 設備上服務和特性的發現
- 讀取特性值
- 寫入特性值
- 特性值通知
- 特性值指示
數據以 profile(配置文件(規范))的形式存儲在服務端
GATT 配置文件指定了配置文件數據交換的結構,該結構定義了配置文件中使用的基本元素,如服務(Service)和特性(Characteristic);所有這些元素都包含在屬性中,屬性協議中使用的屬性是承載配置文件數據的容器
層次結構的頂層是配置文件,配置文件由一個或多個服務組成,這些服務是為了實現某個使用場景所必需的,一個服務由特性或對其他服務的引用組成;每個特性包含一個值,并且可能包含關于該值的可選信息
GATT Profile Hierarchy
GATT 配置文件的基本結構如下
Profile 配置文件(規范)
?配置文件(規范)是最高層次,通常由一個或多個服務組成,它定義了完成某個特定使用場景所必需的所有元素Service 服務
?服務由一個或多個特性組成,并且可能包含對其他服務的引用; 服務是一個邏輯集合,用于組織和管理特性;在 GATT 配置文件中,服務是為了滿足特定功能需求而設計的Characteristic 特性
?特性是服務的基本組成部分,每個特性通常包含一個值,并且可能包含與該值相關的描述符(如用戶描述符、客戶端配置描述符等);這些特性承載著實際的配置文件數據Descriptor 描述符
?描述符是與特性相關的附加信息,用于進一步解釋特性的值或控制特性的行為,常見的描述符包括用戶描述符、客戶端配置描述符等
規范是一個預定義的服務集合,實現了某規范中所定義的所有服務的設備即滿足該規范。例如 Heart Rate Profile 規范由 Heart Rate Service 和 Device Information Service 兩個服務組成,那么可以稱實現了 Heart Rate Service 和 Device Information Service 服務的設備符合 Heart Rate Profile 規范
?
GATT Profile 文件層次結構
圖源:《Bluetooth Core Specification v5.0》
Service
Server 服務是一組數據和相關行為的集合,用于實現特定的功能或特性,在 GATT 中,服務由其服務定義(service definition)來定義
服務定義可以包含
- 引用的服務
- 必需的特性
- 可選的特性
為了保持與早期客戶端的向后兼容,服務定義的后續版本只能添加新的引用服務或可選特性,不能修改以前版本中的行為
Primary Service 主服務
?是暴露設備主要功能的服務,主服務可以被其他服務包含,并且可以通過主服務發現程序進行發現Secondary Service 次服務
?僅用于從主服務、另一個次服務或其他更高層規范中引用,次服務只在引用它的實體的上下文中相關
是否將一個服務定義為主服務或次服務,可能由更高層的規范進行規定,服務可以在一個或多個更高層的規范中使用,以實現特定的使用場景
Service 數據結構
- Service Declaration
- Service Include
- Characteristic 01
- Characteristic xx
特點
- 服務定義在下一個服務聲明之前結束,或者在達到最大屬性句柄時結束;服務定義在服務器上按屬性句柄的順序出現
- 服務定義必須包含一個服務聲明(Service Declaration),并且可以包含包含定義和特性定義
- 服務定義中包含的所有包含定義和特性定義都視為服務的一部分,所有包含定義必須緊跟在服務聲明之后,并且在任何特性定義之前
- 所有特性定義必須緊跟在最后一個包含定義之后,如果沒有包含定義,則緊跟在服務聲明之后
- 一個服務定義可以有零個或多個包含定義和特性定義,包含定義和特性定義沒有上限
- 服務器上的所有屬性要么包含服務聲明,要么存在于服務定義內
- 服務器中包含的服務定義可以按任意順序出現,客戶端不應假設服務器上服務定義的順序
所有的定義均以屬性 Attribute (ATT 屬性協議)的形式存在,內容包括
Attribute Handle 屬性句柄
? 2 OctetsAttribute Type 屬性類型
? 2 or 16 OctetsAttribute Value 屬性值
? variable lengthAttribute Permissions 屬性權限
? implementation specific(工具自定義)
?屬性的類型由 UUID 表示,可以分為 16 位、32 位與 128 位 UUID 三類。 16 位 UUID 由藍牙技術聯盟 (Bluetooth Special Interest Group, Bluetooth SIG) 統一定義,可以在其公開發布的 Assigned Numbers 文件中查詢;其他兩種長度的 UUID 用于表示廠商自定義的屬性類型,其中 128 位 UUID 較為常用
Service Declaration
服務聲明是一個屬性(Attribute),
Attribute Type 屬性類型
?設置為 Primary Service 主服務 或 Secondary Service 次服務 的 UUIDAttribute Value 屬性值
?應為服務的 16 位或 128 位 UUID(參見 Assigned_Numbers.pdf),稱為服務 UUID,客戶端必須支持 16 位和 128 位 UUID 的使用,客戶端可以忽略任何具有未知服務 UUID 的服務定義(未知服務 UUID 是指不支持的服務的 UUID)- SIG 定義的 16 位 UUID
- 廠商自定義的 128 位 UUID (在 SIG 官方提供的 Assigned Numbers 標準文件中,給出了一些常用特征數據和服務的 UUID)
Attribute Permission 屬性權限
?應為只讀,并且不要求身份驗證或授權
UUID(通用唯一標識符) 是一種 128 位的標識符,廣泛用于標識不同的對象、服務或數據元素,確保它們在全球范圍內的唯一性
在藍牙技術中,UUID 被用于區分和標識不同的服務、特性和描述符
UUID 可以是 16 位或 128 位格式,其中 16 位 UUID 常用于標準服務,而 128 位 UUID 通常用于自定義服務,UUID 的使用確保了設備間的兼容性和通信的準確性
Bluetooth UUID 是一種特定于藍牙協議的 UUID,用于標識藍牙設備中的服務、特性和描述符。與通用的 UUID(通用唯一標識符)相比,Bluetooth UUID 通常采用 16 位、32 位 或 128 位 格式,其中 16 位 UUID 用于標準藍牙服務
規范-分配的編號-藍牙?技術網站
服務聲明結構
圖源:《Bluetooth Core Specification v5.0》
當存在多個服務時,使用不同位數 UUID 的服務定義應當分組在一起(使用 16 位 Bluetooth UUID 的服務定義分組在一起(即按順序列出),使用 128 位 UUID 的服務定義分組在一起)
一個設備或更高層規范可以有多個服務定義,且可以有多個服務定義使用相同的服務 UUID
Service Include
包含服務是一種將服務器上存在的另一個服務定義引用到當前定義的服務中的方法
要包含另一個服務,在服務定義的開始部分使用包含定義(include definition)
特點
- 通過包含定義引用的服務的整個服務定義將成為新服務定義的一部分,這包括所有包含的服務和該服務的特性
- 被包含的服務仍然是獨立的服務
- 一個被包含的服務不應因包含或包含的服務而被修改,服務定義中對包含定義或嵌套包含的數量沒有限制
Include Declaration
一個 包含定義(include definition) 應僅包含一個包含聲明(include declaration)
Attribute Type
? 設置為 Include 的 UUIDAttribute Value
- 包含服務的屬性句柄
- 結束組句柄(每個服務或服務的一部分都有一個 開始句柄(Start Handle,即 Attribute Handle) 和 結束句柄(End Handle),它們定義了服務的范圍)
- 所包含服務的 UUID
Attribute Permission
? 應為只讀,并且不要求身份驗證或授權
包含聲明結構
圖源:《Bluetooth Core Specification v5.0》
當 UUID 是 16 位 Bluetooth UUID 時,服務 UUID 必須被直接指定
GATT(Generic Attribute Profile) 中,當一個服務使用 16 位 Bluetooth UUID 時,服務 UUID 必須在服務的定義中明確指定
在某些情況下,如某些包含(Include)服務,UUID 可能通過引用的其他服務的 Attribute Handle 來隱式獲得,但這并不等同于“未指定”UUID
服務定義中的包含聲明不能指向自己,這適用于包含定義引用的每個服務(這被稱為 循環引用(circular reference));如果客戶端檢測到循環引用或檢測到嵌套包含聲明超過其預期的層次,客戶端應終止 ATT 承載通道(ATT Bearer)
Characteristic
Characteristic 特性是服務中使用的值,伴隨有關于如何訪問該值的屬性和配置信息,以及關于如何顯示或表示該值的信息
一個特性定義(Characteristic Definition)應包含
- 特性聲明(Characteristic Declaration)
- 特性值聲明(Characteristic Value Declaration)
并且可能包含
- 特性描述符聲明(Characteristic Descriptor Declarations)
特點
- 特性值聲明應緊隨其后放置在特性聲明之后,任何可選的特性描述符聲明應放置在特性值聲明之后,可選的特性描述符聲明的順序沒有限制
- 特性定義的結束位置是下一個特性聲明、服務聲明的開始,或者是最大 Attribute Handle,特性定義在服務器的服務定義中按 Attribute Handle 順序出現
- 特性定義可以通過將多個特性值合并為一個單獨的聚合特性值來進行定義,這可以用于通過讀取和寫入單個聚合特性值來優化多個特性值的讀取和寫入;這類特性定義與普通的特性定義相同,特性聲明應使用唯一的特性 UUID 來標識該聚合特性定義;聚合特性定義還可以包含一個特性聚合格式描述符,用于描述聚合特性值的顯示格式
Characteristic Declaration
一個 特性聲明(Characteristic Declaration) 是一個 Attribute
Attribute Type
? 設置為特性的 UUIDAttribute Value
?- 特性屬性(Characteristic Properties)
- 特性值屬性句柄(Characteristic Value Attribute Handle)
- 特性 UUID
Attribute Permission
? 應為可讀,并且不要求身份驗證或授權
特性聲明的 Attribute Value 在服務器與任何客戶端建立信任關系時不得更改
特征聲明結構
圖源:《Bluetooth Core Specification v5.0》
Attribute Value
Attribute Value | Size | Description |
---|---|---|
Characteristic Properties | 1 octets(1 個 8 位數據) | 特性屬性的位域 |
Characteristic Value Handle | 2 octets | 包含此特性值的屬性的句柄 |
Characteristic UUID | 2 or 16 octets | 16 位 Bluetooth UUID 或 128 位 UUID,用于特性值 |
一個服務可以有多個具有相同特征 UUID的特征定義
在服務定義中,某些特征可能是必需的,這些特性應位于包含聲明(include declarations)之后、任何可選特性之前
客戶端不應假設服務定義中必需特性或可選特性的順序
盡可能地,并且在前述要求范圍內,使用 16 位 Bluetooth UUID 的特性聲明應當按順序分組在一起(即按順序列出),而使用 128 位 UUID 的特性聲明應當分組在一起
Characteristic Properties
特性屬性位域(Characteristic Properties)決定了特性值如何使用,或者如何訪問特性描述符,可以設置多個 特性屬性
這些位應根據該特性所允許的程序進行設置,并由更高層規范定義,而不考慮安全要求
Properties | Value | 描述 |
---|---|---|
Broadcast | 0x01 | 如果設置,則允許使用服務器特性配置描述符廣播特性值 如果設置,必須存在服務器特性配置描述符 |
Read | 0x02 | 如果設置,則允許使用第 4.8 節中定義的程序讀取特性值 |
Write Without Response | 0x04 | 如果設置,則允許使用第 4.9.1 節中定義的程序寫入特性值且不要求響應 |
Write | 0x08 | 如果設置,則允許使用第 4.9.3 或第 4.9.4 節中定義的程序寫入特性值并要求響應 |
Notify | 0x10 | 如果設置,則允許在沒有確認的情況下使用第 4.10 節中定義的程序通知特性值 如果設置,則必須存在客戶端特性配置描述符 |
Indicate | 0x20 | 如果設置,則允許在有確認的情況下使用第 4.11 節中定義的程序指示特性值 如果設置,則必須存在客戶端特性配置描述符 |
Authenticated Signed Writes | 0x40 | 如果設置,則允許使用第 4.9.2 節中定義的程序向特性值寫入簽名 |
Extended Properties | 0x80 | 如果設置,則在第 3.3.3.1 節中定義的特性擴展屬性描述符中定義附加特性屬性 如果設置,則必須存在特性擴展屬性描述符 |
見《Bluetooth Core Specification v5.0》 P2236
Characteristic Value Handle
特性值屬性句柄字段(Characteristic Value Attribute Handle) 是指包含特性值(Characteristic Value) 的屬性的屬性句柄(Attribute Handle)
Characteristic UUID
特性 UUID 字段 是一個 16 位 Bluetooth UUID 或 128 位 UUID,用于描述特性值(Characteristic Value) 的類型。客戶端必須支持使用 16 位 和 128 位 特性 UUID
如果客戶端遇到一個具有未知 特性 UUID 的特性定義(不支持的特性所使用的 UUID),可以忽略該特性
Characteristic Value Declaration
特性值聲明(Characteristic Value Declaration) 包含特性值,它是特性聲明之后的第一個屬性,所有特性定義必須具有特性值聲明
特性值聲明是一個 Attribute
Attribute Type
? 設置為在特性聲明中使用的 16 位 Bluetooth UUID 或 128 位 UUID,用于標識特性值Attribute Value
? 設置為特性值Attribute Permissions
? 由服務指定,或者如果沒有特別指定,則可以由實現決定
ESP32 IDF ??規定 MTU 可以設置的范圍是 23~517 字節,對屬性值的總?度沒有做限制
特征值聲明結構
圖源:《Bluetooth Core Specification v5.0》
Characteristic Descriptor Declarations
特性描述符(Characteristic Descriptors)用于包含與特性值(Characteristic Value)相關的信息
GATT 配置文件定義了一組標準的特性描述符,可以供更高層配置文件使用,更高層的配置文件可能會定義額外的特性描述符,這些描述符是特定于該配置文件的
每個特性描述符由特性描述符 UUID 標識,客戶端必須支持使用 16 位 和 128 位 特性描述符 UUID;如果客戶端遇到一個具有未知特性描述符 UUID 的特性描述符聲明,可以忽略該描述符
如果特性描述符存在于特性定義中,它們應跟隨特性值聲明之后;特性描述符聲明可以按任意順序出現在特性定義中,客戶端不應假設特性描述符聲明在特性值聲明之后的順序
特性描述符聲明的權限由更高層的配置文件定義,或者如果未指定,則由實現決定
客戶端不應假設所有的特性描述符聲明都是可讀的
Characteristic Extended Properties
特性擴展屬性(Characteristic Extended Properties)聲明是一個描述符,用于定義附加的特性屬性;如果特性屬性中的擴展屬性位被設置,則該特性描述符必須存在
在一個特性定義中只能有一個特性擴展屬性聲明
特性描述符包含在一個 Attribute 中
Attribute Type
? 應設置為 “特性擴展屬性(Characteristic Extended Properties)” 的 UUIDAttribute Value
? 應設置為特性擴展屬性位域(Characteristic Extended Properties Bit Field)Attribute Permissions
? 應為可讀,不需要身份驗證和授權
特征擴展屬性結構
圖源:《Bluetooth Core Specification v5.0》
特性擴展屬性位域描述了如何使用特性值(Characteristic Value) 或如何訪問特性描述符
如果表中定義的位被設置,則表示允許執行相應的操作;可以設置多個 特性屬性
Properties | Value | Description |
---|---|---|
Reliable Write | 0x0001 | 如果設置,則允許使用第 4.9.5 節中定義的程序進行可靠的特性值寫入 |
Writable Auxiliaries | 0x0002 | 如果設置,則允許寫入第 3.3.3.2 節中定義的特性描述符 |
Reserved for Future Use | 0xFFFC | 保留供未來使用 |
Characteristic User Description
特性用戶描述(Characteristic User Description) 聲明是一個可選的特性描述符,用于定義一個可變大小的 UTF-8 字符串,它是對特性值(Characteristic Value) 的用戶文本描述;如果特性屬性(Characteristic Properties) 中的可寫輔助位(Writable Auxiliary) 被設置,則該特性描述符可以被寫入
在一個特性定義中只能有一個特性用戶描述聲明
特性描述符包含在一個 Attribute 中
Attribute Type
? 應設置為 “特性用戶描述(Characteristic User Description)” 的 UUIDAttribute Value
? 應設置為特性用戶描述的 UTF-8 字符串Attribute Permissions
? 由配置文件指定,或者如果未特別指定,則可以由實現決定
特征用戶描述結構
圖源:《Bluetooth Core Specification v5.0》
Client Characteristic Configuration
客戶端特性配置(Client Characteristic Configuration) 聲明是一個可選的特性描述符,用于定義特性如何由特定客戶端進行配置
客戶端特性配置描述符的值應在已配對設備之間的連接中保持持久性;在與非配對設備的每次連接中,客戶端特性配置描述符的值應設置為默認值
該特性描述符值是一個 位域(bit field),當某個位被設置時,相應的操作將被啟用,否則將不使用
在一個特性定義中只能有一個客戶端特性配置聲明
客戶端可以寫入此配置描述符來控制服務器上該特性的配置,每個客戶端都有自己獨立的客戶端特性配置 實例,讀取客戶端特性配置僅顯示該客戶端的配置,寫入僅影響該客戶端的配置
寫入配置描述符時,服務器可能需要身份驗證和授權
客戶端特性配置聲明應為可讀和可寫,該特性描述符包含在一個 Attribute 中
Attribute Type
? 應設置為 “客戶端特性配置(Client Characteristic Configuration)” 的 UUIDAttribute Value
? 應設置為特性描述符值Attribute Permissions
? 由配置文件指定,或如果未特別指定,則可以由實現決定
客戶端特性配置結構
圖源:《Bluetooth Core Specification v5.0》
客戶端特性配置位定義
Configuration | Value | Description |
---|---|---|
Notification | 0x0001 | 特性值將被通知。只有在特性屬性設置了通知位時,此值才可以設置 |
Indication | 0x0002 | 特性值將被指示。只有在特性屬性設置了指示位時,此值才可以設置 |
Reserved for Future Use | 0xFFFC | 保留供未來使用 |
- 客戶端特性配置描述符值 的默認值應為 0x0000
- 如果 GATT 服務器 支持來自同一設備的多個 ATT 承載通道(ATT bearers),則每個 ATT 承載通道應視為具有獨立的 GATT 客戶端實例,因此,每個 GATT 客戶端應擁有獨立的 客戶端特性配置
Notification 通知
?是一種無確認的數據傳輸方式,服務器發送數據后無需等待客戶端的響應;這使得通知在需要高效、頻繁更新數據的場景中非常適用,但不能保證數據已經被客戶端成功接收
Indication 指示
?則是一種有確認的傳輸方式,服務器發送數據后會等待客戶端的確認響應;這確保了客戶端已經成功接收數據,因此適用于那些需要可靠傳輸和確保數據到達的場景,但相較通知,指示會增加一定的延遲和開銷
Server Characteristic Configuration
服務器特性配置(Server Characteristic Configuration) 聲明是一個可選的特性描述符,用于定義如何為服務器配置特性
特性描述符值是一個 位域(bit field),當某個位被設置時,相應的操作將被啟用,否則將不使用
在一個特性定義中只能有一個服務器特性配置聲明
服務器特性配置聲明應為可讀和可寫,客戶端可以寫入該配置描述符來控制服務器上所有客戶端的特性配置;對于所有客戶端來說,服務器特性配置是單一實例,讀取服務器特性配置顯示的是所有客戶端的配置,而寫入則會影響所有客戶端的配置
服務器可能需要身份驗證和授權才能寫入配置描述符
該特性描述符包含在一個 Attribute 中
Attribute Type
? 應設置為 “服務器特性配置(Server Characteristic Configuration)” 的 UUIDAttribute Value
? 應設置為特性描述符值Attribute Permissions
? 由配置文件指定,或者如果沒有特別指定,則可以由實現決定
服務器特性配置結構
圖源:《Bluetooth Core Specification v5.0》
服務器特性配置位定義
Configuration | Value | 描述 |
---|---|---|
Broadcast | 0x0001 | 當服務器處于廣播過程并且廣告數據資源可用時,特性值將被廣播 只有在特性屬性設置了廣播位時,此值才可以設置 |
Reserved for Future Use | 0xFFFE | 保留供未來使用 |
Characteristic Presentation Format
特性展示格式(Characteristic Presentation Format) 聲明是一個可選的特性描述符,用于定義特性值(Characteristic Value) 的格式,即如何解析特征值
如果一個特性定義中存在多個特性展示格式聲明(Characteristic Presentation Format declarations),則必須存在特性聚合格式聲明(Characteristic Aggregate Format declaration) 作為該特性定義的一部分
特性格式值由五個部分組成:
- 格式(format)
- 指數(exponent)
- 單位(unit)
- 命名空間(name space)
- 描述(description)
該特性描述符包含在一個Attribute 中
Attribute Type
? 應設置為 “特性格式(Characteristic Format)” 的 UUIDAttribute Value
? 應設置為特性描述符值Attribute Permissions
? 應為只讀,并且不需要身份驗證或授權
特征展示格式屬性結構
圖源:《Bluetooth Core Specification v5.0》
特性展示格式描述符屬性值字段的定義
Field Name | Value Size | Description |
---|---|---|
Format | 1 octet | 該特性值的格式 |
Exponent | 1 octet | 指數字段,用于確定該特性值如何進一步格式化 |
Unit | 2 octets | 該特性的單位,如在《Assigned Number Specification》中定義 |
Name Space | 1 octet | 描述的命名空間,如在《Assigned Number Specification》中定義 |
Description | 2 octets | 該特性的描述,如在更高層配置文件中定義 |
位序
Characteristic Format descriptor 使用的位序應該是 小端序(little-endian)(低位字節存儲在低地址,而高位字節存儲在 高地址,即數據的 最低有效字節(LSB) 放在最前面)
格式
格式(Format) 字段決定了 特性值(Characteristic Value) 中單個值的格式
如果格式不是一個完整的字節數,則數據應以能夠容納該值的最小字節數進行存儲;數據應占用每個字節的全部內容,除了最后一個字節的最高有效位;最后一個字節的其他位應預留供未來使用
帶符號整數應使用二進制補碼表示法(two’s-complement representation)
定義的格式值
Format | Short Name | Description | Exponent Value |
---|---|---|---|
0x00 | rfu | Reserved for Future Use | No |
0x01 | boolean | unsigned 1-bit; 0 = false, 1 = true | No |
0x02 | 2bit | unsigned 2-bit integer | No |
0x03 | nibble | unsigned 4-bit integer | No |
0x04 | uint8 | unsigned 8-bit integer | Yes |
0x05 | uint12 | unsigned 12-bit integer | Yes |
0x06 | uint16 | unsigned 16-bit integer | Yes |
0x07 | uint24 | unsigned 24-bit integer | Yes |
0x08 | uint32 | unsigned 32-bit integer | Yes |
0x09 | uint48 | unsigned 48-bit integer | Yes |
0x0A | uint64 | unsigned 64-bit integer | Yes |
0x0B | uint128 | unsigned 128-bit integer | Yes |
0x0C | sint8 | signed 8-bit integer | Yes |
0x0D | sint12 | signed 12-bit integer | Yes |
0x0E | sint16 | signed 16-bit integer | Yes |
0x0F | sint24 | signed 24-bit integer | Yes |
0x10 | sint32 | signed 32-bit integer | Yes |
0x11 | sint48 | signed 48-bit integer | Yes |
0x12 | sint64 | signed 64-bit integer | Yes |
0x13 | sint128 | signed 128-bit integer | Yes |
0x14 | float32 | IEEE-754 32-bit floating point | No |
0x15 | float64 | IEEE-754 64-bit floating point | No |
0x16 | SFLOAT | IEEE-11073 16-bit SFLOAT | No |
0x17 | FLOAT | IEEE-11073 32-bit FLOAT | No |
0x18 | duint16 | IEEE-20601 format | No |
0x19 | utf8s | UTF-8 string | No |
0x1A | utf16s | UTF-16 string | No |
0x1B | struct | Opaque structure | No |
0x1C – 0xFF | rfu | Reserved for Future Use | No |
- 當編碼 IPv4 地址 時,應使用 uint32 格式類型
- 當編碼 IPv6 地址 時,應使用 uint128 格式類型
- 當編碼 藍牙 BD_ADDR 時,應使用 uint48 格式類型
- duint16 是由兩個 uint16 值連接在一起組成的
Exponent
指數(Exponent) 字段與整數數據類型一起使用,用于確定值如何進一步格式化
指數字段僅在 格式字段(format field) 中指定為整數格式類型時使用,是二進制補碼有符號整數
實際值 = 特性值 × 1 0 指數 \text{實際值} = \text{特性值} \times 10^{\text{指數}} 實際值=特性值×10指數
實際值是特性值 與 10 的 指數(Exponent) 次方的組合
Unit
單位(Unit) 是一個 UUID,如在 分配編號文檔(Assigned Numbers document) 中定義
Name Space
命名空間(Name Space) 字段用于標識 負責定義描述字段枚舉值的組織,該組織在分配編號文檔中有定義
Description
描述(Description) 是一個枚舉值,如在 分配編號文檔(Assigned Numbers document)中定義,來自 命名空間字段(Name Space) 中標識的組織
Characteristic Aggregate Format
特性聚合格式(Characteristic Aggregate Format) 聲明是一個可選的特性描述符,用于定義聚合的特性值(Characteristic Value) 的格式
在一個特性定義中只能有一個特性聚合格式聲明
特性聚合格式值由特性展示格式聲明(Characteristic Presentation Format declarations) 的屬性句柄列表(Attribute Handles) 組成,每個屬性句柄指向一個特性展示格式聲明,Attribute Permissions 應為只讀,并且不需要身份驗證或授權
屬性句柄列表是多個 16 位屬性句柄(Attribute Handle) 值連接成一個 Attribute Value,該列表至少應包含兩個特性展示格式聲明(Characteristic Presentation Format declarations) 的屬性句柄
特性值應根據每個由屬性句柄指向的特性展示格式聲明進行解構,列表中屬性句柄的順序是有意義的
如果在一個特性定義中存在多個特性展示格式聲明,則必須有一個特性聚合格式聲明;該聲明應在屬性句柄列表中包含特性定義中的每個特性展示格式聲明;其他特性定義中的特性展示格式聲明也可以被使用
特性聚合格式屬性結構
圖源:《Bluetooth Core Specification v5.0》
?
GATT Profile Attribute Types
Attribute Type | UUID | Description |
---|---|---|
Primary Service | 0x2800 | Primary Service Declaration |
Secondary Service | 0x2801 | Secondary Service Declaration |
Include | 0x2802 | Include Declaration |
Characteristic | 0x2803 | Characteristic Declaration |
Characteristic Extended Properties | 0x2900 | Characteristic Extended Properties |
Characteristic User Description | 0x2901 | Characteristic User Description Descriptor |
Client Characteristic Configuration | 0x2902 | Client Characteristic Configuration Descriptor |
Server Characteristic Configuration | 0x2903 | Server Characteristic Configuration Descriptor |
Characteristic Format | 0x2904 | Characteristic Format Descriptor |
Characteristic Aggregate Format | 0x2905 | Characteristic Aggregate Format Descriptor |
GATT Send Command
命令代碼 + 輸入參數 + 授權
GATT Server
BLE 通信中 Server 和 Client 工作流程圖解
原圖較大由于網站壓縮,圖像畫質可能較差,原圖見Github_CodeFlashier
我們把存有數據(即屬性)的設備叫做服務器 (Server),?將獲取別?設備數據的設備叫做客戶端 (Client)
GAP與GATT的關系
維度 | GAP | GATT |
---|---|---|
層級 | 控制層(決定設備可見性和連接方式) | 數據層(定義連接后的數據傳輸規則) |
工作階段 | 連接前(廣播、發現、配對) | 連接后(數據讀寫、服務交互) |
依賴關系 | GATT依賴GAP建立的連接 | GAP為GATT提供通信基礎 |
典型應用 | 設備配對、廣播信息 | 傳感器數據讀取、設備控制 |
GATT Server Work Flow
此過程指的是初始化和啟動 GATT 服務器所涉及的步驟,其中包括設置GATT服務、特征和描述符等任務,并使服務器準備好處理來自 GATT 客戶端的請求
GAP Callback 處理客戶端的連接、掃描等事件
GATT Callback 在客戶端連接成功后,底層協議棧會發送 GATT 事件到上層程序進行處理,從而完成客戶端對服務端數據的讀寫
GATT 客戶端在與 GATT 服務器初次建立通信時,會從 GATT 服務器拉取屬性表中的元信息,從而獲取 GATT 服務器上可用的服務以及數據特征,這一過程被稱為服務發現 (Service Discovery)
屬性表中包含:
參數 | 作用 |
---|---|
auto_rsp | 控制誰處理讀/寫操作的響應 如果設置為 ESP_GATT_RSP_BY_APP ,則由應用程序負責生成響應;如果設置為 ESP_GATT_AUTO_RSP ,則 GATT 協議棧會自動生成響應。 |
uuid_length | UUID 的長度(以字節為單位) |
*uuid_p | 指向 UUID 值的指針 |
perm | 屬性的權限,由 esp_gatt_perm_t 定義 |
max_length | 屬性值的最大長度 |
length | 屬性值的當前長度 |
*value | 指向屬性值數組的指針 |
創建 GATT Profile 實例,用于后續功能實現
struct gatts_profile_inst // GATT Profile 實例
{ esp_gatts_cb_t gatts_cb; // GATT 事件回調函數 uint16_t gatts_if; // GATT 接口 uint16_t app_id; // Application ID uint16_t conn_id; // 連接 ID uint16_t service_handle; // 服務句柄 esp_gatt_srvc_id_t service_id; // 服務 ID uint16_t char_handle; // 特征值句柄 esp_bt_uuid_t char_uuid; // 特征值 UUID esp_gatt_perm_t perm; // 特征值權限 esp_gatt_char_prop_t property; // 特征值屬性 uint16_t descr_handle; // 描述符句柄 esp_bt_uuid_t descr_uuid; // 描述符 UUID};
BLE Server 設置主要步驟
- 定義服務和特征值:通過
gatt_db
屬性表 - 創建服務:通過
esp_ble_gatts_create_attr_tab
- 啟動服務:通過
esp_ble_gatts_start_service
- 注冊服務:通過
esp_ble_gatts_app_register
- 處理事件:通過
gatts_event_handler
- 設置廣播:通過
esp_ble_gap_config_adv_data
或esp_ble_gap_config_adv_data_raw
Advertising
在 Bluetooth LE 4.2 標準中, RF 信道分為兩種類型,如下
類型 | 數量 | 編號 | 作用 |
---|---|---|---|
廣播信道 (Advertising Channel) | 3 | 37-39 | 用于發送廣播數據包和掃描響應數據包 |
數據信道 (Data Channel) | 37 | 0-36 | 用于發送數據通道數據包 |
廣播者在廣播時,會在 37-39 這三個廣播信道中進行廣播數據包的發送
在三個廣播信道的廣播數據包均發送完畢后,可以認為一次廣播結束,廣播者會在下一次廣播時刻到來時重復上述過程
廣播數據包的最外層包含四個部分,分別是
序號 | 名稱 | 字節數 | 功能 |
---|---|---|---|
1 | 預置碼 (Preamble) | 1 | 特殊的比特序列,用于設備時鐘同步 |
2 | 訪問地址 (Access Address) | 4 | 標記廣播數據包的地址 |
3 | 協議數據單元 (Protocol Data Unit, PDU) | 2-39 | 有效數據的存放區域 |
4 | 循環冗余校驗和 (Cyclic Redundancy Check, CRC) | 3 | 用于循環冗余校驗 |
廣播參數配置結構體:
typedef struct {uint16_t adv_int_min; /*!< 無定向廣播和低占空比定向廣播的最小廣播間隔。范圍:0x0020 到 0x4000,默認值:N = 0x0800(1.28 秒)。時間 = N * 0.625 毫秒,時間范圍:20 毫秒到 10.24 秒。 */uint16_t adv_int_max; /*!< 無定向廣播和低占空比定向廣播的最大廣播間隔。范圍:0x0020 到 0x4000,默認值:N = 0x0800(1.28 秒)。時間 = N * 0.625 毫秒,時間范圍:20 毫秒到 10.24 秒。 */esp_ble_adv_type_t adv_type; /*!< 廣播類型 */esp_ble_addr_type_t own_addr_type; /*!< 本地藍牙設備地址類型 */esp_bd_addr_t peer_addr; /*!< 目標設備的藍牙設備地址 */esp_ble_addr_type_t peer_addr_type; /*!< 目標設備的藍牙設備地址類型,僅支持公共地址類型和隨機地址類型 */esp_ble_adv_channel_t channel_map; /*!< 廣播信道映射 */esp_ble_adv_filter_t adv_filter_policy; /*!< 廣播過濾策略 */
} esp_ble_adv_params_t;---static esp_ble_adv_params_t adv_params = { .adv_int_min = 0x20, // 廣播間隔最小值,單位為 0.625ms .adv_int_max = 0x40, .adv_type = ADV_TYPE_IND, // 使用 ADV_IND 為藍牙5.0以下的 PDUs .own_addr_type = BLE_ADDR_TYPE_PUBLIC, // 自身地址類型,此處為公共地址 .channel_map = ADV_CHNL_ALL, // 廣播通道,使用所有通道 .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, // 廣播過濾策略,允許掃描和連接
};
MTU
MTU ( Maximum Transmission Unit 最大傳輸單元)指定發送方在通道上能夠接收的最大SDU(服務數據單元)大小
服務器和客戶端之間的交互操作都是通過上述的消息 ATT PDU 實現的。每個設備可以指定??設備?持的最? ATT 消息?度,我們稱之為 MTU。ESP32 IDF ??規定 MTU 可以設置的范圍是 23~517 字節,對屬性值的總?度沒有做限制
如果?戶需要發送的數據包?度?于 (MTU-3)*,則需要調?準?寫?請求 (Prepare Write Request) 來完成數據的寫操作。同理,在讀取?個數據時候,如果數據的?度超過 (MTU- 1),則需要通過?對象讀取請求 (Read Blob Request) 來繼續讀取剩余的值。
其類型為 0x01,負載長度為 2 個八位字節(octet),并攜帶兩個八位字節的 MTU 大小值;與 B 幀長度字段不同,I 幀長度字段可以大于配置的 MTU,因為它包括了控制字段、L2CAP SDU 長度(如果存在)、幀校驗序列字段以及信息字節的長度
MTU 選項格式
圖源:《Bluetooth Core Specification v5.0》
MTU不是協商值,它是一個信息性參數,每個設備可以獨立指定;它向遠程設備表明,當前設備能夠在該通道中接收比最低要求更大的MTU
MTU 的默認值為 23 字節,恰為 Bluetooth LE 4.2 之前單個數據 PDU 的最大可承載 ATT 數據字節數
MTU 可以設定為更大的值,例如 140 字節。在 Bluetooth LE 4.2 以前,由于有效負載中最多只有 23 字節可以承載 ATT 數據,所以必須將完整的一包 ATT 數據包拆分成若干份,分散到多個數據 PDU 中。在 Bluetooth LE 4.2 以后,單個數據 PDU 最多可以承載 247 字節 ATT 數據,所以 MTU 為 140 字節時仍然可以使用單個數據 PDU 承載
Broadcast Frame B 幀
? 用于傳輸控制信息或鏈路管理數據,包含控制字段和幀檢查序列等額外的管理信息,不直接傳輸應用數據
Information Frame I 幀
? 用于傳輸實際的應用數據,包含有效負載和控制信息,它通常包括L2CAP SDU長度、幀校驗序列等,用于數據傳輸
L2CAP SDU (L2CAP Service Data Unit)
?是L2CAP(邏輯鏈路控制和適配協議)中的一種數據單位,它指的是 L2CAP 協議層所處理的完整數據單元;L2CAP 用于藍牙設備之間的通信,負責數據分段和重組、流量控制、錯誤檢測等功能
在響應配置請求時,指定通道的 MTU 大小時應遵循以下規則:
- 如果請求中指定的 MTU 大于或等于通道的最小 MTU ,則應接受該請求
- 如果請求中指定的 MTU 小于通道的最小MTU,則該請求可能會被拒絕
PDU
PDU 段為有效數據存放的區域,其結構如下
序號 | 名稱 | 字節數 |
---|---|---|
1 | 頭 (Header) | 2 |
2 | 有效負載 (Payload) | 0-37 |
PDU 頭中含有較多信息,可以分為以下六個部分 |
序號 | 名稱 | 比特位數 | 備注 |
---|---|---|---|
1 | PDU 類型 (PDU Type) | 4 | |
2 | 保留位 (Reserved for Future Use, RFU) | 1 | |
3 | 通道選擇位 (Channel Selection Bit, ChSel) | 1 | 標記廣播者是否支持 LE Channel Selection Algorithm #2 通道選擇算法 |
4 | 發送地址類型 (Tx Address, TxAdd) | 1 | 0/1 分別表示公共地址/隨機地址 |
5 | 接收地址類型 (Rx Address, RxAdd) | 1 | 0/1 分別表示公共地址/隨機地址 |
6 | 有效負載長度 (Payload Length) | 8 |
PDU 類型位反映了設備的廣播行為。在藍牙標準中,共有以下三對廣播行為
- 可連接 (Connectable) 與 不可連接 (Non-connectable)
- 是否接受其他設備的連接請求
- 可掃描 (Scannable) 與 不可掃描 (Non-scannable)
- 是否接受其他設備的掃描請求
- 不定向 (Undirected) 與 定向 (Directed)
- 是否發送廣播數據至指定設備
上述廣播行為可以組合成以下四種常見的廣播類型,對應四種不同的 PDU 類型
- 是否發送廣播數據至指定設備
可連接? | 可掃描? | 不定向? | PDU 類型 | 作用 |
---|---|---|---|---|
是 | 是 | 是 | ADV_IND | 最常見的廣播類型 |
是 | 否 | 否 | ADV_DIRECT_IND | 常用于已知設備重連 |
否 | 否 | 是 | ADV_NONCONN_IND | 作為信標設備,僅向外發送廣播數據 |
否 | 是 | 是 | ADV_SCAN_IND | 作為信標設備,一般用于廣播數據包長度不足的情況,此時可以通過掃描響應向外發送額外的數據 |
PDU 有效負載也分為兩部分
序號 | 名稱 | 字節數 | 備注 |
---|---|---|---|
1 | 廣播地址 (Advertisement Address, AdvA) | 6 | 廣播設備的 48 位藍牙地址 |
2 | 廣播數據 (Advertisement Data, AdvData) | 0-31 | 由若干廣播數據結構 (Advertisement Data Structure) 組成 |
藍牙地址,可以分為
類型 | 說明 |
---|---|
公共地址 (Public Address) | 全球范圍內獨一無二的固定設備地址,廠商必須為此到 IEEE 組織注冊并繳納一定費用 |
隨機地址 (Random Address) | 隨機生成的地址 |
隨機地址又根據用途分為兩類
類型 | 說明 |
---|---|
隨機靜態地址 (Random Static Address) | 可以隨固件固化于設備,也可以在設備啟動時隨機生成,但在設備運行過程中不得變更;常作為公共地址的平替 |
隨機私有地址 (Random Private Address) | 可在設備運行過程中周期性變更,避免被其他設備追蹤 |
若使用隨機私有地址的設備要與其他受信任的設備通信,則應使用身份解析秘鑰 (Identity Resolving Key, IRK) 生成隨機地址,此時其他持有相同 IRK 的設備可以解析并得到設備的真實地址,此時,隨機私有地址又可以分為兩類
類型 | 說明 |
---|---|
可解析隨機私有地址 (Resolvable Random Private Address) | 可通過 IRK 解析得到設備真實地址 |
不可解析隨機私有地址 (Non-resolvable Random Private Address) | 完全隨機的地址,僅用于防止設備被追蹤,非常少用 |
廣播數據
一個廣播數據結構的格式定義如下
序號 | 名稱 | 字節數 | 備注 |
---|---|---|---|
1 | 數據長度 (AD Length) | 1 | |
2 | 數據類型 (AD Type) | n | 大部分數據類型占用 1 字節 |
3 | 數據 (AD Data) | (AD Length - n) |
Advertising Flow
設備在 2.4 GHz ISM 頻段廣播數據
2.4 GHz ISM 頻段是一個全球可用的免費無線電頻段,不被任何國家以軍事用途等理由管控,也無需向任何組織支付許可費用,因此該頻段的可用性極高,且沒有任何使用成本
這也意味著 2.4 GHz ISM 頻段非常擁擠,可能會與其他無線通信協議發生數據沖突,如 2.4 GHz WiFi
Bluetooth LE 應用了自適應跳頻技術 (Adaptive Frequency Hopping, AFH) ,該技術可以判斷 RF 信道的擁擠程度,通過跳頻避開擁擠的 RF 信道,以提高通信質量
Bluetooth LE ?播主要有 5 種類型,分別為:可連接可掃描?定向?播 (Connectable scannable undirected mode)、?占空?定向?播 (High duty cycle directed event type)、可掃描?定向?播 (Scannable undirected mode)、不可連接?定向?播 (Non-connectable undirected mode)、可連接低占空?定向?播 (Connectable low duty cycle directed mode)。
Advertising State
Undirected Advertising
設備通過啟用廣播進入廣播狀態,在此之前必須先配置好廣播參數
不定向廣播
圖源:《Bluetooth Core Specification v5.0》
Host A
? 藍牙設備 A 的上層(主機)
?LL A
? 藍牙設備 A 的鏈接層(link layer)
Advertising Flow
LE Set Advertising Parameters
? Host 發送廣播參數命令到 LLCommand Complete
? LL 設置成功后返回命令完成 Event 到 HostLE Read Advertising Channel Tx Power
? Host 讀取廣播 Tx 的功率Command Complete
? LL 返回命令完成 Event 到 HostLE Set Advertising Data
? Host 設置廣播數據Command Complete
? LL 返回命令完成 Event 到 HostLE Set Scan Response Data
? Host 設置掃描應答數據Command Complete
? LL 返回命令完成 Event 到 HostLE Set Advertising Enable(Enable)
? Host 發送使能命令Command Complete
? LL 返回命令完成 Event 到 HostAdvert
? LL 開始廣播數據(從 LL B 到 LL A)LE Set Advertising Enable(Disable)
? Host 發送停止廣播命令Command Complete
? LL 返回命令完成 Event 到 Host
屬性 | SAMPLE_DEVICE_NAME | 廣播數據中的名字 |
---|---|---|
設置方式 | esp_ble_gap_set_device_name() | 在廣播數據中通過 0x09 字段設置 |
作用范圍 | GAP 名稱,全局標識設備 | 廣播包中的本地名稱,廣播時可見 |
是否必須 | 是,設備必須有一個 GAP 名稱 | 否,廣播包中可以不包含名字字段 |
是否可以不同 | 不依賴廣播數據,可以與廣播數據中的名字不同 | 可以與 GAP 名稱不同 |
顯示位置 | 客戶端掃描設備時顯示 | 客戶端解析廣播包時顯示 |
Directed Advertising
設備可以使用定向廣播允許發起方與其連接
高占空比定向廣播在控制器中是時間有限的,因此在建立連接之前可能會失敗
低占空比定向廣播也必須啟用才能進入廣播狀態,設備在此之前還應配置廣播參數
?
高占空比循環定向廣播失敗情況
圖源:《Bluetooth Core Specification v5.0》
低占空比循環定向廣播失敗情況
圖源:《Bluetooth Core Specification v5.0》
占空比
? 指的是在一個周期內,信號處于“活動”狀態的時間比例。它通常用百分比表示,計算公式為:占空比 = 活動時間 總周期時間 × 100 % \text{占空比} = \frac{\text{活動時間}}{\text{總周期時間}} \times 100\% 占空比=總周期時間活動時間?×100%
高占空比意味著信號在大部分時間內處于“活動”狀態,只有少部分時間處于“空閑”狀態
- 發送的信號較強,持續時間較長,適合需要高接入概率的場景
- 由于廣播持續時間較長,設備的功耗較高,因此適用于短時間內需要建立連接的情況
低占空比意味著信號的“活動”時間較短,大部分時間處于“空閑”狀態
- 廣播時間較短,信號的持續時間較低,適用于功耗敏感的場景
- 這種方式會減少設備的功耗,但建立連接的概率較低,因為廣播的時間較短,接收方可能錯過廣播
?
Scanning State
Passive Scanning
設備可以使用被動掃描來查找區域內的廣播設備
該設備將接收來自對等設備的廣播數據包,并將這些數據報告給主機
?
被動掃描
圖源:《Bluetooth Core Specification v5.0》
?
Scanning Flow
LE Set Scan Parameters (Passive Scanning)
? Host 設置被動掃描的掃描參數Command Complete
? LL 返回命令完成 Event 到 HostLE Set Scan Enable (Enable)
? Host 設置掃描允許命令Command Complete
? LL 返回命令完成 Event 到 HostAdvert
? LL A 收到來自 LL B 的掃描LE Advertising Report
? LL 上報收到的廣播數據LE Set Scan Enable (Disable)
? Host 發送停止掃描命令Command Complete
? LL 返回命令完成 Event 到 Host
Active Scanning
設備可以使用主動掃描獲取更多關于設備的信息,這些信息可能對填充用戶界面有幫助
主動掃描涉及更多的鏈路層廣播消息
?
主動掃描
圖源:《Bluetooth Core Specification v5.0》
Active Scanning Flow
LE Set Scan Parameters (Passive Scanning)
?Command Complete
?LE Set Scan Enable (Enable)
?Command Complete
?Advert
?SCAN_REQ
? LL A 發送掃描請求到 LL B (廣播數據最大只有 32 個 Bytes,更多的數據需要放在掃描應答中)SCAN_RSP
? LL B 返回掃描請求應答數據LE Advertising Report
上報廣播數據和掃描應答數據?LE Set Scan Enable (Disable)
?Command Complete
?
?
Callback Parameters
GATT Server Callback Parameters 詳見 esp-idf_GATT Server
GAP Callback Parameter 詳見 esp-idf_GATT Client
?
Advertising And Scanning Response Data Format
廣播數據和掃描響應數據的格式由兩個部分組成:重要部分和非重要部分
- 重要部分
- 包含一系列
AD 結構
?,每個 AD 結構包含兩個字段長度字段
? 1 字節,表示數據的長度,即后面的長度不能超過 0xff數據字段
? 長度由長度字段決定,數據字段的第一個字節是 AD 類型字段,剩余的長度 - 1 字節是 AD 數據,其內容取決于 AD 類型字段的值
- 包含一系列
- 非重要部分
- 當需要時,用來擴展廣播和掃描響應數據
- 必須包含全零字節
廣播數據和掃描響應數據的格式
圖源:《Bluetooth Core Specification v5.0》
長度字段如果設置為零,則數據字段沒有字節,這僅在需要提前終止廣告或掃描響應數據時發生
只有重要部分的廣告或掃描響應數據應通過無線信號發送
廣播和掃描響應數據在廣播事件中發送:
- 廣播數據放置在 ADV_IND、ADV_NONCONN_IND、ADV_SCAN_IND、AUX_ADV_IND、AUX_CHAIN_IND 和 AUX_SYNC_IND 數據包的 AdvData 字段中
- 掃描響應數據放置在 SCAN_RSP 數據包的 ScanRspData 字段中,或者放置在 AUX_SCAN_RSP 數據包的 AdvData 字段中
如果完整的廣播或掃描響應數據無法容納在 AUX_ADV_IND 或 AUX_SCAN_RSP 數據包中,則使用 AUX_CHAIN_IND 數據包傳送剩余的數據
AD 類型數據的格式和含義在 Core Specification Supplement 的 A 部分中定義,AD 類型標識符值在 Assigned_Numbers.pdf 文檔中 2.3 Common Data Types 部分定義
對于藍牙 5.0 及以下,廣播可以攜帶 0~31 個字節
對藍牙 5.0 及以上,廣播可以攜帶 0~254 個字節,通過分組技術,可以攜帶更多數據(不超過 1650Bytes)
詳見:Bluetooth Core Specification Vol6 PartB 2.3
These PDUs are sent by the Link Layer in the Advertising State and received by a Link Layer in the Scanning State or Initiating State. The ADV_IND, ADV_DIRECT_IND, ADV_NONCONN_IND, and ADV_SCAN_IND PDUs are called “legacy advertising PDUs”. The ADV_EXT_IND, AUX_ADV_IND, AUX_SYNC_IND, and AUX_CHAIN_IND PDUs are called “extended advertising PDUs”. Advertising events using legacy advertising PDUs are called “legacy advertising events”
來源:Bluetooth Core Specification v5.0, 頁面 2,570
gatts_table_creat_demo
GATT APP 的工作流程:
- (app_main)
esp_ble_gatts_app_register ()
注冊 profile ID,返回ESP_GATTS_REG_EVT
- (gatts_profile_event_handler)當觸發
ESP_GATTS_REG_EVT
,設置設備名稱、原始廣播數據,觸發ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT
- (gatts_profile_event_handler)
esp_ble_gap_config_scan_rsp_data_raw()
(GATT)設置廣播數據、掃描響應數據,觸發ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT
- (gap_event_handler)當觸發
ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT
事件如果廣播數據和掃描響應數據都設置了,則 (GAP) 調用esp_ble_gap_start_advertising
開始廣播,觸發ESP_GAP_BLE_ADV_START_COMPLETE_EVT
事件 - 設備廣播數據
- 可以調用
esp_ble_gap_stop_advertising()
停止廣播,返回ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT
可以在 LightBlue 中讀到廣播數據
應用程序處理客戶端讀取特征值事件
case ESP_GATTS_READ_EVT: // 讀事件,當客戶端讀取特征值時觸發,如果設置為 AUTO_RSP,協議棧會自動處理,否則需要應用程序處理 ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT"); esp_gatt_rsp_t rsp; // 定義變量 memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); // 初始化變量 rsp.attr_value.handle = param->read.handle; // 設置 handle rsp.attr_value.len = 4; // 設置長度 rsp.attr_value.value[0] = 0xde; // 設置值 rsp.attr_value.value[1] = 0xed; rsp.attr_value.value[2] = 0xbe; rsp.attr_value.value[3] = 0xef; esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp); // 返回數據至客戶端 break;
GATT Client
GATT Client Work Flow
GATT Client 工作流程
- (app_main) 中初始化 NVS
- (app_main) 釋放經典藍牙模式
- (app_main) 初始化藍牙控制器
- (app_main) 使能藍牙控制器
- (app_main) 初始化 bluedroid
- (app_main) 使能 bluedroid
- (app_main) 注冊 GAP 回調函數
- (app_main) 注冊 GATT 回調函數
- (app_main) 注冊 GATT APP ID,觸發
ESP_GATTC_REG_EVT
事件 - (gattc_profile_event_handler)設置掃描參數,觸發
ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT
事件 - (esp_gap_cb)當觸發
ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT
事件時,開始掃描,觸發ESP_GAP_BLE_SCAN_START_COMPLETE_EVT
事件 - (esp_gap_cb)掃描結果觸發
ESP_GAP_BLE_SCAN_RESULT_EVT
事件,它有兩個子事件:ESP_GAP_SEARCH_INQ_RES_EVT
和ESP_GAP_SEARCH_INQ_CMPL_EVT
- (esp_gap_cb)掃描到每一個藍牙 Service 時,觸發
ESP_GAP_SEARCH_INQ_RES_EVT
,對掃描到的數據進行解析,如果掃描到的設備名和目標設備名相同,則停止掃描,打開 GATT 連接,觸發ESP_GATTC_CONNECT_EVT
、ESP_GATTC_OPEN_EVT
事件 - (esp_gap_cb)掃描完所有的藍牙 Service 時,觸發
ESP_GAP_SEARCH_INQ_CMPL_EVT
- (esp_gap_cb)掃描到每一個藍牙 Service 時,觸發
- (gattc_profile_event_handler)當觸發
ESP_GATTC_CONNECT_EVT
事件時,打印連接 ID,發送 MTU 請求,觸發ESP_GATTC_DIS_SRVC_CMPL_EVT
、ESP_GATTC_CFG_MTU_EVT
事件 - (gattc_profile_event_handler)當觸發
ESP_GATTC_CFG_MTU_EVT
事件時,檢查 MTU 設置是否成功 - (gattc_profile_event_handler)當觸發
ESP_GATTC_DIS_SRVC_CMPL_EVT
事件時,搜索服務,當找到服務時,會觸發ESP_GATTC_SEARCH_RES_EVT
事件;當搜索完所有服務時,會觸發ESP_GATTC_SEARCH_CMPL_EVT
事件 - (gattc_profile_event_handler)當觸發
ESP_GATTC_SEARCH_RES_EVT
事件時,保存服務的起始句柄和結束句柄 - (gattc_profile_event_handler)當觸發
ESP_GATTC_SEARCH_CMPL_EVT
事件,獲取服務的特征數量和服務特征,注冊通知,觸發ESP_GATTC_REG_FOR_NOTIFY_EVT
事件 - (gattc_profile_event_handler)當觸發
ESP_GATTC_REG_FOR_NOTIFY_EVT
事件,寫入描述符,觸發ESP_GATTC_WRITE_DESCR_EVT
事件 - (gattc_profile_event_handler)當觸發
ESP_GATTC_WRITE_DESCR_EVT
事件,,輸出寫入成功或失敗 - (gattc_profile_event_handler)如果 Service 發送通知,觸發
ESP_GATTC_NOTIFY_EVT
特征讀取函數
esp_ble_gattc_read_char(gattc_if, // 特征接口 p_data->search_cmpl.conn_id, // 連接 ID char_elem_result[0].char_handle, // 特征句柄 ESP_GATT_AUTH_REQ_NONE); // 無需授權 // 觸發 ESP_GATTC_READ_CHAR_EVT 事件
特征輸出函數
case ESP_GATTC_READ_CHAR_EVT: ESP_LOGI(GATTC_TAG, "ESP_GATTC_READ_CHAR_EVT, len %d, value:", p_data->read.value_len); esp_log_buffer_hex(GATTC_TAG, p_data->read.value, p_data->read.value_len);
break;
Connection
當掃描者在某一個廣播信道接收到一個廣播數據包時,若該廣播者是可連接的,那么掃描者可以在同一廣播信道發送連接請求 (Connection Request)
對廣播者,它可以設置 接受列表 (Filter Accept List) 以過濾不受信任的設備,或接受任一掃描者的連接請求
隨后,廣播者轉變為外圍設備,掃描者轉變為中央設備,兩者之間可以在數據信道進行雙向通信
在連接中,中央設備與外圍設備會周期性地進行數據交換,這個數據交換的周期被稱為連接間隔 (Connection Interval)
- 連接間隔作為連接參數之一,在連接請求中被首次確定,后續也可以進行修改
- 連接間隔的取值步長 (Step Size) 為 1.25 ms ,取值范圍為 7.5 ms (6 steps) - 4.0 s (3200 steps)
一次數據交換的過程被稱為連接事件 (Connection Event)
一次連接事件中,存在一次或多次數據包交換(數據量比較大時需分包發送)
- 一次數據包交換的過程是,中央設備先給外圍設備發送一個數據包,隨后外圍設備給中央設備發送一個數據包
- 即便連接中任意一方在連接間隔開始時無需發送數據,也必須發送空數據包以維持連接
- 若一次連接事件中需要發送的數據很多,導致連接事件時長超過了連接間隔,那么必須將一次連接事件拆分成多次連接事件(假如連接間隔的剩余時間不足以完成下一次數據包交換,那么下一次數據包交換必須等到下一次連接間隔開始時才能進行)
Supervision Timeout
連接超時參數 (Supervision Timeout) 規定了兩次成功連接事件之間的最長時間
若在一次成功的連接事件之后,經過了連接超時時間卻仍沒有完成另一次成功的連接事件,則可以認為連接已斷開
Peripheral Latency
外圍設備延遲 (Peripheral Latency) 規定了外圍設備在無需發送數據的前提下,最多可忽略的連接事件數量(即可以根據實際情況動態調整連接間隔,低間隔則高能耗,高間隔則高延遲)
MTU
詳見本文MTU部分
Data Exchange
由客戶端發起的操作有以下三種
- 讀 (Read)
- 從 GATT 服務器上拉取某一特征數據的當前值
- 寫 (Write)
- 普通的寫操作要求 GATT 服務器在收到客戶端的寫請求以及對應數據以后,進行確認響應
- 寫(無需響應) (Write without response)
- 快速寫操作則不需要服務器進行確認響應
由服務器發起的操作分兩種
- 通知 (Notify)
- 通知是 GATT 服務器主動向客戶端推送數據的操作,不需要客戶端回復確認響應
- 指示 (Indicate)
- 與通知相似,區別在于指示需要客戶端回復確認,因此數據推送速度比通知慢
雖然通知和指示都是由服務器發起的操作,但是服務器發起操作的前提是,客戶端啟用了通知或指示
所以,本質上 GATT 的數據交換過程總是以客戶端請求數據開始
Write Data
flowchart TB
A[Client] --write data--> B[Server]
B --> C{Data}
C --<=MTU-3-->D[ESP_GATTS_WRITE_EVT]
C -->MTU-3-->D[ESP_GATTS_WRITE_EVT]
C -->MTU-3-->E[ESP_GATTS_EXEC_WRITE_EVT]
當接收到的數據 > MTU - 3 時,會將超出的數據放入一個 buffer 中,接受完所有數據后,再進行處理
- 客戶端發起寫入請求
- 服務器接收并存儲到屬性數據庫
- 服務器應用邏輯讀取該值
- 服務器處理該值
Notification for Server
可以用于在觸發 ESP_GATTS_WRITE_EVT 事件后回復 client
Notification for Client
- 客戶端查找服務事件
ESP_GATTC_SEARCH_CMPL_EVT
,即藍牙客戶端在查找完服務端后,會上報上層程序,如果找到了目標服務,則會調用esp_ble_gattc_get_attr_count()
函數,取得屬性數目 - 如果取得的數目 >0,則會調用
esp_ble_gattc_get_char_by_uuid()
函數,取得所用對應特征值的設置,同時取得通知值的設置,從而判斷是 notification 還是 indication - 之后調用
esp_ble_gattc_register_for_notify()
注冊通知,觸發ESP_GATTC_REG_FOR_NOTIFY_EVT
事件 - 通過
esp_ble_gattc_get_descr_by_char_handle()
取得 describe 位 - 通過
esp_ble_gattc_write_char_descr()
函數將notify_en
參數(0x0001-notification,0x0002-indication)寫入 Server,觸發ESP_GATTC_WRITE_DESCR_EVT
事件(在服務端觸發ESP_GATTS_WRITE_EVT
) - 檢查寫入是否成功,如果成功,則進行下一步流程
- Server 發送 notification,觸發客戶端的
ESP_GATTC_NOTIFY_EVT
事件
flowchart TDA[Register] --esp_ble_gattc_register_for_notify()--> B[ESP_GATTC_REG_FOR_NOTIFY_EVT]B --esp_ble_gattc_get_descr_by_char_handle(), esp_ble_gattc_write_char_descr() -->C[ESP_GATTC_WRITE_DESCR_EVT]