蓝牙Mesh网络是一种多对多通信网络,节点设备之间可以相互通信,具有覆盖范围大、功耗低、安全性高、入网灵活、支持大规模节点设备等特点。 蓝牙SIG组织于2017年7月发布了蓝牙Mesh V1.0标准,AliOS Things BLE Mesh协议栈是基于该标准的实现。下面的架构图,展示了AliOS Things中提供的蓝牙相关软件产品,以及BLE Mesh协议栈在产品架构中的位置。
Ble mesh组件源代码位于component/wireless/bluetooth/blemesh
下,头文件位于include/wireless/bluetooth/blemesh
下。
API列表
bt_mesh_init | 蓝牙Mesh协议栈初始化 |
bt_mesh_reset | 蓝牙Mesh节点状态重置 |
bt_mesh_prov_enable | 节点Provision使能设置(ADV或者GATT) |
bt_mesh_prov_disable | 节点Provision禁止设置(ADV或者GATT) |
bt_mesh_model_msg_init | BLE model消息初始化 |
bt_mesh_model_send | 发送一条应用层消息 |
bt_mesh_model_publish | 发送model的发布消息 |
bt_mesh_get_shell_cmd_list | 获取BLE mesh相关的命令 |
使用
组件使能需要在需要引用blemesh组件的aos.mk中添加:
$(NAME)_COMPONENTS := bt_mesh
包含头文件
应用需要在源文件中添加ble mesh的头文件
#include <blemesh.h>
使用示例
1.蓝牙协议初始化
int ret;
ret = bt_enable(bt_ready);
if (ret) {
printk("Bluetooth init failed (err %d)\n", ret);
}
//然后在协议栈初始化成功回调函数中执行ble mesh初始化的流程
2.Mesh composition data准备
该步骤准备provision过程中所需的composition data,包括company ID、节点包含的elements信息。本示例中,element包括Configuration Client、Configuration Server、Sensor Client三个Model。
static struct bt_mesh_model root_models[] = {
/* BLE mesh强制配置server model */
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL(BT_MESH_MODEL_ID_SENSOR_CLI, temp_cli_op,
&temp_cli_pub, NULL),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
};
/* 配置一个Provisioning Node的 composition data */
static const struct bt_mesh_comp comp = {
.cid = CID_INTEL,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
3.Mesh provision数据准备
Mesh provision时所需的参数,包括设备uuid、OOB输出/入方式、provision完成的回调处理函数等。该示例代码中,指定设备uuid为0xdddd,OOB以数字形式输出,并指定了provision完成后的回调。
static const uint8_t dev_uuid[16] = { 0xdd, 0xdd };
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
.output_size = 4,
.output_actions = BT_MESH_DISPLAY_NUMBER,
.output_number = output_number,
.complete = prov_complete,
};
4. 初始化mesh协议栈
int ret;
ret = bt_mesh_init(&prov, &comp);
if (ret) {
printk("Initializing mesh failed (err %d)\n", ret);
return;
}
5. 使能provision
该步骤使能节点的provision功能,使设备可以被provisioner设备发现和provision。provision类型支持PB-ADV(BT_MESH_PROV_GATT)和PB-GATT(BT_MESH_PROV_ADV)。 通过以上几个步骤后,设备还需要主动调用bt_mesh_prov_enable来具备被provisioner发现和配置的功能,传入参数指定参数PB-GATT或者PB-ADV方式,或者都指定。用户可以通过Bluez meshctl、nRF Mesh手机APP等工具对该设备进行provision操作。
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
API详情
bt_mesh_init
初始化BLE mesh协议栈,成功之后Node需要调用bt_mesh_prov_enable()来使能unprovisioned adv。
函数原型
int bt_mesh_init(const struct bt_mesh_prov *prov, const struct bt_mesh_comp *comp)
输入参数
prov | const struct bt_mesh_prov * | provision配置信息,包含uuid、OOB认证方式和认证信息长度、provision相关回调等 |
comp | const struct bt_mesh_comp * | 节点支持的element、model等配置 |
返回参数
0 :成功。
负值:错误, 见错误编码定义部分。
调用示例:
/*定义Node上的各个element*/
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, vnd_models),
};
static const struct bt_mesh_comp comp = {
.cid = CID_INTEL,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
/*定义provisioning的能力和属性*/
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
.output_size = 4,
.output_actions = BT_MESH_DISPLAY_NUMBER,
.output_number = output_number,
.complete = prov_complete,
.reset = prov_reset,
};
/*初始化调用BLE mesh协议栈*/
int ret;
ret = bt_mesh_init(&prov, &comp);
if (ret) {
printk("Initializing mesh failed (err %d)\n", ret);
return;
}
bt_mesh_reset
蓝牙Mesh节点状态重置。调用该接口后,设备需要重新provision才能加入mesh网络。此外,调用该接口后,设备不会自动广播unprovision beacon,要调用bt_mesh_prov_enable接口重新使能相应bearer的广播。
函数原型
void bt_mesh_reset(void)
输入参数
无
返回参数
无
调用示例
static int cmd_reset(int argc, char *argv[])
{
bt_mesh_reset();
printk("Local node reset complete\n");
return 0;
}
bt_mesh_prov_enable
Provision使能设置,调用此接口设备才能进入unprovisioned广播态,参数可以指定provision方式(PB-ADV或者PB-GATT)
函数原型
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
输入参数
bearer | bt_mesh_prov_bearer_t | Bearer设置,ADV或者GATT。 |
返回参数
0 :成功。负值:错误, 具体错误见错误编码定义部分。
bt_mesh_prov_disable
关闭Provision能力(PB-ADV或者PB-GATT)。
函数原型
int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers)
输入参数
bearer | bt_mesh_prov_bearer_t | Bearer provision方式,ADV或者GATT,或者全部。 |
返回参数
0 :成功。
负值:错误编码, 见错误编码定义部分。
调用示例:
err = bt_mesh_prov_disable(bearer);
if (err) {
printk("Failed to disable %s (err %d)\n", bearer2str(bearer), err);
} else {
printk("%s disabled\n", bearer2str(bearer));
}
bt_mesh_model_msg_init
model消息初始化。该接口初始化消息buf,并填充opcode头信息。
函数原型
void bt_mesh_model_msg_init(struct net_buf_simple *msg, u32_t opcode)
输入参数
msg | struct net_buf_simple * | 用于发送消息的net_buf |
opcode | u32_t | 消息对应的opcode码 |
返回参数
无
调用示例
static void gen_onoff_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 1 + 4);
printk("onoff get: addr 0x%04x onoff 0x%02x\n",
model->elem->addr, g_onoff_state.current);
bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
net_buf_simple_add_u8(&msg, g_onoff_state.current);
if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) {
printk("Unable to send On Off Status response\n");
}
}
bt_mesh_model_send
发送一条应用层消息。
函数原型
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *msg,
const struct bt_mesh_send_cb *cb, void *cb_data)
输入参数
model | struct bt_mesh_model * | 消息对应的model |
ctx | struct bt_mesh_msg_ctx * | 消息的上下文信息,包括key索引、对端地址、TTL等 |
msg | struct net_buf_simple * | 需要发送的消息 |
cb | const struct bt_mesh_send_cb * | 消息发送完毕的回调。该参数可选 |
cb_data | void* | 回调函数的用户参数 |
返回参数
0 :成功。
负值:错误编码,见错误编码定义部分。
调用示例
可参考bt_mesh_model_msg_init部分示例。
bt_mesh_model_publish
发送model的发布消息。调用该接口前,用户确保需要model的bt_mesh_model_pub.msg中包含有效的消息。该接口仅用于非周期性的消息发布。
函数原型
int bt_mesh_model_publish(struct bt_mesh_model *model)
输入参数
model | struct bt_mesh_model * | 消息对应的model |
返回参数
0:成功 。
负值:错误, 编码见错误编码定义部分。
调用示例:
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
net_buf_simple_add_u8(msg, g_onoff_state.current);
err = bt_mesh_model_publish(model);
if (err) {
printk("bt_mesh_model_publish err %d\n", err);
}
bt_mesh_get_shell_cmd_list
获取ble mesh相关的命令,此部分命令列表可以参考通过shell 命令部分。
函数原型
struct mesh_shell_cmd *bt_mesh_get_shell_cmd_list()
输入参数
无
返回参数
struct mesh_shell_cmd的命令列表。
调用示例:
mesh_cmds = bt_mesh_get_shell_cmd_list();
if (mesh_cmds) {
p = mesh_cmds;
while (p->cmd_name != NULL) {
if (strcmp(p->cmd_name, cmd_str) != 0) {
p++;
continue;
}
if (p->cb) {
no_match = 0;
p->cb(argc - 1, &(argv[1]));//这里会调用注册的回调函数
}
break;
}
}
配置说明
在ble mesh配置选项中选择后可以继续根据配置使能相对应的功能和配置。

