BLE 5協議棧-通用屬性規范層(GATT)


文章轉載自:http://www.sunyouqun.com/2017/04/page/2/

通用屬性規范GATT(Generic Attribute Profile)將ATT層定義的屬性打包成不同的屬性實體,包括服務項、特征項和描述符,這些屬性實體組合在一起組成規范,即GATT規范。GATT規范是服務項的集合,服務項是特征項的集合,特征項攜帶了屬性參數和數據,描述符協助特征項描述特征值的形式和功能。

GATT層按照命令的傳輸方向將設備分成GATT客戶端和GATT服務端。客戶端發起命令,服務端發出數據。GATT規范定義了客戶端設備發現服務端設備的服務項的方法,建立連接以后,客戶端設備可以通過發現方法檢索服務端設備的GATT服務項和特征項,進而發送命了或數據。

服務端向客戶端發送數據以通知和指示的形式發送,客戶端收到指示信息需要返回確認信息。

服務端可以向客戶端發送通知和指示,客戶端按需返回響應。

1. 屬性

1.1 GATT角色

客戶端:設備發起命令、請求並接受響應、通知和指示。

服務端:設備接收命令、 請求並發出響應、通知和指示。

設備可以同時屬於客戶端和服務端。

GATT角色與執行過程相關,它不與設備綁定。設備在執行一個過程時,根據發起命令或接收命令而決定它是服務端還是客戶端,該過程結束后就釋放GATT角色。

GATT角色不與鏈路層的主機和從機角色綁定。一個鏈路層的主機,通常擔任GATT客戶端角色,也可以擔任GATT服務端角色。

1.2 屬性PDU

屬性實體PDU如下:

字段 Attribute Handle Attribute Type Attribute Value Attribute Permissions
長度 2 octets 2 or 16 octets variable implementation specific

一個屬性包含四個字段:屬性句柄、屬性類型、屬性值和屬性權限。

屬性句柄用於指定具體的屬性。屬性句柄有效范圍為0x0000-0xFFFF,屬性句柄按步進1的增序排列,但有時可能會出現空缺。

屬性類型為2字節、4字節或16字節的UUID。 如果是4字節UUID,在封裝成屬性PDU時根據藍牙基礎UUID轉換成16字節標准UUID。

屬性值字段包含了屬性的具體數據。

屬性權限決定了屬性是否可讀或可寫。

1.3 屬性協議PDU

兩個設備屬性層之間根據屬性協議傳輸數據,屬性協議包括幾種類型:命令、請求、響應、通知、指示和確認。

屬性協議PDU如下:

字段 Opcode Attribute Parameters Authentication Signature
長度 1 octet variable 12 octets

操作碼Opcode決定了該PDU的操作過程類型。另外,操作碼中包含一個認證標志位。

屬性參數中包含了命令或請求的參數,或響應的數據。

最后字段的認證簽名為可選字段,僅用於帶簽名的寫操作,當操作碼的認證標志位為1,則需要認證簽名字段,否則不需要改字段。

1.4 屬性緩存

客戶端與服務端建立連接后,執行發現過程,以獲取服務端所攜帶的全部屬性。屬性緩存功能用於保存服務端設備的屬性句柄,使下一次重新連接時無需執行發現過程。

一般情況下,服務端設備的屬性不會改變,但是執行固件升級則可以改變設備的屬性。

如果改變設備的屬性,將從Service Changed characteristic發出一個指示PDU,告知客戶端設備服務端設備的屬性發生了改變。該指示PDU中包含了發生改變的屬性句柄范圍,客戶端設備收到該指示,重新執行發現過程,獲取更新后的服務端設備的屬性句柄。

如果設備的屬性確定不能發生改變,則無需增加Service Changed characteristic屬性。

如果兩端設備完成綁定,則屬性緩存信息一直有效,直到收到了Service Changed characteristic發出的指示。如果在服務端的屬性在斷開后發生了改變,則服務端在下次重連時候發送指示給客戶端設備重新緩存屬性句柄。

1.5 屬性分組

