![]() | | |
通用屬性配置檔案(GATT)
正如GAP層負責連接配接相關的功能,GATT主要是負責在兩個已經連接配接的裝置互動資料,GAP層把BLE裝置區分為主機Master(Central)和從機Slave(Perpherial),在GATT層則區分為Server和Client。用戶端讀取和寫入存儲在服務端的特征值(Characteristics )。
Server
該裝置包含由GATT用戶端讀取或寫入的characteristic。
Client
從GATT伺服器讀取或寫入資料的藍牙裝置。
注意:對于GATT分層的Server/Client角色和GAP分層的Master(Central)/Slave(Perpherial)并沒有直接關系。如上圖,手機作為Central/Client,CC2640R2開發闆作為 Peripheral/Server。
GATT的Profile、Service、Characteristics、Attributes
對于GATT層的Profile、Service、Characteristics、Attributes概念,我們一定要深入了解,因為一旦建立連接配接後,不管是嵌入式端還是應用端進行資料互動的都是這些概念。為了幫助了解,我們抽象以下包含關系:
一個或者多個Characteristic組成一個Service,一個多個Service組成Profile,Characteristic又由多個Attributes組成,每個Attribute由包含 Handle、Type、Permissions三個屬性。
以下我們着重了解Characteristic,也是我們資料互動的最終實體,每個特征包含以下4個Attributes。
-
Characteristic Value(特征值)
用于characteristic的值
-
Characteristic Declaration(特征聲明)
存儲特征值的屬性,位置和類型的描述符
-
Client Characteristic Configuration(用戶端特征配置)
允許GATT伺服器配置要通知的特性(異步發送消息)或訓示的配置(與确認異步發送消息)
-
Characteristic User Description(特征使用者描述)
描述特征的ASCII字元串
這些屬性存儲在屬性表中的GATT伺服器中。除了該值之外,以下屬性與每個屬性相關聯。
以上的每個Attributes 又由以下元素組成。
-
Handle(句柄)
表中屬性的索引(每個屬性都有一個唯一的句柄)
-
Type(類型)
訓示屬性資料表示什麼(稱為UUID [通用唯一辨別符],其中一些是藍牙SIG定義的,一些是自定義的)
-
Permissions(權限)
強制GATT用戶端裝置如何以及如何通路屬性的值
GATT用戶端抽象層
下圖所示,在GATT用戶端應用程式大部分是直接使用GATT的API(少部分直接使用ATT層API),沒有profile檔案,因為GATT客戶是得到資料,不需要建立屬性表和配置檔案。
GATT服務端抽象層
如圖所示,在GATT服務端,GATT層的大部分功能由獨立的profiles處理,然後可以看見perfiles又使用GAttservApp子產品(一個可配置的子產品,用于儲存和管理屬性表,詳見BLE Stack API Reference)處理。
是以在建立GATT服務端的時候首先需要配置profiles檔案,profiles檔案調用GattServAppApp子產品并使用其API與GATT層接口。在這種情況下應用程式不需要直接調用GATT層API,應用程式和Profiles檔案接口。
GATT Services 和 Profile
在概述部分講過,GATT service是characteristic的集合,多個service可以組合在一起形成一個profile,許多profile僅實作一個service,是以profile和service可以互換。
在simple_peripheral示例應用程式項目中定義了四個GATT服務。
-
GAP GATT服務(GGS)
此服務包含裝置和通路資訊,例如裝置名稱,供應商辨別和産品辨別。
為此服務定義了以下特征:
裝置名稱
表現(Appearance)
外圍首選連接配接參數
-
通用屬性服務
該服務包含有關GATT伺服器的資訊,是藍牙低功耗協定棧的一部分,每個GATT伺服器裝置都需要根據藍牙5.0版本核心規範。
-
裝置資訊服務
此服務公開了有關裝置的資訊,如硬體,軟體版本,固件版本,規範資訊,合規性資訊和制造商名稱。裝置資訊服務是藍牙低功耗協定棧的一部分,由應用程式配置。
-
simple_gatt_profile服務
此服務是用于測試和示範的示例配置檔案。完整的源代碼在simple_gatt_profile.c和simple_gatt_profile.h檔案中提供。
// Initialize GATT attributes
GGS_AddService(GATT_ALL_SERVICES); // GAP GATT Service
GATTServApp_AddService(GATT_ALL_SERVICES); // GATT Service
DevInfo_AddService(); // Device Information Service
SimpleProfile_AddService(GATT_ALL_SERVICES); // Simple GATT Profile
下圖顯示了simple_peripheral項目中的屬性表,這些屬性的設定都是通過上面4個服務函數。可以逐一打開檢視修改。
使用BTool擷取的簡單GATT配置檔案特性表。紅色表示Profile聲明,黃色表示字元聲明,White表示與特定聲明相關的屬性。
simple_gatt_profile包含以下特性:
-
SIMPLEPROFILE_CHAR1
可以從GATT用戶端裝置讀取或寫入的1位元組值
-
SIMPLEPROFILE_CHAR2
可以從GATT用戶端裝置讀取但不能寫入的1位元組值
-
SIMPLEPROFILE_CHAR3
可以從GATT用戶端裝置寫入但不能讀取的1位元組值
-
SIMPLEPROFILE_CHAR4
不能從GATT用戶端裝置直接讀取或寫入的1位元組值(該值是通知屬性)
-
SIMPLEPROFILE_CHAR5
可從GATT用戶端裝置讀取(但不寫入)的5位元組值
0x001C是simple_gatt_profile服務聲明。
此聲明的UUID為0x2800(藍牙定義 GATT_PRIMARY_SERVICE_UUID)。該聲明的值是simple_gatt_profile(自定義)的UUID。
0x001D是SimpleProfileChar1特征聲明。
該聲明可以被認為是指向SimpleProfileChar1值的指針。該聲明的UUID為0x2803(藍牙定義GATT_CHARACTER_UUID)。下面解釋characteristic聲明值的含義(MSB到LSB):
-
位元組0是藍牙核心規範版本5.0中定義的SimpleProfileChar1的屬性 (以下是某些相關屬性)。
0x02:允許讀取特征值
0x04:允許寫入特征值(無響應)
0x08:允許寫入特征值(帶響應)
0x10:允許通知特征值(無确認)
0x20:允許通知特征值(帶确認)
characteristic1 0x0A的意義是該特性可讀可寫(0x02|0x08)
- 位元組1-2:SimpleProfileChar1的值的句柄(句柄0x001E)
- 位元組3-4:SimpleProfileChar1值的UUID(自定義0xFFF1)
-
0x001E是SimpleProfileChar1特征值
該值的UUID為0xFFF1(自定義)。該值是characteristic的實際有效載荷資料。如其SimpleProfileChar1聲明(句柄0x01D)所示,該值是可讀寫的。
-
0x001F是SimpleProfileChar1特征使用者描述
該描述的UUID為0x2901(藍牙定義)。該描述的值是描述特征的使用者可讀字元串。
-
0x0020 - 0x002C
剩下的四個特征描述具有和simpleProfileChar1相同結構的屬性。唯一不同的屬性是處理0x0028時,描述如下。
0x0028是SimpleProfileChar4用戶端特征配置。此配置的UUID為0x2902(藍牙定義)。通過寫入此屬性,GATT伺服器可以将SimpleProfileChar4配置為通知(寫入0x0001)或訓示(寫入0x0002)。将0x0000寫入此屬性将禁用通知和訓示。
GATT安全
如GATT 服務端抽象所述,GATT伺服器可以為每個特性獨立定義權限。伺服器可能允許任何用戶端通路某些characteristic,同時将通路其他characteristic僅限于認證或授權的用戶端。這些權限通常被定義為更進階别的配置檔案規範的一部分。對于自定義配置檔案,使用者可以選擇他們認為合适的權限。有關GATT安全性的更多資訊,請參閱藍牙核心規範版本5.0的安全注意事項部分([第3卷,第G部分,第8部分])。
認證(Authentication)
在用戶端通過認證配對方法之前,無法通路需要身份驗證的特性。此驗證在堆棧内執行,無需應用程式處理。唯一的要求是使GATT服務端正确注冊該特性。
例如,simple_gatt_profile的characteristic5設定需要認證的讀取。
//characteristic 5
{
{ ATT_BT_UUID_SIZE , simpleProfilechar5UUID },
GATT_PERMIT_AUTHEN_READ ,
0 ,
simpleProfileChar5
},
當未經身份驗證的用戶端嘗試讀取此值時,GATT伺服器将自動拒絕它,而不調用simpleProfile_ReadAttrCB()。隻有當認證成功之後,讀寫的請求才會轉發到profiles的讀寫回調,請參閱一下代碼,該代碼在simple_gatt_profile.c中simpleProfile_ReadAttrCB()函數裡面。
case SIMPLEPROFILE_CHAR1_UUID:
case SIMPLEPROFILE_CHAR2_UUID:
case SIMPLEPROFILE_CHAR4_UUID:
*pLen = 1;
pValue[0] = *pAttr->pValue;
break;
case SIMPLEPROFILE_CHAR5_UUID:
*pLen = SIMPLEPROFILE_CHAR5_LEN;
VOID memcpy( pValue, pAttr->pValue, SIMPLEPROFILE_CHAR5_LEN );
break;
default:
// Should never get here! (characteristics 3 和 4沒有讀權限)
*pLen = 0;
status = ATT_ERR_ATTR_NOT_FOUND;
break;
授權(Authorization)
授權是發生在認證之後對一些文檔的通路權限更改删除,需要授權。授權是BLE已經實作的一個安全層。由于應用程式需要定義自己的授權要求,是以協定棧将這些特性的讀/寫請求轉發到配置檔案的應用程式層。
要從profile檔案注冊GATT伺服器的授權資訊,它必須使用堆棧定義一個授權回調。如下面僞代碼(例程中沒有使用授權)。
- 注冊授權回調
CONST gattServiceCBs_t simpleProfileCBs = {
simpleProfile_ReadAttrCB , //讀回調函數指針
simpleProfile_WriteAttrCB , //寫回調函數指針
simpleProfile_authorizationCB //授權回調函數指針
};
- 實作授權回調代碼
static bStatus_t simpleProfile_authorizationCB ( uint16 connHandle , gattAttribute_t * pAttr , uint8 opcode )
{
//這隻是一個示例實作,正常的用例将需要
更複雜的邏輯來确定裝置是否被授權
if (clientIsAuthorized )
return SUCCESS ;
else
return ATT_ERR_INSUFFICIENT_AUTHOR ;
}
授權回調在協定棧上下文中執行,是以在這個函數中不應該執行太複雜的處理。具體實作由開發人員決定;上述回調應該被視為一個shell。如果用戶端有權通路該特征傳回SUCCESS,如果沒有傳回ATT_ERR_INSUFFICIENT_AUTHOR,授權需要事先通過連接配接進行身份驗證,否則ATT_ERR_INSUFFICIENT_AUTHEN将作為錯誤響應發送。
如果需要授權的特性并注冊了授權回調,但沒有定義應用級授權回調,那麼協定棧将傳回ATT_ERR_UNLIKELY。因為這個錯誤并不明确,是以TI建議使用授權回調。
直接使用GATT層
上面用戶端抽象說過,應用程式也可以直接使用GATT層API,本節就介紹如何在應用程式中使用GATT層,GATT層的功能在庫中實作,但頭檔案功能可在gatt.h中找到。BLE Stack API Reference中有完整的API參考。作為GATT用戶端(在simple_central項目中)使用GATT層的一般過程如下:
圖中可以看出,GATT用戶端發送指令之後,通過ICALL給協定棧發送ATT指令,然後協定棧處理之後傳回響應,再由ICALL以ATT事件通知應用程式,應用程式得到ATT事件之後異步處理。注意:除了收到對自己的指令的響應外,GATT用戶端還可以從GATT伺服器接收異步資料作為訓示或通知。使用GATT_RegisterForInd(selfEntity)注冊接收這些ATT通知和訓示。這些通知和訓示也作為ATT事件(ATT_HANDLE_VALUE_NOTI& ATT_HANDLE_VALUE_INDG)發送到應用程式。這些事件必須按照GATT Services和Profile中的說明進行處理。
GAP GATT 服務(GGS)
在前面GATT服務和簡介中說過,GGS服務包含裝置和通路資訊,例如裝置名稱,Appearance,外圍首選連接配接參數。GGS的目的是在裝置發現和連接配接啟動過程中進行輔助。有關GGS的更多資訊,請參閱藍牙核心規範版本5.0的“GAT service”和“Characteristics for GATT Server”部分([Vol 3],C部分,第12節)。
- 包含标題
#include “gapgattserver.h”
- 初始化GGS參數
// GAP GATT Attributes
static uint8_t attDeviceName [ GAP_DEVICE_NAME_LEN ] = “This is a text” ;
GGS_SetParameter (GGS_DEVICE_NAME_ATT , GAP_DEVICE_NAME_LEN , attDeviceName );
- 使用GGS初始化應用程式回調(可選)。當GGS中的任何特征發生變化時,都會通知應用程式。
GGS_RegisterAppCB (&appGGSCBs );
- 将GGS添加到GATT伺服器。
bStatus_t GGS_AddService (GATT_ALL_SERVICES );
經過上面4個步驟的配置,就成功設定了GGS的參數,在central裝置連接配接外圍裝置的時候就能擷取這些參數,使用我們公司提供的XXX.apk可以在手機界面直接檢視我們設定的參數值。
加入我們
文章所有代碼、工具、文檔開源。加入我們QQ群 591679055擷取更多支援,共同研究CC2640R2F&BLE5.0。
© Copyright 2017, 成都樂控暢聯科技有限公司.