最近发现bluez下面还有一个比较有意思的命令,那就是gatttool
。这个命令实际上是一个gatt client,不知道大家有没有用过手机上的BLE调试工具,比如苹果上最好用的就是lightblue,安卓上类似的工具比较多,我个人比较常用的就是rfconnect。而现在将要介绍的这个命令gatttool
的功能就类似于手机上的BLE调试工具。它可以扫描gatt server上的服务,可以给他们发送指令等
gatttool的命令选项
命令行终端下查看帮助信息
$ gatttool --help
Usage:
gatttool [OPTION?]
Help Options:
-h, --help Show help options
--help-all Show all help options
--help-gatt Show all GATT commands
--help-params Show all Primary Services/Characteristics arguments
--help-char-read-write Show all Characteristics Value/Descriptor Read/Write arguments
Application Options:
-i, --adapter=hciX Specify local adapter interface
-b, --device=MAC Specify remote Bluetooth address
-t, --addr-type=[public | random] Set LE address type. Default: public
-m, --mtu=MTU Specify the MTU size
-p, --psm=PSM Specify the PSM for GATT/ATT over BR/EDR
-l, --sec-level=[low | medium | high] Set security level. Default: low
-I, --interactive Use interactive mode
选项说明
- -i : 后面接设备描述, 如hci0等
- -b: 远端设备的蓝牙地址
- -t: 远端设备蓝牙地址的类型,默认为public
- -m: att协议的MTU大小
- -p: 制定gatt的PSM,默认值为0
- -l: 安全等级
- -I: 交互式模式
查看gatt的命令:
$ gatttool --help-gatt
Usage:
gatttool [OPTION?]
GATT commands
--primary Primary Service Discovery
--characteristics Characteristics Discovery
--char-read Characteristics Value/Descriptor Read
--char-write Characteristics Value Write Without Response (Write Command)
--char-write-req Characteristics Value Write (Write Request)
--char-desc Characteristics Descriptor Discovery
--listen Listen for notifications and indications
-I, --interactive Use interactive mode
选项说明:
- –primary: 发现GATT服务
- –characteristics: 发现设备上所有的characteristics
- –char-read: 读某个characteristics,需要指定一个handle
- –char-write: 写某个characteristics,需要指定一个handle,使用Write Without Response的方式
- –char-write-req: 写某个characteristics,需要指定一个handle,使用Write Request的方式
- –char-desc: 发现所有的Characteristics Descriptor
- –listen: 监听Characteristics的notification或者indication
查看读写characteristics命令下的参数选项:
$ gatttool --help-char-read-write
Usage:
gatttool [OPTION?]
Characteristics Value/Descriptor Read/Write arguments
-a, --handle=0x0001 Read/Write characteristic by handle(required)
-n, --value=0x0001 Write characteristic value (required for write operation)
选项说明:
- -a:通过handle来读写characteristic, 后面接handle值
- -n:写characteristic时候的参数,后面接具体的值
查看服务发现命令下的参数选项
$ gatttool --help-params
Usage:
gatttool [OPTION?]
Primary Services/Characteristics arguments
-s, --start=0x0001 Starting handle(optional)
-e, --end=0xffff Ending handle(optional)
-u, --uuid=0x1801 UUID16 or UUID128(optional)
选项说明:
- -s:起始handle
- -e:结束handle
- -u:16比特或者128比特的UUID
命令使用示例
我们先扫描一下周围的BLE设备
$ hcitool -i hci0 lescan
LE Scan ...
12:34:56:C2:9C:C7 Headset
我们发现了一个叫做名字叫做Headset的BLE设备,接下来我们将使用gatttool
命令来操作这个设备
发现设备的服务
现在我们并不知道远端设备究竟提供了哪些服务,下面我们扫描下
$ gatttool -i hci0 -b 12:34:56:C2:9C:C7 --primary
attr handle = 0x0001, end grp handle = 0x0005 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle = 0x0006, end grp handle = 0x0009 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle = 0x000a, end grp handle = 0x0011 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
attr handle = 0x0012, end grp handle = 0x0015 uuid: 66666666-6666-6666-6666-666666666666
attr handle = 0x0016, end grp handle = 0x0019 uuid: 86868686-8686-8686-8686-868686868686
事实上gatttool先连上远端的BLE设备,读取对方的服务之后就立刻断开了,通过hcitool con
命令我们可以看到执行上述命令之后并没有存在一个BLE连接。
现在我们读取所有的characteristic
$ gatttool -i hci0 -b 12:34:56:C2:9C:C7 --characteristics
handle = 0x0002, char properties = 0x02, char value handle = 0x0003, uuid = 00002a00-0000-1000-8000-00805f9b34fb
handle = 0x0004, char properties = 0x02, char value handle = 0x0005, uuid = 00002a01-0000-1000-8000-00805f9b34fb
handle = 0x0007, char properties = 0x22, char value handle = 0x0008, uuid = 00002a05-0000-1000-8000-00805f9b34fb
handle = 0x000b, char properties = 0x10, char value handle = 0x000c, uuid = 0000ffe1-0000-1000-8000-00805f9b34fb
handle = 0x000f, char properties = 0x0c, char value handle = 0x0010, uuid = 0000ffe2-0000-1000-8000-00805f9b34fb
handle = 0x0013, char properties = 0x18, char value handle = 0x0014, uuid = 77777777-7777-7777-7777-777777777777
handle = 0x0017, char properties = 0x18, char value handle = 0x0018, uuid = 97979797-9797-9797-9797-979797979797
现在可以通过指定handle范围的方式去读取characteristic,现在我把起始handle设置为0x08,结束handle设置为0x12
$ gatttool -i hci0 -b 12:34:56:C2:9C:C7 --characteristics -s 0x08 -e 0x12
handle = 0x000b, char properties = 0x10, char value handle = 0x000c, uuid = 0000ffe1-0000-1000-8000-00805f9b34fb
handle = 0x000f, char properties = 0x0c, char value handle = 0x0010, uuid = 0000ffe2-0000-1000-8000-00805f9b34fb
可以看到,我们只读取了制定范围的characteristic
因为最有2个characteristic是用户自己定义的,所以我们现在只想查看这2个characteristic
$ gatttool -i hci0 -b 12:34:56:C2:9C:C7 --characteristics -s 0x12
handle = 0x0013, char properties = 0x18, char value handle = 0x0014, uuid = 77777777-7777-7777-7777-777777777777
handle = 0x0017, char properties = 0x18, char value handle = 0x0018, uuid = 97979797-9797-9797-9797-979797979797
读characteristic
$ gatttool -i hci0 -b 12:34:56:C2:9C:C7 --char-read -a 0x0014
Characteristic value/descriptor read failed: Attribute can't be read
由于这个characteristic的属性是write/notify,所以读失败,我们可以尝试下:
$ gatttool -i hci0 -b 12:34:56:C2:9C:C7 --char-write-req -a 0x0014 -n 0x0001
Characteristic value was written successfully
有兴趣的话可以自行尝试更多的命令,这里就不再赘述了。
gatttool
还有一种交互模式,个人觉得还是比较好用的
命令交互式模式
我们在终端输入如下命令进入交互式模式:
$ gatttool -I
[ ][LE]> help
help Show this help
exit Exit interactive mode
quit Exit interactive mode
connect [address [address type]] Connect to a remote device
disconnect Disconnect from a remote device
primary [UUID] Primary Service Discovery
included [start hnd [end hnd]] Find Included Services
characteristics [start hnd [end hnd [UUID]]] Characteristics Discovery
char-desc [start hnd] [end hnd] Characteristics Descriptor Discovery
char-read-hnd <handle> Characteristics Value/Descriptor Read by handle
char-read-uuid <UUID> [start hnd] [end hnd] Characteristics Value/Descriptor Read by UUID
char-write-req <handle> <new value> Characteristic Value Write (Write Request)
char-write-cmd <handle> <new value> Characteristic Value Write (No response)
sec-level [low | medium | high] Set security level. Default: low
mtu <value> Exchange MTU for GATT/ATT
进入交互式模式之后,我们在终端输入help
命令,于是显示出当前所有可用的命令,现在我们准备连接设备
[ ][LE]> connect 12:34:56:C2:9C:C7
Attempting to connect to 12:34:56:C2:9C:C7
Connection successful
[12:34:56:C2:9C:C7][LE]>
提示连接成功,我们输入primary
查看下服务
[12:34:56:C2:9C:C7][LE]> primary
attr handle: 0x0001, end grp handle: 0x0005 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0006, end grp handle: 0x0009 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000a, end grp handle: 0x0011 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
attr handle: 0x0012, end grp handle: 0x0015 uuid: 66666666-6666-6666-6666-666666666666
attr handle: 0x0016, end grp handle: 0x0019 uuid: 86868686-8686-8686-8686-868686868686
更改下MTU的值
[12:34:56:C2:9C:C7][LE]> mtu 512
MTU was exchanged successfully: 512
写入characteristic
12:34:56:C2:9C:C7][LE]> char-write-req 0x14 0x111
Characteristic value was written successfully
监听从蓝牙设备发过来的Notification或者Indication
如果需要接收从蓝牙设备发过来的数据,我们也必须使用交互式模式,按如下命令进入
$ gatttool -I --listen
然后连接设备
[ ][LE]> connect 12:34:56:C2:9C:C7
Attempting to connect to 12:34:56:C2:9C:C7
Connection successful
[12:34:56:C2:9C:C7][LE]>
只有在characteristic的client config配置为Enable Notification/Indication的时候,我们才能接收到蓝牙设备的数据,通过查看设备的服务,我知道这个属性的handle值为0x000d,于是我向这个属性写1,使能这个功能
[12:34:56:C2:9C:C7][LE]> char-write-req 0x000d 01
Characteristic value was written successfully
此时我的``gatttool`处于监听状态,我把蓝牙设备配置成向某个Characteristic写数据,他会把数据从另外一个Characteristic 再原样发回
[12:34:56:C2:9C:C7][LE]> char-write-req 0x0010 0x345589
Characteristic value was written successfully
Notification handle = 0x000c value: 00 34 55 89
上面可以看到,gatttool收到了从蓝牙设备发回的内容
断开连接
[12:34:56:C2:9C:C7][LE]> disconnect
其他命令自行验证即可