GATT定義了三種屬性分組:主要服務、次要服務和特征項。

一個屬性分組包括聲明和定義。

主要服務和次要服務可以使用“按組類型讀取”請求獲得,特征項不可以。

1.6 屬性結構

藍牙協議中包含了許多種GATT規范,每個規范適配一種用戶案例,比如FindMe規范適配查找物件的場景,心率傳感器規范適配心率測量場景。

每個規范均中均有若干服務項和特征項,服務項和特征項都屬於屬性實體,它們攜帶了通信中傳輸的數據。

服務項分為主要服務和次要服務,主要服務可以引用(Include)另一個主要服務或次要服務,客戶端設備可以通過“主要服務發現過程”獲取主要服務信息。

特征項包括一個聲明、配置、數據和描述符。描述符用於描述特征項的數據如何被訪問和展示。

規范、服務項和特征項之間有明確的包含關系,一個GATT規范中可以包括多個服務項,一個服務項中可以包括多個特征項。

GATT的規范結構框圖如下:

GATT_Profile_Structure

2. 屬性類型

屬性的類型由UUID表示,協議棧預留了一些16-bit的UUID來表示常用的屬性類型。

2.1 服務項

服務項必須包含一個服務項聲明,可選地包含多個其他服務項和特征項。所包含的其他服務項和特征項均是該服務項的一部分。

服務項的聲明格式如下:

GATT_Service_Declaration

服務項可以是主要服務項(UUID=0x2800)或次要服務項(UUID=0x2801)。

主要服務項可以獨立使用,次要服務項一定要被其他服務項包含引用。

協議棧文檔中對次要服務項的使用場景解釋有限,在絕大多數情況下均可以不使用次要服務項,僅使用主要服務。

2.2 包含

包含現了一個引用機制,比如需要擴展一個現有的服務項,可以在新的服務項中引用該服務項。

假如服務項中包含了其他服務項,則需要加入包含的聲明(UUID=0x2802)。

協議棧文檔中對包含的使用場景解釋有限,在絕大多數情況下均可以不使用包含功能。

2.2 特征項

特征項是GATT數據的載體。

特征項包括:特征項的聲明(UUID=0x2803),特征值的聲明,以及若干描述符。特征值也是一個屬性,它的句柄和UUID在特征項的聲明中給出。

特征項始於該特征項的聲明,結束語下一個特征項的聲明。

特征項的聲明數據格式如下:

GATT_Characteristic_Format

其中屬性值字段包括了特征值功能特性(Characteristic Properties),特征值的屬性句柄和特征值的UUID。

特征值功能特性如下表所示:

特征值功能 描述
Broadcast 0x01 允許廣播該特征值
Read 0x02 允許讀該特征值
Write Without Response 0x04 允許寫該特征值,不需要Response
Write 0x08 允許寫該特征值,需要Response
Notify 0x10 允許該特征值發送通知
Indicate 0x20 允許該特征值發送指示
Authenticated Signed Writes 0x40 允許帶認證簽名的寫該特征值
Extended Properties 0x80 擴展特性

其中,Broadcase(0x01)、Notify(0x10)和Indicate(0x20)要求該特征值具有服務端特征項配置描述符(CCCD)。

特征項的聲明中屬性字段的特征值UUID跟特征值的聲明中的UUID一致。

特征值的聲明中包含了特征值所攜帶的數據內容,其格式如下:

GATT_Characteristic_Value_Format

2.3 描述符

描述符也是一種屬性,它是特征項的一部分,用以提供特征值的額外信息。協議棧定義了6種不同的描述符,如下:

屬性類型 UUID 描述
«Characteristic Extended Properties» 0x2900 特征項的擴展描述符
«Characteristic User Description» 0x2901 特征項的用戶描述符
«Client Characteristic Configuration» 0x2902 客戶端特征項配置描述符
«Server Characteristic Configuration» 0x2903 服務端特征項配置描述符
«Characteristic Format» 0x2904 特征項數據格式描述符
«Characteristic Aggregate Format» 0x2905 聚合特征項數據格式描述符

