专栏首页Android开发者家园Android 蓝牙开发(3)——蓝牙的详细介绍

Android 蓝牙开发(3)——蓝牙的详细介绍

前面的两篇文章,主要是在 Android 官网关于蓝牙介绍的基础上加上自己的理解完成的。主要针对的是 Android 开发中的一些 API 的使用。 第一篇文章 Android 蓝牙开发(1) 主要是介绍了普通的蓝牙在 Android 开发中的运用。 第二篇文章 Android 蓝牙开发(2) 主要是介绍了低功耗蓝牙的开发。 这篇文章主要介绍的是蓝牙的历史和一些关于蓝牙的通用知识,还有广播包的知识。要想彻底了解蓝牙开发,这些基础的知识也是需要的,就像网络协议一样,这些都是基础的内容。我们的 API 的调用都是以这个为基础的,了解这些,开发过程中遇到问题,才可以知道什么怎么一回事。

下篇文章主要讲的就是实际开发中的一些坑。

蓝牙的发展历史

蓝牙技术最初是由爱立信创制的。技术始于爱立信公司 1994 方案,它是研究在移动电话和其他配件间进行低功耗、低成本无线通信连接的方法。发明者希望为设备间的通讯创造一组统一规则(标准化协议)用来解决用户间相互不兼容的移动电子设备。

1998 年 5 月 20 日,索尼以立信、国际商业机器、英特尔、诺基亚及东芝公司等业界龙头创立“特别兴趣小组”(Special Interest Group SIG),即蓝牙技术联盟的前身,目标是开发一个成本低、效益高、可以在短距离范围内随意无线连接的蓝牙技术标准。负责蓝牙规范的制定和推广的国际组织。

1998年推出了 0.7 规格,1999 年推出了 0.8、0.9等等。1999 年 7 月正式公布 1.0 版本,使用 2.4GHz频谱,最高资料传输速度 1Mbps。2001 年的 1.1 版本正式列入 IEEE 标准。

蓝牙其实就是一种近距离无线通信技术。

蓝牙历史版本.png

  • 低功耗蓝牙 BLE 全称是 Bluetooth Low Energy 简称 BLE 。最大的特点就是低功耗,有些 BLE 设备一个纽扣电池可以使用一两年。这对于现在的穿戴设备以及各种物联网传感器来说是一个很大的突破。同时它的传输的数据就很少。
  • 在 Android 4.3 的时候开始支持低功耗蓝牙。仅仅支持中心模式,就是只可以连接其他蓝牙外设。到了 2014 年 Android 5.0 开始也支持周边模式。

协议栈

蓝牙协议栈.png 图片来自网络

从下到上分别为:控制器(Controller)-->主机(host)-->应用(Application)

控制器:协议栈的底层的实现,直接和硬件相关,由芯片厂商实现,包括物理层、链路层、主机控制接口。

主机:协议栈的上层实现是硬件的抽象,与具体的硬件厂商没有关系。

应用层:使用主机层提供的 API 开发的应用。

详细介绍各个层的含义:

  • PHY(Physical Layer)物理层,蓝牙是工作在 2.4GHz 附近,这是工业、科学、医疗 ISM 的频段,免许可证。WIFI 也是工作在同一个频段。蓝牙把频段切分为 40 个通道,其中 3 个广播通道,37 个数据通道,按照一个规律跳频通信。
  • LL(Linker Layer)链路层,用于控制设备的射频状态,设备将处于五种状态之一:等待、广告、扫描、初始化、连接。广播设备不需要建立连接就可以发送数据,而扫描设备接受广播设备发送的数据;发起连接的设备通过发送连接请求来回应广播设备,如果广播设备接受请求,那么广播设备与发起连接的设备将会进入连接状态。发起连接的设备称为主机,接受连接请求的设备称为从机。
  • HCI(Host Controller Interface):主机和控制器就是通过这个接口来进行通讯的,通讯的介质就是 HCI 命令。这层在协议栈中是可选的,一些小型终端可能没有,但是 Android 设备上肯定有,这层是蓝牙上层和芯片的交互必经之路,对于蓝牙硬件开发者,这里的 log 能够很好的帮助解决问题。
  • HOST 部分要复杂。有链路控制和适配层(L2CAP),安全管理(SM)等。重点看属性协议层,也就是 ATT。它是整个 BLE 通信的基础。ATT负责数据封装,向外暴露为 “属性”,提供“属性”的为服务端,获取“属性”的为客户端。ATT 是专门为 BLE 低功耗蓝牙而设计的传输协议,结构简单,传输数据短。
  • GATT(Generic Attribute Profile):全称叫做通用属性配置文件,是基于 ATT 做的进一步的逻辑封装,定义数据的交互方式和含义,APP 开发就是用的这一层。GATT 定义了三个非常重要的概念:服务(Service)、特征(Characteristic)、描述(Descripter)。他们的关系如下图

gatt内部组成.png

