ATT(Attribute Protocol)屬性層是GATT和GAP的基礎,它定義了BLE協議棧上層的數據結構和組織方式。html
屬性(Attribute)概念是ATT層的核心,ATT層定義了屬性的內容,規定了訪問屬性的方法和權限。以編程的眼光來看,屬性是一個數據結構,它包括了數據類型和數據值,就如同C語言結構體的概念,開發者能夠設計獨特的結構,來描述外部世界實體。數據庫
屬性包括三種類型:服務項、特徵值和描述符。三者之間存在樹狀包含關係,服務項包含一個或多個特徵值,特徵值包含一個或多個描述符,多個服務項組織在一塊兒,構成屬性規範(Attribute Profile)。對於經常使用的屬性規範,好比體重計、心率計,SIG(藍牙技術聯盟)作了具體定義,這樣的話,只要BLE主從設備均遵照某個Profile來進行設計,那麼兩者就可以優雅的通訊。編程
ATT層相關的東西與開發者比較近,易於理解,可是章節內容圖表較少,闡述偏多。安全
屬性主要由如下四部分組成:屬性句柄(Attribute Handler)、屬性類型(Attribute Type)、屬性值(Attribute Value)、屬性權限(Attribute Permissions)。服務器
1.1 屬性句柄數據結構
屬性句柄(Attribute Handle)猶如指向屬性實體的指針,對端設備可經過屬性句柄來訪問該屬性,它是一個2字節長度的十六進制碼,起始於0x0001,在系統初始化時候,各個屬性的句柄逐步加一,最大不超過0xFFFF。框架
1.2 屬性類型ide
做用是用以區分當前屬性是服務項或是特徵值等,它用UUID來表示。UUID(universally unique identifier,通用惟一識別碼)是一個軟件構建標準,並不是BLE獨有的概念,一個合法的UUID,必定是隨機的、全球惟一的,不該該出現兩個相同的UUID(出現了,就說明它們倆是同一個UUID)。標準的UUID是一串16字節十六進制字符串,如f6257d37-34e5-41dd-8f40-e308210498b4,在網上能夠方便的生成一個UUID。
BLE的屬性類型是有限的,有四個大類:加密
這些屬性類型分別對應了指定的UUID,BLE對這些UUID與屬性類型的映射關係作了規定:spa
假如UUID=0x1800,就表示它是一個首要服務項。
UUID是16個字節的字符串,爲何這裏只使用了2字節?
由於這些是經常使用的UUID,爲了減小傳輸的數據量,BLE協議作了一個轉換約定,給定一個固定的16字節模板,只設置2個字節爲變化量,其餘爲常量,2字節的UUID在系統內部會被替換,進而轉換成標準的16字節UUID。UUID模板爲:
0000XXXX-0000-1000-8000-00805F9B34FB
其中從左數第三、4個字節「XXXX」就是變化位,其餘爲固定位。如:UUID=0x2A00在系統內部會轉換成00002A00-0000-1000-8000-00805F9B34FB。
反之,若是一個特徵值的UUID是16字節的,在系統內部它的屬性類型也可能寫成第三、4字節組成的雙字節,好比UUID=1234ABCD-0000-1000-8000-00805F9B34FB,它的屬性類型在內部表示爲ABCD。主機端掃描到該屬性類型,會將其當作是「用戶自定義」的類型,而後從其餘位置獲取該UUID的真實值。
1.3 屬性值
用於存放數據。若是該屬性是服務項類型或者是特徵值聲明類型,那麼它的屬性值就是UUID等信息。若是是普通的特徵值,則屬性值是用戶的數據。屬性值須要預留空間以保存用戶數據。爲了方便理解,咱們能夠將屬性值的空間看作I2C的數據空間,操做特徵值裏的用戶數據,就是對那塊內存空間進行讀寫。
1.4 屬性權限
屬性權限主要有如下四種:
訪問(Access)權限好理解,若是是隻讀權限,就不能對其寫數據,其餘相似。
加密(Encryption)權限也好理解,就是對數據進行加密。
認證(Authentication)是指相互確認對方身份。完成認證流程的兩個設備,雙方創建信任關係,兩者之間的通訊通道便可以認爲是安全的。BLE中,「認證」過程就是配對。
受權(Authorization)是指對授信設備開放權利。
認證和受權功能容易混淆,其英文拼寫也很類似。從上面的概念上看,受權要求設備必須是可信任的,所以受權的管控等級要高於認證——認證的設備未必被受權,受權的設備必定是認證的。理解兩者關係,須要引入一個概念:Trusted Device(可信任設備)一個沒有通過認證的設備,被稱爲Unknown Device(未知設備);通過了認證該設備會在綁定信息中被標記爲Untrusted,被稱爲Untrusted Device(不可信設備);通過了認證,而且在綁定信息中被標記爲Trusted的設備被稱爲Trusted Device(可信設備)。
受權要求設備爲Trusted Device(可信任設備)。在實際使用中,通過配對之後設備即爲Untrusted Device——認證,在代碼中調用API能夠設置設備爲Trusted Device——受權。
屬性大體能夠分爲三種類型:服務項、特徵值和描述符。它們的層級關係爲:最頂級爲Profile, 下面是多個服務項(Service), 服務項下面是多個特徵值(Characteristic), 特徵值下面是多個描述符(Descriptor)。
每一個設備都包含如下必要的特徵值和服務項:
PROFILE
服務項這種類型自己並不包含數據,僅僅至關因而一個容器,用來容納特徵值。特徵值用於保存用戶數據,但它也有本身的UUID, 有點像C語言中的變量int var=0xFF,整形變量var攜帶了用戶數據0xFF,可是它自身還有地址信息(&var),所以在使用時須要先定義再賦值兩個步驟。相似的,在處理特徵值所攜帶的用戶數據以前,須要先對特徵值自身進行聲明。
特徵值在系統中的表達形式是:聲明 + 特徵值屬性。好比Device Name,它在GATT數據庫中表示方式是:
Characteristic 聲明: 0x0002, 0x2803, access_property, 0x2A00 Characteristic 項: 0x0003, 0x2A00, access_property, data
其中第一列雙字節數表明句柄,第二列雙字節數表明屬性類型(UUID),0x2803表示該項爲「特徵值的聲明」,0x2A00表示該特徵值是Device Name。在第一行特徵值聲明中,最後一項的屬性值就是該特徵值的UUID。能夠注意到,聲明裏面的屬性值爲0x2A00,特徵值本身的屬性類型也是0x2A00,顯然信息冗餘了。緣由是,假如特徵值的UUID爲自定義的16字節UUID,在特徵值的屬性類型中,只能存放2個字節,而UUID的真實值,就存放在特徵值聲明的屬性值項中。
BLE的屬性體系在系統中以GattDB表示,即屬性數據庫。打開CyBle_gatt.c文件,找到cyBle_gattDB變量,以下圖
const CYBLE_GATTS_DB_T cyBle_gattDB[0x10u] = { { 0x0001u, 0x2800u /* Primary service */, 0x00000001u /* */, 0x0007u, {{0x1800u, NULL}} }, { 0x0002u, 0x2803u /* Characteristic */, 0x00000201u /* rd */, 0x0003u, {{0x2A00u, NULL}} }, { 0x0003u, 0x2A00u /* Device Name */, 0x00000201u /* rd */, 0x0003u, {{0x0009u, (void *)&cyBle_attValuesLen[0]}} }, { 0x0004u, 0x2803u /* Characteristic */, 0x00000201u /* rd */, 0x0005u, {{0x2A01u, NULL}} }, { 0x0005u, 0x2A01u /* Appearance */, 0x00000201u /* rd */, 0x0005u, {{0x0002u, (void *)&cyBle_attValuesLen[1]}} }, { 0x0006u, 0x2803u /* Characteristic */, 0x00000201u /* rd */, 0x0007u, {{0x2A04u, NULL}} }, { 0x0007u, 0x2A04u /* Peripheral Preferred Connection Par */, 0x00000201u /* rd */, 0x0007u, {{0x0008u, (void *)&cyBle_attValuesLen[2]}} }, { 0x0008u, 0x2800u /* Primary service */, 0x00000001u /* */, 0x000Bu, {{0x1801u, NULL}} }, { 0x0009u, 0x2803u /* Characteristic */, 0x00002201u /* rd,ind */, 0x000Bu, {{0x2A05u, NULL}} }, { 0x000Au, 0x2A05u /* Service Changed */, 0x00002201u /* rd,ind */, 0x000Bu, {{0x0004u, (void *)&cyBle_attValuesLen[3]}} }, { 0x000Bu, 0x2902u /* Client Characteristic Configuration */, 0x00000A04u /* rd,wr */, 0x000Bu, {{0x0002u, (void *)&cyBle_attValuesLen[4]}} }, { 0x000Cu, 0x2800u /* Primary service */, 0x00000001u /* */, 0x0010u, {{0xCBBBu, NULL}} }, { 0x000Du, 0x2803u /* Characteristic */, 0x00001A01u /* rd,wr,ntf */, 0x0010u, {{0xCBB1u, NULL}} }, { 0x000Eu, 0xCBB1u /* Custom Buffer */, 0x00011A04u /* rd,wr,ntf */, 0x0010u, {{0x00C8u, (void *)&cyBle_attValuesLen[5]}} }, { 0x000Fu, 0x2901u /* Custom Descriptor */, 0x00010001u /* */, 0x000Fu, {{0x001Cu, (void *)&cyBle_attValuesLen[6]}} }, { 0x0010u, 0x2902u /* Client Characteristic Configuration */, 0x00010A04u /* rd,wr */, 0x0010u, {{0x0002u, (void *)&cyBle_attValuesLen[7]}} }, };
經過註釋能夠看到,每一個特徵值都有聲明和特徵值項兩部分組成。
因爲各個屬性的句柄是遞增的,所以屬性的聲明順序會影響句柄的計算。
描述符是特徵值的補充信息,掛載在特徵值之下,它能夠開闢一段數據空間以攜帶數據,客戶端能夠像操做特徵值同樣對其進行讀寫,可是描述符弱於特徵值,它不具有Notify/Write等讀寫屬性,遠不如特徵值靈活。有一種描述符叫CCCD(Client Characteristic Configuration Description),當對特徵值設置Notify或Indication時,用以控制Notify和Indication的使能狀況。
關於gattDB,值得注意的一點是,gattDB是BLE協議棧在內存中開闢的一段專有區域,它會在特定的時候寫入Flash進行保存,並在啓動時讀取出來回寫到內存中去。並不是全部的BLE數據通訊是操做gattDB!好比手機向BLE設備發送一串字符串,從機收到這串字符串並打印出來,這個過程當中,這個字符串並無寫入gattDB。那麼,即便開發者限制某個特徵值爲認證、只讀等權限,仍然不能阻止這個字符串的發送和打印,由於特徵值的權限,都是針對gattDB而言的。進一步,假如BLE從機收到字符串後,但願寫入gattDB進行保存,那麼就會觸發權限問題。以往有開發者說爲何我勾選了屬性須要認證,可是配對失敗後仍然可以看到手機發來的數據,緣由就在這裏,就是手機端傳來的數據沒有涉及到gattDB,當嘗試寫入gattDB的時候,就會發現報錯了。
在ATT層協議框架內,擁有一組屬性的設備稱爲服務端(Server),讀寫該屬性值的設備稱爲客戶端(Client),Server和Client經過ATT PDU進行交互。屬性協議共有6種:
屬性PDU | 方向 | 觸發響應 |
---|---|---|
Command | Client -> Server | – |
Request | Client -> Server | Response |
Response | Server -> Client | – |
Notification | Server -> Client | – |
Indication | Server -> Client | Confirmation |
Confirmation | Client -> Server | – |
它們的區別以下:
客戶端發送Request,服務器須要返回一個Response,代表服務器收到了。
服務器發送Indication,客戶端須要返回一個Confirmation,代表客戶端收到了。
以上兩種方式,均是單線程操做,即下一個Request/Indication操做須要在上一個操做收到Response/Confirmation以後才能開始。
客戶端發送Command,服務器無需任何返回。
服務器發送Notification,客戶端無需任何返回。
所以Command和Notification是不可靠的通訊。當通訊環境不佳,客戶端頻繁發送Command,可能發生服務器接收不到或丟棄的狀況,Notification也相似。
PDU的具體格式定義以下:
參數說明:
Opcode: bit 0-5:操做屬性的方法 bit 6:Command 標識位 bit 7:Authentication Signature標識位 Attribute Parameters: 若是Attribute Opcode中身份驗證簽名標記位爲0,則X = 1; 若是Attribute Opcode中身份驗證簽名標記位爲1,則X = 13; Authentication Signature: 屬性操做碼和屬性參數的可選身份驗證簽名
參考連接:
1. 藍牙BLE實用教程
2. BLE協議棧-ATT