上一篇,树莓派和手机通过蓝牙通信,用的是经典蓝牙。这一篇中将尝试用蓝牙的另外一种模式,低功耗蓝牙BLE。主角当然是树莓派3B+,与之搭配做通信测试的,是当前一款比较流行的BLE SoC,TI的CC2640R2F(以下简称R2F)。
一、R2F上程序的简单介绍
R2F是CC2640的升级版, 增加了FLASH空间,支持蓝牙5并向下兼容蓝牙4.x。测试时,R2F上跑的是官方提供的SDK中的simple_peripheral demo程序。在SDK中的路径为:
simple_peripheral文件夹下的README.html是这个demo程序的介绍及演示过程。简单来讲,simple_peripheral例程提供了一个服务custom service,custom service下有五个characteristics,每个characteristics或者可读,或者可写,或者可通知,或者需要先authentication才能读取。README文档展示了手机上的BLE scanner App访问这五个characteristics的过程。这个演示基本涵盖了BLE通信中的常见操作。
那接下来的操作,将是在树莓派上通过python编程,与R2F通信,逐一访问这五个characteristics,重复一遍README文档中的演示操作。下面是具体的介绍。
二、PYGATT
上一篇测评中,树莓派和手机之间的经典蓝牙通信,用的是蓝牙中的RFCOMM协议。现在树莓派与R2F之间的通信,用到的是BLE中的GATT协议。Python有一个名为pygatt的模块,提供了python编程时访问GATT descriptors的API接口。
下面是pygatt的安装方法:
- sudo pip install "pygatt[GATTTOOL]"
复制代码
注意:pexpect也是需要手动安装的。否则下面运行代码时会报与pexpect有关的错误。
三、python编程访问R2F的代码
先将通信代码贴在这里。
- import pygatt
- import sys
- from time import sleep
- def notify_callback(handle,value):
- print("notify:handle=%d,value=%d" %(handle,ord(value)))
- adapter = pygatt.GATTToolBackend()
- try:
- adapter.start()
- device = adapter.connect('54:6C:0E:6D:D7:96')
- dev_name = device.char_read("00002a00-0000-1000-8000-00805f9b34fb")
- print("DevName:%s" %dev_name)
- print("Char 1 wr=66")
- device.char_write_handle(30,bytearray([66]))
- #char1=device.char_read_handle(30)
- char1=device.char_read('0000fff1-0000-1000-8000-00805f9b34fb')
- print("Char 1 rd=%x" %ord(char1))
- #char2=device.char_read_handle(33)
- char2=device.char_read('0000fff2-0000-1000-8000-00805f9b34fb')
- print("Char 2 rd=%x" %ord(char2))
- print("Char 3 wr=88")
- device.char_write_handle(36,bytearray([88]))
- device.subscribe('0000fff4-0000-1000-8000-00805f9b34fb',notify_callback,False)
- sleep(10)
- print("Char 5 rd=")
- char5=device.char_read('0000fff5-0000-1000-8000-00805f9b34fb')
- for i in char5:
- print(i)
- finally:
- adapter.stop()
复制代码
四、代码说明
在与R2F通信之前,我们需要先获取一些通信对象R2F的参数,这些可以通过python调用pygatt的API获得。这里是在终端里输入几个指令来获取。
首先是获取R2F的地址,需要先扫描一下:
sudo hcitool lescan
第五行的SimpleBLEPeripheral便是R2F了,它的地址是54:6C:0E:6D:D7:96
接下来是获取R2F的service和characteristics信息。
这里需要关注的是蓝框中的handle值和绿框中的uuid。最上面框住的一行,是用来获取设备名称的,最下面框住的五行,就是第一部分中提到的5个characteristics。下面编程访问,都需要对应的char value handle或者uuid(第一部分截图中的uuid是16位的,这里应该是补全成标准格式的uuid了,fff1-fff5还是很好识别的)。
除了char value handle和uuid,前面的handle似乎就是个顺序标号,在下面的编程中没有用到这个。char properties是指明读写和通知属性的。读=0x02 写=0x08 通知=0x10。 characteristics1(uuid=0xfff1)是可读可写的,那么它的char properties=0x02|0x08=0x0a
下面简单介绍一下程序内容。
第12行是通过指定地址,建立与R2F的连接
第13行是获取R2F的设备名称,char_read的参数是uuid,返回值是characteristics对应的值。
第17行是通过handle写characteristics1,char_write_handle的第一个参数是上面图片中的char value handle,十六进制的0x1e是十进制的30,第二个参数是要写入的值。
第19行是通过uuid读characteristics1,我尝试用char_read_handle通过char value handle去读,但总是报错,这个目前还没弄明白是怎么回事。
第29行是使能characteristics的notification并注册回调函数,subscribe函数的第一个参数是characteristics的uuid,第二个参数是通知的回调函数句柄,第三个参数为True时为indicate,为False时为notification。回调函数的两个参数是系统收到notification传回来的,分别是对应的char value handle以及返回的数值。
第33行是也是一个读操作,如simple_peripheral例程的介绍文档README中所描述的,要读取characteristics5 先要有认证过程。用BLE scanner读取时,会弹出配对的对话框,并提示输入配对密码(这个密码是R2F那端给出的,会实时通过串口把密码打印出来)。这里python编程读取时,也会尝试与R2F配对,但一般都是失败,这个我猜测可能是没有输入配对密码的缘故(也不会有任何提示要输入配对密码的)。
为了绕过这个过程,我尝试先让树莓派和R2F配对上,我在图形界面里点击最上方的蓝牙图标,搜索到SimpleBLEPeripheral,点击pair,提示输入配对密码,然后正确配对上了。但是运行程序到读取characteristics5时,依然会提示配对失败。后来我尝试通过在终端中调用bluetoothctl相关的指令建立配对,中间也有曲折,但是按如下操作,也是可以实现配对的,并且此后再一次运行程序读取characteristics5时,是可以成功读取的。
终端中运行bluetoothctl建立配对的截图如下(左侧是R2F的打印信息,右侧是树莓派终端中的操作,红框是需要输入的指令)。如果上来直接pair device,则会报错。需要先remove device,再trust device,最后pair,这样成功率较高。pair成功后会打印出R2F上的service等信息,因内容较多,这里只截了两行(图片中的最后两行)。
最后附上python程序运行时,R2F以及python程序的打印信息截图。那两行notify,是在sleep(10)的十秒钟时间内收到的两个通知信息。其余的,与第一部分中介绍的例程中的操作基本一致。
五、总结
这一篇里,主要是通过python的pygatt模块编程完成了与CC2640R2F的一些通信操作。另外中途还用到了gatttool和bluetoothctl这两个工具。整个流程走下来,还是学到了很多linux上与BLE相关的东西,对BLE的通信过程,以及service,characteristics,notification等概念有了初步的了解。当然对gatt的内容还只是略知皮毛。
就python下的ble相关的模块而言,我找到的,除了pygatt,还有pygattlib和bluepy。运用另外两个模块我也实现了与R2F的读写操作,但是在处理notification遇到了问题,首先就是不知道如何使能notification,R2F的程序上默认characteristics4 的notification是关闭的,但我在这两个模块上都没有找到打开操作的API,另外回调函数的实现形式上也没有pygatt的API这么容易理解。如果大家谁在这方面有心得,也可以交流一下。
受时间限制,蓝牙这一块就告一段落了,后续开始实现8266与树莓派的通信。
本文来自论坛,点击查看完整帖子内容。