第08節-開源藍牙協議棧BTStack數據處理


本篇博客根據韋東山的視頻整理所得。

在上篇博客,通過閱讀BTStack的源碼,大體了解了其框架,對於任何一個BTStack的應用程序都有一個main函數,這個main函數是統一的。這個main函數做了某些初始化之后,最終會調用到應用程序提供的btstack_main,在btstack_main里面首先做一些初始化,然后調用hci_power_on函數去打開藍牙模塊。

一. 數據類型

運行BTStack程序時,會生成hci_dump.pklg文件,可以使用WireShark打開此文件,截圖如下:

怎么理解上圖中的數據呢?

BTStack中涉及的數據有2類:

1.從硬件上獲得的數據、發給硬件的數據

2.為更新系統狀態而虛構的數據

 

 

 

1. 跟硬件相關的數據有4類:

① 發送給藍牙控制器的Command

② 從藍牙控制器獲得的Event,藍牙控制器收到Command后會回復Event

③ ACL數據,這涉及收、發兩個方向

④ SCO數據,這涉及收、發兩個方向

注意:ACL、SCO數據的含義以后再講。

這4種數據類型,用一個頭部信息來表示,參考bluetooth.h:

#define HCI_COMMAND_DATA_PACKET 0x01

#define HCI_ACL_DATA_PACKET       0x02

#define HCI_SCO_DATA_PACKET       0x03

#define HCI_EVENT_PACKET           0x04

但是在程序中,單憑這4個數值無法分辨數據的流向,比如ACL數據的類型是0x03,我們單憑0x03無法知道這數據是發給硬件、還是從硬件讀到。

為了便於調試,BTStack在打印Log信息時,把這些硬件數據類型轉換為新數值:

參考函數: hci_dump_packetlogger_setup_header

1. Command :  0x00

2. Event:       0x01

3. ACL out     0x02

4. ACL in      0x03

5. SCO out    0x08

6. SCO in     0x09

7. Log Message 0xfc

我們可以使用WireShark打開Log文件hci_dump.pklg時,觀察里面原始數據。

2. 為更新系統狀態而虛構的數據:

有很多種虛構的數據,下面舉幾個例子:

① 提示狀態發生了變化:

在BTStack中,可能有很多層對hci_stack->state感興趣,所以當hci_stack->state發生變化時,可以使用hci_emit_state發送一個虛擬的Event數據包,這會導致這些層的處理函數被調用。

BTStack中使用下面函數發送state信息:

在WireShark中看到的原始數據為:01 60 01 xx,

第1個01表示Event,60表示BTSTACK_EVENT_STATE,第2個01表示數據長度為1, xx表示數據即state值。

② 當一個數據包已經成功發給硬件之后,我們要通知上層:你可以繼續發送數據給硬件了。這通過hci_emit_transport_packet_sent函數來實現:

在WireShark中看到的原始數據為:01 6e 00,

第1個01表示Event,6e表示HCI_EVENT_TRANSPORT_PACKET_SENT,00表示后續數據長度為0。

二、狀態機:

我們常說:初始化好藍牙模塊后,就可以使用它了。

仔細琢磨這句話,藍牙模塊至少有這2個狀態:

1. 初始化狀態:HCI_STATE_INITIALIZING

2. 工作狀態:HCI_STATE_WORKING

當然,還有其他狀態,在代碼中如下表示(hci_cmd.h):

在HCI_STATE_INITIALIZING狀態下,需要跟藍牙模塊多次交互,才可以完成藍牙模塊的初始化。使用“子狀態”來表示這些多次交互,在代碼中如下表示(hci.h):

 

 

 舉個例子,子狀態中有“HCI_INIT_SEND_RESET”和“HCI_INIT_W4_SEND_RESET”:

1.當子狀態為HCI_INIT_SEND_RESET時:

我們發送復位命令給藍牙模塊,然后子狀態變為HCI_INIT_W4_SEND_RESET,它的意思是“wait for”,等待收到復位命令的回復信息。

2.收到該回復信息后,子狀態變為HCI_INIT_SEND_READ_LOCAL_VERSION_INFORMATION:

於是繼續給藍牙模塊發送“read loacal version”命令,然后子狀態變為HCI_INIT_W4_SEND_READ_LOCAL_VERSION_INFORMATION,表示等待回復信息

如此繼續,直到子狀態變為“HCI_INIT_DONE”,初始化才結束,藍牙模塊的“狀態”才放為HCI_STATE_WORKING。

代碼中有一個結構體:

static hci_stack_t * hci_stack

hci_stack->state表示“狀態”,hci_stack->substate表示“子狀態”。

BTStack的代碼有函數hci_run,它就是根據hci_stack結構體中的這些狀態、其他值來收發數據的。

注意:hci.c中的hci_run是核心函數,它根據hci_stack的狀態進行不同的處理。

舉例說明:

1.例子1:hci_power_control(HCI_POWER_ON);

 

 

 

hci_stack->state初始值為0,即HCI_STATE_OFF;

調用hci_power_transition_to_initializing后,各狀態值如下:

// set up state machine

hci_stack->num_cmd_packets = 1; // assume that one cmd can be sent

hci_stack->hci_packet_buffer_reserved = 0;

hci_stack->state = HCI_STATE_INITIALIZING;

hci_stack->substate = HCI_INIT_SEND_RESET;

接着調用如下代碼:

// trigger next/first action

hci_run();

hci_run函數中,在hci_stack->state等於HCI_STATE_INITIALIZING時,調用:hci_initializing_run();

hci_initializing_run()函數內部,會根據hci_stack->substate等於HCI_INIT_SEND_RESET而發出復位命令,並令substate等於HCI_INIT_W4_SEND_RESET,這表示等待收到該命令的回復信息。

在等待過程中,程序休眠。

當收到數據時,程序的主循環繼續執行,根據上節內容,將會調用hci.c中的event_handler函數來處理

該函數有如下代碼:

    // handle BT initialization

    if (hci_stack->state == HCI_STATE_INITIALIZING){

        hci_initializing_event_handler(packet, size);

}

……

hci_run( );

模塊的當前狀態仍為HCI_STATE_INITIALIZING,進而調用hci_initializing_event_handler(packet, size)。

hci_initializing_event_handler將調用hci_initializing_next_state(),把subsate設置為HCI_INIT_SEND_READ_LOCAL_VERSION_INFORMATION。

后續的hci_run會根據這個substate發出READ_LOCAL_VERSION_INFORMATION的命令。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM