1. BLE client和server
通俗地说吧,Server(服务器)就是数据中心,Client(客户端)就是访问数据者。特别说明,它与主/从设备是独立的概念:一个主设备既可以充当Server,又可以充当Client;从设备亦然
Server首先将一个服务按“属性/句柄/数值/描述”这种格式予以组织,然后调用API函数GATTServApp_RegisterService将服务数据进行注册。举个实例吧,设提供一个电池电量服务字节,它允许Client读取,数据为一个8比特无符号数(0~100%),它的组织如下:02 25 00 19 2A, 这5个数据(小端格式)分别是:0x02=只读属性,0x0025=句柄;0x2A19=服务UUID。
句柄(Handle)就是服务数据在数据中心的地址,当所有的服务数据组织起来后,它总得有个先后顺序,某个服务的位置就是它的句柄。还是上面的类比,如果想去图书馆借阅《现代操作系统》,需要查明该书在哪一层楼,哪个房间,这就是该书的Hanle
大致分三类:读取服务的值,需要知道服务的UUID或者Handle;写服务的值,需要知道服务的Hanle;写服务描述符,需要知道该Descriptor的Hanle。
根据服务的UUID调用API函数GATT_ReadUsingCharUUID 协议栈会返回该服务的Handle。特别注意的是,一个服务的Descriptor的Handle总是该服务的Handle+1,如电池电量服务的Handle是0x0025,那么它的Descriptor的Handle是0x0026
蓝牙通信中,Server不能直接访问(读/写)Client,但是可以通知(Notification)Client,通知的前提是Client通过写Descriptor使能通知功能。例如,某Server发现电池电量已经低于安全阀值,它可以调用GATT_Notification通知所有已连接的Client,但是Client接收后如果处理是它自己的事情。
2. RSSI的机制和获取方法
问:如何知道两个蓝牙通信节点之间的距离?
答:要知道蓝牙通信节点(如手机和蓝牙设备)之间的距离,最容易实现的方法是通过读取接收RSSI(Received Signal Strength Indication)值来计算。无线通讯中功率与距离的关系如下: 其中A可以看作是信号传输1米远时接收信号的功率, n是传播因子(它受障碍,温度和湿度等影响),r是节点之间的距离。当确定了常数A与n的值后,距离r就可以根据PR(dBm)计算出来。
问:如何获取蓝牙节点的接收RSSI值?
答:具体的设备接收RSSI值的方法不一样,以iPhone手机为例,iOS提供API函数获取RSSI值;TI公司的CC2540芯片的BLE协议栈中,首先将读取RSSI值回调函数挂载到gapRolesRssiRead_t类型的指针下,建立连接后,主设备调用GAPCentralRole_StartRssi(),从设备调用
GAPRole_SetParameter(GAPROLE_RSSI_READ_RATE, ??)。这样就可以定时读取接收的RSSI值了。
得到指数函数公式为:y = -49.53 – 17.7 ln (x),再把自然对数换成10常用对数,则有:y = -49.53 – 40.71 lg (x)。通过以上几步就轻松得到RSSI与距离之间的计算公式 3. 特征值如何获取,各profile在架构中的作用
1、profile
profile可以理解为一种规范,一个标准的通信协议,它存在于从机中。蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器,心率计等。每个profile中会包含多个service,每个service代表从机的一种能力。
2、service
service可以理解为一个服务,在ble从机中,通过有多个服务,例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,所以会通过电量的characteristic特征值存在从机的profile里,这样主机就可以通过这个characteristic来读取80%这个数据
3、characteristic
characteristic特征值,ble主从机的通信均是通过characteristic来实现,可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。
4、UUID
UUID,统一识别码,我们刚才提到的service和characteristic,都需要一个唯一的uuid来标识
整理一下,每个从机都会有一个叫做profile的东西存在,不管是上面的自定义的simpleprofile,还是标准的防丢器profile,他们都是由一些列service组成,然后每个service又包含了多个characteristic,主机和从机之间的通信,均是通过characteristic来实现。
3.3.1通用访问配置文件(GAP)
BLE协议栈中的GAP层负责处理设备访问模式和程序,包括设备发现、建立连接、终止连接、初始化安全特色和设备配置.
GAP层总是作为下面四种角色之一: 广播者--不可连接的广告设备
观测者--扫描设备,但不发起建立连接
外部设备--可连接的广告设备,可以在单个链路层连接中作为从机. 集中器--扫描广告设备并发起连接,在单链路层或多链路层作为主机. 目前BLE协议栈支持一个集中器连接三个外设.
外部设备广告特定的数据使集中器知道它是一个可以连接的设备。广告内容包括设备地址以及一些额外的数据,如设备名等。集中器收到广告数据后向外部设备发送扫描请求,然后外部设备将特定的数据回应给集中器,称为扫描回应。集中器收到扫描回应后便知道这是一个可以建立连接的外部设备。这就是设备发现的全过程。此时集中器可以向外部设备发起建立连接的请求。连接请求包括下面一些链接参数:
连接间隔--在两个BLE设备的连接中使用跳频机制,两个设备使用特定的信道收发数据,然后过一段时间后再使用新的信道(链路层处理信道切换),两个设备在信道切换后收发数据称之为连接事件。即使没有应用数据的收发,两设备仍然会通过交换链路层数据来维持连接,连接间隔就是两个连接事件之间的时间间隔,连接间隔以1.25为单位,连接间隔的值为6(7.5ms)~3200(4s).不同的应用可能要求不同的时间间隔。长的时间间隔的优势是显著地节省功耗,因为设备可以在连接事件之间有较长时间的休眠,坏处是当设备有应用数据需要发送时,必须要等到下一个连接事件;短的时间间隔优势是两设备连接频发,可以更快地收发数据,不利之处是设备因连接事件的到来而被频繁的唤醒,会有较多功耗.
从机延迟--这个参数的设置可以使从机(外部设备)跳过若干连接事件,这样外设就更加灵活,在没有数据发送时,可以选择跳过连接事件继续休眠以节省功耗.
管理超时--这是两个成功连接事件之间的最大允许间隔,如果超过了这个时间而没有成功地连接事件,设备被认为是丢失连接,返回到未连接状态.这个值的单位是10ms,
管理超时的范围是10(100ms)~3200(32s),另外、超时值必须大于有效的链接间隔(有效的链接间隔=连接间隔*(1+从机延迟)).
外设可以通过向集中器发送”连接参数更新请求”来改变连接设置,这个请求由协议栈的L2CAP层处理,这个请求包含4个参数:最小连接间隔、最大连接间隔、从机延迟、超时。集中器收到请求后,可以选择接受或拒绝这些新的参数.连接可以被主机或从机以任何原因自动终止,一方发其终止连接时,另一方必然响应,然后两个设备才能退出连接状态.
GAP层也处理BLE连接中安全特征的初始化。只有在已认证的连接中特定的数据才能被读写,一旦连接建立,两个设备进行配对,当配对完成后,形成加密链接的密钥.典型应用中外设请求集中器提供密钥来完成配对工作,密钥可以是一个固定的值,如000000,也可以随机生成一个数据提供给使用者,集中器设备发送正确的密钥后,两设备交换安全密钥并加密认证链接。
在许多情况下,同一对外设和集中器会不定时地连接和断开,BLE的安全机制中有一项特性允许两个设备之间建立长期的安全密钥信息,这种特性称为绑定,它允许两设备重新连接时快速地完成加密认证,而不需要每次连接时执行配对的完整过程.
3.3.2 通用属性配置文件(GATT)
两个设备应用数据的通信是通过协议栈的GATT层实现,从GATT角度来看,当两个设备建立连接后,它们处于下面两种角色之一:
GATT服务器--为GATT客户端提供数据的服务的设备 GATT客户端--从GATT服务器读写应用数据的设备.
GATT角色中的客户端和服务器的概念与链路层的主机和从机概念完全独立,与GAO角色中的外设和集中器概念也是完全独立.
一个GATT服务器中可包含一个或多个GATT服务,GATT服务是完成特定功能的一系列数据的集合。
“特性”(Characteristic)是服务用到的值,以及其内容和配置信息.GATT定义了在BLE连接中发现、读取和写入属性的子过程。GATT服务器上的特性值,及其内容和配置信息(称为描述符)存储于属性表中。属性表是一个数据库,包含了成为属性的小块数据,除了值本身,每个属性都包含下列属性:
句柄--属性在表中的地址,每个属性有唯一的句柄
类型--表示数据代表的事务,通常是蓝牙技术联盟规定或用户自定义的UUID(Universally Unique Identifier)
权限--规定了GATT客户端设备对属性的访问权限,包括是否能访问和怎样访问. GATT定义了若干在GATT服务器和客户端之间的通信的子过程.
读特性值--客户端设备请求读取句柄处的特性值,服务器将此值回应给客户端. 使用特性的UUID读--客户端请求读基于一个特定类型的所有特性值,服务器将所有与指定类型匹配的特性的句柄和值回应给客户端设备。
读多个特性值--客户端一次请求中读取几个句柄的特性值,服务器将这些特性值回应给客户端,客户端需要知道如何解析这些不同的特性值数据
读特性描述符--客户端请求读特定句柄处的特性描述符,服务器将特性描述符的值回应给客户端设备。
使用UUID发现特性--客户端通过发送”特性”的类型(UUID)来请求发现这个”特性”的句柄。服务器将这个”特性”的声明回应给客户端设备,其中包括特性值的句柄以及”特性”的权限.
写特性值--客户端设备请求向服务器特定的句柄处写入特性描述符,服务器将特性描述符是否写入成功的信息反馈给客户端。
特性值通知--服务器将一个特性值通知给客户端,客户端设备不需要向服务器请求这个数据,客户端收到这个数据时,也不需要回应服务器,要想使能服务器通知,首先要配置好特性,profile中定义了什么时候服务器应该发送这个数据。
每个Profile初始化其相应的服务并内在的通过设备的GATT服务器来注册服务。GATT服务器将整个服务加到属性表中,并为每个属性分配唯一句柄. GATT属性表中有一些特殊的属性类型,其值由蓝牙技术联盟定义. 7. payload包格式 包结构: 1.总体结构:
preamble(1 Byte)+ Access Address(4 Bytes)+ PDU + CRC(3 Bytes) preamble = 10101010 or 01010101 Access Address = 0x8e89bedd6 2. 广播包
PDU = Header(2 Bytes)+ Payload (37 Bytes max.)
Header: 1)0000 - connected undirected advertising event 可连接非定向广播事件 2)0001 - connected directed advertising event 可连接定向广播事件
3)0010 - non-connected undirected advertising event 不可连接非定向广播事件 4)0011 - response to scan request form scanner扫描请求响应 5)0101 - connect request by initiator连接请求
6)0110 -connected directed advertising event 可发现非定向广播事件
?
非定向广播包(Undirected advertising packets)
Payload = AdvA (6 Bytes) + AdvData (31 Bytes max.) ;
// AdvA contains advertiser‘s public address if TxAdd = 1, or a random address if TxAdd = 0;
// AdvData advertising data;
?
定向广播包(Directed advertising packets)
Payload = AdvA (6 Bytes) + InitA(6 Bytes) ;
// AdvA contains advertiser‘s public address if TxAdd = 1, or a random address if TxAdd = 0;
// InitA contains initiator's address if RxAdd = 1, or a random address if RxAdd = 0;
3. 扫描请求及扫描响应
PDU = Header(2 Bytes)+ Payload (37 Bytes max.)
Header: 1)0011 - scan request for further information from advertiser 扫描请求 2)0100 - response to scan request from scanner 扫描响应
?
扫描请求
Payload = ScanA (6 Bytes) + AdvA(6 Bytes) ;
// ScanA contains Scanner's public address if TxAdd = 1, or a random address if TxAdd = 0;
// AdvA contains advertiser‘s public address if TxAdd = 1, or a random address if TxAdd = 0;
?
扫描响应
Payload = AdvA(6 Bytes) + ScanRspData(0~31Bytes); // ScanRspData data from advertiser’s host;
// AdvA contains advertiser‘s public address if TxAdd = 1, or a random address if TxAdd = 0;
3. 连接请求
PDU = Header(2 Bytes)+ Payload (34 Bytes) Header:0101 - connect request by initiator
Payload =InitA(6 Bytes)+ AdvA(6bytes)+ LLData(22 Bytes) LLData 包含连接信息,详细结构参考bluetooth 4.0 协议。 4. LL 数据通道及控制包
PDU = Header(2 Bytes)+ Payload (27 Bytes max.) Header:详细说明参考bluetooth 4.0 协议;
?
LL 数据通道
Payload = 0~27 bytes
?
LL 控制包
Payload = 1~23 Bytes
若只考虑蓝牙设备连接之后,评估数据传输速率
? 最大包长度:preamble(1 Byte)+ Access Address(4 Bytes)+ PDU(29 Bytes) + CRC(3 Bytes)= 41 Bytes
? 射频PHY传输速率 1Mbps
则传输有效payload 27字节耗时:41*8/1 = 328 us
一个27字节的传输周期 :328 + 150 + 80 + 150 = 708 us,若能持续传输,即传输速度:38KB/s,这样显然功耗不会低,也不符合BLE协议规范,真正的传输速度受连接事件间隔和间隔内能传输数据包数目相关。
如果连接时间间隔设置到7.5ms(协议规定最小值),一个连接事件传输3个包,则传输速率大约是10.8kB/s,一个连接事件能传输几个包与连接设备密切相关,看到很多CC2540实测数据,时间间隔7.5ms和一个传输时间3个包以上很多都达不到,51内核是其重要原因之一