BlueZ是Linux官方蓝牙协议栈。它是一个基于GNU General Public License (GPL)发布的开源项目,从Linux 2.4.6开始便成为Linux 内核的一部分。如果你是linux平台开发蓝牙的的工程师,肯定会接触过Bluez协议栈,hciconfig,hciattach,hciconfig等工具都是很好用的工具。
关于蓝牙Mesh的功能,Bluez协议栈从Release 5.47(14th September 2017)逐步开始支持,在Bluez官网可以看到目前最新的是2022年11月14日发布的Release 5.66(14th November 2022),但从该文件夹中的TODO文件中可以看到,截至到今天蓝牙Mesh的单元测试还没有全部实现。
Bluez协议栈的代码庞大,同时支持经典蓝牙和BLE,使用大量的linux系统的api,在linux系统上运行稳定,但不方便移植到其他RTOS平台,同时又对BLE Mesh的支持相对比较慢,所以导致了很多芯片原厂并没有使用Bluez的开源Mesh协议栈部分,而是自己开发或者移植的一套。但仍然有一些原厂使用了Bluez的mesh协议栈,并使用它通过了QDID认证,所以虽然Bluez的Mesh协议栈目前大厂使用的比较少,但是也是可以放心使用的。
另外一点需要注意的是Bluez的Mesh协议栈对运行的linux内核版本有要求,需要目标平台的内核版本在4.9及以上才行,原因是Bluez的Mesh代码为了执行效率,使用了内核的加解密实现,当然这部分完全可以不调用内核的接口,在应用层替换为的加解密库来代替。
If Mesh Cryptography is not working, the following configuration options
may need to be enabled, and the kernel rebuilt.
1. A minimum of kernel version 4.9 or later is required
2. The kernel must at a minimum have the following .config options turned on:
CONFIG_CRYPTO_USER
CONFIG_CRYPTO_USER_API
CONFIG_CRYPTO_USER_API_AEAD
CONFIG_CRYPTO_USER_API_HASH
CONFIG_CRYPTO_USER_API_SKCIPHER
CONFIG_CRYPTO_AES
CONFIG_CRYPTO_CCM
CONFIG_CRYPTO_AEAD
CONFIG_CRYPTO_CMAC
进入到bluez的目录中,configure,make,然后sudo make install。
bluez源码在编译时,会依赖很多第三方的开源库,网上相关文档有很多,可以自行查找。
解决完依赖问题之后,运行如下:
#./configure --enable-mesh --enable-debug --enable-testing --enable-logger --enable-library --enable-threads --disable-optimization --disable-systemd --disable-silent-rules --disable-obex --disable-datafiles --disable-manpages --enable-experimental --enable-deprecated --enable-tools --sysconfdir=/etc --localstatedir=/userdata
配置中最重要的是--enable-mesh。编译成功之后,我们进入下一个章节部分。
编译完成之后,在tools目录下除了bluez最常用的hciconfig,hciattach和btmon等可执行文件之外,还有mesh相关的meshctl,mesh-cfgtest和mesh-cfgclient可执行文件。
我们首先回归一下bluez的最常见操作,一个service叫做bluetoothd在后台运行,一个client叫做bluetoothctl在前台运行,他们通过dbus进行通信,详情如下:
client/bluetoothctl:前台运行,需要在终端窗口执行bluetoothctl命令,然后输入相关操作指令。
src/bluetoothd:后台运行,由系统启动和关闭。
mesh功能也是类似的操作,它的前台执行程序和后台执行程序分别是mesh-cfgclient和bluetooth-meshd,核心的业务逻辑在bluetooth-meshd中实现。
tools/mesh-cfgclient:通过dbus和bluetooth-meshd通信,实现了mesh协议的adv bear层的scan,provision和configuration功能,支持发送config消息,但是却没有generic onoff的代码实现,需要使用者自己实现generic onoff和vendor消息。
mesh/bluetooth-meshd:后台运行,linux系统不会默认启动,需要手动启动或者在systemd,init.rc等启动配置文件中手动添加。需要说明的是启动bluetooth-meshd的时候,需要关闭bluetoothd。
tools/mesh-cfgtest:测试bluetooth-meshd和client是否可以正常通信的工具,它在源码中会fork出来一个进程去执行bluetooth-meshd程序,然后mesh-cfgtest的主程序会和bluetooth-meshd进行通信,根据相对路径找到mesh/bluetooth-meshd可执行程序然后执行,因此如果执行失败,可以看看是否是因为找不到bluetooth-meshd程序导致的。
tools/meshctl:该程序实现了mesh协议栈的proxy特性,同样可以扫描,provision和configuration,并且有控制灯开关的generic onoff代码实现,但是它是基于gatt bear层实现的,并不是通过adv bear层实现。 另外一点是它并不依赖bluetooth-meshd程序,它是与bluetoothd后台程序进行通信的。
bluetooth-meshd:源码在bluez-5.65/mesh/目录中,是mesh协议栈的核心代码。
mesh-cfgclient:源码在bluez-5.65/tools/mesh目录中,tools/mesh-cfgclient.c文件是程序的入口。
mesh-cfgtest:源码在bluez-5.65/tools/mesh目录中,tools/mesh-cfgtest.c文件时程序的入口。
meshctl:源码在bluez-5.65/tools/mesh-gatt目录中,meshctl.c是程序的入口。
电脑:thinkpad-neo14,电脑支持蓝牙,但是经过查看,该蓝牙并不支持BLE。
系统:ubuntu-20.04(内核版本5.15.0-60-generic)。
Bluez 5.65源码:打开mesh配置,编译生成可执行文件。
PTS-dongle:由于电脑的蓝牙不支持BLE,因此通过插入USB Dongle来支持BLE功能。
Nordic PCA10040开发板:基于Nordic芯片nrf 52832,作为外围的mesh设备使用,运行nordic的官方light历程。
将pts dongle插入电脑usb口,通过hciattach命令,将它挂载到hci总线上。
bluez-5.65$ sudo hciattach /dev/ttyACM0 any 115200 flow
Device setup complete
通过hciconfig命令,查看到当前的dongle对应的是hci 1。
bluez-5.65$ hciconfig
hci1:Type: Primary Bus: UART
BD Address: C0:07:E8:34:E1:B1 ACL MTU: 256:4 SCO MTU: 0:0
UP RUNNING
RX bytes:298 acl:0 sco:0 events:25 errors:0
TX bytes:181 acl:0 sco:0 commands:25 errors:0
hci0:Type: Primary Bus: USB
BD Address: 00:93:37:8D:57:D8 ACL MTU: 8192:128 SCO MTU: 64:128
UP RUNNING
RX bytes:1062 acl:0 sco:0 events:53 errors:0
TX bytes:1215 acl:0 sco:0 commands:53 errors:0
Nordic开发板烧录mesh light固件,重置让其处于待配网状态。
mesh-ctl在运行时需要load自身provisioner的mesh网络配置信息,该信息存在local_node.json文件中,该文件在mesh-gatt目录中。再次强调,不需要启动bluetooth-meshd程序,mesh-ctl与bluetoothd进行通信,使用的是gatt连接通道。
启动meshctl。
bluez-5.65/tools$ meshctl --config mesh-gatt/
Waiting to connect to bluetoothd...Reading prov_db.json and local_node.json from mesh-gatt/ directory
[meshctl]#
执行list指令,查看当前使用的是否为pts dongle的controller,如果不是的话,需要执行select指令来切换controller。
[meshctl]# list
Controller C0:07:E8:34:E1:B1 ubuntu #2 [default]
Controller 00:93:37:8D:57:D8 ubuntu
执行discover-unprovisioned on指令,查找周边unprovision的mesh设备。
[meshctl]# discover-unprovisioned on
SetDiscoveryFilter success
Discovery started
Adapter property changed
[CHG] Controller C0:07:E8:34:E1:B1 Discovering: yes
Mesh Provisioning Service (00001827-0000-1000-8000-00805f9b34fb)
Device UUID: 12fd23161a044a37ab06feb08680db3f
OOB: 0000
[NEW] Device C0:86:B0:FE:06:6B nRF5x Mesh Light
执行provision指令 +该设备的UUID,选择nRF5x Mesh Light设备进行配网。
[meshctl]# provision 12fd23161a044a37ab06feb08680db3f
Trying to connect Device C0:86:B0:FE:06:6B nRF5x Mesh Light
Adapter property changed
[CHG] Controller C0:07:E8:34:E1:B1 Discovering: no
Connection successful
Service added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000a
Service added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e
Char added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f:
Char added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011:
Services resolved yes
Found matching char: path /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f, uuid 00002adb-0000-1000-8000-00805f9b34fb
Found matching char: path /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011, uuid 00002adc-0000-1000-8000-00805f9b34fb
Start notification on /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011
Characteristic property changed /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011
AcquireNotify success: fd 7 MTU 69
Notify for Mesh Provisioning Out Data started
Open-Node: 0x561b6ffe1950
Open-Prov: 0x561b6ffeea50
Open-Prov: proxy 0x561b6ffe5160
Initiated provisioning
Characteristic property changed /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f
AcquireWrite success: fd 8 MTU 69
GATT-TX: 03 00 10
GATT-RX: 03 01 01 00 01 00 01 00 00 00 00 00 00
Got provisioning data (12 bytes)
01 01 00 01 00 01 00 00 00 00 00 00
GATT-TX: 03 02 00 00 01 00 00
GATT-TX: 03 03 ee 84 1d fe 6d 12 07 cd 64 b7 27 f0 9f 6a
GATT-TX: f0 7d 40 1d 7b a7 58 73 a1 46 fd 0f 91 59 1e 51
GATT-TX: ae 8f 3c 75 33 0c 23 73 dc 1f 04 aa de e5 5f 70
GATT-TX: 3e 7d 32 d8 b3 b8 44 63 5f bb d2 e0 d5 83 49 73
GATT-TX: 71 3a
GATT-RX: 03 03 a6 3f 72 b2 30 c4 d1 da a0 fb f0 9c 04 b6
GATT-RX: ea cf 95 c2 ca 79 f4 6a a7 ca 5b 4d f1 dd f0 aa
GATT-RX: 35 28 bd 4b ff 2c 6c e3 65 eb d4 89 52 6a 44 34
GATT-RX: 89 f6 1b 13 0e 47 98 e6 a9 1f fa 90 5e 0e ac 58
GATT-RX: f6 05
Got provisioning data (65 bytes)
03 a6 3f 72 b2 30 c4 d1 da a0 fb f0 9c 04 b6 ea
cf 95 c2 ca 79 f4 6a a7 ca 5b 4d f1 dd f0 aa 35
28 bd 4b ff 2c 6c e3 65 eb d4 89 52 6a 44 34 89
f6 1b 13 0e 47 98 e6 a9 1f fa 90 5e 0e ac 58 f6
05
该设备的固件是Nordic的标准demo程序,使用static oob方式认证,因此在命令行提示输入时,需要输入该设备的static oob(static oob信息在Nordic的demo程序中可以搜索到,我将它改为0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16)。
Request hexadecimal key (hex 16 octets)
[[mesh-agent]# ] Enter key (hex number): 01020304050607080910111213141516
GATT-TX: 03 05 8b bc c6 62 d1 02 ea 6c 2d 65 8c 81 7c 21
GATT-TX: 93 01
GATT-RX: 03 05 dc fa 72 ca 23 14 54 9e fc 8a a1 e4 36 45
GATT-RX: 8a 09
Got provisioning data (17 bytes)
05 dc fa 72 ca 23 14 54 9e fc 8a a1 e4 36 45 8a
09
GATT-TX: 03 06 6b b0 b0 b6 25 1a cf f5 ee 2d cd ef 90 c2
GATT-TX: f3 9c
GATT-RX: 03 06 a0 b6 92 4e e5 7f 70 eb a3 7d 6e 24 fd fc
GATT-RX: 6b 95
Got provisioning data (17 bytes)
06 a0 b6 92 4e e5 7f 70 eb a3 7d 6e 24 fd fc 6b
95
Confirmation Validated
S-Key c7 e5 6e db ad 8e 22 dd 5c 79 39 94 a3 c6 12 7a
S-Nonce d9 79 41 09 71 ff be 7a 1b 50 67 36 83
DevKey 65 2f 98 92 6e 8f fe 48 cf 83 19 5f 2a ce 13 6d
Data 18 ee d9 c2 a5 6a dd 85 04 9f fc 3c 59 ad 0e 12
Data 00 00 00 00 00 00 05 01 01
DataEncrypted + mic 55 40 57 7c a6 1f 7c de 96 e9 03 9f 6c 34 a0 25
DataEncrypted + mic 7f ae cb ea 59 cd 04 51 7d 0d 84 77 9b 49 f8 95
DataEncrypted + mic 88
GATT-TX: 03 07 55 40 57 7c a6 1f 7c de 96 e9 03 9f 6c 34
GATT-TX: a0 25 7f ae cb ea 59 cd 04 51 7d 0d 84 77 9b 49
GATT-TX: f8 95 88
GATT-RX: 03 08
Got provisioning data (1 bytes)
08
Provision success. Assigned Primary Unicast 0101
Attempting to disconnect from C0:86:B0:FE:06:6B
Characteristic property changed /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011
Write closed
Services resolved no
Characteristic property changed /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f
SetDiscoveryFilter success
Discovery started
Adapter property changed
[CHG] Controller C0:07:E8:34:E1:B1 Discovering: yes
Mesh Proxy Service (00001828-0000-1000-8000-00805f9b34fb)
Identity for node 0101
Trying to connect to mesh
Adapter property changed
[CHG] Controller C0:07:E8:34:E1:B1 Discovering: no
Connection successful
Service added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e
Char added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f:
Char added /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011:
Services resolved yes
Found matching char: path /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f, uuid 00002add-0000-1000-8000-00805f9b34fb
Found matching char: path /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011, uuid 00002ade-0000-1000-8000-00805f9b34fb
Start notification on /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011
Characteristic property changed /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char0011
AcquireNotify success: fd 7 MTU 69
Notify for Mesh Proxy Out Data started
Trying to open mesh session
GATT-RX: 01 01 00 d4 76 79 43 3f db 10 4a 00 00 00 05 f4
GATT-RX: 0a 41 fa b0 af 32 0b
iv_upd_state = IV_UPD_NORMAL
Mesh session is open
Characteristic property changed /org/bluez/hci1/dev_C0_86_B0_FE_06_6B/service000e/char000f
AcquireWrite success: fd 8 MTU 69
GATT-TX: 02 f4 8c 6d ef 98 ac 2e 79 c8 e0 2c 83 2b 4a b4
GATT-TX: c9 1f e3 a9
GATT-TX: 00 f4 34 db 0a 23 20 65 a4 40 e9 3c e1 c0 13 e8
GATT-TX: f9 04 ee 42 34 ab
GATT-RX: 02 f4 35 d1 c4 66 28 17 1b 6d ed 86 f9 26 19 ca
GATT-RX: d5 6f 3c 9e 7b cd
Proxy Accept list filter length: 0
GATT-RX: 00 f4 e6 5e ff 9d 4c 8d ec 50 a8 70 23 94 12 ce
GATT-RX: 72 71 52 2d 5b 81 d3 26 ba 20 11 8d 4f 6c
GATT-RX: 00 f4 2a d1 1b ec 8d cf 93 dd 2f c7 63 f0 79 29
GATT-RX: 55 a5 b6 29 9b e3 15 fa fe 61 65 6b 1d 81
GATT-RX: 00 f4 55 4d c6 8b ae 4a 36 ef 3e 2d 5a 2b 2a 24
GATT-RX: 60 54 fd 03 0f b3 e8 1c 6d e7
Composition data for node 0101 {
"cid":"0059",
"pid":"0000",
"vid":"0000",
"crpl":"0028",
"features":{
"relay":true,
"proxy":true,
"friend":true,
"lpn":false
},
"elements":[
{
"elementIndex":0,
"location":"0000",
"models":[
"0000",
"0002",
"1000",
"1004",
"1203",
"1204"
]
}
]
}
GATT-TX: 00 f4 71 66 e6 89 61 44 19 6b c1 75 a4 a9 b8 f2
GATT-TX: ed 9b b9 ee 99 b5 96 bc 05
[nRF5x Mesh Light-Node-0101]#
provision成功之后,需要对该节点进行config,创建添加netkey和appkey,再bind之后,就可以进行控制了,从以上日志中可以看到Node的unicast address是0101(之前配置多了一次,正常情况是从0100开始分配地址)。
# menu config
# target 0101
# netkey-add 0
# appkey-add 1
# bind 0 1 1000 (第一个0并不是netkey的index,而是element index)
# back
[nRF5x Mesh Light-Node-0101]# menu config
Menu config:
Available commands:
-------------------
target <unicast> Set target node to configure
composition-get [page_num] Get composition data
netkey-add <net_idx> Add network key
netkey-del <net_idx> Delete network key
appkey-add <app_idx> Add application key
appkey-del <app_idx> Delete application key
bind <ele_idx> <app_idx> <mod_id> [cid] Bind app key to a model
mod-appidx-get <ele_addr> <model id> Get model app_idx
ttl-set <ttl> Set default TTL
ttl-get Get default TTL
pub-set <ele_addr> <pub_addr> <app_idx> <per (step|res)> <re-xmt (cnt|per)> <mod id> [cid]
Set publication
pub-get <ele_addr> <model> Get publication
proxy-set <proxy> Set proxy state
proxy-get Get proxy state
ident-set <net_idx> <state> Set node identity state
ident-get <net_idx> Get node identity state
beacon-set <state> Set node identity state
beacon-get Get node beacon state
relay-set <relay> <rexmt count> <rexmt steps> Set relay
relay-get Get relay
hb-pub-set <pub_addr> <count> <period> <ttl> <features> <net_idx> Set heartbeat publish
hb-pub-get Get heartbeat publish
hb-sub-set <src_addr> <dst_addr> <period> Set heartbeat subscribe
hb-sub-get Get heartbeat subscribe
sub-add <ele_addr> <sub_addr> <mod id> [cid] Add subscription
sub-get <ele_addr> <model id> Get subscription
node-reset Reset a node and remove it from network
back Return to main menu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[nRF5x Mesh Light-Node-0101]# target 0101
Configuring node 0101
[config: Target = 0101]# netkey-add 0
GATT-TX: 00 f4 ac dd 2f b5 e8 e4 ba 41 b3 c8 d9 0c 3a 5d
GATT-TX: 70 e2 ee d2 d0 93 1e f4 1a d3 ae e2 d3 d4
GATT-TX: 00 f4 25 d7 4b 06 f3 ec 4b 05 a0 1b c0 48 12 db
GATT-TX: 77 fd de 25 73 4c 43 79 f7 df 82 b6 14 0d
GATT-RX: 00 f4 67 0d 0b 8d 9d c6 9c a0 0a f2 b1 8a cd f3
GATT-RX: 26 e5 21 3f 9e 4b 39 d9 f9
GATT-RX: 00 f4 2d 38 85 ca 04 95 db 66 c5 9e b4 b8 1a 94
GATT-RX: 13 26 23 ab b3 bd b3 49
Node 0101 NetKey status Success
NetKey 000
[config: Target = 0101]# appkey-add 1
GATT-TX: 00 f4 64 9d a0 bd bf 64 c3 c6 fc 86 af 3e 5c fe
GATT-TX: 86 0f 02 25 dc a2 00 5e 10 fc e2 fc e7 f2
GATT-TX: 00 f4 43 c2 3d 7a 00 84 3b 28 94 b2 f7 e5 6d f8
GATT-TX: 41 59 42 ef 79 76 90 43 53 d2 7f 78 8e d7
GATT-RX: 00 f4 69 80 59 aa 2c d5 a4 c7 ca b1 38 67 df dc
GATT-RX: 2c 37 c6 52 4e e2 79 7d 2b
GATT-RX: 00 f4 fc c6 51 35 07 5e 79 b1 29 99 38 89 67 d4
GATT-RX: fa ab 55 c5 38 ab b1 b1 24
Node 0101 AppKey status Success
NetKey000
AppKey001
[config: Target = 0101]# bind 0 1 1000
GATT-TX: 00 f4 db 88 7a d1 04 e4 94 a9 ff 75 a0 75 31 2d
GATT-TX: b5 cf 8a 3a 93 6a 73 95 f7 81 ae
GATT-RX: 00 f4 b2 e7 31 ec 0e a7 2c 20 22 9c 4d e3 a0 77
GATT-RX: 06 31 59 d4 2c 58 7f 0c 0b ee e9 6a
Node 0101 Model App status Success
Element Addr0101
Model Id1000
AppIdx001
[config: Target = 0101]# back
Menu main:
Available commands:
-------------------
config Configuration Model Submenu
onoff On/Off Model Submenu
list List available controllers
show [ctrl] Controller information
select <ctrl> Select default controller
security [0(low)/1(medium)/2(high)] Display or change provision security level
info [dev] Device information
connect [net_idx] [dst] Connect to mesh network or node on network
discover-unprovisioned <on/off> Look for devices to provision
provision <uuid> Initiate provisioning
power <on/off> Set controller power
disconnect [dev] Disconnect device
mesh-info Mesh networkinfo (provisioner)
local-info Local mesh node info
menu <name> Select submenu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[config: Target = 0101]#
进入onoff菜单开始控制mesh light。
# menu onoff
# target 0101
# onoff 0
# onoff 1
[config: Target = 0101]# menu onoff
Menu onoff:
Available commands:
-------------------
target <unicast> Set node to configure
get Get ON/OFF status
onoff <0/1> Send "SET ON/OFF" command
back Return to main menu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[config: Target = 0101]# target 0101
Controlling ON/OFF for node 0101
[on/off: Target = 0101]# onoff 0
GATT-TX: 00 f4 5b af 3e 2b 49 56 ab 12 1d 7e fa 21 10 cd
GATT-TX: b8 87 44 82 e2 a6 4f
GATT-RX: 00 f4 60 4a 41 80 22 5c 54 f4 37 33 5e c4 66 30
GATT-RX: db af c0 85 1b 00
On Off Model Message received (1) opcode 8204
00
[on/off: Target = 0101]# onoff 1
GATT-TX: 00 f4 02 6d 3d be 75 62 9d 88 27 fe a4 c5 81 6d
GATT-TX: b5 95 a2 e4 46 9e 8c
GATT-RX: 00 f4 b3 7d a7 bc ab 23 54 ec fb 1c f3 1e 04 60
GATT-RX: da ca 72 a9 80 b6
On Off Model Message received (1) opcode 8204
01
与local_node.json的同级目录中,会生成prov_db.json,里面记录了provision的子设备。
注意:如果当前controller不支持BLE特性,discover-unprovisioned on会返回错误。
[meshctl]# list
Controller C0:07:E8:34:E1:B1 ubuntu #2
Controller 00:93:37:8D:57:D8 ubuntu [default]
[meshctl]# discover-unprovisioned on
SetDiscoveryFilter success
Failed to start discovery: org.bluez.Error.InProgress
该测试程序的意义是确定bluetooth-meshd程序和cfgclient程序是否可以正常进行dbus通信,通信接口是否可以正常调度而已。
bluez-5.65$ ./tools/mesh-cfgtest
Config AppKey Add: Success - init
Connected to D-Bus
D-Bus ready
D-Bus client connected
Loading node configuration from /tmp/mesh
mesh_ready_callback
Added Network Interface on /org/bluez/mesh
Proxy added: org.bluez.mesh.Network1 (/org/bluez/mesh)
D-Bus client ready
Proxy added: org.bluez.mesh.Node1 (/org/bluez/mesh/node4349778868df46f5959d6df8caccc57f)
Proxy added: org.bluez.mesh.Management1 (/org/bluez/mesh/node4349778868df46f5959d6df8caccc57f)
Attached with path /org/bluez/mesh/node4349778868df46f5959d6df8caccc57f
Received dev key message (len 5):80 44 0 1 0
Received dev key message (len 6):80 3 0 1 10 0
Config AppKey Add: Success - setup
Config AppKey Add: Success - setup complete
Config AppKey Add: Success - run
Received dev key message (len 6):80 3 0 1 20 0
Config AppKey Add: Success - test passed
Config AppKey Add: Success - teardown
Config AppKey Add: Success - teardown complete
Config AppKey Add: Success - done
Config Default TTL Set: Success - init
Config Default TTL Set: Success - setup
Config Default TTL Set: Success - setup complete
Config Default TTL Set: Success - run
Received dev key message (len 3):80 e 7
Config Default TTL Set: Success - test passed
Config Default TTL Set: Success - teardown
Config Default TTL Set: Success - teardown complete
Config Default TTL Set: Success - done
Config Get Device Composition: Success - init
Config Get Device Composition: Success - setup
Config Get Device Composition: Success - setup complete
Config Get Device Composition: Success - run
Received dev key message (len 28):2 0 f1 5 2 0 1 0 ff 7f 5 0 0 0 1 0 0 0 0 0 1 1 0 10 f1 5 1 0
Config Get Device Composition: Success - test passed
Config Get Device Composition: Success - teardown
Config Get Device Composition: Success - teardown complete
Config Get Device Composition: Success - done
Config Bind: Success - init
Config Bind: Success - setup
Config Bind: Success - setup complete
Config Bind: Success - run
Received dev key message (len 9):80 3e 0 ce b 1 0 0 10
Config Bind: Success - test passed
Config Bind: Success - teardown
Config Bind: Success - teardown complete
Config Bind: Success - done
Config Bind: Error Invalid Model - init
Config Bind: Error Invalid Model - setup
Config Bind: Error Invalid Model - setup complete
Config Bind: Error Invalid Model - run
Received dev key message (len 9):80 3e 2 ce b 1 0 0 11
Config Bind: Error Invalid Model - test passed
Config Bind: Error Invalid Model - teardown
Config Bind: Error Invalid Model - teardown complete
Config Bind: Error Invalid Model - done
Test Summary
------------
Config AppKey Add: Success Passed 0.063 seconds
Config Default TTL Set: Success Passed 0.004 seconds
Config Get Device Composition: Success Passed 0.003 seconds
Config Bind: Success Passed 0.006 seconds
Config Bind: Error Invalid Model Passed 0.006 seconds
Total: 5, Passed: 5 (100.0%), Failed: 0, Not Run: 0
Overall execution time: 0.082 seconds
mesh-cfgclient是通过adv bear进行操作的,也是mesh协议栈的更核心的功能,mesh-cfgclient在执行时,需要后台运行bluetooth-meshd程序,由于改程序与bluetoothd程序都是对controller独占的,因此需要先将bluetoothd后台服务程序停掉,再启动mesh-cfgclient。
停止bluetoothd程序。
$ sudo systemctl stop bluetooth
启动bluetooth-meshd程序,ubuntu系统下有多个蓝牙芯片时,需要指定所使用的支持BLE的Controller,我这里是hci1。
$ sudo bluetooth-meshd --io generic:hci1 -nd
D-Bus ready
Loading node configuration from /userdata/lib/bluetooth/mesh
Loading configuration from /userdata/lib/bluetooth/mesh/bbfde82d96b64230a8dca2c319260eb5/node.json
mesh/node.c:init_from_storage() relay 00, proxy 02, lpn 02, friend 00
mesh/net-keys.c:net_key_beacon_refresh() Setting SNB: IVI: 00000000, IVU: 0, KR: 0
mesh/util.c:print_packet() 96361.194 Set SNB Beacon to: 2b0100d9c583863ec0f8fb00000000088395e198dc3555
mesh/net.c:trigger_heartbeat() HB: 0002 --> 0
mesh/net.c:mesh_net_set_friend_mode() mesh_net_set_friend_mode - 0
mesh/net.c:trigger_heartbeat() HB: 0001 --> 0
mesh/cfgmod-server.c:cfgmod_server_init() 00
mesh/mesh.c:mesh_init() io 0x55e882721f40
mesh/mesh-io-generic.c:hci_init() Started mesh on hci 1
mesh_ready_callback
Added Network Interface on /org/bluez/mesh
mesh/net-keys.c:snb_timeout() beacon 1 for 1 nodes, period 20, obs 2, exp 2
另外启动一个窗口,运行mesh-cfgclient程序,依此运行。
# create(创建db文件)
# discover-unprovisioned on(扫描未配网设备)
# provision 12FD23161A044A37AB06FEB08680DB3F(provision设备)
# ] Enter key (hex number): 01020304050607080910111213141516(输入static oob)
# appkey-create 0 0(创建appkey)
# list-nodes(列出已配网的nodes)
# keys(显示已创建的密钥)
# menu config(进入config配置菜单)
# target 00aa(配置0x00aa设备)
# composition-get (获取子设备的composition data)
# proxy-get (获取子设备的proxy feature开关状态)
# proxy-set 0(设置子设备的proxy feature开关状态)
# appkey-add 0(给子设备添加appkey)
# bind 00aa 0 1000(绑定appkey到model上)
[config: Target = 00aa]#(这时候应该支持通过广播通路发送onoff消息控制mesh灯了,只是未实现)
tools$ ./mesh-cfgclient
Warning: config file "/home/***/.config/meshcfg/config_db.json" not found
[mesh-cfgclient]# create
Created new node with token f6742b9205917f5b
Proxy added: org.bluez.mesh.Node1 (/org/bluez/mesh/node40289f0c72b24cb8b7d73e6e21f952c4)
Proxy added: org.bluez.mesh.Management1 (/org/bluez/mesh/node40289f0c72b24cb8b7d73e6e21f952c4)
Attached with path /org/bluez/mesh/node40289f0c72b24cb8b7d73e6e21f952c4
[mesh-cfgclient]# discover-unprovisioned on
Unprovisioned scan started
Scan result:
rssi = -37
UUID = 12FD23161A044A37AB06FEB08680DB3F
OOB = 0000
URI Hash = 74F97940
Scan result:
rssi = -36
UUID = 12FD23161A044A37AB06FEB08680DB3F
OOB = 0000
URI Hash = 74F97940
[mesh-cfgclient]# provision 12FD23161A044A37AB06FEB08680DB3F
Provisioning started
Request hexadecimal key (hex 16 octets)
[[mesh-agent]# ] Enter key (hex number): 01020304050607080910111213141516
Assign addresses for 1 elements
Provisioning done:
Mesh node:
UUID = 12FD23161A044A37AB06FEB08680DB3F
primary = 00aa
elements (1):
[mesh-cfgclient]# help
Menu main:
Available commands:
-------------------
config Configuration Model Submenu
create [unicast_range_low] Create new mesh network with one initial node
discover-unprovisioned <on/off> [seconds] Look for devices to provision
appkey-create <net_idx> <app_idx> Create a new local AppKey
appkey-import <net_idx> <app_idx> <key> Import a new local AppKey
appkey-update <app_idx> Update local AppKey
appkey-delete <app_idx> Delete local AppKey
subnet-create <net_idx> Create a new local subnet (NetKey)
subnet-import <net_idx> <key> Import a new local subnet (NetKey)
subnet-update <net_idx> Update local subnet (NetKey)
subnet-delete <net_idx> Delete local subnet (NetKey)
subnet-set-phase <net_idx> <phase> Set subnet (NetKey) phase
list-unprovisioned List unprovisioned devices
provision <uuid> Initiate provisioning
node-import <uuid> <net_idx> <primary> <ele_count> <dev_key> Import an externally provisioned remote node
list-nodes List remote mesh nodes
keys List available keys
export-db Export mesh configuration database
menu <name> Select submenu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[mesh-cfgclient]# appkey-create 0 0
[mesh-cfgclient]# list-nodes
Mesh node:
UUID = 40289F0C72B24CB8B7D73E6E21F952C4
primary = 0001
net_keys = 0 (0x000) ,
elements (1):
Mesh node:
UUID = 12FD23161A044A37AB06FEB08680DB3F
primary = 00aa
net_keys = 0 (0x000) ,
elements (1):
[mesh-cfgclient]# keys
NetKey: 0 (0x000), phase: 0
app_keys = 0 (0x000),
[mesh-cfgclient]# help
Menu main:
Available commands:
-------------------
config Configuration Model Submenu
create [unicast_range_low] Create new mesh network with one initial node
discover-unprovisioned <on/off> [seconds] Look for devices to provision
appkey-create <net_idx> <app_idx> Create a new local AppKey
appkey-import <net_idx> <app_idx> <key> Import a new local AppKey
appkey-update <app_idx> Update local AppKey
appkey-delete <app_idx> Delete local AppKey
subnet-create <net_idx> Create a new local subnet (NetKey)
subnet-import <net_idx> <key> Import a new local subnet (NetKey)
subnet-update <net_idx> Update local subnet (NetKey)
subnet-delete <net_idx> Delete local subnet (NetKey)
subnet-set-phase <net_idx> <phase> Set subnet (NetKey) phase
list-unprovisioned List unprovisioned devices
provision <uuid> Initiate provisioning
node-import <uuid> <net_idx> <primary> <ele_count> <dev_key> Import an externally provisioned remote node
list-nodes List remote mesh nodes
keys List available keys
export-db Export mesh configuration database
menu <name> Select submenu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[mesh-cfgclient]# menu config
Menu config:
Available commands:
-------------------
target <unicast> Set target node to configure
timeout <seconds> Set response timeout (seconds)
composition-get [page_num] Get composition data
netkey-add <net_idx> Add NetKey
netkey-update <net_idx> Update NetKey
netkey-del <net_idx> Delete NetKey
netkey-get List NetKeys known to the node
kr-phase-get <net_idx> Get Key Refresh phase of a NetKey
kr-phase-set <net_idx> <phase> Set Key Refresh phase transition of a NetKey
appkey-add <app_idx> Add AppKey
appkey-update <app_idx> Add AppKey
appkey-del <app_idx> Delete AppKey
appkey-get <net_idx> List AppKeys bound to the NetKey
bind <ele_addr> <app_idx> <model_id> [vendor_id] Bind AppKey to a model
unbind <ele_addr> <app_idx> <model_id> [vendor_id] Remove AppKey from a model
mod-appidx-get <ele_addr> <model_id> [vendor_id] Get model app_idx
ttl-set <ttl> Set default TTL
ttl-get Get default TTL
pub-set <ele_addr> <pub_addr> <app_idx> <per (step|res)> <re-xmt (cnt|per)> <model_id> [vendor_id] Set publication
pub-get <ele_addr> <model_id> [vendor_id] Get publication
proxy-set <proxy> Set proxy state
proxy-get Get proxy state
ident-set <net_idx> <state> Set node identity state
ident-get <net_idx> Get node identity state
beacon-set <state> Set node identity state
beacon-get Get node beacon state
relay-set <relay> <rexmt count> <rexmt steps> Set relay
relay-get Get relay
friend-set <state> Set friend state
friend-get Get friend state
network-transmit-get Get network transmit state
network-transmit-set <count> <steps> Set network transmit state
hb-pub-set <pub_addr> <count> <period> <ttl> <features> <net_idx> Set heartbeat publish
hb-pub-get Get heartbeat publish
hb-sub-set <src_addr> <dst_addr> <period> Set heartbeat subscribe
hb-sub-get Get heartbeat subscribe
virt-add Generate and add a virtual label
group-list Display existing group addresses and virtual labels
sub-add <ele_addr> <sub_addr> <model_id> [vendor] Add subscription
sub-del <ele_addr> <sub_addr> <model_id> [vendor] Delete subscription
sub-wrt <ele_addr> <sub_addr> <model_id> [vendor] Overwrite subscription
sub-del-all <ele_addr> <model_id> [vendor] Delete subscription
sub-get <ele_addr> <model_id> [vendor] Get subscription
node-reset Reset a node and remove it from network
back Return to main menu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[mesh-cfgclient]# target 00aa
Configuring node 00aa
[config: Target = 00aa]# composition-get
Received DeviceCompositionStatus (len 27)
Received composion:
Feature support:
relay: yes
proxy: yes
friend: yes
lpn: no
Element 0:
location: 0000
SIG defined models:
Model ID0000 "Configuration Server"
Model ID0002 "Health Server"
Model ID1000 "Generic OnOff Server"
Model ID1004 "Generic Default Transition Time Server"
Model ID1203 "Scene Server"
Model ID1204 "Scene Setup Server"
[config: Target = 00aa]# proxy-get
Received ProxyStatus (len 1)
Node 00aa Proxy state 0x01
[config: Target = 00aa]# proxy-set 0
Received ProxyStatus (len 1)
Node 00aa Proxy state 0x00
[config: Target = 00aa]# proxy-get
Received ProxyStatus (len 1)
Node 00aa Proxy state 0x00
[config: Target = 00aa]# appkey-
appkey-add appkey-del appkey-get appkey-update
[config: Target = 00aa]# appkey-add 0
Received AppKeyStatus (len 4)
Node 00aa AppKey status Success
NetKey0 (0x000)
AppKey0 (0x000)
Usage: bind <ele_addr> <app_idx> <model_id> [vendor_id]
[config: Target = 00aa]# bind 00aa 0 1000
Received ModelAppStatus (len 7)
Node 00aa: Model App status Success
Element Addr00aa
Model ID1000 "Generic OnOff Server"
AppIdx0 (0x000)
[config: Target = 00aa]#
重启启动程序,仍然可以很流程的收发config消息(mesh的广播通路)。
tools$ ./mesh-cfgclient
Mesh configuration loaded from /home/****/.config/meshcfg/config_db.json
Proxy added: org.bluez.mesh.Node1 (/org/bluez/mesh/nodec7c80e5eb2b34095a73fd42e381e048e)
Proxy added: org.bluez.mesh.Management1 (/org/bluez/mesh/nodec7c80e5eb2b34095a73fd42e381e048e)
Attached with path /org/bluez/mesh/nodec7c80e5eb2b34095a73fd42e381e048e
[mesh-cfgclient]# list-nodes
Mesh node:
UUID = C7C80E5EB2B34095A73FD42E381E048E
primary = 0001
net_keys = 0 (0x000) ,
elements (1):
Mesh node:
UUID = 12FD23161A044A37AB06FEB08680DB3F
primary = 00aa
net_keys = 0 (0x000) ,
app_keys = 0 (0x000) ,
elements (1):
element 0:
SIG model: 0000 "Configuration Server"
SIG model: 0002 "Health Server"
SIG model: 1000 "Generic OnOff Server"
SIG model: 1004 "Generic Default Transition Time Server"
SIG model: 1203 "Scene Server"
SIG model: 1204 "Scene Setup Server"
[mesh-cfgclient]# menu config
Menu config:
Available commands:
-------------------
target <unicast> Set target node to configure
timeout <seconds> Set response timeout (seconds)
composition-get [page_num] Get composition data
netkey-add <net_idx> Add NetKey
netkey-update <net_idx> Update NetKey
netkey-del <net_idx> Delete NetKey
netkey-get List NetKeys known to the node
kr-phase-get <net_idx> Get Key Refresh phase of a NetKey
kr-phase-set <net_idx> <phase> Set Key Refresh phase transition of a NetKey
appkey-add <app_idx> Add AppKey
appkey-update <app_idx> Add AppKey
appkey-del <app_idx> Delete AppKey
appkey-get <net_idx> List AppKeys bound to the NetKey
bind <ele_addr> <app_idx> <model_id> [vendor_id] Bind AppKey to a model
unbind <ele_addr> <app_idx> <model_id> [vendor_id] Remove AppKey from a model
mod-appidx-get <ele_addr> <model_id> [vendor_id] Get model app_idx
ttl-set <ttl> Set default TTL
ttl-get Get default TTL
pub-set <ele_addr> <pub_addr> <app_idx> <per (step|res)> <re-xmt (cnt|per)> <model_id> [vendor_id] Set publication
pub-get <ele_addr> <model_id> [vendor_id] Get publication
proxy-set <proxy> Set proxy state
proxy-get Get proxy state
ident-set <net_idx> <state> Set node identity state
ident-get <net_idx> Get node identity state
beacon-set <state> Set node identity state
beacon-get Get node beacon state
relay-set <relay> <rexmt count> <rexmt steps> Set relay
relay-get Get relay
friend-set <state> Set friend state
friend-get Get friend state
network-transmit-get Get network transmit state
network-transmit-set <count> <steps> Set network transmit state
hb-pub-set <pub_addr> <count> <period> <ttl> <features> <net_idx> Set heartbeat publish
hb-pub-get Get heartbeat publish
hb-sub-set <src_addr> <dst_addr> <period> Set heartbeat subscribe
hb-sub-get Get heartbeat subscribe
virt-add Generate and add a virtual label
group-list Display existing group addresses and virtual labels
sub-add <ele_addr> <sub_addr> <model_id> [vendor] Add subscription
sub-del <ele_addr> <sub_addr> <model_id> [vendor] Delete subscription
sub-wrt <ele_addr> <sub_addr> <model_id> [vendor] Overwrite subscription
sub-del-all <ele_addr> <model_id> [vendor] Delete subscription
sub-get <ele_addr> <model_id> [vendor] Get subscription
node-reset Reset a node and remove it from network
back Return to main menu
version Display version
quit Quit program
exit Quit program
help Display help about this program
export Print environment variables
[mesh-cfgclient]# target 00aa
Configuring node 00aa
[config: Target = 00aa]# friend-get
Received FriendStatus (len 1)
Node 00aa Friend state 0x00
[config: Target = 00aa]# friend-set 1
No response for "FrienSet" from 00aa
[config: Target = 00aa]# friend-set 1
Received FriendStatus (len 1)
Node 00aa Friend state 0x01
[config: Target = 00aa]# friend-get
No response for "FriendGet" from 00aa
[config: Target = 00aa]# friend-get
Received FriendStatus (len 1)
Node 00aa Friend state 0x01
[config: Target = 00aa]# friend-get
Received FriendStatus (len 1)
Node 00aa Friend state 0x01
[config: Target = 00aa]# friend-get
Received FriendStatus (len 1)
Node 00aa Friend state 0x01
[config: Target = 00aa]#
bluez的mesh协议栈的核心在bluetooth-meshd的实现中,我们使用mesh协议栈,是想用它的mesh泛洪网络,因此我们还需要多关注广播通路的代码实现。多关注bluetooth-meshd和mesh-cfgclient。
嵌入式linux系统的kernel有可能要小于4.9版本,因此需要在前期做好选型,如果只能选择低版本kernel,可以通过更新kernel的CRYPTO部分来兼容bluez的mesh协议栈。
mesh-cfgclient美中不足的一点是没有generic onoff的demo代码,也没有vendor model的demo代码,因此需要使用者自行去实现。
bluez的mesh协议栈,原生代码并没有开放太细致的接口给client端,比如用client配置netkey和appkey等,这部分也需要使用者自己去构建dbus的通信接口,修改bluetooth-meshd的源代码以更好的支持业务场景。或者直接在bluetooth-meshd的代码上进行开发,将dbus的整套逻辑去掉。
Generic OnOff Model的实现范例,我放在了下一篇文章中介绍。