引言
在WinCE上调试蓝牙的过程中,对于一些Bluetooth Core相关的问题,经常需要去分析HCI数据(包括Command、Data和Event),然后和Bluetooth Core Spec中的相关内容进行对比以定位问题,最后寻找根本原因。
列举一下在分析HCI数据的时候可选的方法:
l 通过打开微软蓝牙协议栈中固有的Debug Zone信息来进行(详细参照http://www.cnblogs.com/strive-forever/archive/2011/09/18/2180354.html)
优点是信息全面,缺点是信息量大。
l 通过Sniff Log
优点是最直接的分析空中包中实际交互的数据,屏蔽其他环节可能出现的问题,缺点是需要昂贵的硬件抓包工具,容易发生丢包的情况,而且从HCI数据和空中包的对应也需要对协议的理解也有较深的要求。
l 直接分析HCI数据,也是本文中所介绍的方法
优点是针对性强,缺点是需要对协议本身有一定的了解。
本文尝试从最基本的HCI数据上来分析HCI命令和事件,对于HCI Data,由于其Payload部分可能多种多样,包括L2CAP、SCO、RFCOMM以及各种各样的Profile等,则不在本文的探讨的范围内。
1. 如何来区分Command和Event Packet
我们知道,通过HCI Packet包括四种,即Command,Event,ACL和SCO/eSCO,对应到MS-Stack中的定义,即为COMMAND_PACKET ,EVENT_PACKET,DATA_PACKET_ACL和DATA_PACKET_SCO。
如下(详细参照bt_hcip.h):
enum HCI_TYPE { COMMAND_PACKET = 1, DATA_PACKET_ACL = 2, DATA_PACKET_SCO = 3, EVENT_PACKET = 4, ETYPE_FINISH = 5 }; |
需要指出的是COMMAND_PACKET方向是从Host写入到Controller,EVENT_PACKET为Controller发送给Host,即单向的数据。而DATA_PACKET_ACL和DATA_PACKET_SCO为双向的数据,即可以HostàController,也可以ControlleràHost。
接下来看两个与发包和收包相关的函数的定义,如下:
int HCI_WritePacket(HCI_TYPE eType, BD_BUFFER *pBuff) int HCI_ReadPacket(HCI_TYPE *peType, BD_BUFFER *pBuff) |
其第一个参数etype就是用来表示R/W Packet的类型,第二个参数为包的具体数据:
所以通过在HCI_WritePacket()/HCI_ReadPacket()中对eType值的判断,很容易知道是Command Packet,还是Event Packet。
2. 如何分析Command包
首先来看HCI包的结构:
其中低10个bit用来表示HCI Command的OCF域,可以拿着这个值到BlueCore Spec中去查询对应的命令,而bit10~bit15用来表示OGF域。对于OGF即使HCI命令的种类,具体的种类包括Link control, Link PolicyController&BaseBand以及Information等。
For example,HCI_Disconnect在MS-Stack的定义值为0x0406,具体参照文件bt_ddi.h。而其OCF域,也即bit0~bit9为0x006,对应的OGF域,也即bit10~bit15域为0x01。根据BlueCore Spec的定义,OGF为1表示Link Control Command。所有HCI Packet的定义在Volume 2-Core System Packet Part E-Host Controller Interface的Chapter 7th-HCI Command and Events中定义(以BlueCore Spec2.1为例),查询7.1th-Link Control Command一节,对应的Command Code为0x006,其对应的Command应该是HCI_Disconnect,如下所示:
下面举一个具体的Command Packet分析过程:
Write(1, 25): 0B 04 16 77 89 39 98 22 00 54 0B 3F 42 F8 38 EE 90 09 BC 1D 1C 1E D1 E2 61 G=0x1, code=0xb |
首先看OCF(bit[0~9])为0x0b,而OGF(bit[10~15])为0x01,对照BlueCore Spec,则该条命令应该为Link Controller Command域中的HCI_LINK_KEY_REQUEST_REPLY(0x0b),Parameter Total Length(bit16~23)0x16,为该命令的解释如下:
根据该命令的详细解释,其参数包括两部分BT_ADDR和Link_key,分别占用6字节和16字节,所以BT_ADDR为77 89 39 98 22 00,而Link_key为54 0B 3F 42 F8 38 EE 90 09 BC 1D 1C 1E D1 E2 61。
所以,可以看到分析Command Packet的关键在于两点,第一点是根据Packet找到OCF,OGF以及total parameter length,然后找到该command的详细解释,即包含了那些参数以及每一个参数的具体长度,就可以来对Command Packet进行解析了。
3. 如何分析Event包
首先,来看Event Packet的结构:
下面以一个具体的Event Packet来进行分析:
Read(5, 8): 17 06 77 89 39 98 22 00 |
很容易可以看出,Event Code为0x17,Parameter Total Length为0x06。由于Event没有域之说,可以直接拿着0x17去BlueCore Spec中的Events中去查找对应Event Link Key Request,如下:
根据该Event的详细解释,其参数为BT_ADDR,共占用6个字节,即为77 89 39 98 22 00。