/*************************************************************************************************/ /*! * \file provisioner.c * * \brief Main file for example * * Copyright (c) 2011-2022 ZhuHai Jieli Technology Co.,Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************************************/ #include "btstack/bluetooth.h" #include "system/includes.h" #include "bt_common.h" #include "api/sig_mesh_api.h" #include "model_api.h" #include "adaptation.h" #include "net.h" #include "provisioner_config.h" #include "foundation.h" #include "feature_correct.h" #include "os/os_api.h" #define LOG_TAG "[Provisioner_demo]" #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_MESH_MODEL == SIG_MESH_PROVISIONER) /************************************************************************************************** Macros **************************************************************************************************/ /* @brief Config current node features(Relay/Proxy/Friend/Low Power) */ #define BT_MESH_FEAT_SUPPORTED_TEMP ( \ 0 \ ) /* @brief Conifg complete local name */ #define BLE_DEV_NAME 'P', 'r', 'o', 'v', 'i', 's', 'i', 'o', 'n', 'e', 'r' /* @brief Conifg MAC of current demo */ #define CUR_DEVICE_MAC_ADDR 0x112233440000 /* @brief Conifg MAC of provisionee */ #define PROVISIONEE_DEVICE_MAC_ADDR 0x112233445566 /* Company Identifiers (see Bluetooth Assigned Numbers) */ #define BT_COMP_ID_LF 0x05D6// Zhuhai Jieli technology Co.,Ltd /* Model Operation Codes */ #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) /************************************************************************************************** Data Types **************************************************************************************************/ 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]; u8_t onoff_state; } __prov_node; /************************************************************************************************** Function declaration **************************************************************************************************/ static void provisioner_node_configuration(void); static void gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); static void provisioner_node_added(u16_t net_idx, u8_t uuid[16], u16_t addr, u8_t num_elem); static void get_unprov_beacon(u8_t uuid[16], bt_mesh_prov_oob_info_t oob_info, u32_t *uri_hash); /************************************************************************************************** Global Variables **************************************************************************************************/ /* * 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); static const uint16_t net_idx; static const uint16_t app_idx; const int config_bt_mesh_features = BT_MESH_FEAT_SUPPORTED; static u8_t flags; static struct bt_mesh_comp prov_comp; static uint8_t unprov_uuid[16]; static __prov_node curr_pair_node; static struct bt_mesh_cfg_cli cfg_cli = {}; const uint8_t mesh_name[] = { BYTE_LEN(BLE_DEV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, BLE_DEV_NAME, }; static const u8_t match_dev_uuid[16] = {MAC_TO_LITTLE_ENDIAN(PROVISIONEE_DEVICE_MAC_ADDR)}; const u8_t prov_net_key[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; const u8_t prov_dev_key[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; const u8_t prov_app_key[16] = { 0x06, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x06, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; static const struct bt_mesh_model_op gen_onoff_cli_op[] = { { BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status }, BT_MESH_MODEL_OP_END, }; /* Element 0 Root Models */ static struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_CFG_CLI(&cfg_cli), // default for self-configuration network BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, &gen_onoff_pub_cli, NULL), }; /* 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 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, }; /************************************************************************************************** Functions **************************************************************************************************/ void get_mesh_adv_name(u8 *len, u8 **data) { *len = sizeof(mesh_name); *data = mesh_name; } static void gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { u8_t state; state = buffer_pull_u8_from_head(buf); log_info("Node 0x%04x OnOff status from 0x%04x with state 0x%02x\n", bt_mesh_model_elem(model)->rt->addr, ctx->addr, state); } /** * @brief Retransmission after failure to send a configuration message * */ static void config_msg_resend(void) { if (curr_pair_node.config_failed_cnt < 3) { curr_pair_node.config_failed_cnt++; sys_timeout_add(NULL, provisioner_node_configuration, 500); } else { if (curr_pair_node.config_step < 2) { curr_pair_node.config_step++; } else { return; } curr_pair_node.config_failed_cnt = 0; sys_timeout_add(NULL, provisioner_node_configuration, 500); } } static void onoff_cli_publish(u16_t addr) { int err; struct bt_mesh_model *mod_cli; struct bt_mesh_model_pub *pub_cli; mod_cli = &root_models[2]; pub_cli = mod_cli->pub; pub_cli->addr = addr; log_info("publish to 0x%04x onoff_state 0x%x\n", pub_cli->addr, curr_pair_node.onoff_state); bt_mesh_model_msg_init(pub_cli->msg, BT_MESH_MODEL_OP_GEN_ONOFF_SET); buffer_add_u8_at_tail(pub_cli->msg, curr_pair_node.onoff_state); buffer_add_u8_at_tail(pub_cli->msg, 0x06); curr_pair_node.onoff_state = !(curr_pair_node.onoff_state); err = bt_mesh_model_publish(mod_cli); if (err) { log_info("bt_mesh_model_publish err %d\n", err); } } /** * @brief Node configuration state machine, step by step node configuration. * */ 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_cli_app_key_add(curr_pair_node.net_idx, curr_pair_node.addr, curr_pair_node.net_idx, 0, prov_app_key, NULL); config_msg_resend(); break; case 1: err = bt_mesh_cfg_cli_mod_app_bind(curr_pair_node.net_idx, curr_pair_node.addr, curr_pair_node.addr, 0, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, NULL); config_msg_resend(); break; case 2: onoff_cli_publish(curr_pair_node.addr); config_msg_resend(); break; default: break; } } /** * @brief New node provisioning complete callback, start node configuration. * */ 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; curr_pair_node.onoff_state = 1; provisioner_node_configuration(); } /** * @brief Scan to unprovisioned beacon callbacks * */ 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 u8_t show_node(struct bt_mesh_cdb_node *node, void *user_data) { log_info("\n[node addr = 0x%x]\n", node->addr); log_info("uuid = %s\n", bt_hex(node->uuid, 6)); log_info("net_idx = 0x%x\n", node->net_idx); log_info("num_elem = %d\n", node->num_elem); log_info("dev_key = %s\n", bt_hex(node->dev_key.key, 16)); return 1; } /** * @brief Show all provisioned devices * */ static void Provisioner_show_cdb_node(void) { log_info("Provisioner_show_cdb_node\n"); bt_mesh_cdb_node_foreach(show_node, NULL); } static u8_t del_node(struct bt_mesh_cdb_node *node, void *user_data) { log_info("\n [node addr = 0x%x]\n", node->addr); bt_mesh_cdb_node_del(node, true); return 1; } /** * @brief Clearing provisioned node records * */ 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; } static void provisioner_reset() { bt_mesh_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) { switch (key_number) { case 0: break; case 2: log_info("\n \n"); sys_timeout_add(NULL, provisioner_reset, 1000 * 3); break; default: break; } } if (key_status == KEY_EVENT_CLICK) { switch (key_number) { case 0: /* show all provisioned devices */ Provisioner_show_cdb_node(); break; case 1: /* Clearing provisioned node records */ clear_store_node(); break; case 4: /* Initiate provisioning for the last scanned device uuid */ bt_mesh_provision_adv(unprov_uuid, PROV_NET_IDX, BT_MESH_ADDR_UNASSIGNED, 0); break; default: break; } } } static void mod_app_bind(void) { int err; err = bt_mesh_cfg_cli_mod_app_bind(PROV_NET_IDX, PROVISIONER_ADDR, PROVISIONER_ADDR, PROV_APP_IDX, BT_MESH_MODEL_ID_GEN_ONOFF_CLI, NULL); if (err) { log_error("Failed to bind app-key (err %d)\n", err); return; } log_info("Configuration complete\n"); struct bt_mesh_cdb_node *node; uint16_t addr = 0x01; do { node = bt_mesh_cdb_node_get(addr); if (node) { log_info("cdb node addr: 0x%x , onoff cli send 10 times.", node->addr); for (int i = 0; i < 10; i++) { onoff_cli_publish(node->addr); os_time_dly(100); } addr++; } else { log_info("provisioner don't have node now."); break; } } while (1); } /** * @brief Provisioner config self. * */ static void configure_self(void) { int err; log_info("Configuring self...\n"); /* Add Application Key */ err = bt_mesh_cfg_cli_app_key_add(PROV_NET_IDX, PROVISIONER_ADDR, PROV_NET_IDX, PROV_APP_IDX, prov_app_key, NULL); if (err) { log_error("Failed to add app-key (err %d)\n", err); return; } /* Bind to onoff client model should be tasked until app key add*/ sys_timeout_add(NULL, mod_app_bind, 100); } static void mesh_init(void) { log_info("--func=%s", __FUNCTION__); int err = bt_mesh_init(&prov, &composition); if (err) { log_error("Initializing mesh failed (err %d)\n", err); return; } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { settings_load(); } bt_mesh_cdb_create(prov_net_key); err = bt_mesh_provision(prov_net_key, PROV_NET_IDX, flags, PROV_IV_IDX, PROVISIONER_ADDR, prov_dev_key); configure_self(); } void bt_ble_init(void) { u8 bt_addr[6] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)}; bt_mac_addr_set(bt_addr); mesh_setup(mesh_init); } #endif /* (CONFIG_MESH_MODEL == SIG_MESH_PROVISIONER) */