0x2900 擴展性描述符,用於Reliable Write和Writable Auxiliaries這兩類寫屬性。

0x2901 用戶描述符,用於給出該特征值的文字描述。

0x2902 客戶端特征項配置描述符,簡稱為CCCD,客戶端設備通過一個標志參數,設置該特征值能否發送通知和指示。如果該標志參數為0x0001,表示該特征值允許發送通知;如果該標志參數為0x0002,表示該特征值允許發送指示。如果該標志參數為0x0000,表示該特征值不能發送通知和指示。

每個特征項最多能包含一個CCCD,對於具有Broadcast、Notify和Indicate功能的特征項,必須擁有一個CCCD。在兩個建立了綁定的設備中,斷開連接不會丟失CCCD信息。

0x2903 服務端特征項配置描述符,服務端設備通過一個標志參數,設置該特征值是否在廣播中發出。如果該標志參數為0x0001,則廣播消息中應該包含該特征值;如果該標志參數為0x0000,則廣播消息中不包含該特征值。

0x2904 特征值格式描述符,用於提供特征值的數據格式。可選的數據類型包括:Boolean、1/4字節、1/2字節、1字節、2字節、3字節、4字節、8字節、16字節、帶符號整數、無符號整數、浮點數、字符串、結構體等。還可以指定數據的指數、單位、名字空間、描述信息等。

0x2905 聚合特征項格式描述符,專用於聚合特征項。所謂聚合特征值,是指多個特征值共同組合成一個數值,每個特征值僅是該聚合數值的一部分。

3. GATT功能

GATT規范實現了以下功能:

  1. Server Configuration
  2. Primary Service Discovery
  3. Relationship Discovery
  4. Characteristic Discovery
  5. Characteristic Descriptor Discovery
  6. Reading a Characteristic Value
  7. Writing a Characteristic Value
  8. Notification of a Characteristic Value
  9. Indication of a Characteristic Value
  10. Reading a Characteristic Descriptor
  11. Writing a Characteristic Descriptor

這些功能利用了“深入BLE協議棧 —— 屬性協議”中的屬性協議PDU一節中的多種讀寫屬性PDU。

下面具體分析。

3.1 服務端配置

該功能呢包含一個子功能:交換兩端設備的ATT_MTU。

客戶端設備發送Exchange MTU Request,其中包含了該設備的ATT_MTU,服務端設備返回Exchange MTU Response,其中包含了該設備的ATT_MTU,取二者的較小值作為協商的ATT_MTU值。

3.2 發現主要服務項

該功能包含兩個子功能:發現全部主要服務項,按UUID發現主要服務項。

發現全部主要服務項

該功能向服務端設備發送Read By Group Type Request,起始句柄為0x0001,結束句柄為0xFFFF,屬性類型為0x2800(主要屬性的UUID),查找全部符合條件的首要服務項。

服務端返回Read By Group Type Response,響應中包含多個屬性信息組成的列表,單個屬性信息包含三個參數:元素長度、屬性組首尾句柄、屬性的UUID。

因為該列表長度不能超過一個屬性層的PDU長度,所以需要多次執行請求和響應,直到服務端設備返回“未找到屬性項”或到達結束句柄,才能獲取全部的主要服務項,如下圖所示:

GATT_Discover_All_Primary_Services

觀察上圖,客戶端第一次發起請求,查找主要服務項,首末句柄分別是0x0001和0xFFFF。

服務端返回響應中包含三個元素,每個元素代表一個首要服務項。每個元素的長度為0x06。第一個首要服務項的屬性句柄為0x0001,類型為UUID1,末尾句柄為0x000F。第二個服務項的屬性句柄為0x0010,類型為UUID2,末尾句柄為0x0017。第三個服務項的屬性句柄為0x0100,類型為UUID3,末尾句柄為0x01FF。

客戶端發起第二次請求,起始句柄設為0x2000。

服務端返回響應中仍然包含三個元素,每個元素的長度為0x06。三個元素分別表示三個首要服務項,其UUID分別為UUID4、UUID5和UUID6,UUID6的末尾句柄為0x04FF。

