蓝牙开发那些事儿(11)——BLE愉快地交互

上一章手机和flip4已经建立了连接,接下来的数据包格式就是data channel pdu了。

Data channel pdu的格式如下:

蓝牙开发那些事儿(11)——BLE愉快地交互

 

之前我们说过,和经典蓝牙不同的是,LE只有一个header,而BR的包头有两个——packet header和payload header,实际上这里的LLID类似于BR的payload header中的LLID,这里的NESN和SN类似于BR的packet header中的SEQN, 当然也并不完全一样,前者收发双方都维护一个sequence number而后者显然只有一方维护。

和经典蓝牙类似,data channel pdu也是根据header中的LLID分成control pdu和data pdu两种。

在建立连接后,master和slave会通过LLCP(link layer control protocl),通过control pdu对连接进行控制。

control pdu的格式如下:

蓝牙开发那些事儿(11)——BLE愉快地交互

 

其中opcode表示控制包的类型。

我们来看看,这次连接后,双方通过LLCP协议交互了一些信息。

蓝牙开发那些事儿(11)——BLE愉快地交互

然后就可以通过data pdu来交互上层信息了。

蓝牙开发那些事儿(11)——BLE愉快地交互

首先是一个att exchange mtu的,这是手机通知flip4其最大接收MTU size的。可以注意一下红线部分,首先LLID标识了这个包是个data pdu,然后l2cap层的cid似乎fixed的0x4,表示是att包,att payload的opcode表示是个exchange mtu request,手机的mtu是185。蓝牙4.0之前的标准,mtu只有23字节,这个mtu用来做OTA等固件升级的应用真的是很慢了,4.2之后mtu才扩大到255字节。

交换完MTU之后,手机需要了解到flip4这个server支持的服务、特性、特性描述等等信息,有点类似经典蓝牙的sdp环节。

首先需要获取service,获取service有两种方法,一是获取所有服务,一是根据uuid获取服务,这里选取的方法是前者,流程是这样的:

蓝牙开发那些事儿(11)——BLE愉快地交互

第一次发送的att_read_by_group_type_req的start handle一定是1,end handle是0xffff,attribute type是primary service(2800),然后server端会顺序从handle 1搜索服务,在att_read_by_group_type_rsp中回复找到的service,因为无法一次回复完,所以这个过程需要循环执行,下一次手机端发送的att_read_by_group_type_req数据包的start handle比att_read_by_group_type_rsp的end handle加1。

我们看一下flip4的第一个回复吧:

蓝牙开发那些事儿(11)——BLE愉快地交互

这个回复中包含了两个primary service,我们先记录在案,一共进行三次的service搜索到之后,一张service的列表就可以出来了:

 

 

Handle

Attribute Type

Attribute Value

1

2800(primary service,蓝牙协会规定的assigned numbers)

1801(GATT service,蓝牙协会规定的assigned numbers)

5

2800

1800(GAP service,蓝牙协会规定的assigned numbers)

10

2800

65786365-6C70-6F69-6E74-2E636F6D0000

16

2800

Fe8f

我们知道profile是service的集合,找到所有service之后,还需要找到各个service的子集,包括include、characteristic等等,使用的命令都是ATT_READ_BY_TYPE_REQ。

如果找到characteristic,还要找到characteristic descriptor等等,使用的命令是ATT_FIND_INFOMATION_REQ。

include表示该service包含其他service,这个过程叫relationship discovery,这里我们没有这个过程。

Characteristic就比较重要了,因为service是characteristic的集合。

这个过程叫characteristic discovery:

蓝牙开发那些事儿(11)——BLE愉快地交互

看看我们找到的characteristic,按照格式,找到的characteristic,本身就是一个attribute,

有2个字节的attribute handel,这里是2,attribute type是2803(characteristic,这个在att_read_by_type_req中包含了,不会找其他的东西),attribute value包括1个字节的property(决定了读写权限等),2个字节的value handle(0003),和2个字节bluetooth UUID(2a05),assigned numbers表示service changed。

蓝牙开发那些事儿(11)——BLE愉快地交互

一般找到characteristic之后紧跟着是找characteristic descriptor:

蓝牙开发那些事儿(11)——BLE愉快地交互

最后,我们形成了一张service的总表:

Handle

Attribute Type

Attribute Value

1

2800(primary service,蓝牙协会规定的assigned numbers)

1801(GATT service,蓝牙协会规定的assigned numbers)

2

2803(characteristic)

{20,0003,service changed}

5

2800(primary service)

1800(GAP service,蓝牙协会规定的assigned numbers)

10

2800(primary service)

65786365-6C70-6F69-6E74-2E636F6D0000

11

2803(characteristic)

{12(read,notify), 000c, 65786365-6C70-6F69-6E74-2E636F6D0001}

14

2803(characteristic)

{08(write), 000f, 65786365-6C70-6F69-6E74-2E636F6D0002}

16

2800(primary service)

Fe8f

从这个表可以看出,10号service是我们提供读写服务的核心service,其中,有0x000c号handle可以用于读数据,0x000f号handle可以用于写数据,下面可以看到app就利用这两个handle号和flip4进行交互:

这是收到的notify数据包:

蓝牙开发那些事儿(11)——BLE愉快地交互

这是write的数据包:

蓝牙开发那些事儿(11)——BLE愉快地交互

具体的数据格式,就是上层app需要关心的内容了,和协议无关。