ATT GATT Profile
Bluetooth: ATT and GATT
Bluetooth 4.0, which includes the Low Energy specification, brings two new core protocols: ATT (Attribute Protocol) and GATT (Generic Attribute Profile). They are mainly targeted for Low Energy, and every LE profile is expected to use them. But they can also be used over "vanilla" Bluetooth (BR/EDR).
Overview
ATT is a wire application protocol, while GATT dictates how ATT is employed in service composition. Every Low Energy profile must be based on GATT. So, ultimately, every LE service uses ATT as the application protocol.
Locking profiles into these protocols brings several advantages:
- Development and implementation of new LE profiles is much easier, since there is no wire protocol to do from scratch;
- ATT is optimized to run on Low Energy devices: it uses as few bytes as possible, and implementation may use fixed-size structures in memory to make data packets (PDUs).
- ATT/GATT simplicity means that firmware may offer some degree of ATT/GATT assistance, saving the microcontroller software from the trouble.
- For software-based stacks, ATT/GATT may be implemented only once in stack itself, saving applications from the trouble.
- There may be profiles for which ATT/GATT is not ideal as the application protocol. But there can always be a second L2CAP connection in parallel with ATT channel, which in turn implements a profile-specific protocol.
Now, let's take a deeper look into each protocol.
ATT: Attribute Protocol
The sole building block of ATT is the attribute. An attribute is composed by three elements:
- a 16-bit handle;
- an UUID which defines the attribute type;
- a value of a certaing length.
From the point of view of ATT, value is amorphous, it is an array of bytes of any size. The actual meaning of the value depends entirely on UUID, and ATT does not check if the value length is consistent with a given UUID etc.
The handle is just a number that uniquely identifies an attribute (since there may be many attributes with the same UUID within a device).
ATT itself does not define any UUID. This is left to GATT and higher-level profiles.
An ATT server stores attributes. An ATT client stores nothing; it uses the ATT wire protocol to read and write values on server attributes.
There may be security permissions associated with each attribute. They are stored somewhere inside the value, and are defined by higher-level profiles. ATT itself does not "know" them, and does not try to interpret attribute values to test permissions. This is GATT's (and higher profile's) problem.
ATT wire protocol has some nice features, like searching attributes by UUID, getting all attributes given a handle range and so on, so the client does not need to know handle numbers beforehand, nor the higher-level profiles have to hardcode them.
But handle numbers are expected to be stable for each given device. This allows clients to cache information, using less packets (and less energy) to retrieve attribute values after a first discovery. Higher-level profiles specify how to "hint" a client that a server has changed attribute layout (e.g. after a firmware upgrade).
Most of the ATT protocol is pure client-server: client takes the initiative, server answers. But ATT has notification and indication capabilities, in which the server takes the initiative of notifying a client that an attribute value has changed, saving the client from having to poll the attribute.
The wire protocol never sends value length; it is always implied from PDU size, and client is expected to "know" the exact value layout for the UUID types it understands.
Not sending value length explicitly saves bytes, which is particularly important in Low Energy, since MTU (maximum transmission unit) in LE is just 23 bytes.
The small LE MTU is a problem for large attribute values. For those, ATT has "read long" and "write long" operations, which transfer big attributes in chunks.
ATT adapts to link MTU; it does not limit packet size to lowest-common denominator. For example, a 40-byte attribute demands using the "read long" operation over LE, but can be read atomically over BR/EDR transport since the minimum MTU for the latter is 48 bytes.
ATT is very, very generic, and would leave too much for higher-level profiles to define. Apart from the excess of freedom, there are some open issues, like: what if a device offers multiple services? There is just one ATT handle space for each device, and multiple services must share the space in a cooperative way.
Fortunately, we have GATT, which shapes and delimits usage of attributes.
GATT: Generic Attribute Profile
GATT is a base profile for all top-level LE profiles. It defines how a bunch of ATT attributes are grouped together into meaningful services.
GATT services
The cornerstone of a GATT service is the attribute with UUID equal to 0x2800. All attributes following this belong to that service, until another attribute 0x2800 is found.
For example, a device with three services might have the following attribute layout:
| Handle | UUID | Description |
|---|---|---|
| 0x0100 | 0x2800 | Service A definition |
| ... | ... | Service details |
| 0x0150 | 0x2800 | Service B definition |
| ... | ... | Service details |
| 0x0300 | 0x2800 | Service C definition |
| ... | ... | Service details |
Each attribute does not "know" by itself to which service it belongs. GATT needs to figure it out based on handle ranges, and ranges are discovered solely on basis of UUID 0x2800 "cornerstones".
Suddenly, the handle value becomes significant. In the example, for an attribute to belong to service B, it must lie between 0x0151 and 0x02ff.
The UUID 0x2800 defines primary services. There are secondary services, too (UUID 0x2801), which are meant to be included by primary services.
Ok, how do I know if a given service is a thermometer, of keyfob, or GPS? By reading its value. The service attribute value contains an UUID, the service UUID.
So, each service definition attribute has actually two UUIDs in its body: 0x2800 or 0x2801 as attribute UUID, and another one stored in value, which specifies the service.
For example, suppose an hypothetical LE thermometer service has UUID 0x1816. The complete service attribute becomes:
| Handle | UUID | Description | Value |
|---|---|---|---|
| 0x0100 | 0x2800 | Thermometer service definition | UUID 0x1816 |
| ... | ... | Service details | ... |
| 0x0150 | 0x2800 | Service B definition | 0x18xx |
| ... | ... | Service details | ... |
| 0x0300 | 0x2800 | Service C definition | 0x18xx |
| ... | ... | Service details | ... |
This sounds a bit confusing at first; two UUIDs to define a single service? It is a result of layered GATT/ATT approach. The UUID 0x2800, which is well-known by GATT, is used to search for service boundaries. Once they are found, the attributes are read and the second UUID (stored as value) specifies the service. So a client may find all GATT services without knowing the specifics of e.g. a thermometer service.
Important note: the thermometer UUID 0x1816 is not real. There is no official profile for an LE thermometer, at the time this article was written!
GATT service characteristics
Each GATT service has a number of characteristics. The characteristics store useful values for the services, as well as their permissions.
For example, a thermometer would likely have a "temperature" characteristic, which is read-only, and possibly a date/time for timestamping, which is read/write.
| Handle | UUID | Description | Value |
|---|---|---|---|
| 0x0100 | 0x2800 | Thermometer service definition | UUID 0x1816 |
| 0x0101 | 0x2803 | Characteristic: temperature | UUID 0x2A2B Value handle: 0x0102 |
| 0x0102 | 0x2A2B | Temperature value | 20 degrees |
| 0x0110 | 0x2803 | Characteristic: date/time | UUID 0x2A08 Value handle: 0x0111 |
| 0x0111 | 0x2A08 | Date/Time | 1/1/1980 12:00 |
First off, there may be several characteristics per service, and each handle ranges for each characteristic are discovered by GATT the same way it does for services: by finding the "cornerstone" attributes.
The main characteristic attribute has UUID = 0x2803. As happens with services, this attribute has "double UUIDs": the generic one (0x2803) which allows for easy discovering, and the specific one (in example: 0x2A2B for temperature) which tells exactly which information the characteristic contains.
Each characteristic has at least two attributes: the main attribute (0x2803) and a value attribute that actually contains the value. The main attribute "knows" the value attribute's handle and UUID. This allows for a certain degree of cross-checking.
The actual value format is entirely defined by its UUID. So, if the client knows how to interpret the value UUID 0x2A08, it is capable of reading date and time from any service that contains such a characteristic. In the other hand, if the client does not know how to interpret a certain value UUID, it may safely ignore it.
Important note: the thermometer service layout shown in table is completely fictitious. It was put together just to explain the concept of characteristics. If you are going to implement a true thermometer, please grab and read the official spec.
Characteristic descriptors
Apart from value, we can hang more attributes in every characteristic, if we need them. In GATT lingo, those extra attributes are called descriptors.
For example, we may need to identify the temperature unit of our thermometer, and this may be carried out by a descriptor:
| Handle | UUID | Description | Value |
|---|---|---|---|
| 0x0100 | 0x2800 | Thermometer service definition | UUID 0x1816 |
| 0x0101 | 0x2803 | Characteristic: temperature | UUID 0x2A2B Value handle: 0x0102 |
| 0x0102 | 0x2A2B | Temperature value | 20 degrees |
| 0x0104 | 0x2A1F | Descriptor: unit | Celsius |
| 0x0110 | 0x2803 | Characteristic: date/time | UUID 0x2A08 Value handle: 0x0111 |
| 0x0111 | 0x2A08 | Date/Time | 1/1/1980 12:00 |
GATT "knows" that handle 0x0104 is a descriptor that belongs to characteristic 0x0101 because
- a) it is not the value attribute, since the value attribute is known to be 0x0102; and
- b) it falls into the range 0x0103..0x010F, which falls between one characteristic and the next.
The descriptor value is interpreted accordingly to attribute UIID. In the example, descriptor's UUID was 0x2A1F. A client may safely ignore a descriptor whose UUID is unknown. This allows for easy extension of a service, without breaking old clients.
Each service may define its own descriptors, but GATT defines a set of standard descriptors that cover most cases, for example:
- Numeric format and presentation;
- Human-readable description;
- Valid range;
- Extended properties;
and so on. One particularly important descriptor is the client characteristic configuration.
Client Characteristic Configuration descriptor
This descriptor, whose UUID is 0x2902, has a read/write 16-bit value, which is meant to be a bitmap.
It is not some kind of client-side descriptor. It is server-side as any other attribute. But the server is required to store and present a separate instance of the value for each bonded client, and each client can only see its own copy. Hence the name.
First two bits of CCC are already taken by GATT specification. They configure characteristic notification and indication. The other bits might be used for other functions, but they are currently reserved.
Remember that ATT has notification capabilities, so the client does not need to poll for updates? By setting CCC, the client tells to server that it wants to be notified when the characteristic changes. It makes all sense for e.g. a thermometer. Let's see the thermometer service layout with CCC included:
| Handle | UUID | Description | Value |
|---|---|---|---|
| 0x0100 | 0x2800 | Thermometer service definition | UUID 0x1816 |
| 0x0101 | 0x2803 | Characteristic: temperature | UUID 0x2A2B Value handle: 0x0102 |
| 0x0102 | 0x2A2B | Temperature value | 20 degrees |
| 0x0104 | 0x2A1F | Descriptor: unit | Celsius |
| 0x0105 | 0x2902 | Client characteristic configuration descriptor | 0x0000 |
| 0x0110 | 0x2803 | Characteristic: date/time | UUID 0x2A08 Value handle: 0x0111 |
| 0x0111 | 0x2A08 | Date/Time | 1/1/1980 12:00 |
As usual, GATT knows that CCC belongs to temperature chraracteristic because the handle falls into the range (0x0102..0x010F). And it knows it is CCC because of the distinctive UUID (0x2902).
Service discovery in Low Energy
Since GATT puts all service details on ATT, there is no need for a separate service discovery protocol (SDP), like we have in BR/EDR. The ATT protocol is used for everything: disconvering services, finding services' characteristics, reading/writing values, and so on.
GATT and vanilla Bluetooth
GATT works over BR/EDR, but specification mandates that service discovery must still happen via SDP, even if the service (or the profile) uses GATT for actual data exchange.
The idea is to segregate LE-only services from dual-mode ones, without having to flag. If a service can only be found via GATT, it is LE-only. If it can be found via GATT and via SDP, it is dual-mode.
If a given profile uses GATT for data exchange and is meant to be dual-mode, it must publish a SDP record, which contains the ATT handle range for the service. So, the service itself is discovered via SDP, and from that moment on GATT is employed to find the characteristics.
Currently, there is no profile that is dual-mode. "Old" profiles are BR/EDR-only and have not been adapted to GATT; and LE profiles in current development are LE-only.
If one wants to test GATT and does not possess LE hardware, he will need to patch the Bluetooth stack in so GATT discovery is carried out over BR/EDR. This violates the spec but it is very useful for developers.
ATT GATT Profile的更多相关文章
- 低功耗蓝牙ATT/GATT/Profile/Service/Characteristic规格解读
什么是蓝牙service和characteristic?到底怎么理解蓝牙profile?ATT和GATT两者如何区分?什么又是attribute?attribute和characteristic的区别 ...
- (一)GATT Profile和GAP 简介(目前所有的BLE应用都基于GATT,所以也要了解是怎么一回事)-转发
个人大总结:(先后顺序) 1.GAP协议定义多个角色(其中就有中心设备[GATT客户端](唯一)叫主设备||和外围设备[GATT服务端端](多个)也叫从设备). 2.先经过GAP协议,再有GATT协议 ...
- 【转】GATT Profile 简介
网上关于讲解 BLE 的内容比较少,看到这篇文章写的非常详细 Introduction to Bluetooth Low Energy,作为 BLE 的入门时介绍是非常合适的.本文主要翻译了一下这篇文 ...
- iOS - GATT Profile 简介
1.引言 现在低功耗蓝牙(BLE)连接都是建立在 GATT (Generic Attribute Profile) 协议之上.GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短 ...
- 蓝牙BLE: GATT Profile 简介(GATT 与 GAP)
一. 引言 现在低功耗蓝牙(BLE)连接都是建立在 GATT (Generic Attribute Profile) 协议之上.GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很 ...
- 低功耗蓝牙 ATT/GATT/Service/Characteristic 规格解读
什么是蓝牙service和characteristic?如何理解蓝牙profile? ATT和GATT两者如何区分?什么是attribute? attribute和characteristic的区别是 ...
- BLE GATT 介绍
做 BLE 快两年了,想想刚开始自己查各种资料学习的时候也是有很多感慨,记得最清楚的就是 GATT 这个东东,当时完全搞不懂,什么是服务?什么是特征值?什么是 UUID?最近感觉对这些概念又有点混乱了 ...
- Bluetooth GATT介绍
目录 1. 介绍 2 内容 2.1 Configured Broadcast 2.2 GATT Profile Hierarchy 3 Service Interoperability Require ...
- 蓝牙 BLE GATT 剖析(一)
一.概述 The Generic Attribute Profile (GATT) defines a service framework using the Attribute Protocol. ...
随机推荐
- mssql 置疑的处理
declare @dbName sysName ALTER DATABASE @dbName SET EMERGENCY ALTER DATABASE @dbName SET SINGLE_USER ...
- IL中的栈和闪电的Owin推荐
最近几天有幸得到闪电大哥的指点,了解了EMIT和IL中的一些指令.虽然有高射炮打蚊子的说法,但是我相信“二八定律”,80%的功能可以用20%的技术解决,20%的功能只能用80%的技术解决.大哥的博客: ...
- python内建函数-数字相关
本篇对于数字有关的内置函数进行总结. 数字包括 int() , long() , float() , complex() ,这些函数都能够用来进行数值类型的转换.同时这些函数也接受字符串参数,返回字符 ...
- [原创]PostgreSQL Plus Advanced Server监控工具PEM(一)
一.概述 PEM是为数据库管理员.系统架构师和性能分析师为管理.监控和优化 PostgreSQL 和 EnterpriseDB 数据库服务器设计的图形化管理工具.旨在解决大量数据库服务器跨地域.精细化 ...
- android开发中经常遇到的问题汇总
大家都在为项目开发成功而喜悦,但可不知成功的路上是会经常出错的,下面是我碰到的一些错误集合! [错误信息] [2011-01-19 16:39:10 - ApiDemos] WARNING: Appl ...
- swift 命令行工具初探
亲爱的同学们好,今天我们要介绍这么一个东西.相信有过解释型语言(PHP,Ruby,等)使用经验的同学会更加熟悉,就是 Swift 也为我们提供了命令行运行工具,俗称 REPL.好了,我们进入正题,在安 ...
- 无法加载一个或多个请求的类型。有关更多信息,请检索 LoaderExceptions 属性
一解决方法: 问题的主要原因出在:跨程序集反射. 即我们需反射的A.dll的程序集引用B.dll程序集,而在反射工具项目中却不存在对B.dll程序集的引用.因此我们只需在反射工具项目中添加对B.dll ...
- html标记列表应用
一.[ul]无序列表 1.无序列表====== 二.[ol]有序列表 1.有序列表用于段落有序的排列, <ol> <li>内容</li> </ol> 三 ...
- InputStream和OutputStream与String之间的转换
//1.字符串转inputstream String str="aaaaa"; InputStream in = new ByteArrayInputStream(str.getB ...
- 开发中可能会用到的几个 jQuery 小提示和技巧(转)
今天,我们将分享一些很有用的技巧和窍门给 jQuery 开发人员.jQuery 是最好的 JavaScript 库之一,用于简化动画,事件处理,支持 Ajax 和 HTML 的客户端脚本.网络中有大量 ...