1. 程式人生 > >低功耗藍芽(5)

低功耗藍芽(5)

在這系列中的前幾篇文章裡,我們探索了低耗藍芽感測器並學習瞭如何建立連線。剩下的問題就是如何從感測器中獲得一些確切的資料,但這並不是像看起來那樣直接。在這篇文章裡,我們繼續探討GATT特徵並學習它是如何在主機和感測器之間進行資料交換的。

在前一篇文章裡,我們瞭解了感測器裝置是如何包含了一個GATT伺服器的,並且我們還發布了一個連線的方法。GATT伺服器包含了一個或多個GATT服務,這些GATT服務代表了不同型別的可被交換的資料。例如,在SensorTag中包含了不同的GATT服務代表著在SensorTag中的每一個不同的感測器元件(溼度感測器、氣壓感測器等)。

每個GATT服務包含著一個或更多GATT特徵。一個GATT特徵是一個能夠通過BLE傳輸的資料的原子塊。一個GATT特徵包含了任意資料和能夠表明該資料型別的標識。它還能不包含或者包含更多的GATT描述。

一個GATT描述包含著關於特徵的元資料,例如特徵值的單位,或者當特徵值改變時是否需要通知。

簡而言之,一個GATT伺服器可以包含一個或者更多GATT服務;每一個GATT服務可以包含一個或者更多的GATT特徵;一個GATT特徵可以不包含或者包含更多的GATT描述。

在GATT服務,特徵和描述中一個共同點是他們都用一個通用唯一識別符號(UUID)來辨認。正如UUID的名字所示,一個UUID是一個簡單唯一的標識,它被用來檢索GATT服務,特徵或描述。

對於SensorTag來說這寫UUID可以在GATT伺服器參考文件中找到。當第一次看的時候可能會有一點困惑,但它確實非常直接。所有的SensorTag UUID都有基本值: F0000000-__0451__-4000-B000-00000000

其中四位加粗的數字是唯一會變的部分來區分不同的GATT服務,特徵或者描述。如果我們看溼度感測器,我們能看到它的UUID是AA20(在黃色的行處標記著GATT_PRIMARY_SERVICE_UUID)。這個服務的UUID的全寫為F000AA20-0451-4000-B000-00000000

這個服務有兩個特徵:

第一個特徵代表著確切的感測器資料,UUID為AA21,全寫為 F000AA21-0451-4000-B000-00000000 。資料為4bytes代表著溫度值和溼度值:溫度最低有效位:溫度最低有效位:溼度最低有效位:溼度最高有效位——我們會稍後研究如何解碼這些資料。這些特徵同樣也有一個描述(GATT_CLIENT_CHAR_CFG_UUID 條目),它在文件裡沒有定義明確的UUID。這是因為這是一個標準的UUID,它為一個公共功能服務,所以它很常用,這是為了註冊當這個值變化時我們需要一個通知。同樣,我們會在後面更加深入的探討。

第二個特徵是一個標記,我們需要設定這個標記來將特定的感測器開啟。它的UUID為AA22,全寫為F000AA22-0451-4000-B000-00000000 。同樣,我們會在適當的時候介紹該如何實際使用這個標記。

為了進一步解釋UUID這裡很有必要多說一句,在某些情況下,特別是它們在SensorTag上時,它們不是裝置。在許多感測器中可能有帶有共同UUID的服務,和被不同製造商支援的結構,這些製造商都為執行相同功能的感測器堅持一個標準的服務標準(例如心率檢測儀有標準的GATT服務定義)。同樣,在裝置發現階段加入GATT服務UUID也是可能的,這樣能夠匹配提供特定服務的裝置。不幸的是SensorTag並不支援這個功能,所以我在這裡不能討論更多內容。對於那些對此感興趣的人,可以通過呼叫不同形式的BluetoothAdapter#onStartLeScan()來完成。

現在我們瞭解了服務是如何被組織的,我們可就以直接開始讀取資料了嗎?不幸的是這並不是那樣簡單。還記得GATT伺服器連線由兩部分組成:在感測器上的GATT伺服器,和一個本地代理嗎?我們或許知道服務而不知道本地代理,所以我們需要引導它來檢索感測器上的服務的列表。這可以用discoverServices()方法完成:

BleService.java

Java
12345678910111213141516171819202122232425 ;html-script:false]privateBluetoothGattCallback mGattCallback=newBluetoothGattCallback(){@OverridepublicvoidonConnectionStateChange(BluetoothGatt gatt,intstatus,intnewState){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);}}@OverridepublicvoidonServicesDiscovered(BluetoothGatt gatt,intstatus){if(status==BluetoothGatt.GATT_SUCCESS){Log.v(TAG,"onServicesDiscovered: "+status);}}}

這又是一個非同步方法,所以我們可以大膽的在UI執行緒中呼叫它。我們需要定義一個確切的回撥方法,以便在當發現服務完成時呼叫。在回撥方法中檢查狀態值是非常重要的,因為有時它會在服務檢測完成之前被呼叫。檢查GATT_SUCCESS值會確保我們只執行了一遍在服務檢測實際完成時。

支援的服務一旦被載入到本地代理中,我們可以實際訪問到它所包含的特徵,我們會在這一系列的文章中繼續討論。

這篇文章中的原始碼