slave
# 简介
从设备模式:工作在从机模式下的蓝牙模块只能被主机搜索,不能主动搜索。从设备跟主机连接以后,也可以和主机设备进行发送和接收数据。
# API说明
以下API是模块BLE从模式用到的接口,其余接口及具体接口参数说明和用法请到API说明章节和demo内查看并学习
| API接口 | 描述 |
| ------------------------- | -------------------------------------- |
| btcore.open() | 打开蓝牙 |
| btcore.close() | 关闭蓝牙 |
| btcore.state() | 查询蓝牙状态(开启或者关闭) |
| btcore.disconnect() | 蓝牙主动断开连接 |
| btcore.setname() | 设置蓝牙名称 |
| btcore.setadvdata() | 设置广播包数据 |
| btcore.setscanrspdata() | 设置扫描响应包数据 |
| btcore.addservice() | 蓝牙添加服务 |
| btcore.addcharacteristic() | 蓝牙添加服务内的特征 |
| btcore.adddescriptor() | 蓝牙添加特征的描述 |
| btcore.setadvparam() | 设置广播参数 |
| btcore.advertising() | 蓝牙广播开关 |
| btcore.send() | 写数据 |
| btcore.recv() | 读数据 |
| btcore.getaddr() | 获取本机蓝牙MAC地址 |
| btcore.addwhitelist() | 将蓝牙地址添加到白名单 |
| btcore.removewhitelist() | 将蓝牙地址从白名单内移除 |
| btvore.clearwhitelist() | 清空白名单 |
BLE从设备模式用到的蓝牙消息
| API接口 | 描述 |
| ------------------------- | -------------------------------------- |
| MSG_OPEN_CNF | 蓝牙打开成功 |
| MSG_CLOSE_CNF | 蓝牙关闭成功 |
| MSG_BLE_CONNECT_IND | 蓝牙从模式连接 |
| MSG_BLE_DISCONNECT_IND | 蓝牙从模式断开连接 |
| MSG_BLE_DATA_IND | 数据接收 |
> 详细的API介绍见[btcore API章节](https://doc.openluat.com/wiki/21?wiki_page_id=2244)
# 实现流程
- 注册蓝牙消息回调函数
通过rtos.on() 注册蓝牙消息回调函数
- 打开蓝牙
使用btcore.open(0)打开蓝牙从设备模式
- 设置蓝牙名称
使用btcore.setname()设置蓝牙名称
- 设置广播数据
使用btcore.setadvdata()设置广播包
使用btcore.setscanrspdata()设置扫描响应包
需要根据蓝牙广播/响应包的格式来设置
- 添加BLE服务、特征、描述
使用btcore.addservice()添加服务
使用btcore.addcharacteristic()添加特征
使用btcore.adddescriptor()添加描述
需要遵从一定的格式来设置,具体使用方式请看bluetooth/slave的demo
- 设置广播参数
使用btcore.setadvparam()来设置广播参数,如果没有设置,则使用默认的广播参数
- 开启蓝牙广播
使用btcore.advertising()来打开广播
- 开启广播后等待其他蓝牙设备的连接
- 连接成功后就可以进行数据的收发
- 收数据 btcore.recv()来读取数据
- 发数据 btcore.send()来发送数据
# 白名单
将一组蓝牙地址添加到一个列表,这个列表就是白名单
通过白名单,可以只允许特定的蓝牙设备(白名单中列出的)扫描(Scan)、连接(connect)我们,也可以只扫描、连接特定的蓝牙设备(白名单中列出的)。
通过以下接口来实现白名单广播与全局广播
```lua
--参数释义:
--其余接口、参数释义请到蓝牙API章节介绍去查询,这里介绍白名单与全局广播用到的接口与参数
--addr:蓝牙mac地址
--addr_type:蓝牙mac地址类型
--advfiter:广播过滤策略
--以下是广播过滤策略的取值,是白名单是否启用的关键
--0: Process scan and connection requests from all devices.
--禁用白名单机制,允许任何设备连接和扫描
--1: Process connection requests from all devices and only scan requests from devices that are in the White List.
--允许任何设备连接,但只允许白名单中的设备扫描。
--2: Process scan requests from all devices and only connection requests from devices that are in the White List.
--允许任何设备扫描,但只允许白名单中的设备连接。
--3: Process scan and connection requests only from devices in the White List
--只允许白名单中的设备扫描和连接。
--btcore.addwhitelist(addr, addr_type)将蓝牙地址添加到白名单
--btcore.removewhitelist(addr, addr_type)将蓝牙地址从白名单内移除
--btvore.clearwhitelist()清空白名单
--btcore.setadvparam(advmin, advmax, advtype, ownaddtype, advchannmap, advfilter[, directaddrtype, directaddr])设置广播参数
```
**白名单广播示例**
将mac地址添加到白名单中,配合广播参数的广播过滤策略的设置,即可开启白名单广播或全局广播功能
**全局广播**
```lua
--禁用白名单机制,允许任何设备连接和扫描
btcore.setadvparam(0x80, 0xa0, 0, 0, 0x07, 0)
btcore.advertising(1)
```
**白名单广播**
```lua
--举个例子,设两个蓝牙设备mac地址分别为A、B,地址类型为Public Device Address(取值为0)
--A的地址为:"11:22:33:44:55:66"
--B的地址为:"aa:bb:cc:dd:ee:ff"
--将A的地址添加进广播设备的白名单,通过以下广播过滤策略即可达到不同的效果
btcore.addwhitelist("11:22:33:44:55:66", 0)
--允许任何设备连接,但只允许白名单中的设备扫描。
--此广播状态下,A、B设备都可以连接此从机设备,但只有A设备可以扫描到它
btcore.setadvparam(0x80, 0xa0, 0, 0, 0x07, 1)
btcore.advertising(1)
--允许任何设备扫描,但只允许白名单中的设备连接。
--此广播状态下,A、B设备都可以扫描到此从机设备,但只有A设备可以连接它
btcore.setadvparam(0x80, 0xa0, 0, 0, 0x07, 2)
btcore.advertising(1)
--只允许白名单中的设备扫描和连接。
--此广播状态下,只有A设备可以扫描并连接此从机设备,B设备无法扫描、连接此从机设备
btcore.setadvparam(0x80, 0xa0, 0, 0, 0x07, 3)
btcore.advertising(1)
```
# 示例
相关实例程序在脚本库的demo\bluetooth文件夹下,包含主机、从机、becaon和经典蓝牙。可以根据实际需要选择demo进行研究。
本示例是对demo的程序删改而来
**初始化注册蓝牙消息回调函数**
以\script_LuaTask_V2.3.9\demo\bluetooth\slave.lua作为基础进行修改。首先使用rtos.on()注册蓝牙消息的回调处理函数。
```lua
local function init()
log.info("bt", "init")
rtos.on(rtos.MSG_BLUETOOTH, function(msg)
if msg.event == btcore.MSG_OPEN_CNF then --蓝牙打开成功
--此处根据自己需要的业务逻辑来处理
--例如:在这里sys.publish一条消息,表示蓝牙打开成功了
sys.publish("BLE_OPEN")
elseif msg.event == btcore.MSG_CLOSE_CNF then --蓝牙关闭成功
--此处根据自己需要的业务逻辑来处理
elseif msg.event == btcore.MSG_BLE_CONNECT_IND then --蓝牙连接结果
--此处根据自己需要的业务逻辑来处理
--msg.result表示连接结果,0为连接成功
--msg.handle为连接句柄
--例如:在这里sys.publish一条消息,消息携带的参数含有蓝牙连接结果
sys.publish("BT_CONNECT_IND", {["handle"] = msg.handle, ["result"] = msg.result})
elseif msg.event == btcore.MSG_BLE_DISCONNECT_IND then--蓝牙断开连接
--此处根据自己需要的业务逻辑来处理
elseif msg.event == btcore.MSG_BLE_DATA_IND then --蓝牙收到消息
--此处根据自己需要的业务逻辑来处理,当收到蓝牙消息时,使用btcore.recv()读取即可
--例如:在这里sys.publish一条消息,表示蓝牙收到数据了
sys.publish("BT_DATA_IND", {["result"] = msg.result})
end
end)
end
```
**打开蓝牙**
```lua
local function poweron()
log.info("bt", "poweron")
btcore.open(0) --打开蓝牙从模式
--蓝牙打开后,在上面的消息回调内会有蓝牙打开成功的消息上报
--在这里阻塞住,当收到蓝牙打开成功消息时退出阻塞
sys.waitUntil("BLE_OPEN")
end
```
***注意:接口返回成功不一定是打开成功,需要等待蓝牙打开成功的消息***
**设置蓝牙名称,广播参数,服务、特征、描述,广播包、响应包、打开广播**
<br>
**这里我们添加一个服务和两个特征作为演示**
**服务uuid为0xfee0,特征uuid分别为0xfee1和0xfee2**
<br>
0xfee1具有write的属性,这表示主机与从机建立链接后可向0xfee1发送数据
0xfee2具有notify、write、write without response
<br>
<br>
```lua
local function service(uuid,struct)
btcore.addservice(uuid) --添加服务
for i = 1, #struct do
btcore.addcharacteristic(struct[i][1],struct[i][2],struct[i][3]) --添加特征
if(type(struct[i][4]) == "table") then
for j = 1,#struct[i][4] do
btcore.adddescriptor(struct[i][4][j][1],struct[i][4][j][2]) --添加描述
end
end
end
end
local function advertising()
btcore.setname("TESTBLE")-- 设置广播名称
btcore.setadvdata(string.fromHex("02010604ff000203"))-- 设置广播数据 根据蓝牙广播包协议格式
--btcore.setscanrspdata(string.fromHex("04ff000203"))-- 设置扫描响应包 根据蓝牙广播包协议格式
local struct1 = {{0xfee1, 0x08, 0x0002},
{0xfee2, 0x1c,0x0003, {{0x2902,0x0003},{0x2901,"123456"}}}}--{特征uuid,特征属性,特征权限,{特征描述uuid,描述属性}}
service(0xfee0, struct1)--添加服务16bit uuid 自定义服务
--btcore.setadvparam(0x80,0xa0,0,0,0x07,2,0,"11:22:33:44:55:66") --广播参数设置 (最小广播间隔,最大广播间隔,广播类型,广播本地地址类型,广播channel map,广播过滤策略,定向地址类型,定向地址)
btcore.advertising(1)-- 打开广播
end
```
**打开广播等待连接成功后,之后可以进行数据收发,例如**
```lua
local function data_trans()
_, bt_connect = sys.waitUntil("BT_CONNECT_IND")
if bt_connect.result ~= 0 then --连接失败
return false
end
while true do
_, bt_recv = sys.waitUntil("BT_DATA_IND") --等待接收到数据
local data = ""
local len = 0
local uuid = ""
while true do
--读取数据,数据来源uuid,数据,数据长度
local recvuuid, recvdata, recvlen = btcore.recv(3)
if recvlen == 0 then
break
end
uuid = recvuuid
len = len + recvlen
data = data .. recvdata
end
--打印出收到的数据
if len ~= 0 then
log.info("bt.recv_data", data)
log.info("bt.recv_data len", len)
log.info("bt.recv_uuid", string.toHex(uuid))
btcore.send(data, 0xfee2, bt_connect.handle)--发送数据(数据 对应特征uuid 连接句柄)
end
end
```
**最后将以上几个功能模块结合起来,就实现了一个简易的蓝牙连接收发数据功能**
```lua
sys.taskInit(
function()
init()
poweron()
advertising()
data_trans()
end
)
```
# 注意事项
使用手机、电脑与模块低功耗蓝牙进行测试时,需要使用专门的低功耗蓝牙调试软件
手机低功耗蓝牙调试软件这里推荐使用nRF Connect
[nRF Connect下载及使用教程](https://hmi.wiki.luatos.com/doc/65042949/e6zPC3k9/sivVjmZk)