客戶端接着發起第三次請求,起始句柄設為0x0500。

服務端返回錯誤,錯誤原因是未找到屬性。客戶端根據該錯誤原因,判斷已經獲取服務端設備的全部主要服務項。

按UUID發現主要服務項

該功能向服務端設備發送Read By Group Type Request,起始句柄為0x0001,結束句柄為0xFFFF,屬性類型為0x2800(主要屬性的UUID),指定的UUID為xxxx,查找全部符合條件的主要服務項。

具體的操作步驟與“發現全部主要服務”一致。

通常具有指定UUID的服務項僅有一個。

3.3 發現關系

該功能呢包含一個子功能:查找包含的服務項。

該功能向服務端設備發送Read By Type Request,起始句柄為0x0001,結束句柄為0xFFFF,屬性類型為0x2802(包含的聲明UUID),查找全部符合條件的被包含服務項。

服務端返回響應,包含了滿足條件的服務項的句柄和屬性值。

3.4 發現特征項

該功能包含兩個子功能:發現服務項下的全部特征項,按UUID發現特征項。

發現服務項下的全部特征項

該功能向服務端設備發送Read By Type Request,設置已知的服務項首末句柄,屬性類型為0x2803(特征項聲明的UUID),查找全部符合條件的特征項。

服務端返回Read By Type Response,響應中包含多個“屬性句柄 – 值”元素組成的列表。單個元素包含三個參數:元素長度、特征項聲明的句柄和特征值參數。特征值參數包括特征值的功能特性、特征值句柄和UUID。

因為該列表長度不能超過一個屬性層的PDU長度,所以需要多次執行請求和響應,直到服務端設備返回“未找到屬性項”或到達結束句柄,才能獲取全部的特征項,如下圖所示:

GATT_Discovery_Characteristic

觀察上圖,客戶端第一次發起請求,查找特征項,首末句柄分別是0x0200和0x0214。

服務端返回響應中包含兩個元素,每個元素代表一個特征項。每個元素的長度為0x07。第一個特征項的聲明句柄為0x0203,特征值的功能特性為0x02,即具有Read功能,特征值的句柄為0x0204,特征值的UUID為UUID1。第二個特征項的聲明句柄為0x0210,特征值的功能特性為0x02,即具有Read功能,特征值的句柄為0x0212,特征值的UUID為UUID2。

由於每個元素的長度為7,表明該兩個特征值的UUID均是2字節UUID,如果是16字節UUID,則每個元素的長度應該為0x15。

按UUID發現特征項

該功能根據已知的特征項UUID和首末句柄范圍,查找滿足條件的 特征項。

具體與“發現服務項下的全部特征項”完全一致。

3.5 發現描述符

該功能包含一個子功能:發現全部描述符。

該功能向服務端設備發送Find Information Request,設置已知的特征項首末句柄,查找全部符合條件的描述符。

服務端返回Find Information Response,響應中包含多個“屬性句柄 – 值”元素組成的列表。單個元素包含三個參數:UUID格式、特征值的句柄和描述符的UUID。如果UUID格式參數等於1,表示描述符的UUID為2字節UUID,如果等於2,表示描述符的UUID為16字節UUID。

因為該列表長度不能超過一個屬性層的PDU長度,所以需要多次執行請求和響應,直到服務端設備返回“未找到屬性項”或到達結束句柄,才能獲取全部的描述符,如下圖所示:

GATT_Discovery_Descriptor

觀察上圖,服務端的響應數據第一個參數0x01表示UUID1和UUID2均為2字節UUID,第二個參數0x0205表示該描述符上級的特征值的句柄。

3.6 讀特征值

該功能包含四個子功能:讀特征值,按UUID讀特征值,讀長包特征值,讀多個特征值。

讀特征值

客戶端已知特征值句柄,向服務端發送Read Request讀取該句柄的特征值。

服務端返回指定句柄的特征值。該特征值長度應小於等於(ATT_MTU-1),如果大於該限制,則僅返回前(ATT_MTU-1)個數據。

