認識BLE 5協議棧 —— 屬性協議層
轉自 http://www.sunyouqun.com/2017/04/understand-ble-5-stack-attribute-protocol-layer/
屬性協議(Attribute Protocol)簡稱ATT。
ATT層定義了屬性實體的概念,包括UUID、控制代碼和屬性值等,也規定了屬性的讀、寫、通知等操作方法和細節,這些與屬性操作相關的內容稱為屬性協議。ATT層規定了ATT_MTU值,如果屬性值很長,超過了ATT_MTU限制,將使用特殊的讀寫方法進行操作。
基於ATT層,可以構建出通用屬性操作規範。
1. 屬性
在藍芽協議中, 屬性是指一個數據實體,它包含識別符號,控制代碼,資料內容,訪問許可權,安全問題等。
屬性協議規定了屬性的發現和讀寫訪問的方法。
1.1 型別
屬性型別由一個UUID(Universally Unique Identifier)表示。UUID是指從時間尺度和空間尺度都具有唯一性的一串128-bit的數字,該數字串在全球範圍內不會重複,並且在未來也不會出現重複。
一個典型的16位元組UUID格式為XXXX-XX-XX-XX-XXXXXX。
藍芽協議設定了一個藍芽基礎UUID: 00000000 – 0000 – 1000 – 8000 – 00805F9B34FB。
利用該基礎UUID,可以使用16-bit或32-bit的UUID來代替128-bit的UUID,當傳遞到對端裝置,再還原成128-bit的UUID。
假如16-bit的UUID為YYYY,則還原後的128-bit的UUID為:0000YYYY – 0000 – 1000 – 8000 – 00805F9B34FB。
假如32-bit的UUID為YYYYYYYY,則還原後的128-bit的UUID為:YYYYYYYY – 0000 – 1000 – 8000 – 00805F9B34FB。
ATT層支援使用16-bit和128-bit兩種UUID,32-bit的UUID在使用前必須轉換成128-bit。
1.2 控制代碼
屬性控制代碼猶如指向屬性實體的指標,對端裝置通過控制代碼來訪問該屬性。
屬性控制代碼是一個2位元組數,有效範圍為0x0001-0xFFFF。
屬性控制代碼為有序排列,後面的控制代碼值會大於前面的控制代碼,通常下一個屬性的控制代碼值是上一個屬性的控制代碼加1。
1.3 分組
多個屬性可以合成一組,一組屬性包含的引數為:開始控制代碼、結束控制代碼。
1.4 值
屬性值可以是一個數字或一個字串。屬性值的長度資訊不包含在PDU中,所以需要從PDU的長度間接推算出屬性值的長度資訊。
屬性值通常在一個PDU中傳送,如果屬性值太長,也可以分成多個PDU進行傳送。
1.5 許可權
屬性的讀寫許可權由ATT層之上的協議層規定,有效的讀寫許可權包括:可讀、可寫、讀寫。
在讀寫屬性之前,客戶端裝置還需要具有足夠的安全許可權,包括:
- 加密許可權:需要加密、無需加密
- 認證許可權:需要認證、無需認證
- 授權許可權:需要授權、無需授權
如果許可權不足,將觸發錯誤處理機制。
1.6 控制點屬性
控制點屬性是一類特殊屬性,它不可讀,只能寫。
1.7 協議方法
對屬性的操作稱為協議方法,包括:命令(Command),請求(Request),響應(Response),通知(Notification),指示(Indication)和確認(Confirmation),某些屬性PDU還涉及授權簽名方法。
1.8 交換MTU Size
ATT_MTU表示ATT層間傳輸的資料包的最大長度。兩端裝置可以通過Exchange MTU Request/Response進行交換MTU。
1.9 長包屬性
對於讀屬性的資料包,最大長度為(ATT_MTU-1)個位元組。其中減去的1表示1位元組的操作碼。
對於寫屬性的資料包,最大長度為(ATT_MTU-3)個位元組。其中減去的3表示1位元組的操作碼和2位元組的屬性控制代碼。
如果資料包超過這個長度,則稱為長包屬性。
讀長包屬性,需要使用Read Blob Request,寫長包屬性,需要使用Prepare Write Request和Execute Write Request。
如果使用普通Read操作讀長包屬性,僅能讀取前(ATT_MTU – 1)個位元組,使用普通Write操作寫長包屬性,僅能寫前(ATT_MTU-3)個位元組。
無論普通屬性還是長包屬性,屬性值的最大長度均為512位元組。
1.10 原子操作
一個請求或一個命令,稱為一個原子操作。一個原子操作結束後,才能進行新的原子操作。
讀寫長包屬性無法在一個原子操作內完成。
2. 屬性PDU
2.1 屬性角色
在ATT層協議框架內,擁有一組屬性的裝置稱為服務端(Server),讀寫該屬性值的裝置稱為客戶端(Client)。
2.2 分類
屬性PDU有六類:
屬性PDU | 方向 | 觸發響應 |
---|---|---|
Command | Client -> Server | – |
Request | Client -> Server | Response |
Response | Server -> Client | – |
Notification | Server -> Client | – |
Indication | Server -> Client | Confirmation |
Confirmation | Client -> Server | – |
屬性PDU格式如下:
欄位 | Opcode | Parameter | Authentication Signature |
---|---|---|---|
長度 | 1 octet | 0 – (ATT_MTU-X) octets | 0 or 12 octets |
其中Opcode的第0-5位表示該屬性的具體型別,第6位表示命令標誌位,如果該位為1,表示該操作碼對應一個命令,最後1位表示認證簽名(Authentication Signature)標誌位,如果該位為1,表示該PDU的最後一個欄位中包含12位元組的認證簽名。
Parameter欄位中包含了引數,其長度為0支ATT_MTU-x,如果認證簽名位為1,則此處x等於13,否則等於1。
只有寫命令才需要認證簽名,其他命令不需要。此外,如果鏈路已經進行加密,則屬性PDU中也無需額外新增認證簽名。
2.3 操作順序
對於Request和Indication屬性,需要接收端返回響應。在發出Request和Indication後,收到響應之前,不能發出新的Request和Indication。
對於其他無需響應的屬性,則可以在自由傳送,但是不保證接收端一定能夠收到和執行。
可以在Request和Response之間,或Indication和Confirmation之間傳送其他無需響應的屬性。
2.4 事務
一個Request-Response對,或Indication-Confirmation對,稱為一個事務。
對於客戶端裝置而言,發出Request或收到Indication表示事務的開始,收到Response或返回Confirmation表示事務的結束。
對於服務端裝置而言,發出Indication或收到Confirmation表示事務的開始,收到Confirmation或返回Response表示事務的結束。
3. 屬性協議PDU
屬性協議規定了多種Request-Response對,請求屬性由客戶端裝置發出,響應屬性由服務端裝置發出。
3.1 錯誤處理
Opcode | PDU |
---|---|
0x01 | Error Response |
如果屬性PDU的操作碼無效,或屬性控制代碼無效,將返回錯誤響應PDU。在PDU的Parameter欄位中,包含了錯誤編碼。
3.2 交換MTU
Opcode | PDU |
---|---|
0x02 | Exchange MTU Request |
0x03 | Exchange MTU Response |
客戶端裝置向服務端裝置傳送交換MTU請求,提供客戶端裝置的MTU值。服務端裝置獲知客戶端的MTU值,並返回自己的MTU值。兩端裝置都將設定較小的MTU值作為新的MTU值。
如果兩端裝置沒有交換MTU,則使用預設的MTU值(BLE下為23)處理屬性事務。
3.3 查詢資訊
PDU | Opcode |
---|---|
0x04 | Find Information Request |
0x05 | Find Information Response |
0x06 | Find By Type Value Request |
0x07 | Find By Type Value Response |
查詢資訊請求,包含兩個引數:起始屬性控制代碼和結束屬性控制代碼,用於獲取服務端裝置屬性控制代碼處於該引數區間內的屬性。
查詢資訊響應,包含指定控制代碼區間內的屬性UUID。如果區間內有多個屬性,則返回多個響應。
按型別值查詢請求,是在查詢資訊請求的基礎上,加上了屬性型別和屬性值兩個引數,這樣能夠更加精確的找到目標屬性。
按型別值查詢響應,包含了滿足條件的屬性控制代碼列表。
3.4 讀屬性
Opcode | PDU |
---|---|
0x08 | Read By Type Request |
0x09 | Read By Type Response |
0x0A | Read Request |
0x0B | Read Response |
0x0C | Read Blob Request |
0x0D | Read Blob Response |
0x0E | Read Multiple Request |
0x0F | Read Multiple Response |
0x10 | Read by Group Type Request |
0x11 | Read by Group Type Response |
按型別讀請求,包含三個引數:起始屬性控制代碼、結束屬性控制代碼和屬性型別。
按型別讀響應,包含了滿足條件的屬性的“控制代碼-值”對的列表。
讀請求,包含一個引數:屬性控制代碼。
讀響應,返回滿足條件的屬性值。
讀片段(blob)請求,用於讀取一個長包屬性的值,它包含兩個引數:屬性控制代碼和偏移量。以不同的偏移量作為引數,多次執行該請求可以讀取長包屬性的完整值。
讀片段響應,包含了長包屬性值的指定偏移量片段。
讀多次請求,用於讀取多個給定控制代碼的屬性值,它包含一個引數:控制代碼列表。
讀多次響應,包含了多個指定控制代碼的屬性值。
按組型別讀請求,用於讀取指定組型別的屬性值,組型別是由ATT層之上的協議層設定的。它包含三個引數:起始屬性控制代碼、結束屬性控制代碼和屬性組型別。
按組型別讀響應,包含了滿足條件的屬性值列表。
3.5 寫屬性
Opcode | PDU |
---|---|
0x12 | Write Request |
0x13 | Write Response |
0x14 | Write Command |
0x15 | Signed Write Command |
寫請求,將待寫數值寫入指定的屬性值,包含兩個引數:屬性控制代碼和數值。
寫響應,表示寫請求執行成功,不含任何引數。
寫命令,將待寫數值寫入指定的屬性值,包含兩個引數:屬性控制代碼和數值。它不會觸發一個寫響應。
簽名的寫命令,與上面的寫命令類似,指示包含了額外的引數:認證簽名。典型應用是寫控制點屬性。
3.6 佇列寫屬性
佇列寫是指利用一個先進先出的佇列,快取多個屬性值的寫操作,然後在一個原子操作中完成所有的值寫入操作。
佇列寫專門用於長包屬性的寫操作,現將一個長資料分成多個部分並記錄偏移量,然後通過佇列快取,等資料傳送完畢,再按照收到的順序,一次性將整個長資料寫入屬性值。
Opcode | PDU |
---|---|
0x16 | Prepare Write Request |
0x17 | Prepare Write Response |
0x18 | Execute Write Request |
0x19 | Execute Write Response |
準備寫請求,用於傳送一個長資料片段,它包含三個引數:屬性控制代碼、偏移量和待寫入資料。
準備寫響應,收到準備寫請求以後,快取收到的資料。
執行寫請求,對前面快取的資料執行寫操作,它包含一個引數:標誌位。如果標誌位為1,則執行寫操作,如果為0,則取消前面的快取資料。
執行寫響應,根據執行寫請求的標誌位,執行或取消寫操作。
3.7 通知屬性
Opcode | PDU |
---|---|
0x1B | Handle Value Notification |
0x1D | Handle Value Indication |
0x1E | Handle Value Confirmation |
傳送數值通知,它包含兩個引數:屬性控制代碼和屬性值。它不需要客戶端收到後返回響應。
傳送數值指示,它包含兩個引數:屬性控制代碼和屬性值。它需要客戶端收到後返回確認。
傳送數值確認,它不包含引數,客戶端發出該確認訊息表示收到了數值指示。
4. 許可權
通知和指示與讀寫操作類似,也可以設定安全許可權。
每個屬性可以設定單獨的許可權。
許可權不足將阻止操作,並觸發錯誤響應。
許可權問題與ATT之上的協議層有較大聯絡。