BLE-HCI淺學
低功耗藍牙協議棧學習之HCI
自我闡述
這幾天的學習來看,藍牙協議棧核心在于“協議棧”,就是很多協議像棧一樣層層遞進。而本文主要闡述HCI層。
本文主要簡單的總結,什么是HCI、HCI流控、HCI的協議格式。
最后舉一個BLE 廣播的例子來闡述一下HCI的自己封裝
什么是HCI?
首先來看看藍牙5.0核心手冊是怎么說的
The HCI provides a uniform command method of accessing Controller
capabilities. The HCI Link commands provide the Host with the ability to control
connections to other BR/EDR Controllers. For the BR/EDR Controller, these
commands typically involve the Link Manager (LM) to exchange LMP
commands or the Link Layer (LL) to exchange LL Control packets with remote
Bluetooth devices. For details see [Vol 2] Part C, Link Manager Protocol
Specification and [Vol 6] Part B, Link Layer Specification. For AMP Controllers,
these commands typically involve the AMP PAL. For details see the
appropriate PAL specification (see [Vol 5] Part A, 802.11 Protocol Adaptation
Layer Functional Specification).
The HCI Policy commands are used to affect the behavior of the local and
remote LM or LL. These Policy commands provide the Host with methods of
influencing how the LM or LL manages the piconet. The Controller &
Baseband, Informational, and Status commands provide the Host access to
various registers in the Controller.
HCI commands may take different amounts of time to be completed. Therefore,
the results of commands will be reported back to the Host in the form of an
event. For example, for most HCI commands the Controller will generate the
Command Complete event when a command is completed. This event
contains the return parameters for the completed HCI command. For enabling
the Host to detect errors on the HCI-Transport Layer, there needs to be a
timeout between the transmission of the Host’s command and the reception of
the Controller’s response (e.g. a Command Complete or Command Status
event). Since the maximum response timeout is strongly dependent on the
HCI-Transport Layer used, it is recommended to use a default value of one
second for this timer. This amount of time is also dependent on the number of
commands unprocessed in the command queue.
簡而言之就是Host層與Controller層之間的接口,兩個層級之間通過HCI進行交互。而藍牙組織就規定了數據的格式和內容
HCI流控?
1. HOST TO CONTROLLER DATA FLOW CONTROL
Host to Controller Data Flow Control 是指在藍牙通信中,主機(Host) 和 控制器(Controller) 之間的數據流量管理機制。它的目的是確保主機和控制器之間的數據傳輸順暢,避免數據丟失、過載或者沖突。通過這種機制,主機和控制器可以協調彼此的發送和接收速率,確保通信鏈路的穩定性。
在藍牙通信中,尤其是 HCI(Host Controller Interface) 層,主機和控制器之間的通信通常是基于命令和事件的交互,并且涉及數據包的傳輸。數據流控制(Flow Control)是管理這些數據包傳輸的機制,它保證了兩者之間的數據傳輸能夠有效且不丟失。
在 HCI 協議中,數據流控制主要體現在以下幾個方面:
- HCI Command Complete Event:
- 當控制器完成命令的處理時,它會通過事件包通知主機。如果控制器有更多的任務需要處理,流控機制確保它能夠以合適的速率響應。
- HCI Data Packets:
- 這些是用于傳輸數據的包。通過流控機制,主機和控制器能夠協商何時開始或暫停數據包的傳輸。
- Queue Management:
- 主機和控制器可能有各自的隊列,用來存儲待處理的命令或數據。數據流控制確保隊列不會溢出,并根據緩沖區的容量調整發送速率。
2. CONTROLLER TO HOST DATA FLOW CONTROL
Controller to Host Data Flow Control(控制器到主機的數據流控制)是藍牙通信中,控制器(Controller) 向 主機(Host) 提供的流量管理機制。它用于確保主機能夠按合理的速率接收從控制器發送的數據,防止主機的緩沖區溢出,確保數據傳輸的高效和可靠。
在藍牙通信中,尤其是基于 HCI(Host Controller Interface) 的通信中,控制器和主機之間的交互非常關鍵。控制器需要將其處理的事件、數據或者命令的結果(例如,連接狀態、數據包等)發送給主機,而 Controller to Host Data Flow Control 就是在此過程中確保數據流不超出主機的接收能力。
在藍牙 HCI 協議中,數據流控制主要通過以下幾種方式來實現:
- 控制器通過事件通知主機緩沖區狀態:
- 控制器可以通過發送 HCI Event,例如
HCI_FLOW_CONTROL_EVENT,通知主機當前的接收狀態。如果控制器的緩沖區已滿,它可以指示主機暫停或減緩發送數據。
- 控制器可以通過發送 HCI Event,例如
- 數據包發送和接收的調節:
- 控制器發送的數據包(例如 HCI 數據包)需要依據主機的接收能力進行調節。如果主機的接收隊列已滿,控制器就需要暫停發送,等待主機的緩沖區騰出空間。
- 隊列管理:
- 控制器和主機之間通過隊列進行數據傳輸。控制器需要根據隊列的可用空間來決定是否繼續發送數據。
- 優先級調度:
- 控制器還可以根據數據的優先級來控制數據的發送順序。例如,優先發送高優先級的命令或事件,而低優先級的數據可能會等待更長時間。
3. Host to Controller
Host to COntroller有兩種流控,分別為Packet-based Data Flow Control 和 Data-Block-Based Data Flow Control。他們之間通過HCI_Write_Flow_Control_Mode進行切換。(Packet-based data flow control 是芯片默認的)。
4. Controller to Host
通俗易懂的說,就是host和controller之間通過“硬件”、“軟件”,流控對數據進行控制。
下面是一個命令的流程:
1. Read_Buffer_Size 命令:
在初始化階段,主機 會向 主機控制器 發送一個 Read_Buffer_Size 命令,這個命令的作用是請求主機控制器返回兩個關鍵參數:
- 最大數據包大小:確定從主機到控制器的 HCI ACL 和 SCO 數據包(數據部分,不包括報頭)的最大長度。
- 緩存數量:表示主機控制器可以緩存的、等待傳輸的 HCI ACL 和 SCO 數據包的數量。
這些參數幫助主機了解控制器的緩存能力,從而可以決定如何合理地發送數據,避免過多數據導致溢出或阻塞。
2. Number Of Completed Packets 事件:
主機控制器通過發送 Number Of Completed Packets 事件來告知主機,已成功發送的 HCI 數據包數量。事件中會返回以下信息:
- 連接句柄列表:哪些連接的 HCI 數據包已經被發送完成。
- 每個連接的已完成數據包數:對于每個連接句柄,已經完成的數據包數量。
在沒有新的事件發生時,這個信息會從連接建立時開始計算。事件會定期發送,幫助主機實時了解已完成的數據包數量。
3. 數據流控制:
- 每當 主機 發送一個數據包,控制器的緩存空間會減少一個數據包的容量。控制器通過 Number Of Completed Packets 事件來告訴主機,這些數據包已經完成(包括傳輸、清除和回送至主機)。
- 主機根據 Read_Buffer_Size 返回的參數(控制器可以緩存的總數據包數量)和 Number Of Completed Packets 事件的反饋來判斷當前緩存的使用情況。
主機通過這些信息來決定是否繼續發送數據包。主機會根據 控制器緩存剩余空間 和 完成的數據包數量 來動態調整發送數據的頻率。
4. SCO 流控制失效的情況:
如果 SCO(Synchronous Connection-Oriented) 數據流控制失效,那么 Number Of Completed Packets 事件 就無法在 SCO 連接句柄中報告。這意味著,對于 SCO 連接,主機無法通過這個事件來獲得關于 SCO 數據包是否已發送完成的信息。
5. 事件發送頻率:
Number Of Completed Packets 事件的發送頻率由 藍牙控制器廠商來決定。它通常是根據控制器的緩存和處理能力來調整的,以確保主機可以及時獲得關于數據包狀態的反饋。
比如說一開始的時候會發送readbuffer的命令,controller會返回SCO和ACL的大小,比如說我總共只能發送16個event,我已經發送了16個,這個時候需要controller返回16個,我才能發送。意思就是說,兩者之間進行一個競爭資源。達到限制的數目了的時候,只有controller釋放了,host才能發送。
HCI格式
這里就說一下HCI Command packet的分析,主要講述一下OpCode這個如何進行封裝,這個數據是小端存儲。OCF占去10bit OGF占區6bit,舉一個例子。
OGF的值為3 OCF的值為8
0011 1000,如果按照正常來說,是不是OCF<< 10 | OGF?但是這個是小端存儲的方式,那么就相當于 OCF >> 8 | OGF << 2
p_data[0] = ocf && 0xff
p_data[1] = (ocf >> 8) | (ogf << 2)
Ble Adv example
-
首先低功耗藍牙需要發送
set event mask這個的作用可以參考藍牙核心手冊。這個是用來告訴controller需要上報那些事件的。 -
發送支持ble的command
write le host support -
發送Ble的廣播設計
LE Set Adverting Parameters -
發送Ble的廣播設計數據
LE Set Adverting Data -
開啟Ble的廣播
LE Set Adverting Enable -
收到Controller的回應數據
-
關閉Ble的廣播
LE Set Adverting Enable
藍牙5.0手冊,page 1245
HCI_LE_Set_Event_Mask和HCI_LE_Read_Buffer_Size就不過多介紹了,就是上述解釋的Read_Buffer_Size的命令。
HCI_LE_Read_Local_Supported_Features就是發送支持Ble的command
HCI_LE_Set_Advertising_Parameters設置廣播的參數
HCI_LE_Set_Advertising_Data 設置廣播包的內容
HCI_LE_Set_Advertising_Enable 開啟或關閉廣播數據包
Code:下面是一個如何封裝設置廣播數據的函數,源自https://github.com/sj15712795029/bluetooth_stack.git
//這個函數是一個封裝Commad的函數,可以看到HCI格式這一目錄我有解釋
struct bt_pbuf_t *hci_cmd_ass(struct bt_pbuf_t *p, uint8_t ocf, uint8_t ogf, uint8_t len)
{
((uint8_t *)p->payload)[0] = (ocf & 0xff); /* OCF & OGF */
((uint8_t *)p->payload)[1] = (ocf >> 8)|(ogf << 2);
((uint8_t *)p->payload)[2] = len-HCI_CMD_HDR_LEN; /* Param len = plen - cmd hdr */
if(hci_pcb->numcmd != 0)
{
--hci_pcb->numcmd; /* Reduce number of cmd packets that the host controller can buffer */
}
return p;
}
// 這是封裝設置廣播包的命令,可以查看藍牙5.0核心手冊1251頁,其中有8個參數
// adv_int_min 這表示最小藍牙廣播間隔,N * 625us 區間為20ms到10.24s
// adv_int_max 這表示最大藍牙廣播間隔。N * 625us 區間為20ms到10.24s
// adv_type 廣播類型,具體查看手冊
// own_address_typ 地址類型,具體查看手冊
// peer_address_type 對方地址類型,具體查看手冊
// peer_address 對方的地址
// channel_map 廣播的信道
// filter_policy 廣播過濾策略
err_t hci_le_set_adv_param(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
uint8_t own_address_typ, uint8_t peer_address_type,struct bd_addr_t *peer_address, uint8_t channel_map, uint8_t filter_policy)
{
struct bt_pbuf_t *p;
uint8_t offset = 0;
if((p = bt_pbuf_alloc(BT_TRANSPORT_TYPE, HCI_SET_LE_ADV_PARAM_PLEN, BT_PBUF_RAM)) == NULL)
{
BT_HCI_TRACE_ERROR("ERROR:file[%s],function[%s],line[%d] bt_pbuf_alloc fail\n",__FILE__,__FUNCTION__,__LINE__);
return BT_ERR_MEM;
}
/* Assembling command packet */
p = hci_cmd_ass(p, HCI_LE_SET_ADV_PARAM, HCI_LE, HCI_SET_LE_ADV_PARAM_PLEN);
offset += 3;
bt_le_store_16((uint8_t *)p->payload,offset,adv_int_min);
offset += 2;
bt_le_store_16((uint8_t *)p->payload,offset,adv_int_max);
offset += 2;
((uint8_t *)p->payload)[offset] = adv_type;
offset += 1;
((uint8_t *)p->payload)[offset] = own_address_typ;
offset += 1;
((uint8_t *)p->payload)[offset] = peer_address_type;
offset += 1;
memcpy(((uint8_t *)p->payload)+offset, peer_address->addr, BD_ADDR_LEN);
offset += BD_ADDR_LEN;
((uint8_t *)p->payload)[offset] = channel_map;
offset += 1;
((uint8_t *)p->payload)[offset] = filter_policy;
phybusif_output(p, p->tot_len,PHYBUSIF_PACKET_TYPE_CMD);
bt_pbuf_free(p);
return BT_ERR_OK;
}

浙公網安備 33010602011771號