學習資料:
1. 藍牙協議core_v5.0.pdf 《Vol 2: Core System Package [BR/EDR Controller volume]》的“Part E: Host Controller Interface Functional Specification”
2. BTStack源碼
對於被動掃描,周邊的外設會給controller發送各種廣播包,解析廣播包,從而得到設備的信息。
對於主動掃描,除了被動的獲得廣播包外,controller還可以給某個設備發出掃描請求,設備就會返回一個掃描回應,將更多的信息給controller。
兩個藍牙設備互相通信,涉及兩個Controller。Controller是具備一定智能的,它可以自行決定做什么事情:不需要Host決定它的每一個細節。比如說:要想讓Controller發出掃描請求(SCAN REQ),Host只需要向Controller發出一個“scan enable”的命令即可,Controller就會根據預設的參數自動發出掃描請求(SCAN REQ)廣播包。
Controller就是一個芯片,它封裝了LL層、PHY層那些復雜的操作;Host不需要理解芯片內部復雜的操作,只需要遵守Controller的規范,向它提供command,從它獲得event,與它交互acl data。
HCI層跟LL層的關系:
a. 有些HCI command只是用來設置本地Controller,不導致無線傳輸
b. 有些HCI command會導致LL層發出各類廣播包,
比如“LE Set Scan Enable Command”在主動掃描時會導致LL層發出SCAN_REQ廣播包,
比如“LE Create Connection Command”會導致LL層發出CONNECT_REQ廣播包
c. 有些HCI command會導致LL層發出數據包,其中的LLID=11b,表示是“LL Control PDU”,
比如“LE Read Channel Map Command”就會導致LL層發數據給對端設備,以便讀取對端設備的信道圖。
d. ACL Data是必定導致LL層發數據給對端設備的,
這時的LL層數據,有可能是起始包,LLID=10b;
也可能是延續包,LLID=01b;
也可能是空包,LLID=01b
在上一篇博客里,在傳遞Command/Event/ACL Data這3類數據時:
1. 對於UART接口的Controller,會在數據前面加上1字節的頭部用來分辨是哪一類數據
2. 對於USB接中里的Controller,每類數據對應一個Endpoint,數據會直接發給Endpoint
下面,介紹Command/Event/ACL Data這3類數據的格式。
一、Command格式:
Command前有2字節的頭部OpCode,用來表示是哪一個Command。
OGF表示“OpCode Group Field”,即“哪一組命令”,它占據高6位。
OCF表示“OpCode Command Field”,即“這組里的哪一個命令”,它占據低10位。
在藍牙協議里,每一個OGF用一節來描述,在這節里會描述該組(OGF)的所有命令(OCF),位置如下圖:
BTStack示例:
btstack-master\src\hci_cmd.c
12211分別表示1個字節用來表示掃描類型、2個字節用來表示掃描間隔、2個字節用來表示scan_window、1個字節用來表示own_address_type、1個字節用來表示scanning_filter_policy。
以后發送命令的時候,就需要根據12211這個格式來組裝這些參數。在代碼中搜索hci_le_set_scan_parameters.
hci_send_cmd(&hci_le_set_scan_parameters, 1, 0x1e0, 0x30, hci_stack->le_own_addr_type, 0);
代碼中和文檔中OCF的值剛好對應,正好是B。
再來看一個例子:
它帶有兩個參數,每個參數占一個字節,即hci_stack->le_scanning_enabled占一個自己;0占一個字節
其他的命令也是類似的,具體需要查看藍牙文檔core_5.0
二、Event格式:
在官方協議中對於Event並沒有明確的分類,按我的理解可以分為以下3類:
Event分類 |
說明 |
Command Status Event |
命令狀態事件, 表示控制器已經接收到命令並正在處理 |
Command Complete Event |
命令完成事件, 表示命令已經處理完畢並返回結果 |
Advertising Report Event |
廣播上報事件,本Event是Controller主動上報的 而上述2個Event都是由command導致的 |
示例:
有些命令需要一定時間才能執行完,比如LE Create Connection命令。控制器接收到該命令后會首先返回一個“命令狀態事件”,隨后等待連接建議完成或者失敗,再返回“命令完成事件”。
Event的格式:
三、ACL Data格式:
ACL Data是傳遞給對端設備的數據,在建立連接之后才可以傳輸ACL Data,格式如下:
Handle表示對端設備:主設備的Controller要與對端設備連接時,會生成一個32位的隨機數,它被稱為Access Address。在LL層的數據包中,Access Address被用來表示對端設備。但是Host程序並不想使用這個32位的數據,於是Controller又分配一個12位的Handle來表示這個Access Address、表示對端的設備。
Packet_Boundary_Flag:
PB Flag |
描述 |
Host to Controller |
Controller to Host |
00b |
L2CAP PDU起始包 |
P |
|
01b |
L2CAP PDU延續包 |
P |
P |
10b |
L2CAP PDU起始包 |
|
P |
Controller在傳輸ACL Data時,每次傳輸的字節數是有限制的,這可以通過“Read Buffer Size”命令讀到這個值。
當要傳輸非常大的ACL Data時,需要把數據拆分來傳輸,這就要用到上面表格中的“PB Flag”來分辨起始包、延續包。
這些起始包、延續包由Host送到Controller后,會馬上通過LL層重新編碼、發給PHY層發給對端設備,對端設備的L2CAP層再把這些起始包、延續包組裝起來。
注意,在LL層的數據包里有LLID域,10b表示起始包、01b表示延續包。
Broadcast_Flag在BLE協議中都是00b,表示“Point-to-point”。
四、示例:
Broadcast_Flag在BLE協議中都是00b,表示“Point-to-point”。
1. 掃描設備
a. Host向Controller發出“LE Set Scan Parameters Command”
b. Controller向Host發送“Command Complete Event”
c. Host向Controller發出“LE Set Scan Enable Command”
d. Controller向Host發送“Command Complete Event”
e. 如果掃描參數為“主動掃描”,對於新發現的設備會,LL層發出“SCAN REQ”廣播包
f. Controller接收到各類廣播包,比如ADV_IND、SCAN_RSP
LL層解析后,會通過HCI上報EVENT
2. 連接設備
a. Host向Controller發出“LE Create Connection Command”
b. 不需要對端設備回應數據,發起方就認為連接已經建立
c. Controller向Host發送“Command Status Event”
d. Controller向Host發送“Command Complete Event”
3. 寫數據
a. Host向Controller發出ACL數據:Write Command, Handle….
b. Controller的LL層構造數據包(LLID=10b),通過PHY發出無線信號
c. Controller向Host發送“Number of Completed Packets”事件
4. 讀數據
a. Host向Controller發出ACL數據:Read Request, Handle….
b. Controller的LL層構造數據包(LLID=10b),通過PHY發出無線信號
c. Controller向Host發送“Number of Completed Packets”事件
d. 對端設備的LL層通過PHY返回數據(LLID=10b)
e. Controller向Host發送ACL數據:Read Response
問題:右邊抓取的空中數據包,在對端設備接收到讀請求后,過了一會才回復一個無線信號給本地設備,中間有很多空包,這些空包是誰發起的呢?
是由master發給slave的,
這些空包起什么作用呢?
兩個設備建立連接之后,本地設備要知道對端設備什么時候要斷開,它是怎么判斷對端設備有沒有斷開呢?
不斷的發送空包給對端設備,對端設備收到空包后,要回復一個空包,這樣本地設備才知道對端設備還沒有斷開。當然為了省電,對端設備沒有必要每次收到空包都要回復,可以在收到幾個空包后回復,但是一定要有回復。這些空包是是由controller自主發起的,與host層沒有什么關系。