Bluetooth LE Exploer(微軟提供的)可以讀取BLE藍牙設備,可以讀寫它的值。本篇博客將使用BTStack寫出一個精簡版的Bluetooth LE Exploer。
涉及文件:
btstack-master\example\le_data_channel_client.c
btstack-master\example\Makefile.inc
注意:在PC上使用軟件Bluetooth LE Exploer來操作藍牙模塊時,使用系統自帶的驅動;
使用btstack來操作藍牙模塊時,使用winusb驅動(使用zadig-2.4.exe安裝此驅動)
在手機上使用藍牙時,過程如下:
1. 掃描周邊的藍牙設備
2. 選擇某個設備,連接它
3. 使用該設備
一、程序效果:
我們寫的藍牙程序也包含這3個過程,我設計出4個菜單:
1.主菜單:
********* Main Menu *********
[s] show scan menu
[c] show connect menu
[t] show test menu
可以在主菜單中:
輸入s進入“Scan Menu”,
輸入c進入“Connect Menu”,
輸入t進入“Test Menu”。
2. 掃描菜單:
********* Scan Menu *********
[s] scan ble devices
[t] stop scan ble devices
[l] list ble devices
[q] Back to main menu
可以在掃描菜單中:
輸入s開始掃描周邊設備,掃描結果會打印出來,並在程序中保存起來;
輸入t停止掃描;
輸入l列出掃描到的設備;
輸入q退回到主菜單。
3. 連接菜單:
********* Connect Menu *********
List devices have beenn scanned
[0] 100ASK
[1] Mi Band 2
[?] Enter the device's number to connect
[d] Disconnet
[q] Back to main menu
在連接菜單的前面,會首先列出之前掃描到的設備。
在連接菜單中,
輸入所列設備的序號,就會連接它;
輸入d則斷開連接;
輸入q退回到主菜單。
4. 測試菜單:
********* Test Menu *********
[r] read att handle 42
[w] write att handle 42
[q] back to main menu
在測試菜單中,
輸入r則會讀取handle等於42的屬性的值;
輸入w則寫handle等於42的屬性的值;
輸入q退回到主菜單。
注意:
之所以固定讀寫handle 42是為了簡化程序,
42這個值是事先使用軟件Bluetooth LE Explorer連接設備后確定的,你的設備可能有所不同。
二、程序演示:
啟動MSYS2 MinGW 64-bit,進入btstack-master/port/windows-winusb目錄:
1. 執行 make 命令編譯程序
2. 執行以下命令啟動程序:
winpty ./le_data_channel_client.exe
注意:在MSYS2下Windows的stdin無法使用,必須通過winpty來啟動程序。
3. 在主菜單中:輸入s進入掃描菜單
4. 在掃描菜單中:輸入s開始掃描設備
在手機上,啟動“Bluetooth LE Peripheral”,選擇“100ASK”,點擊“START”按鈕。
這時在MSYS2中可以看到不斷打印如下信息(這表示不斷收到手機發來的廣播信號):
advertisement_report_gets_name get 100ASK
5. 在掃描菜單中:輸入t停止掃描設備
6. 在掃描菜單中:輸入q退回到主菜單
7. 在主菜單中:輸入c進入連接菜單
8. 在連接菜單中:輸入0表示連接第掃描到的第0個設備
9. 在連接菜單中:輸入q退回到主菜單
10. 在主菜單中:輸入t進入測試菜單
11. 在測試菜單中:輸入w寫數值
觀察手機上“Bluetooth LE Peripheral”的Service-1中收到的值。
不斷輸入w,可以觀察到手機上收到的值不斷加1。
12. 在測試菜單中:輸入r讀取數值
13. 在測試菜單中:輸入q退回到主菜單
14. 在主菜單中:輸入c進入連接菜單
15. 在連接菜單中:輸入d斷開連接
三、主要函數:
本程序主要源文件是btstack-master\example\le_data_channel_client.c,我在上面做了大量的修改。
1.要用鍵盤來控制程序,需要給程序增加一個“數據源”,即btstack_data_source_t結構體。
這個數據源從stdin獲得數據,根據這些數據進行菜單操作。
使用如下代碼增加數據源:
btstack_stdin_setup(stdin_process);
stdin_process是我們編寫的處理函數。
2. 啟動掃描:
printf("Start scanning!\n");
state = TC_W4_SCAN_RESULT;
gap_set_scan_parameters(0,0x0030, 0x0030);
gap_start_scan();
3. 記錄打描結果:
掃描到的設備會上報3種信息:MAC地址、地址類型、名。我們要從上報的信息中取出這些信息,記錄起來。
使用函數gap_event_advertising_report_get_address獲得地址;
使用函數gap_event_advertising_report_get_address_type獲得地址類型;
使用函數advertisement_report_gets_name獲得名字(這函數是我從advertisement_report_contains_name改出來的)。
這3個信息會保存在ble_devs結構體數組中。
4. 連接設備:
gap_connect(ble_devs[i].le_data_channel_addr, ble_devs[i].le_data_channel_addr_type);
gap_connect函數只需要2個參數:MAC地址、地址類型。
連接成功后會返回一個hci_con_handle_t,也就是一個16位的整數。
一個中央設備可以連接多個外設,每一個連接都用一個hci_con_handle_t來分辨。
5. 斷開連接:
gap_disconnect(connection_handle);
6. 寫數據:
gatt_client_write_value_of_characteristic_without_response(connection_handle, 42, 1, &g_value);
第1個參數表示要寫哪一個設備,用connection_handle 來表示(哪一個連接對應的設備);
第2個參數表示要寫哪一個屬性,每一個屬性也都有一個標號即handle;
第3個參數表示要寫多少字節的數據;
第4個參數表示數據的buffer。
7. 讀數據:
gatt_client_read_value_of_characteristic_using_value_handle(handle_gatt_client_event,connection_handle, 42);
第2個參數表示要寫哪一個設備,用connection_handle 來表示(哪一個連接對應的設備);
第3個參數表示要寫哪一個屬性,每一個屬性也都有一個標號即handle;
第1個參數比較特殊:讀數據時,要先向外設備發出無線信號,過一會收到對方發回到信號后,才可以解析出數據。所以讀函數不可能立刻返回結果,我們需要提供一個回調函數。第1個參數就是一個回調函數。
在回調函數中,我們去解析數據,從中取出我們關注的數值。
回調函數handle_gatt_client_event源自btstack-master\test\pts\Ble_central_test.c,我做了一些精簡。