下圖為一次讀取過程:

GATT_Read_Request

按UUID讀特征值

客戶端已知特征值的UUID,不知道其句柄,向服務端發送Read By Type Request讀取該特征值。

具體操作與“按UUID發現特征項”一致。

讀長包特征值

客戶端已知特征值的句柄,但是特征值的長度大於(ATT_MTU-1),向服務端發送Read Request以讀取前(ATT_MTU-1)個字節,然后發送Read Blob Request並設置合適的偏移量,以讀取隨后的(ATT_MTU-1)個字節,重復執行Read Blob Request直到服務端的Read Blob Response內容小於(ATT_MTU-1),表明該特征值完全被讀取。

具體步驟如下:

GATT_Read_Blob_Request

讀多個特征值

客戶端已知多個特征值的句柄,向服務端發送Read Multiple Request,參數為多個特征值句柄。

服務端返回Read Multiple Response,包含了多個指定的特征值數據。

3.7 寫特征值

該功能包含五個子功能:寫命令,帶簽名的寫命令,寫請求,寫長包請求,可靠的寫請求。

寫命令

客戶端已知特征值句柄,向服務端發送Write Command,寫入指定數據。

數據長度不能超過(ATT_MTU-3)字節,如果超過,僅寫入前(ATT_MTU-3)個字節。

該命令無需服務端返回響應。

帶簽名的寫命令

客戶端已知特征值句柄,且鏈接沒有經過認證,向服務端發送Write Command,並設置簽名認證標志位,實現帶簽名的寫命令。

數據長度不能超過(ATT_MTU-3-12)字節,其中12表示認證簽名的長度,如果超過,僅寫入前(ATT_MTU-3-12)個字節。

該命令無需服務端返回響應。

寫請求

客戶端已知特征值句柄,向服務端發送Write Request,寫入指定數據。

數據長度不能超過(ATT_MTU-3)字節,如果超過,僅寫入前(ATT_MTU-3)個字節。

該命令需要服務端返回響應Write Response。

寫長包請求

客戶端已知特征值句柄,但待寫入數據長度過長,向服務端發送Prepare Write Request,設置適當的偏移量,將數據發送至服務端緩存起來,數據發送完畢后,項服務端發送Execute Write Request執行寫請求。

待寫數據總長度不受限制,但是分步發送數據每次數據長度不得超過(ATT_MTU-3)。

兩種請求均需要對應的服務端響應。

一個寫長包請求流程如下:

GATT_Long_Write_Request

可靠的寫請求

客戶端已知特征值句柄,希望一次性寫入多字節的數據,或者要求數據的每個字節都必須被安全寫入服務端設備,向服務端發送Prepare Write Request,偏移量永遠等於0,一次性只發送一個數據,帶多字節數據緩存完畢,再發送Execute Write Request執行寫請求。

具體的操作與“寫長包請求”完全一致。

3.8 通知

該功能包含一個子功能:通知。

服務端執行Handle Value Notification,參數為特征值句柄和通知數據,向客戶端推送通知。

執行通知前,該特征值需要已經使能通知,並且將通知數據寫入該特征值。

該命令無需客戶端返回響應。

3.9 指示

該功能包含一個子功能:指示。

服務端執行Handle Value Indication,參數為特征值句柄和指示數據,向客戶端推送指示。

執行指示前,該特征值需要已經使能指示,並且將指示數據寫入該特征值。

該命令需要客戶端返回響應Handle Value Confirmation。

3.10 讀寫描述符

該功能包含四個子功能:讀描述符,讀長包描述符,寫描述符,寫長包描述符。

讀描述符與讀特征值一致。

讀長包描述符與讀長包特征值一致。

寫描述符與寫請求一致。

寫長包描述符與寫長包請求一致。

4. 與L2CAP層互操作

GATT使用的L2CAP固定信道傳輸屬性數據。

GATT的PDU長度限制ATT_MTU默認大小為23,它與L2CAP層的MTU值保持一致。

(完)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM