一、前言
1、推荐资料
《Core_5.x》英文,蓝牙sig官网就能下载到的规范文档
《Bluetooth Low Energy The The Developer’s Handbook》:英文,最初蓝牙4.0制定人之一写的,外国人写的书就是啰嗦了一些但是能解惑
《低功耗蓝牙开发权威指南》:中文,前一本书的翻译版,英文阅读ok的建议直接看英文的,不行的就这个跟上面那个对照着看,本人看中文版的有些名词看了不知道是对应啥,回去翻英文的才知道是哪个东西毕竟平时工作看到的名称都是英文的
《BLE4.0低功耗蓝牙协议总结》:csdn上看到的一个文档,看目录跟内容似乎也是读的上面那本书但是作者的个人的总结。
其他的概念问题遇到了在网上搜索或者找文档,另外有条件可以通过抓取空中包来加深理解,再不济导出手机的hci log包也行,总会有收获,如果对协议栈很有兴趣可以看开源的例如乐鑫的sdk则能看到host这部分,乐鑫sdk也有使用开源协议栈:bluedriod、nimble。
gitee上甚至能下载到一份nimble代码能跑的host+controller代码,硬件使用的是nrf52832,这部分在csdn能看到有同学做的代码笔记,然后网上有博客写的比较好的文章是这位大佬:Jayden's Blog (jdhblog.com)。
其他资料如博客园有个文章写的也不错的这:iini - 博客园 (cnblogs.com),https://www.cnblogs.com/simpleGao
以下内容为个人查资料解答疑惑后的总结和记录,从下到上的介绍原理和应用场景,可能存在错误。
2、学习的目的
学习和记录的目的是为了了解,为了解答使用过程中遇到让人疑惑的现象,但是很细节的没去纠结因为个人把蓝牙当作工具,跟串口,tcp接口之类一样对待。除非工作有这个需求,例如需要去对协议栈(host)做优化做改动,或者说能看到协议栈(host)但是遇到了问题需要人为去跟进去追究。原则是能查能记录的绝不背起来。
二、射频原理
大学的专业是电气工程及其自动化,对无线没什么概念,因此第一次接触的时候第一个问题就是:
1、空气中是如何传递数据的?
对于串口,网口,之类有线的总线的原理好理解,例如通信两端通过一根物理的导线连接,当需要发送二进制数据如10100101的时候,发送方只需要通过控制导线的电平为高或者低,接收方则根据读到的低或者高来判断数据是1还是0。但是对于空气中二进制数据又是怎么传递的,这里在B站看到一个形象的视频:
总的来说就是电子在天线(ant)上的快速移动产生的电磁波,这点好理解高中的时候物理老师会说“电生磁”和“磁生电”,数字信号通过天线对外发射电磁波,这个电磁波被另一个天线接收,再转换成数字信号,完成一次通信。无线通信系统简略框图如下:
图片来自网络:无线通信基本原理_无线通信原理-CSDN博客
到这里只是解答了数字信号是通过转换为模拟信号(电磁波)发到空中,即上图中的“射频发”和“射频收”,但是又怎么通过电磁波区分bit数据呢,例如有线的时候可以通过电压(例如大于3.3v是1,小于2.4V则是0)。
2、如何利用电磁波传递0和1
这里就回到解释上图中的编码和调制了,编码的种类有很多种这里不关心这个,将这步理解为得到机器码数据(如101010这样的二进制数据),调制则是将需要传递的二进制数据放入高频载波信号再传递(例如蓝牙则是2.4G~2.48G频段),这里又得到一个新问题,为啥要将有用的数据通过调制再发送,后面再解答这个问题。
调制又分为好几种,有模拟调制,数字调制,每种调制又有更具体的调制方式,但是原理上分为三种,幅值,频率,相位,把传递的电磁波的基带信号理解为一个正弦波的话,那可以把有用的信息通过修改这个载波信号的幅值,频率,相位来区分bit0或者bit1,不同的原理又有其产生的历史,优点,缺点。感兴趣的可以去查资料,这里我们只需要知道蓝牙使用的是 高斯频移键控( Gaussian frequency-shift keying),这种调制方式区分1和0的方式如下图(这里以第一个信道为例子):
负频偏代表0,正频偏代表1,最小频偏为185khz。做过蓝牙产品的应该都会听到硬件说“频偏校准”这个词,这个应该跟这里有关系,试想如果频率不准确那接收的数据也没法保证正确。
3、校准相关
这部分为个人理解,不一定准确,规范里有提到一个叫“直接测试模式”的东西
如框图里,UT通过发指令控制DUT(理解为待测设备)跟LT(理解为参考设备)做相应的操作,例如控制LT往某频段里发1010101这样的数据,控制DUT做接收,或者反过来,理论上就能验证DUT是否正常,通过一些方法来验证频率偏差多少,但是可以确定的是软件只能纠正细微的偏差,例如待测设备晶振的频率就不准确那设备的频率怎么会准确。
这里又有个问题,如何保证LT的频率是准确的?以前因为一些工作原因在代理商那边验证天线的问题,大概原理是这样,先设置待测设备的一直往固定频点发送数据,那频谱仪上应该能看到该设备天线的在某频率通道上有个‘尖’代表活跃在这个频点,这样就能验证待测设备是否频偏正常。例如设置了2440M这个频点,那如果实际上偏差了一点点例如2445,那么就通过设置软件校正让它往低频段偏移到正确的范围,但是如果偏太大的话则不行,可能是晶振有问题了。
此外这种方式也能确认发射功率是否正常,例如设置发射功率为5dbm,但是实际上频谱仪上验证发现只有0dbm,这时候则需要调整天线的阻抗参数,这里原理大概是当阻抗匹配的时候天线部分电路产生谐振,这时候天线效率能达到最大(这里也是查资料才了解)。无论用哪家方案厂家都会提供一套校准的方案如上图那样,例如炬芯的方案就跟上图几乎一样了。
4、为什么需要把需要传递的数字信息通过调制后再发送?
现在回到前面那个问题,例如蓝牙为什么需要加载在2.4G频段的基带信号再发送?这里回到高中物理学到的一个公式,
电磁波传递速度这里默认为等于光速的话,频率越低,波长就越长,如果说我们需要传递一个48Khz的音频信号,那波长会是好几公里,我们总没有这么长的天线吧?第二个好处是抗干扰,空气中存在着许多不同频率的电磁波,通过将信号加载再固定的高频载波上再传递,同时也是避开了其他频段的干扰。但是同一个环境里,2.4G~2.4835G频段上还有其他设备使用例如其他蓝牙设备或者wifi设备,怎么能说加载在这个频段上就避开了干扰呢?为了解答这个问题,就是解答蓝牙有哪些避开这些干扰的策略了,这里又留下一个问题。
网上能查到的其他好处个人没get到,这里没记录。
到这里了解到蓝牙传递信息的物理介质是电磁波,那电磁波传递的缺点,蓝牙都会存在,感兴趣的可以去网上搜索这里不展开描述。
5、蓝牙使用的频段为2.4G频段,这个频段有什么优点?
2.4G~2.4835G频段(ISM)免费不需要授权,在任何国家都通用的频段。
下面再记录几个物理概念。
6、射频信道
ble将ISM频段划为为40个频段,如下图:
中心频率为(f=2402+k*2MHz,k=0, ··· ,39),共40个RF信道,不同频段之间中心频点差距为2M带宽,对于经典则有79个频段,中心频段之间差距为1M带宽。其中ble广播信道有3个,分别对应图中的37,38,39,数据信道0~36个。随机(伪)跳频算法能通过定时切换信道的方式来减少同个环境中不同无线设备之间(例如同蓝牙或者wifi设备)带来的互相干扰,wifi的话如下图:
此外目前的蓝牙芯片厂商制造的射频控制器(controller)可以实时识别信道的好坏(这里就是不同厂家自己的算法),如何通过对信道的重映射指令和远端设备更新信道的使用表,例如某几个信道收到环境干扰,然后射频控制器检测出这几个信道有问题然后和远端设备沟通更新信道表,这样后面就能跳开着几个频段,着叫自适应跳频(AFH).目前了解过的做耳机的芯片都有这类功能。前面说了2.4G~2.4835G频段是免授权的,那这个频段将会比较拥堵,因为用的人多,所以抗干扰的策略影响了用户体验,例如我买的某家骨传导耳机在办公室听歌,附近的测试同事在使用蓝多台设备煲机的时候会经常卡。
7、发射功率
衡量发射机发射的强度,可以在频谱仪上直观看到。前面说ISM信道免费的不需要授权但是也不能为所欲为,发射功率有限制,对于ble最大发射功率为+10dbm,最小则为-20dbm,不过目前遇到的只有出口的需要设置最大不能超过+10dbm,跟当地政策有关。10dbm对于发射功率为10mW,-20dbm对应10uW。
8、灵敏度
量化衡量接收机是否‘足够好’,简单来表达就是天线能识别周围的最小电磁能量,通常以dBm为测量单位。但是只是能检测也是无意义的,还要能正确解码,所以蓝牙的灵敏度指的是最小的能识别的电磁能量,且能解码误码率<=0.1%。
二、大体框架
1-方案设计的常见框图
(以下图片来自:三种蓝牙架构实现方案(蓝牙协议栈方案) - iini - 博客园 (cnblogs.com),建议阅读原文):
双芯片标准架构,常见的例如手机,电脑。
单芯片方案,单颗soc解决全部,例如消费电子,国产还是国外的一大堆,例如nrf52832等.
非上面两种的都是属于第三种。
2-软件设计上的框图
下图来自规范5.2文档:
但是看nimble代码的时候,感觉更倾向于这张,这里以一个例子来了解,后面有机会了解其他的也好上手。
下面结合第二张图从下往上记录做的内容。
三、软件内容
协议的东西从上往下就是一层一层的打包,例如网络协议,规范只定义行为,每层维护自己的负责的内容,在这里蓝牙也是类似的,这里不详细记录协议字段相关的内容,能用工具解析数据绝不自己挨个字节分析。了解这个东西的重点是:规范定义的是一系列规则,规则就是规则,内部具体如何实现无所谓,但是对外的表现,和外部交互的时候,就必须遵守规则,否则就没法和外部正常通信。
1、controller
phy(物理层):实际控制RF的部分,指定BLE所用的无线频段,调制解调方式和方法等。不同的phy也决定了其最大速率,例如蓝牙4.2和之前的le只支持1Mbps PHY的速率,蓝牙5.0开始则支持2M的PHY。
LL(链路层):实际负责控制广播,扫描,建立并且维护连接,以及确保数据能够按照正确的方式组织、正确的计算校验值以及加密序列。链路层有自己的报文格式,定义了两种信道,无连接的广播信道,有连接的数据信道。数据信道中允许一端向另一端发送数据、响应并且在需要时重传,链路层里两个序号字段(SN和NESN)用于判断是否丢包重传。在nimble代码里这部分看到这层做了个很重要的事情(虽然nimble这里的ll是跟ble_phy.c这个文件配合但是这里还是将它理解为LL层的一部分)保证数据在该发送的时刻发送,该切换成接收的时候切换为接收,接收的时候又怎么向上传递(例如nrf52832这里有些如检测地址接受完整,crc校验通过等都是硬件实现,具体可看其手册)。这里也好理解,因为蓝牙是半双工,天线只有一根,在天线为tx状态的时候发送,为rx的时候接收,连接的两边互相配合,根据信道表和跳频的步数(step)协商好下次通信的频段。
链路层数据的字段里还有个4字节access address,环境中多个设备在空中互相通信的时候这个就是唯一标志,连接的时候由主生成和确定的一个随机的地址,然后接下来主跟从之间就使用这个地址。对于广播数据的这种无连接的access address为固定的0x8E89BED6,到这里是不是发现跟网络协议里的ip协议有些像,里面广播也是有个固定的地址,通过ip地址跟网卡的mac地址找到唯一的一个通信设备,而蓝牙再上一层还有个固定的设备地址。
链路层实际上也维护了一个状态机,如下图:
其中isochronuous broadcasting跟synchronization是5.2引入的特性,主要是用于le audio,链路层在同一个时刻只能处于一个状态,这里介绍一下其他常见状态:
standby:理解为空闲状态,不发也不收数据。
advertising:广播状态,往广播的物理信道发送数据并且可能监听和响应数据。
scanning:从物理信道里监听广播的数据包。
connection:顾名思义就是连接状态。
initiating:监听目标广播信道的状态,可随时切换到连接状态或者空闲状态。
进入连接状态后又定义了两个角色:central role 和 peripheral role。central 确定rf发射的时间电,与此相反的为peripheral,这两个词对于使用过ble的应用开发者不会陌生。
上面这个图有一定参考意义,这里以nrf52832的官方demo代码为使用举例子,在作为peripheral设备的时候,需要启动广播需要调用一个参数的init函数来设置adv和rsp的参数,然后再调用adv的start函数,然后就能拿手机搜到它的广播信息了,这时候想修改广播的数据再调用init是不行的,得先按上图的逻辑,先调用adv的stop切换到standy,再调用init,然后再调用start函数回到advertising状态;另一个例如在连接状态下,然后出现断连了会收到一些disconnect事件,会看到这个事件下面会再调用一次adv的start,因为disconnect后按照上图的逻辑是切换到standy状态而不是其他所以还得再调用一次adv的start;52832的官方代码有一定参考价值,包括下面介绍一些协议层次也能在代码里看到,是按照官方定义的层次,包括接口所在的文件命名这些都比较好理解。
HCI:如前面所述,对于一些方案这层没有这么清晰,在nimble使用52832的代码里hci实际上就是传递消息用,内存作为hci的传递接口。规范了host跟controller之间的一些通信协议,看规范里的框图,通过hci发送的数据主要有以下几种:
1、cmd/event(C/E),cmd主要是向controller发指令,event则是controller向host上报事件,
2、acl链路,双向交互数据用,例如耳机播放音乐的时候也是通过这个链路,配对,att之类都是通过这个。
3、sco链路,目前只了解到耳机打电话的时候通过这个链路,跟acl的区别的话个人理解是sco的优先级高,可靠,acl则相对优先级低,不可靠,
4、iso链路,这里不讨论。
2、host
这部分是一个纯软件的东西,那理解为纯逻辑的内容。
2.1、L2CAP(logic link control and adaption protocol):
对链路层的数据进行了封装,规范对这部分的作用描述是:多路复用,分段和重组,服务质量(如重传,流控)。这层定义了多通道,每个通道有自己的ID(CID),在ble里用的都是固定的通道,感兴趣可以看规范.把L2CAP之上的协议理解为网络协议里的应用协议的话(如http,mqtt等),L2CAP就跟TCP一样是个传输协议,那这里这个CID对应的就是端口号。部分CID如下图:
下面介绍下规范定义的功能:
多路复用:理解为上层多个功能协议都用这一层,往下层丢(从上面框架图看的话le除了gap)需要通过这层。
分段和重组:理解为l2cap可控制了每次能往链路层丢多少,例如从上往下丢多了就被切成多段再丢,也就是分段了,最后接受方再重新拼凑从下往上传则就叫重组。
服务质量控制:也好理解都能控制发多少了管通信速度这些也是ok的。
这里感兴趣的可以看看开源代码怎么实现,多通道在nimble里的逻辑就是一段段内存,有需要就分配一段,定义该段内存为某CID。另外nimble里有个内存叫sig指的就是上面的CID为0x0001的通道。下面要介绍的ATT协议的CID为0x0004,通过这个字段解析里l2cap协议的payload数据为att的数据。
2.2、ATT(Attribute protocol):
定义了用户命令及操作的数据。定义从机作为服务端,而主机作为客户端,客户端去发现服务端支持哪些功能,定义的是一个规范,一个基础通讯框架,这里解答几个问题来理解att协议:
1、既然att是协议,那它是如何描述"属性"的?
为了有个感性化的理解,这里先下载一个手机的ble工具,例如nrf connect,随便连接上一个设备会看到一个可视化界面,我连接的是我的华为手环,如下图
属性句柄(att Handle):16bit的整数,做过应用的无论哪个方案,应该都好理解,无论是实际的连接还是att的某个服务,我们获取到的都是一个handle,就像指针一样通过这个handle的值应用之下就能找到跟这个连接相关的一切内容。
属性类型(Att type,即UUID):没错就是图里的这个uuid,可以看到有两种uuid,一种很长的(128bit)是2个字节(16bit)的。有个特殊的128bit-uuid
00000000 – xxxx – 1000 – 8000 – 00805F9B34FB,可以使用16-bi来代替128-bit的UUID,例如0000xxxx – 0000 – 1000 – 8000 – 00805F9B34FB=xxxx。其中有一些是标准的有sig定义的,上图例如“heart rate”是这个app显示出来的,只是因为他的uuid是0x180d,所以手机app就显示0x180d,其他有字符显示的也是一样,基于标准的东西这个app就会给你显示出来,但是协议就是协议,只是定义了规范,实际上是不是个heart rate取决于连接双方怎么处理它例如就不想按照规范。
属性值(Att value):上图中的Value,属性中存储数据实际位置,实际上不请求上图是看不到value那一行,长度为0~512
属性权限(att Permission ):例如上图中可以看到有的显示Read,write,就是指其操作权限
2、客户端如何发现服务端支持哪些"属性"?
说的话描述太麻烦,这里上个抓包文件,抓的手机跟设备通讯的hci log,用wireshark 或者 frontline打开,有需要的可以下载下来。流程大概理解但是不熟悉,看主和从交互的流程大概就能理解代码会怎么写。
链接: 百度网盘 请输入提取码 提取码: igev
相关的字段看规范或者百度应该都能搜到,例如这个:https://www.cnblogs.com/yeshenmeng/p/10819339.html
大概就是以handle作为标签,主跟从获取,从会回复一个handle的范围(0x0001-0xffff),例如上面的手机截图,从上往下每个att属性之间的handle都是差1,然后主机挨个挨个跟从,通过传递handle值的范围,从响应相关的属性,主收集完了后就得到了一个属性表然后可视化的界面显示就如上图。
att不同的“权限”支持不同的操作,另外att的操作指令(上面抓包文件att协议里的opcode)也定义了不同的操作规则,例如command可以不等待对方响应就能马上发送下一条att数据,indicate却得等对方响应了才能继续发送,具体能容易查到的这里不重复介绍。
3、其他
1、主发现从的服务的时候,回复的包里只能是16bit的att或者128bit的att数据而不能是两种混着来,为了提高效率定义的时候可以将16bit的放在前面,128bit的放在后面。
2、交互att的mtu之前,默认都是最短23字节,能支持最长的mtu,除了跟host有关,也跟链路层有关,以通讯两边最短的为准。
2.3、GATT(Generic attribute profile):
att之上的一层协议。服务(Service)、特征(Characteristic)和描述符(Descriptor)的概念规定了它们如何被组织和管理。上面讲att部分的那个图片里面我们也能看到这几个单词。profile这词经常看到,大概意思还是‘规范’,例如有心率(heart rate),在蓝牙的官网里能下载相关的规范文档,个人理解这就是profile,所以这里将profile理解为规范,因此这里将gatt的作用理解为对att协议的数据赋予含义,还是以上面的图片为例子,为什么手机会把uuid是0x180d跟他下面的Characteristic都显示上心率相关的内容,我们在att协议上的时候看到的就是一堆数据而已吗?因为心率的profile赋予了它心率的含义。
2.4、SMP(Secure manager protocol):
管理BLE连接的加密和安全.个人觉得安全相关是最难理解的,要理解加密和安全需要有一些密码学了解,类似的东西看过几次每次都看的懵一知半解,这里只回答两个问题,通过找到这两个问题的答案来了解这部分,感兴趣的可以查询相关资料(推荐书《图解密码技术》,一些名词看不懂的可以翻这个,对加密算法原理感兴趣也可以翻这个)。
1、smp有什么用?
定义了配对和密钥分发的过程,以及实现这些方法的协议和工具。SM协议负责在蓝牙设备之间建立安全连接,确保数据传输的安全性。通信安全要做的事情主要有三个要点:密钥分配,链路加密,身份认证,smp则完成了这三点。
2、实现加密的原理是什么?
关于加密首先了解两种加密方式,一个叫对称加密,一个叫不对称加密。
简单的理解,对称加密就是秘钥只有一个,叫公钥,发送方把明文通过公钥加密就得到密文,然后发送密文,接受方收到密文后通过公钥解密,得到明文。不对称加密就是有两个秘钥,一个叫公钥,用于加密,但是加密后只能通过私钥解密;两种方式对比的话对称加密速度快效率高。
前面说的两种加密方式都用到了密钥,所以密钥是否泄露,容易破解,跟通讯是否安全息息相关,所以配对的过程主要是在空中如何安全的协商出一个通讯用的秘钥,总不能在设备两边都各输入一个密码吧,当我们使用的蓝牙设备支持配对的时候会发现跟手机在第一次连接的时候比较慢,但是后面回连的时候就很快了,慢的原因就是配对的流程耗时,这里介绍一种配对的方式,来了解这个过程。
第一阶段:在手机和设备acl连接上后,前期通过acl交互数据发现对方支持的配对方法,支持的io能力(例如是否支持数字输入,支持带外通讯等,例如有的蓝牙键盘是真配对的时候,手机或者电脑是真显示6个数字,让键盘这边输入6个数字),然后发现对方支持的时候则会发起加密的启动流程,这个叫pairing(配对)。
第二阶段:利用Dh密钥交换算法,生成一个Dhkey。这里大概逻辑是双方各生成一个公钥一个私钥,明文交换公钥,双方拿到对方公钥后,利用对方的公钥和自己的私钥计算后生成一个共享秘钥dhkey,这里解决了前面说的密钥协商问题,完成了要点之一:密钥分配,避免了明文传输秘钥导致泄露。通过这个dhkey生成一个ltk跟Mac key。
第三阶段:双方使用前面Ltk来使用对称加密通讯,蓝牙对称加密算法使用的是aes128,接下来就是密文通讯了,这里完成了上面说的要点之二:链路加密。前面生成的Mac key则是防止数据被篡改用的,这个叫mitm(中间人攻击),就是说虽然不知道你的密文数据是什么内容但是中间人通过修改你的数据来影响,Mac key可以理解为检验用的,保证数据的一致性,因为中间人没有这个key那它修改了密文后会导致接收方的mic字段检验出错而终止通讯,这里完成了上面说的要点之三:身份认证。
后面回连的时候就能直接使用这个ltk进行加密通讯了,相关内容会被双方保存到各自flash之类非易失的介质,后面回连就直接使用这个ltk,这个叫bonding(绑定),实际上配对的流程会复杂的多,感兴趣的可以看规范。
2.5、GAP(Generic access profile):
定义广播和扫描相关的部分,数据最容易理解的一种,从框图里能看到gap不通过l2cap,是直接通过hci往下层丢的。前面说协议就是规则,当和外部一样使用蓝牙的设备交互的时候就必须要按照sig定义的规则,那这里其实就是设备之间遵守了gap的规则,因此scaning状态的设备能发现advertising状态的设备,做central的设备能向作为peripheral的发起连接,peripheral能向周围发起定向的广播这些都是基于gap的规则。gap跟前面介绍的协议不一样,基于无连接的模型,下面介绍一下定义的两个角色的行为:central 和 peripheral,这部分对于一些小消费电子会接触比较多,然后要清楚一个概念就是连接一定是central向peripheral发起。
1、peripheral:
例如手环,蓝牙鼠标,键盘等作为蓝牙从机的设备都是这个角色。
然后广播又有几种方式,这里网上查资料包括看书发现定义了好几种,这里上我手机的hci log,型号是小米11,是设置广播参数的指令,如下图:
有注意上面有三个字段:directed,scannable,connectable,然后这几个字段会组合成好几种广播模式,这里解释这几个字段不去对这些模式做定义。directed为1的时候是定向广播,顾名思义就是为了快速建立连接(为了能连接connectable字段也要为1),这个模式报文会包含自己的地址跟需要被连接的对方地址,要求是完整的广播事件必须3.75ms重复一次,规范定义是最长持续1.28s,定向广播的设备不能被扫描,用比较高的频率广播来让周围的广播信道充斥报文,如果抓空中包的话会看到连续好多个都是定向广播的报文,目的是快速让主扫描到并且发起连接。scannable就是可扫描,当设置为1的时候,主可以对这个设备发起扫描请求,然后接收到设备响应的广播rsp包。connectable顾名思义这里不解释了。此外还有两个字段平时会用到是 advertising interval注意这是个范围,代表产生一个发广播事件的时间间隔。假如同个环境中多个设备在发广播,为了减少往信道同个时刻发广播包碰撞的概率,实际上发广播的时间是有个随机的小延时,为0~10ms:
一个广播事件产生的时候会往设置了的广播信道里发送广播数据(如上面抓包的图片里就设置了3个信道37 38 39 都为true):
一包广播包的链路层数据的payload有37个字节,其中6个字节为设备地址(mac地址),所以广播数据实际上只能设置31个字节,广播数据的结构是:[len+type+data][len+type+data]...这样的形式,例如下图:
注意的是len是包括type的,type对于的含义在sig的css文档能查到一些详细说明:核心规范补充 |® 蓝牙技术网站 --- Core Specification Supplement | Bluetooth® Technology Website,还有这篇是关于所有分配的字段:分配号码 |® 蓝牙技术网站 --- Assigned Numbers | Bluetooth® Technology Website这里介绍几个我关注过的字段:
type 0x01(flags):指示了设备的发现模式和功能支持,有个字段是le general discoverable,实际发现把这个false后,安卓跟pc的手机系统就不会扫描出设备,但是ios手机还是能扫出,如果想手机都扫描不出来可以考虑把device name字段去掉.
type 0x02~0x07(uuid相关):公开服务,指示包含的功能,实际发现有的soc(如52832)需要连接后发现指定服务的时候得把这个放上去;有些fast pair也需要这个。
type 0x08~0x09(device name):08跟09的区别是一个是完整的名字一个是缩写,就是你拿手机系统搜索到设备的那个名字,如果没设置这个字段你拿一些ble工具会搜到“N/A”这样的名字。
type 0x0A(tx power level):发射功率,这个的用处个人理解是计算信号损耗,例如发射功率为0dbm,然后远端rf通过计算灵敏度发现它为-50dbm可以大概估算距离。
type 0x0D(class of device):告诉远端本机是什么类型的设备,这个字段目前个人只在一个支持fast pair的设备用过,例如window的fast pair把这个字段设置为鼠标设备的时候电脑会提示附近有个鼠标设备是否需要配对。
type 0x0E~0x0F(simple pair相关):例如Google fast pair用到。
type 0x19(appearance):代表这个设备的类型,打开你的手机系统的蓝牙搜索界面,你会看到各种各样的图标,这里只说le的,有的显示一个游戏手柄,有的显示鼠标,就是这个字段的作用。
type 0xff(厂商信息):顾名思义本来是厂商信息,如果需要显示某家公司的需要向sig申请,后来我发现这个字段被各家拿来实现各种功能。
除了广播数据包之外还有个rsp包,同样是只有31个字节,前面说设备在广播的时候会往设置的信道发射广播数据,发送数据后的时候rf为tx,在往一个信道发送数据后rf会短暂的切换到rx,如果这时候收到了扫描请求会响应一个rsp数据包到这个信道,这部分在nimble的代码能看到详细的过程。
讲完现在来讲central.
2、central:
和从机相反的角色,同理作为扫描的一方,也有一些参数,但是这里我用wireshark解析的看的内容不明显,这里截个规范里的图:
le_scan_type:分为主动扫描和被动扫描两个,区别是被动扫描只管监听不主动发出扫描请求,好处是功耗低。
le_scan_interval:扫描间隔,为controller扫描的频率,即间隔多久扫描一次。
le_scan_window:扫描窗口,为一次扫描持续的时间,注意的是扫描间隔必须>=扫描窗口,例如扫描间隔100ms,扫描窗口10ms,那实际上扫描的占空比就是10%。
scanning_filter_policy:扫描过滤策略,例如是否使用白名单等。
实际扫描的时候,也是挨个信道扫描的,只有扫描方在某个信道扫描到了广播方的广播包才算扫描到,所以如果需要对比测试查找设备速度的话,两边都得设置一样的参数(无论是扫描的参数还是广播的参数),并且这里也是个概率的问题,可以通过加大扫描者的扫描窗口,或者加大广播的频率,但是这样也会增加功耗。只有当扫描到目标设备,并且发起连接的时候,会在这个信道上先向从发起一个连接请求,从接收到了后,下次他们就从数据通道上开始交互,一旦主收到从的数据响应了则就认为是成功进入连接状态,如下图,调试的时候发现手点连接瞬间把设备断电会发现手机会显示连接中显示好久,可能是这个原因。
连接请求里会带有很多内容,这里抓一个从机的hci log,如下图:
这是host收到链路层上报的一个连接请求包,大概介绍一下几个参数,connection interval:连接间隔就是两边交互的频率,不同手机支持设置的最短间隔不一样,connection latency:一个延迟参数用于节省功耗用,设置为1的话,那每次通信最少有一次交互为空包,例如你想发两包数据,并且调用了发送的api,那中间一定会有一次是空包,如果设置为了0就没有这次空包。空包能接受功耗的原理可以想象像pwm那样,数据越少耗电的占空比就越小。supervision timeout:没有交互数据认为是断连的时间,例如收到08断连错误码。举个例子,如上设置为5秒后,你把和手机连接中的设备断电,手机得5秒后才认为它真断连了。
白名单:
前面提到了这里就补充一下白名单的概念,这部分是由链路层,也就是controller实现的,对于host来说,它只是通过hci发送白名单的重置,添加,删除等。以nrf52832为例子,假如使用了白名单,则需要将加白名单的设备保存到掉电不会丢失的介质例如内部flash,再需要扫描或者广播期间则需要将白名单添加指令往下层发送,而对于controller来说则要实现“非白名单的设备需要过滤掉”这个逻辑,nrf52832的datasheet里可以看到是支持硬件上就实现这个功能即将白名单设备写入到寄存器但是有数量限制,其他方案可能有区别。但是白名单对于ble广播的一方来说不太友好,因为有的扫描方例如手机,它的设备地址是会动态改变的例如苹果手机。