Mesh Provisioner
Mesh Provisioner Sample 展示了如何使用 Mesh Provisioner 以及如何开发基于 Mesh Provisioner 的应用程序。
Mesh Provisioner 作为 mesh 网络的管理员,主要功能如下:
在 Mesh Device 入网时分发地址和密钥。
管理各个节点。
环境需求
该示例支持以下开发工具包:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
该示例需要还需要另一个设备或多个设备运行 Mesh Device,作为网络中的节点。
更多要求,请参考 快速入门 。
硬件连线
配置选项
关于 LE 所需要的配置请查看
samples\bluetooth\mesh\mesh_provisioner\src\app_flags.h
。关于 Mesh 所需要的配置请查看
samples\bluetooth\mesh\mesh_provisioner\src\app_mesh_flags.h
。
编译和下载
该示例可以在 SDK 文件夹中找到:
Project file: samples\bluetooth\mesh\mesh_provisioner\proj\rtl87x2g\mdk
Project file: samples\bluetooth\mesh\mesh_provisioner\proj\rtl87x2g\gcc
编译和运行该示例请遵循以下步骤:
打开项目文件。
编译目标文件, 请参考 快速入门 中 编译APP Image 中列出的步骤。
编译成功后,目录
samples\bluetooth\mesh\mesh_provisioner\proj\rtl87x2g\mdk\bin
下 会生成文件app_MP_sdk_xxx.bin
。在 EVB 板上按下 reset 按钮,程序将开始运行。
测试验证
将示例工程烧录到 EVB 板后,可以使用另一个开发板运行 Mesh Device 工程相互进行测试。
准备阶段
准备一个 Mesh Provisioner,如有必要请使用
Debug Analyzer
工具获取日志。准备一个或者多个 Mesh Device,如有必要请使用
Debug Analyzer
工具获取日志。
测试阶段
本节主要介绍 Mesh Provisioner 的测试部分和相关 User Command 的用法,方便用户前期学习,后期调试。 有关 User Command 的详细信息,请参阅 User Command Interface。
用户可以使用任何串口助手软件与 EVB 板进行交互。有关 Mesh Provisioner 的详细用户命令,请参阅 mesh_cmd.c
、 provisioner_cmd.c
、 client_cmd.c
Provisioning
Provisioner 可以收集附近节点信息并显示出来,通过 dis
命令开关。
Step |
Provisioner |
说明 |
---|---|---|
1 |
dis 1 |
显示周边 mesh device |
2 |
dis 0 |
搜集到目标 device 的信息后(device UUID 或者 Bluetooth address),关闭搜索 |
Device 会在 Provisioning 中获得地址和网络密钥,成功后即加入网络,可以进行 mesh 通信。
使用 transport 层 ping 功能,即 tping
命令,进行网络层测试,
可以与网络中的任意节点互相发送和接收 transport 层的 ping/pong 消息。
Provisioner 也可以使用 configuration client 和指定的 device 进行通信,例如获取 composition data page 0。
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
pbadvcon 000102030405 060708090a0b0c0d0e0f |
发起对 UUID 为 000102030405060708090a0b0c0d0e0f 的设备的连接, 等待提示 PB-ADV bearer 是否成功建立 |
|
2 |
prov |
等待提示 provisioning 流程结束 |
|
3 |
ls |
查看 device 是否成功获得地址和密钥,假定地址为 0x0100 |
|
4 |
tping xffff |
测试是否能互相进行网络层通信 |
|
5 |
cdg x100 |
获取 device 0x100 的 composition data page 0 |
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
con ff0011223344 |
与对端蓝牙地址 0xff0011223344 的设备建立 LE link,等待提示成功建立 |
|
2 |
provdis |
查询 provision service |
|
3 |
provcmd 0 1 |
使能 provision CCCD |
|
4 |
prov |
等待提示 provisioning 流程结束 |
|
5 |
ls |
查看 device 是否成功获得地址和密钥 |
|
6 |
tping xffff |
测试是否能互相进行网络层通信 |
|
7 |
cdg x100 |
获取 device 0x100 的 composition data page 0 |
已经被 Provisioning 的 device,可以通过 nr
命令恢复到 Unprovisioned 状态。
密钥管理
已经被 Provisioning 的设备可以被 configuration client 配置。 例如添加 AppKey、绑定 AppKey 到 ping model 上。 然后 ping model 就可以发送 model 层的 ping 消息。
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
aka x100 0 0 |
给目标节点 0x100 添加 AppKey 0,并绑定到 NetKey 0 上 |
|
2 |
ls |
查看 device 是否成功添加 AppKey 0 |
|
3 |
mab x100 0 x5d 0 |
给目标节点 0x100 的第 0 个 element 的 model id 为 0x5d 的 ping model 绑定 AppKey 0 |
|
4 |
ls |
查看 device 的 ping model 是否成功绑定 AppKey 0 |
|
5 |
ping xffff 3 |
测试 ping model control model |
订阅配置
Provisioner 可以管理 device 的 model 订阅地址。 例如为 ping model 添加订阅地址。
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
msa x100 0 x5d xc000 |
给目标节点 0x100 的第 0 个 element 的 model id 为 0x5d 的 ping model 添加 subscribe address 0xc000 |
|
2 |
ls |
查看 device 的 model 是否成功添加 subscribe address 0xc000 |
|
3 |
ping xc000 3 |
测试 device 是否订阅 0xc000 |
Friendship
已经被 Provisioning 的 low power node 设备可以开始建立 friendship。
Step |
Friend Node |
Low Power Node |
说明 |
---|---|---|---|
1 |
fninit 1 5 |
lpninit 1 |
初始化 friend node,支持与 1 个 LPN node 建立 friendship 且 queue 大小为 5, 初始化 LPN node,支持与 1 个 friend node 建立 friendship |
2 |
lpnreq 0 0 |
等待提示 friendship 建立结果 |
|
3 |
tping xffff 3 |
发现 tping 耗时会变长 |
Remote Provisioning
已经被 Provisioning 的 remote provisioning server 设备可以帮助收集其附近节点信息并传递给 remote provisioning client。
Step |
Provisioner |
RPR server |
说明 |
---|---|---|---|
1 |
rpsst x100 10 20 |
指示 RPR server 搜索其周边 mesh device |
|
2 |
rpssp x100 0 |
搜集到目标 device 的信息后(device UUID 或者 Bluetooth address), 指示其关闭搜索 |
Step |
Provisioner |
RPR server |
说明 |
---|---|---|---|
1 |
rplop x100 0 x00010203040506070 8090a0b0c0d0e0f 10 |
指示 RPR server 发起对 000102030405060708090a0b0c0d0e0f 的 连接,等待 RPR server 提示是否成功建立 |
|
2 |
prov |
等待提示 provisioning 流程结束 |
|
3 |
ls |
查看 device 是否成功获得地址和密钥 |
|
4 |
tping xffff |
测试是否能互相进行网络层通信 |
|
5 |
cdg x101 |
获取 device 0x101 的 composition data page 0 |
Step |
Provisioner |
RPR server |
说明 |
---|---|---|---|
1 |
rplod x100 0 0 |
发起对 RPR server 的连接,并指示该程序为 device key refresh |
|
2 |
rprdk |
启动 refresh device key 流程 |
Step |
Provisioner |
RPR server |
说明 |
---|---|---|---|
1 |
rplod x100 0 1 |
发起对 RPR server 的连接,并指示该程序为 node address refresh |
|
2 |
rprna x103 |
启动 refresh node address 流程 |
Step |
Provisioner |
RPR server |
说明 |
---|---|---|---|
1 |
pids x21 |
为 composition page 128 设置新数据 |
|
2 |
rplod x103 0 2 |
发起对 RPR server 的连接,并指示该程序为 composition data refresh |
|
3 |
rprcd |
启动 refresh composition data 流程 |
Directed Forwarding
已经被 Provisioning 的设备想要使用 directed forwarding 功能可以参考以下流程,需要先配置 directed forwarding control state,将已经配置好 AppKey 的 model 的 publish policy 方式设置为 directed forwarding。
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
dcs x100 0 0 1 1 1 1 1 |
使能 device 的 directed forwarding control state |
|
2 |
dpps x100 0 1 x100 x5d |
将 ping model 的 publish policy 设置为 directed forwarding 方式 |
|
3 |
ping x1 3 |
ping 的同时会自动触发 path discovery 流程 |
|
4 |
dfpdis 0 x1 0 0 |
也可以主动触发 path discovery 流程 |
|
5 |
dfpsol 0 x100 |
主动触发 path solicitation 流程 |
|
6 |
dfpdupt 0 x100 x120 1 |
主动触发 path dependents update 流程 |
|
7 |
fta x100 0 0 1 1 x200 2 x300 2 1 1 |
通过 directed forwarding model 添加 fixed path |
|
8 |
ftda x100 0 0 x200 x300 1 1 x700 10 x220 1 |
通过 directed forwarding model 添加 fixed path 的 dependents 信息 |
Subnet Bridge
节点同时处于 net 0 (NetKey index 为 0)和 net 1 (NetKey index 为 1)网络时, subnet bridge client 可以通过 subnet bridge model 为节点配置 subnet bridge table, 配置后节点可以将 net 0 的 message 转发到 net 1。 注意,桥接的消息在转发时会使用对应的 NetKey 加密,但是 AppKey 不会改变, 发送与接收消息的节点需要 AppKey 一致才可以正确解密 Access layer 的数据。
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
bta x100 0 1 0 1 x102 x103 |
为 0x100 节点配置 subnet bridge table, 0x102 (net 0) –> 0x103 (net 1) |
Binary Large Object Transfer
已经被 Provisioning 的设备可以参考以下流程使用 BLOB models 进行传输。
Step |
Provisioner |
Device |
说明 |
---|---|---|---|
1 |
mab x100 0 x1400ffff 0 |
为 0x100 节点 blob transfer server 添加 AppKey 0 |
|
2 |
btsi 0x1100000000000011 10 3 |
初始化 blob transfer server |
|
3 |
btccr 0 2 1 x100 |
启动 capability retrieve 流程 |
|
4 |
btcbt x100 0 2 0x1100000000000011 2000 1 1 0 1 x100 |
启动 blob transfer 流程 |
|
5 |
btctc 0x1100000000000011 1 x100 |
取消 blob transfer 流程 |
Device Firmware Update
请参考 Bluetooth Mesh OTA。
代码介绍
本章的主要目的是帮助用户熟悉 Mesh Provisioner 相关的开发流程。本章将按照以下几个部分进行介绍:
源码路径
Project directory:
sdk\samples\bluetooth\mesh\mesh_provisioner\proj
Source code directory:
sdk\samples\bluetooth\mesh\mesh_provisioner\src
Mesh Provisioner 应用程序项目中的源文件结构如下所示。
└── Project: mesh_provisioner
└── secure_only_app
├── Device includes startup code
├── CMSE Library Non-secure callable lib
├── lib includes all binary symbol files that user application is built on
├── ROM_NS.lib
├── rtl87x2g_sdk.lib
├── rtl87x2g_io.lib
├── gap_utils.lib
├── mesh_prov.lib
└── lowerstack.lib
├── io includes all peripheral drivers and module code used by the application
├── profile includes LE profiles or services used by the application
├── model includes mesh models used by the application
├── dfu includes dfu source code used by the application
└── APP includes the mesh_provisioner user application implementation
├── main.c includes the io, os, platform, le host and mesh stack initialization
├── app_task.c includes app task initialization and main loop
├── provisioner_app.c includes provisioner application code
├── mesh_sdk.c includes mesh sdk version record
├── mesh_cmd.c includes mesh user commands
├── provisioner_cmd.c includes provisioner user commands
├── test_cmd.c includes test user commands
├── client_cmd.c includes client user commands
├── delay_msg_rsp.c includes delay message response
├── ping_app.c includes ping model application code
├── generic_client_app.c includes generic client model application code
├── light_client_app.c includes light client model application code
├── datatrans_client_app.c includes datatrans client model application code
├── rmt_prov_client_app.c includes remote provisioning client model application code
├── blob_client_app.c includes blob client model application code
├── dfu_distributor_app.c includes dfu distributor application code
└── dfu_initiator_app.c includes dfu Initiator application code
其中,mesh_prov.lib
根据 Mesh Protocol 版本分为 V1.0
和 V1.1
,
用户可以根据所需 feature 选择合适的 lib。
Library file: subsys\bluetooth\mesh\chips\rtl87x2g\lib\v1_0\mdk\mesh_prov.lib
, subsys\bluetooth\mesh\chips\rtl87x2g\lib\v1_0\gcc\mesh_prov.a
Header file: subsys\bluetooth\mesh\chips\rtl87x2g\lib\v1_0\mesh_config.h
Library file: subsys\bluetooth\mesh\chips\rtl87x2g\lib\v1_1\mdk\mesh_prov.lib
, subsys\bluetooth\mesh\chips\rtl87x2g\lib\v1_1\gcc\mesh_prov.a
Header file: subsys\bluetooth\mesh\chips\rtl87x2g\lib\v1_1\mesh_config.h
初始化
当 EVB 板 reset 时,main()
函数会执行,初始化流程如下:
int main(void)
{
extern uint32_t random_seed_value;
srand(random_seed_value);
board_init();
driver_init();
le_gap_init(APP_MAX_LINKS);
gap_lib_init();
app_le_gap_init();
app_le_profile_init();
mesh_stack_init();
pwr_mgr_init();
task_init();
os_sched_start();
return 0;
}
le_gap_init()
用于初始化 GAP 并设置 link 数目。app_le_gap_init()
用于初始化 GAP 参数。app_le_profile_init()
用于初始化 Profile。mesh_stack_init()
用于初始化 Mesh Stack, 有关配置可以参考 设备信息配置、 Device UUID 设置 、 网络特性和参数配置 、 Mesh Log 配置 等。
相比于网络中其他节点,Provisioner 在初始化时就需要为自己分配 Mesh 地址以及部分 Keys,示例如下。
void mesh_stack_init(void)
{
......
/** init mesh stack */
mesh_init();
/** configure provisioner */
mesh_node.node_state = PROV_NODE;
mesh_node.unicast_addr = bt_addr[0] % 99 + 1;
const uint8_t net_key[] = MESH_NET_KEY;
const uint8_t net_key1[] = MESH_NET_KEY1;
const uint8_t app_key[] = MESH_APP_KEY;
const uint8_t app_key1[] = MESH_APP_KEY1;
uint16_t net_key_index = net_key_add(0, net_key);
app_key_add(net_key_index, 0, app_key);
uint8_t net_key_index1 = net_key_add(1, net_key1);
app_key_add(net_key_index1, 1, app_key1);
mesh_model_bind_all_key();
......
}
在 os_sched_start()
调用之后, app_main_task()
会得到调度,Mesh message 相关的处理如下:
#define EVENT_MESH 0x80
......
void app_main_task(void *p_param)
{
......
mesh_start(EVENT_MESH, EVENT_IO_TO_APP, evt_queue_handle, io_queue_handle);
......
while (true)
{
if (os_msg_recv(evt_queue_handle, &event, 0xFFFFFFFF) == true)
{
if (event == EVENT_IO_TO_APP)
{
......
}
else if (event == EVENT_MESH)
{
mesh_inner_msg_handle(event);
}
else
{
......
}
}
}
}
网络管理
Provisioner 做为网络管理员,需要对加入网络中的所有节点进行管理, 包括 Provisioning 流程,Configuration models 的配置过程,以及后续的消息交互。
Provisioning: Provisioning 详情请参考 Mesh 配网 , 操作流程请参考 Provisioning 操作流程。
Model: Provisioner 会包含一些固定的 Models 和 部分用户自行注册的 Models。 有关 Model 的部分请参考 Mesh Model。
Message Send: 发送消息部分请参考 Mesh 消息发送。