<p>在这之前我们得先了解一下一些专业词汇:</p>
<p>1、profile<br />
profile可以理解为一种规范,一个标准的通信协议,它存在于从机中。蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器 ,心率计等。每个profile中会包含多个service,每个service代表从机的一种能力。</p>
<p>2、service<br />
service可以理解为一个服务,在ble从机中,通过有多个服务,例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,所以会通过电量的characteristic特征值存在从机的profile里,这样主机就可以通过这个characteristic来读取80%这个数据</p>
<p>3、characteristic<br />
characteristic特征值,ble主从机的通信均是通过characteristic来实现,可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。</p>
<p>4、UUID<br />
UUID,统一识别码,我们刚才提到的service和characteristic,都需要一个唯一的uuid来标识<br />
整理一下,每个从机都会有一个叫做profile的东西存在,不管是上面的自定义的simpleprofile,还是标准的防丢器profile,他们都是由一些列service组成,然后每个service又包含了多个characteristic,主机和从机之间的通信,均是通过characteristic来实现。</p>
<p><strong>一、 引言</strong></p>
<p>现在低功耗蓝牙(BLE)连接都是建立在 GATT (Generic Attribute Profile) 协议之上。GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短的数据段被称为属性(Attribute)。</p>
<p><strong>二、 GAP</strong></p>
<p>详细介绍 GATT 之前,需要了解 GAP(Generic Access Profile),它在用来控制设备连接和广播。GAP 使你的设备被其他设备可见,并决定了你的设备是否可以或者怎样与合同设备进行交互。例如 Beacon 设备就只是向外广播,不支持连接,小米手环就等设备就可以与中心设备连接。</p>
<p>1. 设备角色</p>
<p>GAP 给设备定义了若干角色,其中主要的两个是:外围设备(Peripheral)和中心设备(Central)。<br />
外围设备:这一般就是非常小或者简单的低功耗设备,用来提供数据,并连接到一个更加相对强大的中心设备。例如小米手环。<br />
中心设备:中心设备相对比较强大,用来连接其他外围设备。例如手机等。</p>
<p>2. 广播数据</p>
<p>在 GAP 中外围设备通过两种方式向外广播数据: Advertising Data Payload(广播数据)和 Scan Response Data Payload(扫描回复),每种数据最长可以包含 31 byte。这里广播数据是必需的,因为外设必需不停的向外广播,让中心设备知道它的存在。扫描回复是可选的,中心设备可以向外设请求扫描回复,这里包含一些设备额外的信息,例如设备的名字。(广播的数据格式我将另外专门写一个篇博客来讲。)</p>
<p>3. 广播流程</p>
<p>GAP 的广播工作流程如下图所示。 </p>
<p><img alt="GAP 的广播工作流程" data-entity-type="file" data-entity-uuid="9e449911-4187-4b2e-8aeb-7dc76164d78e" src="/sites/default/files/inline-images/%E5%9B%BE1%EF%BC%9AGAP%20%E7%9A%84%E5%B9%BF%E6%92%AD%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B_0.JPG" /></p>
<p>从图中我们可以清晰看出广播数据和扫描回复数据是怎么工作的。外围设备会设定一个广播间隔,每个广播间隔中,它会重新发送自己的广播数据。广播间隔越长,越省电,同时也不太容易扫描到。</p>
<p>4. 广播的网络拓扑结构</p>
<p>大部分情况下,外设通过广播自己来让中心设备发现自己,并建立 GATT 连接,从而进行更多的数据交换。也有些情况是不需要连接的,只要外设广播自己的数据即可。用这种方式主要目的是让外围设备,把自己的信息发送给多个中心设备。因为基于 GATT 连接的方式的,只能是一个外设连接一个中心设备。使用广播这种方式最典型的应用就是苹果的 iBeacon。广播工作模式下的网络拓扑图如下:</p>
<p><img alt="广播工作模式下的网络拓扑图" data-entity-type="file" data-entity-uuid="7696b0e8-c868-493d-aec7-4ea7ea463f26" src="/sites/default/files/inline-images/%E5%9B%BE2%EF%BC%9A%E5%B9%BF%E6%92%AD%E5%B7%A5%E4%BD%9C%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E7%BD%91%E7%BB%9C%E6%8B%93%E6%89%91%E5%9B%BE.JPG" /></p>
<p><strong>三、GATT</strong></p>
<p>GATT 的全名是 Generic Attribute Profile(姑且翻译成:普通属性协议),它定义两个 BLE 设备通过叫做 Service 和 Characteristic 的东西进行通信。GATT 就是使用了 ATT(Attribute Protocol)协议,ATT 协议把 Service, Characteristic遗迹对应的数据保存在一个查找表中,次查找表使用 16 bit ID 作为每一项的索引。<br />
一旦两个设备建立起了连接,GATT 就开始起作用了,这也意味着,你必需完成前面的 GAP 协议。这里需要说明的是,GATT 连接,必需先经过 GAP 协议。实际上,我们在 Android 开发中,可以直接使用设备的 MAC 地址,发起连接,可以不经过扫描的步骤。这并不意味不需要经过 GAP,实际上在芯片级别已经给你做好了,蓝牙芯片发起连接,总是先扫描设备,扫描到了才会发起连接。<br />
GATT 连接需要特别注意的是:GATT 连接是独占的。也就是一个 BLE 外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就对其他设备不可见了。当设备断开,它又开始广播。<br />
中心设备和外设需要双向通信的话,唯一的方式就是建立 GATT 连接。</p>
<p>1. GATT 连接的网络拓扑</p>
<p>下图展示了 GTT 连接网络拓扑结构。这里很清楚的显示,一个外设只能连接一个中心设备,而一个中心设备可以连接多个外设。ConnectedTopology一旦建立起了连接,通信就是双向的了,对比前面的 GAP 广播的网络拓扑,GAP 通信是单向的。如果你要让两个设备外设能通信,就只能通过中心设备中转。</p>
<p><img alt=" GTT 连接网络拓扑结构" data-entity-type="file" data-entity-uuid="8cbcb097-065e-4a68-bdb6-acb5fb2e20a1" src="/sites/default/files/inline-images/%E5%9B%BE3%EF%BC%9A%20GTT%20%E8%BF%9E%E6%8E%A5%E7%BD%91%E7%BB%9C%E6%8B%93%E6%89%91%E7%BB%93%E6%9E%84.JPG" /></p>
<p>2. GATT 通信事务</p>
<p>GATT 通信的双方是 C/S 关系。外设作为 GATT 服务端(Server),它维持了 ATT 的查找表以及 service 和 characteristic 的定义。中心设备是 GATT 客户端(Client),它向 Server 发起请求。需要注意的是,所有的通信事件,都是由客户端(也叫主设备,Master)发起,并且接收服务端(也叫从设备,Slave)的响应。</p>
<p>一旦连接建立,外设将会给中心设备建议一个连接间隔(Connection Interval),这样,中心设备就会在每个连接间隔尝试去重新连接,检查是否有新的数据。但是,这个连接间隔只是一个建议,你的中心设备可能并不会严格按照这个间隔来执行,例如你的中心设备正在忙于连接其他的外设,或者中心设备资源太忙。</p>
<p>下图展示一个外设(GATT 服务端)和中心设备(GATT 客户端)之间的数据交换流程,可以看到的是,每次都是主设备发起请求:</p>
<p><img alt="GATT 通信" data-entity-type="file" data-entity-uuid="ca0a6a5a-1244-4cba-956d-6e798d447e6f" src="/sites/default/files/inline-images/%E5%9B%BE4%EF%BC%9A%20GATT%20%E9%80%9A%E4%BF%A1.JPG" /></p>
<p>3. GATT 结构</p>
<p>GATT 事务是建立在嵌套的Profiles, Services 和 Characteristics之上的的,如下图所示:</p>
<p><img alt="GATT 结构" data-entity-type="file" data-entity-uuid="b866bc3b-d874-4a8a-8a68-32b743029e9b" src="/sites/default/files/inline-images/%E5%9B%BE5%EF%BC%9AGATT%20%E7%BB%93%E6%9E%84.JPG" /></p>
<ul>
<li>
<p><strong>Profile</strong>Profile 并不是实际存在于 BLE 外设上的,它只是一个被 Bluetooth SIG 或者外设设计者预先定义的 Service 的集合。例如<a href="https://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx" target="_blank">心率Profile(Heart Rate Profile)</a>就是结合了 Heart Rate Service 和 Device Information Service。所有官方通过 GATT Profile 的列表可以从<a href="http://developer.bluetooth.org/TechnologyOverview/Pages/Profiles.aspx#G…; target="_blank">这里</a>找到。</p>
</li>
<li>
<p><strong>Service</strong>Service 是把数据分成一个个的独立逻辑项,它包含一个或者多个 Characteristic。每个 Service 有一个 UUID 唯一标识。 UUID 有 16 bit 的,或者 128 bit 的。16 bit 的 UUID 是官方通过认证的,需要花钱购买,128 bit 是自定义的,这个就可以自己随便设置。</p>
</li>
</ul>
<p>官方通过了一些标准 Service,完整列表在<a href="https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx&q…; target="_blank">这里</a>。以 <a href="https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?…; target="_blank">Heart Rate Service</a>为例,可以看到它的官方通过 16 bit UUID 是 <code>0x180D</code>,包含 3 个 Characteristic:<em>Heart Rate Measurement</em>, <em>Body Sensor Location</em> 和 <em>Heart Rate Control Point</em>,并且定义了只有第一个是必须的,它是可选实现的。</p>
<ul>
<li><strong>Characteristic</strong>在 GATT 事务中的最低界别的是 Characteristic,Characteristic 是最小的逻辑数据单元,当然它可能包含一个组关联的数据,例如加速度计的 X/Y/Z 三轴值。</li>
</ul>
<p>与 Service 类似,每个 Characteristic 用 16 bit 或者 128 bit 的 UUID 唯一标识。你可以免费使用 Bluetooth SIG 官方定义的<a href="https://developer.bluetooth.org/gatt/characteristics/Pages/Characterist…; target="_blank">标准 Characteristic</a>,使用官方定义的,可以确保 BLE 的软件和硬件能相互理解。当然,你可以自定义 Characteristic,这样的话,就只有你自己的软件和外设能够相互理解。</p>
<p>举个例子, <a href="https://developer.bluetooth.org/gatt/characteristics/Pages/Characterist…; target="_blank">Heart Rate Measurement Characteristic</a>,这是上面提到的 <em>Heart Rate Service</em> 必需实现的 Characteristic,它的 UUID 是 0x2A37。它的数据结构是,开始 8 bit 定义心率数据格式(是UINT8 还是 UINT16?),接下来就是对应格式的实际心率数据。</p>
<p>实际上,和 BLE 外设打交道,主要是通过 Characteristic。你可以从 Characteristic 读取数据,也可以往 Characteristic 写数据。这样就实现了双向的通信。所以你可以自己实现一个类似串口(UART)的 Sevice,这个 Service 中包含两个 Characteristic,一个被配置只读的通道(RX),另一个配置为只写的通道(TX)。</p>
<p id=""><strong>更多内容</strong></p>
<ul>
<li>
<p>Bluetooth SIG 官方文档</p>
<ul>
<li><a href="https://www.bluetooth.org/en-us/specification/adopted-specifications&qu…; target="_blank">蓝牙核心协议文档</a></li>
<li><a href="https://developer.bluetooth.org/Pages/default.aspx" target="_blank">Bluetooth Developer Portal</a></li>
<li>官方通过的 <a href="https://developer.bluetooth.org/TechnologyOverview/Pages/Profiles.aspx#…; target="_blank">BLE Profile</a></li>
<li>官方通过的 <a href="https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx&q…; target="_blank">BLE Service</a></li>
<li>官方通过的 <a href="https://developer.bluetooth.org/gatt/characteristics/Pages/Characterist…; target="_blank">BLE Characteristic</a></li>
</ul>
</li>
<li>
<p>移动开发资源</p>
<ul>
<li><a href="https://developer.android.com/guide/topics/connectivity/bluetooth-le.ht…; target="_blank">Android BLE GUIDE</a> - Android developer 官网的入门文章,里面有实例代码和讲解视频。</li>
<li><a href="https://developer.bluetooth.org/Pages/Bluetooth-Smart-Developers.aspx&q…; target="_blank">Application Accelerator Kit</a> - iOS, Android or Windows Phone 移动开发样例</li>
<li>视频: <a href="https://developer.apple.com/videos/wwdc/2012/" target="_blank">Core Bluetooth 101</a> - WWDC 2012 关于 BLE 开发的视频。</li>
</ul>
</li>
</ul>
<p>文章来源:<a href="http://blog.csdn.net/u013378580" id="uid" target="_blank">Session__CSDN</a></p>