第07節-開源藍牙協議BTStack框架代碼閱讀(下)


上篇博客中已經對BTStack框架進行了較為詳細的說明,本篇博客將進一步總結一下(由韋大仙筆記所得)。

 

 

可以從5個方面來理解BTStack的框架:

1.硬件操作:hci_transport_t

BTStack支持多種接口的藍牙模塊,比如USB口、3線串口、5線串口。

對於這些接口,會抽象出對應的hci_transport_t結構體。

該結構體成員如下:

 

 里面有init、open、send_packet等重要成員。

對於3線串口、5線串口,它們在init、open設備時,不需要寫兩套代碼。因為它們都是串口設備,只不過前者不使用硬件流控、后者使用硬件流控。

對串口硬件的操作,再抽象出一個btstack_uart_block_t結構體:

 

 

2. 操作系統相關代碼:btstack_run_loop

BTStack支持多種操作系統,比如Windows、Linux、IOS。

不同的操作系統,操作設備的函數不一樣,比如:

① Windows使用WaitForMultipleObjects函數來等待數據

② Linux使用select函數來等待數據

BTStack針對不同的運行環境,抽象出了對應的btstack_run_loop結構體,共同成員為:

比如其中的execute成員很重要,它是一個循環,在循環中等待、讀取、處理函數。

3. 循環體中,怎么讀取、處理數據

BTStack可以同時支持多個藍牙設備,每一個藍牙設備被open時都會返回一個文件句柄,Windows/Linux就是通過監視這些文件句柄來等待數據的。

顯然,循環體從句柄A得到了數據,應該調用句標A對應的處理函數:句柄和處理函數是綁定的。

所以,BTStack里抽象出了btstack_data_source_t結構體,里面含有句柄、處理函數:

打開硬件設備時,

1)要設置對應的btstack_data_source_t結構體:句柄、處理函數

2)  並調用btstack_run_loop_add_data_source把這個結構體告訴btstack_run_loop,

3)  btstack_run_loop的execute循環中,就監視該句標,獲得數據后調用對應的處理函數

對於各種btstack_data_source_t結構體,都有自己的處理函數:

1)對於UART

UART有兩種:

  3線串口(其數據傳輸協議被稱為H5),

  5線串口(其數據傳輸協議被稱為H4)。

使用H4、H5協議時它的處理函數都是btstack_uart_windows_process_read:

這個函數會調用block_received()來處理,block_received是函數指針。

對於H4協議,它指向:hci_transport_h4_block_read;

對於H5協議,它指向:hci_transport_h5_block_received:

所以:

對於H4協議,uart data source的process函數最終是hci_transport_h4_block_read;

對於H5協議,uart data source的process函數最終是hci_transport_h5_block_read。

2)對於USB

每一個endpoint都有對應的btstack_data_source_t結構體,也都有對應的process函數,比如:

 

 可以看到,對於不同的接口,即對於H2、H4、H5,都分別有自己的處理函數。

各個句柄對應的處理函數,是該句柄數據的處理起點,它將會調用上面各層提供的處理函數。這些處理函數,最終都會通過以下調用,把數據上報給各層:

packet_handler(packet_type, packet, size);   // h2,h4,h5中的packet_handler指針

這個packet_handler是hci.c提供的。hci.c文件中hci_init函數它通過以下調用,把hci.c的packet_handler函數傳給hci_transport_t結構體,用來設置H2、H4或H5文件中的packet_handler指針:

 

 4. 上面各層如何處理數據

hci.c提供的packet_handler函數,根據packet_type的不同,分別處理。

有3類packet_type:event、acl data、soc data。

btstack_data_source_t結構體中的process函數是數據處理的起點,該“起點”會調用hci.c中的packet_handler函數。

那么hci.c中的packet_handler可以認為是數據處理的分發站。

HCI層可以處理這些數據時,就由HCI層來處理,處理不了就上報。

L2CAP、SM、GATT、GAP、APP等等,都可以提供處理函數。

1)對於EVENT數據:

hci.c中的event_handler函數用來處理這些數據,

在HCI層能處理的數據將被用來設置hci_stack結構體;

有必要上報的數據,通過hci_emit_event函數上報。

hci_emit_event函數會調用hci_stack->event_handlers鏈表中的各個callback函數。該鏈表中的函數,來自上面各層,它們通過hci_add_event_handler注冊這些callback函數。

調用hci_add_event_handler的文件有:

le_data_channel_client.c屬於APP,即APP可以處理感興趣的數據;

main.c中注冊的函數沒什么用處,就是在藍牙模塊初始化完畢后,打印一個提示信息:“BTstack up and running at …”;

gatt_client.c這個文件,在le_data_channel_client.c這個APP中沒被使用;

att_Server.c這個文件是用於ATT Server的,在le_data_channel_client.c這個APP中沒被使用;

btstack_crypto.c、sm.c都是用於安全管理;

l2cap.c,這很重要,ATT、GATT、GAP、SM各層都要使用L2CAP來收、發數據。

2)對於ACL數據:

hci.c中的acl_handler函數用來處理這些數據,

在HCI能處理的數據將被用來設置對應的hci_connection_t結構體,

有必要上報的數據,通過hci_emit_acl_packet函數上報。

hci_emit_acl_packet函數會調用hci_stack->acl_packet_handler來處理。

在l2cap.c中,通過如下調用設置hci_stack->acl_packet_handler:

hci_register_acl_packet_handler(&l2cap_acl_handler);

即:上報的ACL數據,將由L2CAP的l2cap_acl_handler函數來處理。

3)對於SCO數據:

hci.c中的sco_handler函數用來處理這些數據,

在HCI能處理的數據將被用來設置對應的hci_connection_t結構體,

有必要上報的數據,通過hci_stack->sco_packet_handler函數上報。

APP如果要處理SCO數據,可以通過hci_register_sco_packet_handler提供自己的處理函數。hci_register_sco_packet_handler就是真接設置hci_stack->sco_packet_handler。

5. 誰觸發了數據的傳輸?

之前我們說過主循環里在等待數據,只有我們給藍牙模塊發送命令之后,它才會回送數據。

那么,在哪里給藍牙模塊發送了第1個命令?在APP代碼中,必有如下語句:

// turn on!

hci_power_control(HCI_POWER_ON);

這會導致給藍牙模塊發送一系列的初始化命令,

初始化成功后,APP通過hci_add_event_handler注冊的函數就會被調用,在這個函數里就可以執行我們自己的代碼,比如發起scan、發起connection等等。

附:3線串口上H5協議

SLIP協議最好文章:

SLIP—串行線路上傳輸數據報的非標准協議

https://blog.csdn.net/pushilong/article/details/80358485

https://wenku.baidu.com/view/809a8a8e8bd63186bcebbcae.html


免責聲明!

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



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