一个 Service 可以包含若干个 Characteristic,一个 Characteristic 可以包含属性(properties)和值(value),还可以包含多个 descripter 。Characteristic 实际上具有读、写、通知等权限。我们在对一个 BLE 设备发起连接成功以后,对他进行读写操作,其实就是对 Characteristic 的操作。图中的 Profile 是一组服务的集合,这些服务组个起来就形成了一个特定的使用场景了,里面的服务是嵌入式工作人员可以添加的。BLE 蓝牙使用 UUID 来区分 Service、Characteristic 、Descripter。

  • GAP(Generic Access Profile):通用访问控制配置文件。定义了 BLE 整个通信过程中的流程,负责处理设备访问模式和程序,包括设备发现、建立连接、终止连接等等。GAP 层总是作为下面四种角色之一:(1)广播者:不可连接的广播设备。(2)观察者:扫描设备,但不发起建立连接 (3)外部设备:可连接的广播设备,可以在单个链路层连接中作为从机。(4)集中器:扫描广播设备并发起连接,可以在单链路层连接中作为主机。

应用开发

BLE 应用可以分为两大类:基于非连接的和基于连接的

基于非连接的:

意思就是外设和周边设备不发生连接,主要靠扫描到的广播来获取信息。发送广播的一方叫做 broadcaster 监听广播的一方叫做 oberver 在 GAP 层有对应的角色定义。

网络拓扑图:

非连接网络拓扑图.png

这种方式就是广播设备不断的向外发送广播(含有特定的信息),然后观察者接受到广播按照两者之间约定好的协议进行解析拿到有用的信息。例如:iBeacon,通过这种设备我们可以实现室内定位。

其实这些设备的角色可以即使广播者又是观察者。接收到广播后作出了处理,然后又发送广播。这样就形成了双向的网络,类似于因特网,这就是蓝牙 Mesh 组网。

广播数据包格式:

广播数据包.png

每个广播数据包由 31 byte 组成。分为有效数据和无效数据两部分。

  • 无效数据部分:因为广播数据包的长度必须是 31 字节,如果有效数据不够 31 个字节那么剩下的就用 0 来补全。这一部分就是无效的,也就是无效数据。
  • 有效数据部分:包含若干个广播数据单元,称为 AD Structure。每个 AD Structure 的组成格式是:第一个字节是长度值 Length,表示接下来的 Length 个字节是数据部分。数据分别的第一个字节表示数据类型 AD Type,剩下的 Length - 1 是真正的数据。数据类型很重要,有标准的规定,决定了数据代表什么意思和怎么解析

例子:

E/TAG:scandata:02011A05FFAC0134560000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

这里是扫描的数据包(转换成了 16 进制,两个代表一个字节),第一个字节是 02 表示后面的两个字节是数据部分,然后第二个字节是 01 表示了数据的类型。后面一个字节就是真正的数据了。这个广播数据单元就分析完了。下面就是另一个数据单元了。依次类推,关于数据类型的解释,官网有。

这是数据类型对应的含义表。

基于连接的:

就是两个设备建立 GATT 连接,需要双方进行通信。这里的两个角色是,外设设备(Peripheral)和中心设备(一般是手机)Centeral。

网络拓扑图:

连接网络拓扑图.png

一个中心设备可连接多个外设,但是一个外设只能连接一个中心(外设连接成功后就会停止对外广播,别人就发现不了它了)。其中一个中心设备的连接外设的数量也是有限的。

本文分享自微信公众号 - Android开发者家园(Android_De_Home)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • IDEA Gradle的配置

    安装Gradle 从官方网站下载安装包,解压到目录 设置环境变量 PATH=D:\gradle\gradle-3.4.1\bin GRAD...

    似水的流年
  • 使用idea创建一个web的Gradle项目

    注意:这里Packaging要选war包,这个选项对自动生成的代码有影响,下面会说。

    似水的流年
  • gradle加载本地jar包

    有时,我们需要的jar包不一定能在远程仓库中找到,这时我们需要加载本地的jar包。 加载单独的jar包 在项目底下添加libs目录,将jar包仍进libs目...

    似水的流年
  • gradle项目与maven项目相互转化

    gradle这几年发展迅猛,github越来越多的项目都开始采用gradle来构建了,但是并不是所有人都对gradle很熟悉,下面的方法可以把gradle转成m...

    似水的流年
  • 中国有哪些不错的开源软件产品?

    在知乎上,有个问题问“中国有什么拿得出手的开源软件产品(在 GitHub 等社区受欢迎度较好的)?”

    Rocky0429
  • Flutter实战 | 从 0 搭建「网易云音乐」APP(九、搜索页面、底部播放控制栏)

    本系列可能会伴随大家很长时间,这里我会从0开始搭建一个「网易云音乐」的APP出来。

    Flutter笔记
  • Istio技术与实践04:最佳实践之教你写一个完整的Mixer Adapter

    Istio的功能与作用在之前的文章中已经向大家展示了,基于Istio的微服务治理也必将登上广大云服务供应商的舞台。本文中,我们将会为您重点介绍一下Istio的核...

    CNCF
  • 安卓SDK无法下载、无法联网API下载

    Android SDK无法下载,因为国内google被屏蔽了,需要通过一些服务器进行访问。

    似水的流年
  • 全网首发Spring Cloud Gateway 添加统一前缀功能

    今天学习一下Spring Cloud Gateway,就先再其他博客上逛了逛。遇到有java开发者在某博客问一个问题:Spring Cloud Gateway ...

    码农小胖哥
  • 获取任何小程序源码

    这种方法,并不能反编译出所有的小程序源码,请自知! 具体的局限请看:qwerty472123大神的md文件  https://github.com/qwert...

    似水的流年

扫码关注云+社区

领取腾讯云代金券