Bluetooth LE(低功耗蓝牙) - 第五部分
回顧:
? ? ?在本系列前面的文章中我們完成了發現BLE傳感器并與之建立連接。現在只剩下從其中獲取數據了,但是這并沒有看起來那么簡單。在這篇文章中我們將討論GATT的特點以及如何促進主機與傳感器之間的數據交換。
GATT服務器的結構:
? ? ?在前面的文章看我們了解了傳感器包含GATT服務器,我們也已經與GATT建立連接。GATT服務器包含一個或多個GATT服務,不同的GATT服務代表了可以進行交換的不同類型的數據。例如,在SensorTag中有不同的GATT服務分別代表著SensorTag中不同的傳感器組件(濕度傳感器,氣壓傳感器,等)。
? ? ?每個GATT服務包含一個或多個GATT特性。一個GATT特性是一個可以通過BLE進行傳遞的原子數據。一個GATT特性可以包含任意的數據,用一個類型標識符表示任意數據的類型。它也可以包含零個或多個GATT描述符。
? ? ?GATT描述符包含了關于該GATT特性的原子數據,例如GATT特性值的單位,或者當GATT特征值變化時是否需要通知我們。
? ? ?總之,GATT服務器可以包含一個或多個GATT服務;每個GATT服務可以包含一個或多個GATT特性;每個GATT特性可包含零個或更多個GATT描述符。
? ? ?GATT服務、特征以及描述符的一個共同點是他們都是使用一個通用唯一標識符(UUID)標識。正如UUID名稱所表現的那樣,UUID是一個簡單且唯的標識符,用來找到GATT服務、特征以及描述符。
? ? ?SensorTag的UUIDs可在?GATT服務器參考文檔?中找到的。這可能有點令人困惑,但它其實是很簡單的。所有的SensorTag UUID 都是基于這種形式:F0000000-0451-4000-B000- 00000000。四個黑體字的數字是不同的GATT服務、特征、描述唯一不一樣的地方。如果我們看看下面的濕度傳感器,我們可以看到其UUID是為AA20(類型為GATT_PRIMARY_SERVICE_UUID)。此服務的完整的UUID是F000AA20-0451-4000-B000-00000000.
? ? ?服務有兩個特征:
? ? ?第一個代表著實際的傳感器數據,UUID為AA21,轉換后完整的UUID為 F000AA21-0451-4000-B000- 00000000。這些數據為4個字節,表示的溫度和濕度值:TempLSB:TempMSB:HumidityLSB:HumidityMSB? 之后我們將看看該如何解碼。該特征有一個描述符(GATT_CLIENT_CHAR_CFG_UUID?條目),在文檔中不會有該特征的UUID定義。這是因為這是一個標準的UUID,因為它提供一個公共的功能而被共同使用,就是當該值改變時我們需要被通知到。我們將在后面深入討論這一點。
? ? ?第二個特征是一個需要我們設置其為打開狀態的標志,UUID為AA22,完整的UUID為 F000AA22-0451-4000-B000- 00000000。還是那句話,我們將在適當的時候看到其使用方法。
? ? ?我們有必要去解釋一些關于UUID以及UUID怎么工作的事情,在某些情況下,他們可能不像在SensorTag上那樣作為設備的顯著的特征。在許多傳感器上可能很多服務都擁有一個共同的UUID和結構,不同的廠商都堅持將執行相同的功能的傳感器使用一個標準的GATT服務標準(例如有一個專門的心率儀GATT服務標準等)。Also, it is possible to include GATT service UUIDS in the device discovery phase to only match devices which offer specific services.?。不幸的是,SensorTag不支持這個,所以在這篇教程不涉及這一塊。如果你有興趣的話,可以通過調用?BluetoothAdapter#onStartLeScan()?方法的不同形式來實現。
? ? ?那么,現在我們知道了服務是如何組織的,我們可以開始讀取數據了,是嗎?不幸的是,它不是那么簡單的。記住,與GATT服務器的連接由兩部分組成:傳感器上的GATT服務器,和一個本地代理。雖然我們可能知道GATT服務,本地代理不知道,所以我們要讓本地代理從傳感器中獲取其服務列表。這個通過使用?discoverservices()?方法實現:
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {@Overridepublic void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {super.onConnectionStateChange(gatt, status, newState);Log.v(TAG, "Connection State Changed: " + (newState == BluetoothProfile.STATE_CONNECTED ? "Connected" : "Disconnected"));if (newState == BluetoothProfile.STATE_CONNECTED) {setState(State.CONNECTED);gatt.discoverServices();} else {setState(State.IDLE);}}@Overridepublic void onServicesDiscovered(BluetoothGatt gatt, int status) {if(status == BluetoothGatt.GATT_SUCCESS) {Log.v(TAG, "onServicesDiscovered: " + status);}} }? ? ?再次說明,這是一個異步方法,所以我們可以毫無顧慮地在UI線程調用,同時我們需要定義一個合適的回調方法,當服務列表被完整后被調用。比較重要的一點事是要在回調方法中檢查狀態值,因為有時在搜索服務的過程中會調用相應的回調,但事實上搜索服務已經完成了。所以檢查是否為GATT_SUCCESS?狀態將確保一旦服務發現完成我們的回調方法只執行一次。
下期預告:
? ? 一旦支持的服務被裝載到當地的代理,我們就可以訪問服務所包含的特征,我們將在本系列文章的總結中討論這一點。
?
? ? ?本文的源代碼在這里?可以找到。
轉載于:https://www.cnblogs.com/xiaorenwu702/p/4304395.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Bluetooth LE(低功耗蓝牙) - 第五部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 初创互联网公司简明创业指南 - YC新掌
- 下一篇: 处理器与内存和硬盘的交互