配置项说明
- PB-GATT: 通过GATT链路进行provisioning。
- GATT Proxy: 支持GATT代理服务,一般用在GATT client和mesh网络之间。
- LOW-Power:Low power功能。
- FRIEND:friend功能。
- CFG_CLI:配置客户端,基本model。
- HEALTH_CLI:基本model health。
- standalone deploy:单独编译ble mesh组件,不包含依赖的ble host。
- enable shell configuration component:使能shell命令的功能。
标准宏和结构体说明
struct bt_mesh_prov
bt mesh属性和能力的结构体。
static struct bt_mesh_prov prov = {
.uuid = dev_uuid,
.link_open = link_open,
.link_close = link_close,
.complete = prov_complete,
.reset = prov_reset,
//.static_val = NULL,
//.static_val_len = 0,
.output_size = 6,
.output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
.output_number = output_number,
.output_string = output_string,
.input_size = 6,
.input_actions = (BT_MESH_ENTER_NUMBER | BT_MESH_ENTER_STRING),
.input = input,
};
struct bt_mesh_provisioner
BLE mesh provisioner实例,初始化调用。如:
static struct bt_mesh_provisioner provisioner = {
.prov_uuid = 0,
.prov_unicast_addr = PROVISIONER_UNICAST_ADDR,
.prov_start_address = NODE_START_UNICAST_ADDR,
.prov_attention = 0,
.prov_algorithm = 0,
.prov_pub_key_oob = 1,
.prov_pub_key_oob_cb = provisioner_pub_key_oob,
.prov_static_oob_val = default_static_oob,
.prov_static_oob_len = 4,
.prov_input_num = provisioner_input_num,
.prov_output_num = provisioner_output_num,
.flags = 0,
.iv_index = 0,
.prov_link_open = provisioner_link_open,
.prov_link_close = provisioner_link_close,
.prov_complete = provisioner_complete,
};
ret = bt_mesh_init(&prov, &comp, &provisioner);
if (ret) {
printk("Mesh initialization failed (err %d)\n", ret);
}
struct bt_mesh_model_pub
model publication的定义。
struct bt_mesh_model_pub {
/** 上下文的model,协议栈初始化需要设置. */
struct bt_mesh_model *mod;
u16_t addr; /**< Publish 地址. */
u16_t key; /**< Publish AppKey 索引. */
u8_t ttl; /**< Publish 的TTL. */
u8_t retransmit; /**< 重试次数. */
u8_t period; /**< Publish 时间长度. */
u8_t period_div:4, /**< Public 时间的除数因子. */
cred:1, /**< Friendship Credentials Flag. */
count:3; /**< 剩余重传次数. */
u32_t period_start; /**< 当前时间段的开始时间. */
struct net_buf_simple *msg;
int (*update)(struct bt_mesh_model *mod);
/** Publish 消息的定时器. */
struct k_delayed_work timer;
};
struct bt_mesh_elem
bt mesh的结构体抽象。
struct bt_mesh_elem {
/* 单播地址,在provisioning的时候设置 */
u16_t addr;
/* 地址的描述符 */
const u16_t loc;
const u8_t model_count;
const u8_t vnd_model_count;
struct bt_mesh_model * const models;
struct bt_mesh_model * const vnd_models;
};
struct bt_mesh_msg_ctx
mesh发送消息的结构体。
struct bt_mesh_msg_ctx {
/** 发送消息目的NetKey的索引*/
u16_t net_idx;
/** 要加密的AppKey索引. */
u16_t app_idx;
/** 目的地址*/
u16_t addr;
/** 收到的TTL */
u8_t recv_ttl:7;
/** 当使用ACK的时候强制发送 */
u8_t send_rel:1;
/** 发送TTL. */
u8_t send_ttl;
};
struct bt_mesh_model_op
mesh model的opcode结构体,包含opcode,handler。
struct bt_mesh_model_op {
/* ble mesh的消息的OpCode */
const u32_t opcode;
/* 最小的消息长度 */
const size_t min_len;
/* 对应opcode的回调函数 */
void (*const func)(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf);
};
struct bt_mesh_model
bt mesh model的实例。
struct bt_mesh_model {
union {
const u16_t id;
struct {
u16_t company;
u16_t id;
} vnd;
};
/* Model属于的Element */
struct bt_mesh_elem *elem;
/* Model的Publication 上下文*/
struct bt_mesh_model_pub * const pub;
/* AppKey列表 */
u16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
/* Subscription 列表 (组播或者虚拟地址) */
u16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
const struct bt_mesh_model_op * const op;
/* Model自定义用户地址 */
void *user_data;
};
struct mesh_shell_cmd
BLE mesh 命令函结构体定义。
struct mesh_shell_cmd {
const char *cmd_name;
shell_cmd_function_t cb;
const char *help;
const char *desc;
};
BT_MESH_ELEM ( loc, mods, _vnd_mods)
BLE mesh element的抽象。可以使用此宏定义一个element, 配合bt_mesh_model, bt_mesh_elem使用如下。
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
BT_MESH_MODEL_HEALTH_CLI(&health_cli),
};
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
};
值定义
_mods | model的数组 |
_vnd_mods | vendor model的数组 |
BT_MESH_MODEL(id, op, pub, user_data)
BT SIG bt mesh model的定义。
op | model opcode的回调函数 |
pub | model publish的参数 |
user | model的用户参数 |
BT_MESH_MODEL_CFG_CLI
定义一个config client的model。
#define BT_MESH_MODEL_CFG_CLI(cli_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_CLI, \
bt_mesh_cfg_cli_op, NULL, cli_data)
BT_MESH_MODEL_CFG_SRV
定义一个config server的model。
#define BT_MESH_MODEL_CFG_SRV(srv_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_SRV, \
bt_mesh_cfg_srv_op, NULL, srv_data
BT_MESH_MODEL_HEALTH_CLI
定义一个health client 的model。
#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_CLI, \
bt_mesh_health_cli_op, NULL, cli_data)
BT_MESH_MODEL_HEALTH_SRV
定义一个health server的model。
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_SRV, \
bt_mesh_health_srv_op, pub, srv)
enum bt_mesh_output_action_t
BLE mesh output能力,现阶段只处理BT_MESH_DISPLAY_STRING和BT_MESH_DISPLAY_NUMBER。
BT_MESH_NO_OUTPUT
BT_MESH_BLINK
BT_MESH_BEEP
BT_MESH_VIBRATE
BT_MESH_DISPLAY_NUMBER
BT_MESH_DISPLAY_STRING
enum bt_mesh_input_action_t
BLE mesh 输入能力,现阶段只处理BT_MESH_ENTER_STRING和BT_MESH_ENTER_NUMBER。
BT_MESH_NO_INPUT
BT_MESH_PUSH
BT_MESH_TWIST
BT_MESH_ENTER_NUMBER
BT_MESH_ENTER_STRING
错误码定义
#define EPERM 1 /*操作不允许*/
#define ENOENT 2 /*文件/路径不存在*/
#define ESRCH 3 /*进程不存在*/
#define EINTR 4 /*中断的系统调用*/
#define EIO 5 /*I/O错误*/
#define ENXIO 6 /*设备/地址不存在*/
#define E2BIG 7 /*参数列表过长*/
#define ENOEXEC 8 /*执行格式错误*/
#define EBADF 9 /*错误文件编号*/
#define ECHILD 10 /*子进程不存在*/
#define EAGAIN 11 /*重试*/
#define ENOMEM 12 /*内存不足*/
#define EACCES 13 /*无权限*/
#define EFAULT 14 /*地址错误*/
#define ENOTBLK 15 /*需要块设备*/
#define EBUSY 16 /*设备或资源忙*/
#define EEXIST 17 /*文件已存在*/
#define EXDEV 18 /*跨设备链路*/
#define ENODEV 19 /*设备不存在*/
#define ENOTDIR 20 /*路径不存在
#define EISDIR 21 /*是路径*/
#define EINVAL 22 /*无效参数*/
#define ENFILE 23 /*文件表溢出*/
#define EMFILE 24 /*打开的文件过多*/
#define ENOTTY 25 /*非打字机*/
#define ETXTBSY 26 /*文本文件忙*/
#define EFBIG 27 /*文件太大*/
#define ENOSPC 28 /*设备无空间*/
#define ESPIPE 29 /*非法查询*/
#define EROFS 30 /*只读文件系统*/
//....POSIX err code
enum bt_mesh_prov_bearer_t
provision bearer的两种类型。
BT_MESH_PROV_ADV
BT_MESH_PROV_GATT
enum bt_mesh_prov_oob_info_t
OOB消息,对应蓝牙mesh协议的OOB消息,16比特,BLE mesh spec定义(Mesh Profile, V1.0, Page 119):
0 | Other |
1 | Electronic / URI |
2 | 2D machine-readable code |
3 | Bar code |
4 | Near Field Communication (NFC) |
5 | Number |
6 | String |
7-10 | Reserved for Future Use |
11 | on box |
12 | in box |
13 | On piece of paper |
14 | Inside manual |
15 | On device |
BT_MESH_PROV_OOB_OTHER
BT_MESH_PROV_OOB_URI
BT_MESH_PROV_OOB_2D_CODE
BT_MESH_PROV_OOB_BAR_CODE
BT_MESH_PROV_OOB_NFC
BT_MESH_PROV_OOB_NUMBER
BT_MESH_PROV_OOB_STRING
BT_MESH_PROV_OOB_ON_BOX
BT_MESH_PROV_OOB_IN_BOX
BT_MESH_PROV_OOB_ON_PAPER
BT_MESH_PROV_OOB_IN_MANUAL
BT_MESH_PROV_OOB_ON_DEV
在文档使用中是否遇到以下问题
更多建议
匿名提交