doubao_chat/apps/common/ble/mesh/examples/provisioner.c

690 lines
19 KiB
C

/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "btstack/bluetooth.h"
#include "bt_common.h"
#include "api/sig_mesh_api.h"
#include "../model_api.h"
#include "adaptation.h"
#include "mesh_net.h"
#include "event/key_event.h"
#include "system/timer.h"
#include "provisioner_config.h"
#include "foundation.h"
#define LOG_TAG "[Mesh-Provisioner]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#if CONFIG_BLE_MESH_ENABLE && (CONFIG_MESH_MODEL == SIG_MESH_PROVISIONER)
extern u16_t primary_addr;
extern void mesh_setup(void (*init_cb)(void));
extern void bt_mac_addr_set(u8 *bt_addr);
extern void prov_complete(u16_t net_idx, u16_t addr);
extern void prov_reset(void);
extern void mesh_cli_cmd_rsp_callback_register(void (*handler)(u32_t opcode));
extern int bt_mesh_pb_adv_open(const u8_t uuid[16], u16_t net_idx, u16_t addr, u8_t attention_duration);
extern void clear_rpl(void);
extern void bt_mesh_tx_reset(void);
extern void mesh_prov_giving_up_callback_register(void (*handler)(void));
static void provisioner_node_configuration(void);
/**
* @brief Config current node features(Relay/Proxy/Friend/Low Power)
*/
/*-----------------------------------------------------------*/
#define BT_MESH_FEAT_SUPPORTED_TEMP ( \
BT_MESH_FEAT_PROXY | \
0 \
)
#include "../feature_correct.h"
const int config_bt_mesh_features = BT_MESH_FEAT_SUPPORTED;
/**
* @brief Config proxy connectable adv hardware param
*/
/*-----------------------------------------------------------*/
#if BT_MESH_FEATURES_GET(BT_MESH_FEAT_LOW_POWER)
const u16 config_bt_mesh_proxy_node_adv_interval = ADV_SCAN_UNIT(3000); // unit: ms
#else
const u16 config_bt_mesh_proxy_node_adv_interval = ADV_SCAN_UNIT(300); // unit: ms
#endif /* BT_MESH_FEATURES_GET(BT_MESH_FEAT_LOW_POWER) */
/**
* @brief Conifg complete local name
*/
/*-----------------------------------------------------------*/
#define BLE_DEV_NAME 'P', 'r', 'o', 'v', 'i', 't', 'i', 'o', 'n', 'e', 'r'
const uint8_t mesh_name[] = {
// Name
BYTE_LEN(BLE_DEV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, BLE_DEV_NAME,
};
void get_mesh_adv_name(u8 *len, u8 **data)
{
*len = sizeof(mesh_name);
*data = mesh_name;
}
/**
* @brief Conifg MAC of current demo
*/
/*-----------------------------------------------------------*/
#define CUR_DEVICE_MAC_ADDR 0x112233440000
static const u8_t prov_net_key[16] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static const u8_t prov_dev_key[16] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static const u8_t prov_app_key[16] = {
0x06, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0x06, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
};
static u8_t flags;
static struct bt_mesh_comp prov_comp;
static uint8_t unprov_uuid[16];
typedef struct {
u16_t net_idx;
u16_t addr;
u8_t num_elem;
u8_t config_step;
u8_t config_failed_cnt;
u8_t uuid[16];
} __prov_node;
static __prov_node curr_pair_node;
/*
* Publication Declarations
*
* The publication messages are initialized to the
* the size of the opcode + content
*
* For publication, the message must be in static or global as
* it is re-transmitted several times. This occurs
* after the function that called bt_mesh_model_publish() has
* exited and the stack is no longer valid.
*
* Note that the additional 4 bytes for the AppMIC is not needed
* because it is added to a stack variable at the time a
* transmission occurs.
*
*/
BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_cli, NULL, 2 + 2);
/* Company Identifiers (see Bluetooth Assigned Numbers) */
#define BT_COMP_ID_LF 0x05D6// Zhuhai Jieli technology Co.,Ltd
/*
* Server Configuration Declaration
*/
static struct bt_mesh_cfg_srv cfg_srv = {
.relay = BT_MESH_FEATURES_GET(BT_MESH_FEAT_RELAY),
.frnd = BT_MESH_FEATURES_GET(BT_MESH_FEAT_FRIEND),
.gatt_proxy = BT_MESH_FEATURES_GET(BT_MESH_FEAT_PROXY),
.beacon = BT_MESH_BEACON_DISABLED,
.default_ttl = 7,
};
static struct bt_mesh_cfg_cli cfg_cli;
static u16 prov_giving_up_timer;
/*
* 给配网者添加generic_onoff_server模型,用于测试实例的待配网设备是否配置成功
*
* 不需要可以去掉
*/
#if 0
BT_MESH_MODEL_PUB_DEFINE(gen_onoff_pub_srv, NULL, 2 + 2);
/* Model Operation Codes */
#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
#define LED0_GPIO_PIN 0
struct onoff_state {
u8_t current;
u8_t previous;
u8_t led_gpio_pin;
};
static struct onoff_state onoff_state[] = {
{ .led_gpio_pin = LED0_GPIO_PIN },
};
const u8 led_use_port[] = {
IO_PORTA_03,
};
static void respond_messsage_schedule(u16 *delay, u16 *duration, void *cb_data)
{
u16 delay_ms;
u16 dst_addr = (u16)cb_data;
pseudo_random_genrate((u8 *)&delay_ms, 2);
if (BT_MESH_ADDR_IS_UNICAST(dst_addr)) {
delay_ms = btctler_get_rand_from_assign_range(delay_ms, 20, 50);
} else {
delay_ms = btctler_get_rand_from_assign_range(delay_ms, 20, 200);
}
*delay = delay_ms;
log_info("respond_messsage delay =%u ms", delay_ms);
}
static const struct bt_mesh_send_cb rsp_msg_cb = {
.user_intercept = respond_messsage_schedule,
};
static void gen_onoff_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4);
struct onoff_state *onoff_state = model->user_data;
log_info("addr 0x%04x onoff 0x%02x",
bt_mesh_model_elem(model)->addr, onoff_state->current);
bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
buffer_add_u8_at_tail(&msg, onoff_state->current);
if (bt_mesh_model_send(model, ctx, &msg, &rsp_msg_cb, (void *)ctx->recv_dst)) {
log_info("Unable to send On Off Status response");
}
}
static void gen_onoff_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *msg = model->pub->msg;
struct onoff_state *onoff_state = model->user_data;
int err;
onoff_state->current = buffer_pull_u8_from_head(buf);
log_info("addr 0x%02x state 0x%02x",
bt_mesh_model_elem(model)->addr, onoff_state->current);
/* log_info_hexdump((u8 *)onoff_state, sizeof(*onoff_state)); */
gpio_direction_output(onoff_state->led_gpio_pin,
onoff_state->current);
}
static void gen_onoff_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
log_info("gen_onoff_set");
gen_onoff_set_unack(model, ctx, buf);
gen_onoff_get(model, ctx, buf);
}
/*
* OnOff Model Server Op Dispatch Table
*
*/
static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
{ BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get },
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set },
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack },
BT_MESH_MODEL_OP_END,
};
#endif
// test---------------------------------------------------------------------
/*
*
* Element Model Declarations
*
* Element 0 Root Models
*/
static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
BT_MESH_MODEL_CFG_CLI(&cfg_cli), // default for self-configuration network
//BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv, &onoff_state[0]),
};
/*
* Root and Secondary Element Declarations
*/
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
};
static const struct bt_mesh_comp composition = {
.cid = BT_COMP_ID_LF,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
static void node_configuration_error()
{
log_error("node configuration error!");
memset(&curr_pair_node, 0, sizeof(curr_pair_node));
cfg_cli.op_pending = 0;
cfg_cli.op_param = NULL;
bt_mesh_tx_reset();
}
/*
* 节点配置回应检查,没有回应会重发配置消息
*/
static void node_configuration_check(void *opcode)
{
log_info("mesh_configuration_check:0x%x", opcode);
if (cfg_cli.op_pending != (u32_t)opcode) {
log_info("check pass");
} else {
// 重发超过10次放弃配置节点
if (curr_pair_node.config_failed_cnt < 10) {
cfg_cli.op_pending = 0;
cfg_cli.op_param = NULL;
log_info("not get the configuration msg rsp:0x%x, resend", opcode);
provisioner_node_configuration();
curr_pair_node.config_failed_cnt++;
} else {
node_configuration_error();
}
}
}
/*
* 节点配置确认定时器
*/
static void mesh_set_configuration_check_timer(u32_t opcode)
{
// 节点配置消息发出后3.5秒校验是否有收到回应
sys_timeout_add((void *)opcode, node_configuration_check, 3500);
}
// 发送配置消息失败后重发
static void config_msg_resend()
{
if (curr_pair_node.config_failed_cnt < 10) {
curr_pair_node.config_failed_cnt++;
sys_timeout_add(NULL, provisioner_node_configuration, 1500);
} else {
node_configuration_error();
}
}
/*
* 节点配置状态机,按步骤配置节点
*
* 此处可自定义新添加节点的配置内容
*/
static void provisioner_node_configuration(void)
{
int err = 0;
static uint8_t status;
log_info("provisioner_node_configuration, step:%d", curr_pair_node.config_step);
switch (curr_pair_node.config_step) {
case 0:
err = bt_mesh_cfg_app_key_add(curr_pair_node.net_idx, curr_pair_node.addr, curr_pair_node.net_idx, 0, prov_app_key, &status);
if (err) {
config_msg_resend();
return;
}
mesh_set_configuration_check_timer(OP_APP_KEY_STATUS);
break;
case 1:
err = bt_mesh_cfg_mod_app_bind(curr_pair_node.net_idx, curr_pair_node.addr, curr_pair_node.addr, 0, BT_MESH_MODEL_ID_GEN_ONOFF_CLI, &status);
if (err) {
config_msg_resend();
return;
}
mesh_set_configuration_check_timer(OP_MOD_APP_STATUS);
break;
case 2:
struct bt_mesh_cfg_mod_pub pub = {
.addr = PROV_GROUP_ADDR,
.app_idx = 0,
.cred_flag = 0,
.ttl = 7,
.period = 0,
.transmit = 0,
};
err = bt_mesh_cfg_mod_pub_set(curr_pair_node.net_idx, curr_pair_node.addr, curr_pair_node.addr, BT_MESH_MODEL_ID_GEN_ONOFF_CLI, &pub, &status);
if (err) {
config_msg_resend();
return;
}
mesh_set_configuration_check_timer(OP_MOD_PUB_STATUS);
break;
default:
break;
}
if (curr_pair_node.config_step == 3) {
log_info("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
log_info("node Configuration finish!");
log_info("-------------------------------------------------------------------");
memset(&curr_pair_node, 0, sizeof(curr_pair_node));
#ifdef CONFIG_WIFI_ENABLE
void set_rf_coexistence_mesh_config(u8 enable);
set_rf_coexistence_mesh_config(2);
if (prov_giving_up_timer) {
sys_timer_del(prov_giving_up_timer);
prov_giving_up_timer = 0;
}
#endif
}
}
/*
* 新节点配网完成回调,开始节点配置
*/
static void provisioner_node_added(u16_t net_idx, u8_t uuid[16], u16_t addr, u8_t num_elem)
{
log_info("Add new node!");
log_info("addr:0x%04x", addr);
log_info("net_idx:0x%x", net_idx);
log_info("num_elem:%d", num_elem);
log_info("uuid:");
put_buf(uuid, 16);
curr_pair_node.net_idx = net_idx;
curr_pair_node.addr = addr;
curr_pair_node.num_elem = num_elem;
memcpy(curr_pair_node.uuid, uuid, 16);
curr_pair_node.config_step = 0;
curr_pair_node.config_failed_cnt = 0;
provisioner_node_configuration();
}
/*
* 扫描到未配网设备beacon回调
*/
static void get_unprov_beacon(u8_t uuid[16],
bt_mesh_prov_oob_info_t oob_info,
u32_t *uri_hash)
{
log_info("get_unprov_beacon, uuid:%s", bt_hex(uuid, 16));
memcpy(unprov_uuid, uuid, 16);
}
static const u8_t dev_uuid[16] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)};
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
#if 0
.output_size = 6,
.output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
.output_number = output_number,
.output_string = output_string,
#else
.output_size = 0,
.output_actions = 0,
.output_number = 0,
#endif
.complete = prov_complete,
.reset = prov_reset,
.node_added = provisioner_node_added,
.unprovisioned_beacon = get_unprov_beacon,
};
static u8_t show_node(struct bt_mesh_cdb_node *node,
void *user_data)
{
log_info("[node addr = 0x%x]", node->addr);
log_info("uuid = %s", bt_hex(node->uuid, 6));
log_info("net_idx = 0x%x", node->net_idx);
log_info("num_elem = %d", node->num_elem);
log_info("dev_key = %s", bt_hex(node->dev_key, 16));
return 1;
}
/*
* 显示所有配网的设备
*/
static void Provisioner_show_cdb_node(void)
{
log_info("Provisioner_show_cdb_node");
bt_mesh_cdb_node_foreach(show_node, NULL);
}
static u8_t del_node(struct bt_mesh_cdb_node *node,
void *user_data)
{
log_info("<Del> [node addr = 0x%x]", node->addr);
bt_mesh_cdb_node_del(node, true);
return 1;
}
/*
* 清除配网节点记录
*/
static void clear_store_node(void)
{
log_info("clear_store_node");
clear_rpl();
bt_mesh_cdb_node_foreach(del_node, NULL);
}
static u8_t get_store_node_num(struct bt_mesh_cdb_node *node,
void *user_data)
{
*(u8_t *)user_data += 1;
return 1;
}
#ifdef CONFIG_WIFI_ENABLE
static void prov_giving_up_timer_cb(void *p)
{
prov_giving_up_timer = 0;
void set_rf_coexistence_mesh_config(u8 enable);
set_rf_coexistence_mesh_config(2);
}
#endif
/*
* 发起配网
*/
int bt_mesh_provision_adv(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
uint8_t attention_duration)
{
u8_t node_cnt = 0;
bt_mesh_cdb_node_foreach(get_store_node_num, &node_cnt);
if (node_cnt >= CONFIG_BT_MESH_CDB_NODE_COUNT) {
log_error("node store is full!");
return -1;
}
if (bt_mesh_cdb_subnet_get(net_idx) == NULL) {
log_error("subnet is NULL!");
return -EINVAL;
}
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) && IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
#ifdef CONFIG_WIFI_ENABLE
void set_rf_coexistence_mesh_config(u8 enable);
set_rf_coexistence_mesh_config(0);
if (!prov_giving_up_timer) {
prov_giving_up_timer = sys_timeout_add(NULL, prov_giving_up_timer_cb, 15000);
} else {
sys_timer_modify(prov_giving_up_timer, 15000);
}
#endif
return bt_mesh_pb_adv_open(uuid, net_idx, addr,
attention_duration);
}
log_error("provisioner is no support!");
return -ENOTSUP;
}
static void prov_giving_up(void)
{
#ifdef CONFIG_WIFI_ENABLE
void set_rf_coexistence_mesh_config(u8 enable);
set_rf_coexistence_mesh_config(2);
#endif
}
static void provisioner_reset(void *p)
{
bt_mesh_reset();
cpu_reset();
/* p33_soft_reset(); */
}
void input_key_handler(u8 key_status, u8 key_number)
{
log_info("key_number=0x%x", key_number);
switch (key_status) {
case KEY_EVENT_CLICK:
log_info(" [KEY_EVENT_CLICK] ");
break;
case KEY_EVENT_LONG:
log_info(" [KEY_EVENT_LONG] ");
break;
case KEY_EVENT_HOLD:
log_info(" [KEY_EVENT_HOLD] ");
break;
default:
return;
}
if (key_status == KEY_EVENT_LONG && key_number == 2) {
switch (key_number) {
case 0:
break;
case 2:
log_info("\n <bt_mesh_reset> \n");
sys_timeout_add(NULL, provisioner_reset, 1000 * 3);
break;
default:
break;
}
}
if (key_status == KEY_EVENT_CLICK) {
switch (key_number) {
case 0:
// 显示已配网节点
Provisioner_show_cdb_node();
break;
case 1:
// 清理配网节点记录
clear_store_node();
break;
case 2:
// 对最后扫描到的设备uuid发起配网
bt_mesh_provision_adv(unprov_uuid, PROV_NET_IDX, BT_MESH_ADDR_UNASSIGNED, 0);
break;
default:
break;
}
}
}
/*
* 节点配置回调,每条配置消息收到回复后调用
*/
static void node_config_cmd_rsp_cb(u32_t opcode)
{
log_info("node_config_cmd_rsp_cb, opcode:0x%x", opcode);
cfg_cli.op_pending = 0;
cfg_cli.op_param = NULL;
curr_pair_node.config_step++;
provisioner_node_configuration();
}
/*
* 配网者自配置
*/
static void self_configure(void)
{
u16_t elem_addr = 0x0001;
int err = 0;
err = bt_mesh_cfg_app_key_add(PROV_NET_IDX, PROV_NODE_ADDR, PROV_NET_IDX, PROV_APP_IDX, prov_app_key, NULL);
if (err) {
log_info("add app key err:%d!", err);
}
err = bt_mesh_cfg_mod_app_bind(PROV_NET_IDX, PROV_NODE_ADDR, elements[0].addr, PROV_APP_IDX, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
if (err) {
log_info("bind app key err:%d!", err);
}
err = bt_mesh_cfg_mod_sub_add(PROV_NET_IDX, PROV_NODE_ADDR, elements[0].addr, PROV_GROUP_ADDR, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL);
if (err) {
log_info("add sub addr err:%d!", err);
}
}
static void mesh_init(void)
{
int err = bt_mesh_init(&prov, &composition);
if (err) {
log_error("Initializing mesh failed (err %d)", err);
return;
}
settings_load();
err = bt_mesh_provision(prov_net_key, PROV_NET_IDX, flags, PROV_IV_IDX, PROV_NODE_ADDR, prov_dev_key);
if (err) {
log_info("Using stored settings");
} else {
log_info("Provisioning completed");
self_configure();
}
mesh_cli_cmd_rsp_callback_register(node_config_cmd_rsp_cb);
bt_mesh_cdb_create(prov_net_key);
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
}
void bt_ble_mesh_init(void)
{
u8 bt_addr[6] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)};
bt_mac_addr_set(bt_addr);
mesh_prov_giving_up_callback_register(prov_giving_up);
mesh_setup(mesh_init);
}
#endif /* (CONFIG_MESH_MODEL == SIG_MESH_PROVISIONER) */