1. BLE Mesh Core * Provisioning: Node Role * PB-ADV and PB-GATT * Authentication OOB * Provisioning: Provisioner Role * PB-ADV and PB-GATT * Authentication OOB * Networking * Relay * Segmentation and Reassembly * Key Refresh * IV Update * Proxy Support * Multiple Client Models Run Simultaneously * Support multiple client models send packets to different nodes simultaneously * No blocking between client model and server * NVS Storage * Store BLE Mesh node related information in flash * Store BLE Mesh Provisioner related information in flash 2. BLE Mesh Models * Foundation Models * Configuration Server Model * Configuration Client Model * Health Server Model * Health Client Model * Generic * Generic OnOff Server * Generic OnOff Client * Generic Level Server * Generic Level Client * Generic Default Transition Time Server * Generic Default Transition Time Client * Generic Power OnOff Server * Generic Power OnOff Setup Server * Generic Power OnOff Client * Generic Power Level Server * Generic Power Level Setup Server * Generic Power Level Client * Generic Battery Server * Generic Battery Client * Generic Location Server * Generic Location Setup Server * Generic Location Client * Generic Admin Property Server * Generic Manufacturer Property Server * Generic User Property Server * Generic Client Property Server * Generic Property Client * Sensor Server Model * Sensor Server * Sensor Setup Server * Sensor Client * Time and Scenes * Time Server * Time Setup Server * Time Client * Scene Server * Scene Setup Server * Scene Client * Scheduler Server * Scheduler Setup Server * Scheduler Client * Lighting * Light Lightness Server * Light Lightness Setup Server * Light Lightness Client * Light CTL Server * Light CTL Setup Server * Light CTL Client * Light CTL Temperature Server * Light HSL Server * Light HSL Setup Server * Light HSL Client * Light HSL Hue Server * Light HSL Saturation Server * Light xyL Server * Light xyL Setup Server * Light xyL Client * Light LC Server * Light LC Setup Server * Light LC Client 3. BLE Mesh Applications * BLE Mesh Node * OnOff Client Example * OnOff Server Example * BLE Mesh Provisioner * Example * Fast Provisioning * Vendor Fast Prov Server Model * Vendor Fast Prov Client Model * Examples * Wi-Fi & BLE Mesh Coexistence * Example * BLE Mesh Console Commands * Examples
601 lines
22 KiB
C
601 lines
22 KiB
C
// Copyright 2017-2019 Espressif Systems (Shanghai) PTE 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 <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "esp_system.h"
|
|
#include "esp_log.h"
|
|
#include "nvs_flash.h"
|
|
|
|
#include "esp_ble_mesh_defs.h"
|
|
#include "esp_ble_mesh_common_api.h"
|
|
#include "esp_ble_mesh_provisioning_api.h"
|
|
#include "esp_ble_mesh_networking_api.h"
|
|
#include "esp_ble_mesh_config_model_api.h"
|
|
#include "esp_ble_mesh_generic_model_api.h"
|
|
|
|
#include "esp_fast_prov_common.h"
|
|
#include "esp_fast_prov_operation.h"
|
|
#include "esp_fast_prov_client_model.h"
|
|
#include "ble_mesh_demo_init.h"
|
|
|
|
#define PROV_OWN_ADDR 0x0001
|
|
#define APP_KEY_OCTET 0x12
|
|
#define GROUP_ADDRESS 0xC000
|
|
|
|
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
|
static uint8_t match[] = { 0xdd, 0xdd };
|
|
|
|
static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = {
|
|
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS },
|
|
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS },
|
|
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS },
|
|
};
|
|
|
|
static esp_ble_mesh_cfg_srv_t config_server = {
|
|
.relay = ESP_BLE_MESH_RELAY_DISABLED,
|
|
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
|
|
#if defined(CONFIG_BLE_MESH_FRIEND)
|
|
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
|
|
#else
|
|
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
|
|
#endif
|
|
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
|
|
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
|
|
#else
|
|
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
|
|
#endif
|
|
.default_ttl = 7,
|
|
/* 3 transmissions with a 20ms interval */
|
|
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
|
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
|
};
|
|
esp_ble_mesh_client_t config_client;
|
|
esp_ble_mesh_client_t gen_onoff_client;
|
|
esp_ble_mesh_client_t fast_prov_client = {
|
|
.op_pair_size = ARRAY_SIZE(fast_prov_cli_op_pair),
|
|
.op_pair = fast_prov_cli_op_pair,
|
|
};
|
|
|
|
static esp_ble_mesh_model_op_t fast_prov_cli_op[] = {
|
|
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS, 1),
|
|
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS, 2),
|
|
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS, 2),
|
|
ESP_BLE_MESH_MODEL_OP_END,
|
|
};
|
|
|
|
static esp_ble_mesh_model_t root_models[] = {
|
|
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
|
|
ESP_BLE_MESH_MODEL_CFG_CLI(&config_client),
|
|
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(NULL, &gen_onoff_client),
|
|
};
|
|
|
|
static esp_ble_mesh_model_t vnd_models[] = {
|
|
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI,
|
|
fast_prov_cli_op, NULL, &fast_prov_client),
|
|
};
|
|
|
|
static esp_ble_mesh_elem_t elements[] = {
|
|
ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
|
|
};
|
|
|
|
static esp_ble_mesh_comp_t comp = {
|
|
.cid = CID_ESP,
|
|
.elements = elements,
|
|
.element_count = ARRAY_SIZE(elements),
|
|
};
|
|
|
|
static esp_ble_mesh_prov_t prov = {
|
|
.prov_uuid = dev_uuid,
|
|
.prov_unicast_addr = PROV_OWN_ADDR,
|
|
.prov_start_address = 0x0005,
|
|
.prov_attention = 0x00,
|
|
.prov_algorithm = 0x00,
|
|
.prov_pub_key_oob = 0x00,
|
|
.prov_static_oob_val = NULL,
|
|
.prov_static_oob_len = 0x00,
|
|
.flags = 0x00,
|
|
.iv_index = 0x00,
|
|
};
|
|
|
|
example_prov_info_t prov_info = {
|
|
.net_idx = ESP_BLE_MESH_KEY_PRIMARY,
|
|
.app_idx = ESP_BLE_MESH_KEY_PRIMARY,
|
|
.node_addr_cnt = 100,
|
|
.unicast_max = 0x7FFF,
|
|
.group_addr = GROUP_ADDRESS,
|
|
.max_node_num = 0x01,
|
|
};
|
|
|
|
static void provisioner_prov_link_open(esp_ble_mesh_prov_bearer_t bearer)
|
|
{
|
|
ESP_LOGI(TAG, "%s link open", bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
|
}
|
|
|
|
static void provisioner_prov_link_close(esp_ble_mesh_prov_bearer_t bearer, uint8_t reason)
|
|
{
|
|
ESP_LOGI(TAG, "%s link close, reason 0x%02x",
|
|
bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason);
|
|
|
|
if (bearer == ESP_BLE_MESH_PROV_ADV && reason != 0x00) {
|
|
prov_info.max_node_num++;
|
|
}
|
|
}
|
|
|
|
static void provisioner_prov_complete(int node_index, const uint8_t uuid[16], uint16_t unicast_addr,
|
|
uint8_t elem_num, uint16_t net_idx)
|
|
{
|
|
example_node_info_t *node = NULL;
|
|
char name[10];
|
|
esp_err_t err;
|
|
|
|
ESP_LOGI(TAG, "Node index: 0x%x, unicast address: 0x%02x, element num: %d, netkey index: 0x%02x",
|
|
node_index, unicast_addr, elem_num, net_idx);
|
|
ESP_LOGI(TAG, "Node uuid: %s", bt_hex(uuid, 16));
|
|
|
|
sprintf(name, "%s%d", "NODE-", node_index);
|
|
if (esp_ble_mesh_provisioner_set_node_name(node_index, name)) {
|
|
ESP_LOGE(TAG, "%s: Failed to set node name", __func__);
|
|
return;
|
|
}
|
|
|
|
/* Sets node info */
|
|
err = example_store_node_info(uuid, unicast_addr, elem_num, prov_info.net_idx,
|
|
prov_info.app_idx, LED_OFF);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to set node info", __func__);
|
|
return;
|
|
}
|
|
|
|
/* Gets node info */
|
|
node = example_get_node_info(unicast_addr);
|
|
if (!node) {
|
|
ESP_LOGE(TAG, "%s: Failed to get node info", __func__);
|
|
return;
|
|
}
|
|
|
|
/* The Provisioner will send Config AppKey Add to the node. */
|
|
example_msg_common_info_t info = {
|
|
.net_idx = node->net_idx,
|
|
.app_idx = node->app_idx,
|
|
.dst = node->unicast_addr,
|
|
.timeout = 0,
|
|
.role = ROLE_PROVISIONER,
|
|
};
|
|
esp_ble_mesh_cfg_app_key_add_t add_key = {
|
|
.net_idx = prov_info.net_idx,
|
|
.app_idx = prov_info.app_idx,
|
|
};
|
|
memcpy(add_key.app_key, prov_info.app_key, 16);
|
|
err = example_send_config_appkey_add(config_client.model, &info, &add_key);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void example_recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[BLE_MESH_ADDR_LEN],
|
|
esp_ble_mesh_addr_type_t addr_type, uint16_t oob_info,
|
|
uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer)
|
|
{
|
|
esp_ble_mesh_unprov_dev_add_t add_dev = {0};
|
|
esp_ble_mesh_dev_add_flag_t flag;
|
|
esp_err_t err;
|
|
bool reprov;
|
|
|
|
if (bearer & ESP_BLE_MESH_PROV_ADV) {
|
|
/* Checks if the device has been provisioned previously. If the device
|
|
* is a re-provisioned one, we will ignore the 'max_node_num' count and
|
|
* start to provision it directly.
|
|
*/
|
|
reprov = example_is_node_exist(dev_uuid);
|
|
if (reprov) {
|
|
goto add;
|
|
}
|
|
|
|
if (prov_info.max_node_num == 0) {
|
|
return;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "address: %s, address type: %d, adv type: %d", bt_hex(addr, 6), addr_type, adv_type);
|
|
ESP_LOGI(TAG, "dev uuid: %s", bt_hex(dev_uuid, 16));
|
|
ESP_LOGI(TAG, "oob info: %d, bearer: %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT");
|
|
|
|
add:
|
|
memcpy(add_dev.addr, addr, 6);
|
|
add_dev.addr_type = (uint8_t)addr_type;
|
|
memcpy(add_dev.uuid, dev_uuid, 16);
|
|
add_dev.oob_info = oob_info;
|
|
add_dev.bearer = (uint8_t)bearer;
|
|
flag = ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG;
|
|
err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev, flag);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to start provisioning a device", __func__);
|
|
return;
|
|
}
|
|
|
|
if (!reprov) {
|
|
if (prov_info.max_node_num) {
|
|
prov_info.max_node_num--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void example_provisioning_callback(esp_ble_mesh_prov_cb_event_t event,
|
|
esp_ble_mesh_prov_cb_param_t *param)
|
|
{
|
|
switch (event) {
|
|
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code: %d",
|
|
param->prov_register_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT");
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT:
|
|
example_recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr,
|
|
param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info,
|
|
param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, bearer %s",
|
|
param->provisioner_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
|
provisioner_prov_link_open(param->provisioner_prov_link_open.bearer);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT, bearer %s reason 0x%02x",
|
|
param->provisioner_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT",
|
|
param->provisioner_prov_link_close.reason);
|
|
provisioner_prov_link_close(param->provisioner_prov_link_close.bearer,
|
|
param->provisioner_prov_link_close.reason);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT");
|
|
provisioner_prov_complete(param->provisioner_prov_complete.node_idx,
|
|
param->provisioner_prov_complete.device_uuid,
|
|
param->provisioner_prov_complete.unicast_addr,
|
|
param->provisioner_prov_complete.element_num,
|
|
param->provisioner_prov_complete.netkey_idx);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code: %d",
|
|
param->provisioner_add_unprov_dev_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code: %d",
|
|
param->provisioner_set_dev_uuid_match_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code: %d",
|
|
param->provisioner_set_node_name_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT: {
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code);
|
|
if (param->provisioner_add_app_key_comp.err_code == ESP_OK) {
|
|
esp_err_t err;
|
|
prov_info.app_idx = param->provisioner_add_app_key_comp.app_idx;
|
|
err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx,
|
|
ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI, CID_NVAL);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to bind AppKey with OnOff Client Model", __func__);
|
|
return;
|
|
}
|
|
err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_info.app_idx,
|
|
ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI, CID_ESP);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to bind AppKey with Fast Prov Client Model", __func__);
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void example_custom_model_callback(esp_ble_mesh_model_cb_event_t event,
|
|
esp_ble_mesh_model_cb_param_t *param)
|
|
{
|
|
uint32_t opcode;
|
|
esp_err_t err;
|
|
|
|
switch (event) {
|
|
case ESP_BLE_MESH_MODEL_OPERATION_EVT: {
|
|
if (!param->model_operation.model || !param->model_operation.model->op ||
|
|
!param->model_operation.ctx) {
|
|
ESP_LOGE(TAG, "%s: model_operation parameter is NULL", __func__);
|
|
return;
|
|
}
|
|
opcode = param->model_operation.opcode;
|
|
switch (opcode) {
|
|
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS:
|
|
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS:
|
|
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS: {
|
|
ESP_LOGI(TAG, "%s: Fast Prov Client Model receives status, opcode 0x%04x", __func__, opcode);
|
|
err = example_fast_prov_client_recv_status(param->model_operation.model,
|
|
param->model_operation.ctx,
|
|
param->model_operation.length,
|
|
param->model_operation.msg);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to handle fast prov status message", __func__);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
ESP_LOGI(TAG, "%s: opcode 0x%04x", __func__, param->model_operation.opcode);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_SEND_COMP_EVT, err_code %d",
|
|
param->model_send_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT, err_code %d",
|
|
param->model_publish_comp.err_code);
|
|
break;
|
|
case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_CLIENT_RECV_PUBLISH_MSG_EVT, opcode 0x%04x",
|
|
param->client_recv_publish_msg.opcode);
|
|
break;
|
|
case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT:
|
|
ESP_LOGI(TAG, "ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT, opcode 0x%04x, dst 0x%04x",
|
|
param->client_send_timeout.opcode, param->client_send_timeout.ctx->addr);
|
|
err = example_fast_prov_client_recv_timeout(param->client_send_timeout.opcode,
|
|
param->client_send_timeout.model,
|
|
param->client_send_timeout.ctx);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to resend fast prov client message", __func__);
|
|
return;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void example_config_client_callback(esp_ble_mesh_cfg_client_cb_event_t event,
|
|
esp_ble_mesh_cfg_client_cb_param_t *param)
|
|
{
|
|
example_node_info_t *node = NULL;
|
|
uint32_t opcode;
|
|
uint16_t address;
|
|
esp_err_t err;
|
|
|
|
ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x",
|
|
__func__, param->error_code, event, param->params->ctx.addr);
|
|
|
|
opcode = param->params->opcode;
|
|
address = param->params->ctx.addr;
|
|
|
|
node = example_get_node_info(address);
|
|
if (!node) {
|
|
ESP_LOGE(TAG, "%s: Failed to get node info", __func__);
|
|
return;
|
|
}
|
|
|
|
if (param->error_code) {
|
|
ESP_LOGE(TAG, "Failed to send config client message, opcode: 0x%04x", opcode);
|
|
return;
|
|
}
|
|
|
|
switch (event) {
|
|
case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT:
|
|
break;
|
|
case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT:
|
|
switch (opcode) {
|
|
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: {
|
|
example_fast_prov_info_set_t set = {0};
|
|
if (!node->reprov || !ESP_BLE_MESH_ADDR_IS_UNICAST(node->unicast_min)) {
|
|
/* If the node is a new one or the node is re-provisioned but the information of the node
|
|
* has not been set before, here we will set the Fast Prov Info Set info to the node.
|
|
*/
|
|
node->node_addr_cnt = prov_info.node_addr_cnt;
|
|
node->unicast_min = prov_info.unicast_min;
|
|
node->unicast_max = prov_info.unicast_max;
|
|
node->flags = prov.flags;
|
|
node->iv_index = prov.iv_index;
|
|
node->fp_net_idx = prov_info.net_idx;
|
|
node->group_addr = prov_info.group_addr;
|
|
node->match_len = prov_info.match_len;
|
|
memcpy(node->match_val, prov_info.match_val, prov_info.match_len);
|
|
node->action = 0x81;
|
|
}
|
|
set.ctx_flags = 0x037F;
|
|
memcpy(&set.node_addr_cnt, &node->node_addr_cnt,
|
|
sizeof(example_node_info_t) - offsetof(example_node_info_t, node_addr_cnt));
|
|
example_msg_common_info_t info = {
|
|
.net_idx = node->net_idx,
|
|
.app_idx = node->app_idx,
|
|
.dst = node->unicast_addr,
|
|
.timeout = 0,
|
|
.role = ROLE_PROVISIONER,
|
|
};
|
|
err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to set Fast Prov Info Set message", __func__);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT:
|
|
break;
|
|
case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT:
|
|
switch (opcode) {
|
|
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: {
|
|
example_msg_common_info_t info = {
|
|
.net_idx = node->net_idx,
|
|
.app_idx = node->app_idx,
|
|
.dst = node->unicast_addr,
|
|
.timeout = 0,
|
|
.role = ROLE_PROVISIONER,
|
|
};
|
|
esp_ble_mesh_cfg_app_key_add_t add_key = {
|
|
.net_idx = prov_info.net_idx,
|
|
.app_idx = prov_info.app_idx,
|
|
};
|
|
memcpy(add_key.app_key, prov_info.app_key, 16);
|
|
err = example_send_config_appkey_add(config_client.model, &info, &add_key);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
ESP_LOGE(TAG, "Not a config client status message event");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void example_generic_client_callback(esp_ble_mesh_generic_client_cb_event_t event,
|
|
esp_ble_mesh_generic_client_cb_param_t *param)
|
|
{
|
|
example_node_info_t *node = NULL;
|
|
uint32_t opcode;
|
|
uint16_t address;
|
|
|
|
ESP_LOGI(TAG, "%s, error_code = 0x%02x, event = 0x%02x, addr: 0x%04x",
|
|
__func__, param->error_code, event, param->params->ctx.addr);
|
|
|
|
opcode = param->params->opcode;
|
|
address = param->params->ctx.addr;
|
|
|
|
node = example_get_node_info(address);
|
|
if (!node) {
|
|
ESP_LOGE(TAG, "%s: Failed to get node info", __func__);
|
|
return;
|
|
}
|
|
|
|
if (param->error_code) {
|
|
ESP_LOGE(TAG, "Failed to send generic client message, opcode: 0x%04x", opcode);
|
|
return;
|
|
}
|
|
|
|
switch (event) {
|
|
case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT:
|
|
break;
|
|
case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT:
|
|
switch (opcode) {
|
|
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
|
|
node->onoff = param->status_cb.onoff_status.present_onoff;
|
|
ESP_LOGI(TAG, "node->onoff: 0x%02x", node->onoff);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT:
|
|
break;
|
|
case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT:
|
|
break;
|
|
default:
|
|
ESP_LOGE(TAG, "Not a generic client status message event");
|
|
break;
|
|
}
|
|
}
|
|
|
|
static esp_err_t ble_mesh_init(void)
|
|
{
|
|
esp_err_t err;
|
|
|
|
prov_info.unicast_min = prov.prov_start_address + prov_info.max_node_num;
|
|
prov_info.match_len = sizeof(match);
|
|
memcpy(prov_info.match_val, match, sizeof(match));
|
|
memset(prov_info.app_key, APP_KEY_OCTET, sizeof(prov_info.app_key));
|
|
|
|
esp_ble_mesh_register_prov_callback(example_provisioning_callback);
|
|
esp_ble_mesh_register_custom_model_callback(example_custom_model_callback);
|
|
esp_ble_mesh_register_config_client_callback(example_config_client_callback);
|
|
esp_ble_mesh_register_generic_client_callback(example_generic_client_callback);
|
|
|
|
err = esp_ble_mesh_init(&prov, &comp);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to initialize BLE Mesh", __func__);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, 0x02, 0x00, false);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to set matching device UUID", __func__);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
err = esp_ble_mesh_client_model_init(&vnd_models[0]);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to initialize fast prov client model", __func__);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
err = esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to enable provisioning", __func__);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
err = esp_ble_mesh_provisioner_add_local_app_key(prov_info.app_key, prov_info.net_idx, prov_info.app_idx);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "%s: Failed to add local application key", __func__);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "BLE Mesh Provisioner initialized");
|
|
|
|
return err;
|
|
}
|
|
|
|
void app_main(void)
|
|
{
|
|
esp_err_t err;
|
|
|
|
ESP_LOGI(TAG, "Initializing...");
|
|
|
|
err = nvs_flash_init();
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
err = nvs_flash_init();
|
|
}
|
|
ESP_ERROR_CHECK(err);
|
|
|
|
err = bluetooth_init();
|
|
if (err) {
|
|
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
|
|
return;
|
|
}
|
|
|
|
ble_mesh_get_dev_uuid(dev_uuid);
|
|
|
|
/* Initialize the Bluetooth Mesh Subsystem */
|
|
err = ble_mesh_init();
|
|
if (err) {
|
|
ESP_LOGE(TAG, "Failed to initialize BLE Mesh (err %d)", err);
|
|
}
|
|
}
|