ble_mesh: Add ESP BLE Mesh implementation
74
examples/bluetooth/esp_ble_mesh/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# ESP BLE Mesh Examples
|
||||
|
||||
[ESP BLE Mesh]($IDF_PATH/components/bt/esp_ble_mesh/) is the official BLE Mesh stack of Espressif Systems. We will provide long-term support for new features, performance optimization, etc.
|
||||
|
||||
Please help note that breaking changes may be introduced into ESP BLE Mesh on [minor IDF versions](https://docs.espressif.com/projects/esp-idf/en/latest/versions.html).
|
||||
|
||||
Note: To use examples in this directory, you need to have Bluetooth enabled in configuration and Bluedroid selected as the host stack. ESP BLE Mesh will support NimBLE host soon, and currently the integration of NimBLE host with ESP BLE Mesh stack is under development.
|
||||
|
||||
# Example Layout
|
||||
|
||||
This directory includes examples to demonstrate BLE Mesh functionality based on Zephyr (https://github.com/zephyrproject-rtos/zephyr) Mesh stack.
|
||||
|
||||
## ble_mesh_client_model
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Node with Generic OnOff Client & Server Models in the Primary Element.
|
||||
|
||||
See the [README.md](./ble_mesh_client_model/README.md) file in the example [ble_mesh_client_model](./ble_mesh_client_model/).
|
||||
|
||||
## ble_mesh_console
|
||||
|
||||
This example demonstrates how ESP BLE Mesh uses Console for message transmitting/receiving tests.
|
||||
|
||||
### ble_mesh_node
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Node and sends vendor messages for testing.
|
||||
|
||||
See the [README.md](./ble_mesh_console/ble_mesh_node/README.md) file in the example [ble_mesh_node](./ble_mesh_console/ble_mesh_node/).
|
||||
|
||||
### ble_mesh_provisioner
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Provisioner and sends vendor messages for testing.
|
||||
|
||||
See the [README.md](./ble_mesh_console/ble_mesh_provisioner/README.md) file in the example [ble_mesh_provisioner](./ble_mesh_console/ble_mesh_provisioner/).
|
||||
|
||||
## ble_mesh_fast_provision
|
||||
|
||||
This example illustrates the solution of ESP BLE Mesh Fast Provisioning.
|
||||
|
||||
### ble_mesh_fast_prov_client
|
||||
|
||||
This example shows how ESP32, acting as a BLE Mesh Fast Provisioning Client, provisions other unprovisioned devices and then control the nodes.
|
||||
|
||||
See the [README.md](./ble_mesh_fast_provision/ble_mesh_fast_prov_client/README.md) file in the example [ble_mesh_fast_prov_client](./ble_mesh_fast_provision/ble_mesh_fast_prov_client/).
|
||||
|
||||
### ble_mesh_fast_prov_server
|
||||
|
||||
This example illustrates the process that:
|
||||
1. Firstly as a BLE Mesh Fast Provisioning Server, ESP32 is provisioned into a Node;
|
||||
2. and then provisions other unprovisioned devices as a Temporary Provisioner.
|
||||
|
||||
See the [README.md](./ble_mesh_fast_provision/ble_mesh_fast_prov_server/README.md) file in the example [ble_mesh_fast_prov_server](./ble_mesh_fast_provision/ble_mesh_fast_prov_server/).
|
||||
|
||||
## ble_mesh_node
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Node with only Generic OnOff Server Model in the Primary Element.
|
||||
|
||||
See the [README.md](./ble_mesh_node/README.md) file in the example [ble_mesh_node](./ble_mesh_node/).
|
||||
|
||||
## ble_mesh_provisioner
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Provisioner and provisions other unprovisioned devices.
|
||||
|
||||
See the [README.md](./ble_mesh_provisioner/README.md) file in the example [ble_mesh_provisioner](./ble_mesh_provisioner/).
|
||||
|
||||
## ble_mesh_wifi_coexist
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Fast Provisioning Server and coexists with Wi-Fi iperf functionality.
|
||||
|
||||
See the [README.md](./ble_mesh_wifi_coexist/README.md) file in the example [ble_mesh_wifi_coexist](./ble_mesh_wifi_coexist/).
|
||||
|
||||
# More
|
||||
|
||||
See the [README.md](../../README.md) file in the upper level [examples](../../) directory for more information about examples.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_mesh_console_node)
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_mesh_console_node
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,9 @@
|
||||
# ble mesh node console demo
|
||||
## Introduction
|
||||
This demo implements ble mesh node basic features.Based on this demo, node can be scaned and proved by provisioner, reply get/set message to provisioner.
|
||||
|
||||
Demo steps:
|
||||
1. Build the ble mesh node console demo with sdkconfig.default
|
||||
2. register node and set oob info, load model to init ble mesh node
|
||||
3. enable bearer, so that it can be scaned and provisioned by provisioner
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_adapter.c"
|
||||
"ble_mesh_cfg_srv_model.c"
|
||||
"ble_mesh_console_lib.c"
|
||||
"ble_mesh_console_main.c"
|
||||
"ble_mesh_console_system.c"
|
||||
"ble_mesh_register_node_cmd.c"
|
||||
"ble_mesh_register_server_cmd.c"
|
||||
"register_bluetooth.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,164 @@
|
||||
// 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 "ble_mesh_adapter.h"
|
||||
|
||||
esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id)
|
||||
{
|
||||
esp_ble_mesh_model_t *model = NULL;
|
||||
|
||||
switch (model_id) {
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_SRV:
|
||||
model = &config_server_models[0];
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI:
|
||||
model = &config_client_models[0];
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV:
|
||||
model = &gen_onoff_srv_models[1];
|
||||
break;
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI:
|
||||
model = &gen_onoff_cli_models[1];
|
||||
break;
|
||||
#endif
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI:
|
||||
model = &test_perf_cli_models[0];
|
||||
break;
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV:
|
||||
model = &test_perf_srv_models[0];
|
||||
break;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id)
|
||||
{
|
||||
esp_ble_mesh_comp_t *comp = NULL;
|
||||
|
||||
switch (model_id) {
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_SRV:
|
||||
comp = &config_server_comp;
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI:
|
||||
comp = &config_client_comp;
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV:
|
||||
comp = &gen_onoff_srv_comp;
|
||||
break;
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI:
|
||||
comp = &gen_onoff_cli_comp;
|
||||
break;
|
||||
#endif
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI:
|
||||
comp = &test_perf_cli_comp;
|
||||
break;
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV:
|
||||
comp = &test_perf_srv_comp;
|
||||
break;
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
void ble_mesh_node_init(void)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) {
|
||||
ble_mesh_node_prestore_params[i].net_idx = 0xFFFF;
|
||||
ble_mesh_node_prestore_params[i].unicast_addr = 0xFFFF;
|
||||
}
|
||||
|
||||
ble_mesh_node_sema = xSemaphoreCreateMutex();
|
||||
if (!ble_mesh_node_sema) {
|
||||
ESP_LOGE(TAG, "%s init fail, mesh node semaphore create fail", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr)
|
||||
{
|
||||
uint16_t i;
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY);
|
||||
for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) {
|
||||
if (ble_mesh_node_prestore_params[i].net_idx != 0xFFFF && ble_mesh_node_prestore_params[i].unicast_addr != 0xFFFF) {
|
||||
ble_mesh_node_prestore_params[i].net_idx = netkey_index;
|
||||
ble_mesh_node_prestore_params[i].unicast_addr = unicast_addr;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(ble_mesh_node_sema);
|
||||
}
|
||||
|
||||
void ble_mesh_node_statistics_get(void)
|
||||
{
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "statistics:%d,%d\n", ble_mesh_node_statistics.statistics, ble_mesh_node_statistics.package_num);
|
||||
xSemaphoreGive(ble_mesh_node_sema);
|
||||
}
|
||||
|
||||
int ble_mesh_node_statistics_accumultate(uint8_t *data, uint32_t value, uint16_t type)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t sequence_num = (data[0] << 8) | data[1];
|
||||
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY);
|
||||
for (i = 0; i < ble_mesh_node_statistics.total_package_num; i++) {
|
||||
if (ble_mesh_node_statistics.package_index[i] == sequence_num) {
|
||||
xSemaphoreGive(ble_mesh_node_sema);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// package type wrong
|
||||
if (data[2] != type) {
|
||||
xSemaphoreGive(ble_mesh_node_sema);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < ble_mesh_node_statistics.total_package_num; i++) {
|
||||
if (ble_mesh_node_statistics.package_index[i] == 0) {
|
||||
ble_mesh_node_statistics.package_index[i] = sequence_num;
|
||||
ble_mesh_node_statistics.package_num += 1;
|
||||
ble_mesh_node_statistics.statistics += value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(ble_mesh_node_sema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_mesh_node_statistics_init(uint16_t package_num)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
ble_mesh_node_statistics.package_index = malloc(sizeof(uint16_t) * package_num);
|
||||
ble_mesh_node_statistics.total_package_num = package_num;
|
||||
if (ble_mesh_node_statistics.package_index == NULL) {
|
||||
ESP_LOGE(TAG, " %s, %d malloc fail\n", __func__, __LINE__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ble_mesh_node_statistics.package_num = 0;
|
||||
for (i = 0; i < package_num; i++) {
|
||||
ble_mesh_node_statistics.package_index[i] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_mesh_node_statistics_destroy(void)
|
||||
{
|
||||
if (ble_mesh_node_statistics.package_index != NULL) {
|
||||
free(ble_mesh_node_statistics.package_index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BLE_MESH_ADAPTER_H_
|
||||
#define _BLE_MESH_ADAPTER_H_
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "ble_mesh_console_lib.h"
|
||||
#include "ble_mesh_cfg_srv_model.h"
|
||||
|
||||
#define TAG "ble_mesh_node_console"
|
||||
|
||||
typedef enum {
|
||||
VENDOR_MODEL_PERF_OPERATION_TYPE_GET = 1,
|
||||
VENDOR_MODEL_PERF_OPERATION_TYPE_SET,
|
||||
VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK
|
||||
} ble_mesh_perf_operation_type;
|
||||
|
||||
typedef struct {
|
||||
uint8_t current;
|
||||
uint8_t previous;
|
||||
char *name;
|
||||
} ble_mesh_node_status;
|
||||
|
||||
typedef struct {
|
||||
uint32_t statistics;
|
||||
uint32_t package_num;
|
||||
uint16_t *package_index;
|
||||
uint32_t total_package_num;
|
||||
} ble_mesh_node_statistics_t;
|
||||
ble_mesh_node_statistics_t ble_mesh_node_statistics;
|
||||
|
||||
extern SemaphoreHandle_t ble_mesh_node_sema;
|
||||
|
||||
#define arg_int_to_value(src_msg, dst_msg, message) do { \
|
||||
if (src_msg->count != 0) {\
|
||||
ESP_LOGD(TAG, "\n%s, %s\n", __func__, message);\
|
||||
dst_msg = src_msg->ival[0];\
|
||||
} \
|
||||
} while(0) \
|
||||
|
||||
#define ble_mesh_node_get_value(index, key, value) do { \
|
||||
uint16_t _index = 0; \
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \
|
||||
for (_index = 0; _index < NODE_MAX_GROUP_CONFIG; _index) { \
|
||||
if (node_set_prestore_params[_index].key == value) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
index = _index; \
|
||||
xSemaphoreGive(ble_mesh_node_sema); \
|
||||
} while(0) \
|
||||
|
||||
#define ble_mesh_node_set_state(status) do { \
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \
|
||||
node_status.previous = node_status.current; \
|
||||
node_status.current = status; \
|
||||
xSemaphoreGive(ble_mesh_node_sema); \
|
||||
}while(0) \
|
||||
|
||||
#define ble_mesh_node_get_state(status) do { \
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \
|
||||
status = node_status.current; \
|
||||
xSemaphoreGive(ble_mesh_node_sema); \
|
||||
}while(0) \
|
||||
|
||||
#define ble_mesh_callback_check_err_code(err_code, message) do { \
|
||||
if (err_code == ESP_OK) { \
|
||||
ESP_LOGI(TAG, "%s,OK\n", message); \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, "%s,Fail,%d\n", message, err_code); \
|
||||
} \
|
||||
}while(0) \
|
||||
|
||||
void ble_mesh_node_init(void);
|
||||
void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr);
|
||||
esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id);
|
||||
esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id);
|
||||
void ble_mesh_node_statistics_get(void);
|
||||
int ble_mesh_node_statistics_accumultate(uint8_t *data, uint32_t value, uint16_t type);
|
||||
int ble_mesh_node_statistics_init(uint16_t package_num);
|
||||
void ble_mesh_node_statistics_destroy(void);
|
||||
|
||||
#endif //_BLE_MESH_ADAOTER_H_
|
||||
@@ -0,0 +1,208 @@
|
||||
// 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 "ble_mesh_cfg_srv_model.h"
|
||||
|
||||
uint8_t dev_uuid[16] = {0xdd, 0xdd};
|
||||
|
||||
#if CONFIG_BLE_MESH_NODE
|
||||
esp_ble_mesh_prov_t prov = {
|
||||
.uuid = dev_uuid,
|
||||
};
|
||||
#endif //CONFIG_BLE_MESH_NODE
|
||||
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
esp_ble_mesh_prov_t prov = {
|
||||
.prov_uuid = dev_uuid,
|
||||
.prov_unicast_addr = 0x0001,
|
||||
.prov_start_address = 0x0005,
|
||||
.prov_attention = 0x00,
|
||||
.prov_algorithm = 0x00,
|
||||
.prov_pub_key_oob = 0x00,
|
||||
.prov_pub_key_oob_cb = NULL,
|
||||
.prov_static_oob_val = NULL,
|
||||
.prov_static_oob_len = 0x00,
|
||||
.prov_input_num = NULL,
|
||||
.prov_output_num = NULL,
|
||||
.flags = 0x00,
|
||||
.iv_index = 0x00,
|
||||
};
|
||||
#endif //CONFIG_BLE_MESH_PROVISIONER
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(model_pub_config, 2 + 1, ROLE_NODE);
|
||||
|
||||
esp_ble_mesh_model_pub_t vendor_model_pub_config;
|
||||
|
||||
// configure server module
|
||||
esp_ble_mesh_cfg_srv_t cfg_srv = {
|
||||
.relay = ESP_BLE_MESH_RELAY_ENABLED,
|
||||
.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 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(0, 20),
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t config_server_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t config_server_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_server_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t config_server_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = config_server_elements,
|
||||
.element_count = ARRAY_SIZE(config_server_elements),
|
||||
};
|
||||
|
||||
// config client model
|
||||
esp_ble_mesh_model_t config_client_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t config_client_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_client_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t config_client_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = config_client_elements,
|
||||
.element_count = ARRAY_SIZE(config_client_elements),
|
||||
};
|
||||
|
||||
// configure special module
|
||||
esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t gen_onoff_srv_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_model_op_config, &model_pub_config, NULL),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t gen_onoff_srv_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, gen_onoff_srv_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t gen_onoff_srv_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = gen_onoff_srv_elements,
|
||||
.element_count = ARRAY_SIZE(gen_onoff_srv_elements),
|
||||
};
|
||||
|
||||
// config generic onoff client
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
|
||||
esp_ble_mesh_client_t gen_onoff_cli;
|
||||
|
||||
esp_ble_mesh_model_t gen_onoff_cli_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&model_pub_config, &gen_onoff_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t gen_onoff_cli_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, gen_onoff_cli_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t gen_onoff_cli_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = gen_onoff_cli_elements,
|
||||
.element_count = ARRAY_SIZE(gen_onoff_cli_elements),
|
||||
};
|
||||
#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI
|
||||
|
||||
//CONFIG VENDOR MODEL TEST PERFORMANCE
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001
|
||||
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP)
|
||||
|
||||
esp_ble_mesh_client_op_pair_t test_perf_cli_op_pair[] = {
|
||||
{ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS},
|
||||
{ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS},
|
||||
{ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS},
|
||||
};
|
||||
|
||||
esp_ble_mesh_client_t test_perf_cli = {
|
||||
.op_pair_size = ARRAY_SIZE(test_perf_cli_op_pair),
|
||||
.op_pair = test_perf_cli_op_pair,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_op_t test_perf_srv_op[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, 1),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, 1),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, 1),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_op_t test_perf_cli_op[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, 1),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t config_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t test_perf_cli_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI,
|
||||
test_perf_cli_op, &vendor_model_pub_config, &test_perf_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t test_perf_cli_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_cli_models),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t test_perf_cli_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = test_perf_cli_elements,
|
||||
.element_count = ARRAY_SIZE(test_perf_cli_elements),
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t test_perf_srv_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV,
|
||||
test_perf_srv_op, NULL, NULL),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t test_perf_srv_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_srv_models),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t test_perf_srv_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = test_perf_srv_elements,
|
||||
.element_count = ARRAY_SIZE(test_perf_srv_elements),
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BLE_MESH_CFG_SRV_MODEL_H_
|
||||
#define _BLE_MESH_CFG_SRV_MODEL_H_
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI
|
||||
|
||||
#define NODE_MAX_GROUP_CONFIG 3
|
||||
#define CID_ESP 0x02C4
|
||||
|
||||
extern uint8_t dev_uuid[16];
|
||||
|
||||
typedef struct {
|
||||
uint16_t net_idx;
|
||||
uint16_t unicast_addr;
|
||||
} ble_mesh_node_config_params;
|
||||
ble_mesh_node_config_params ble_mesh_node_prestore_params[NODE_MAX_GROUP_CONFIG];
|
||||
|
||||
extern esp_ble_mesh_prov_t prov;
|
||||
|
||||
extern esp_ble_mesh_model_pub_t vendor_model_pub_config;
|
||||
|
||||
// configure server module
|
||||
extern esp_ble_mesh_cfg_srv_t cfg_srv;
|
||||
|
||||
extern esp_ble_mesh_model_t config_server_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t config_server_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t config_server_comp;
|
||||
|
||||
// config client model
|
||||
esp_ble_mesh_client_t cfg_cli;
|
||||
extern esp_ble_mesh_model_t config_client_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t config_client_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t config_client_comp;
|
||||
|
||||
// configure special module
|
||||
extern esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[];
|
||||
|
||||
extern esp_ble_mesh_model_t gen_onoff_srv_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t gen_onoff_srv_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t gen_onoff_srv_comp;
|
||||
|
||||
// config generic onoff client
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
|
||||
extern esp_ble_mesh_client_t gen_onoff_cli;
|
||||
|
||||
extern esp_ble_mesh_model_t gen_onoff_cli_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t gen_onoff_cli_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t gen_onoff_cli_comp;
|
||||
#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI
|
||||
|
||||
//CONFIG VENDOR MODEL TEST PERFORMANCE
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001
|
||||
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP)
|
||||
|
||||
extern esp_ble_mesh_client_t test_perf_cli;
|
||||
|
||||
extern esp_ble_mesh_model_op_t test_perf_srv_op[];
|
||||
|
||||
extern esp_ble_mesh_model_op_t test_perf_cli_op[];
|
||||
|
||||
extern esp_ble_mesh_model_t config_models[];
|
||||
|
||||
extern esp_ble_mesh_model_t test_perf_cli_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t test_perf_cli_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t test_perf_cli_comp;
|
||||
|
||||
extern esp_ble_mesh_model_t test_perf_srv_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t test_perf_srv_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t test_perf_srv_comp;
|
||||
|
||||
#endif //_BLE_MESH_CFG_SRV_MODEL_H_
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Console example — declarations of command registration functions.
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
|
||||
// Register system functions
|
||||
void register_system(void);
|
||||
|
||||
// Register blutooth
|
||||
void register_bluetooth(void);
|
||||
|
||||
// Register mesh node cmd
|
||||
void ble_mesh_register_mesh_node(void);
|
||||
|
||||
// Register mesh config server and generic server operation cmd
|
||||
void ble_mesh_register_server(void);
|
||||
|
||||
#if (CONFIG_BLE_MESH_CFG_CLI)
|
||||
// Register mesh config client operation cmd
|
||||
void ble_mesh_register_configuration_client_model(void);
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
// 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 "ble_mesh_console_lib.h"
|
||||
|
||||
static int hex2num(char c);
|
||||
static int hex2byte(const char *hex);
|
||||
|
||||
static int hex2num(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int hex2byte(const char *hex)
|
||||
{
|
||||
int a, b;
|
||||
a = hex2num(*hex++);
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
b = hex2num(*hex++);
|
||||
if (b < 0) {
|
||||
return -1;
|
||||
}
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
int a;
|
||||
const char *ipos = hex;
|
||||
uint8_t *opos = buf;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
a = hex2byte(ipos);
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
*opos ++ = a;
|
||||
ipos += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_value_string(char *value_in, char *buf)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
uint16_t length = strlen(value_in);
|
||||
for(int i = 0; i<length; i++) {
|
||||
printf("%c", value_in[i]);
|
||||
}
|
||||
|
||||
if (length > 2) {
|
||||
if (value_in[0] == '0' && value_in[1] == 'x') {
|
||||
buf[(length - 2) / 2] = 0;
|
||||
result = hexstr_2_bin(&value_in[2], (uint8_t *)buf, (length - 2) / 2);
|
||||
length = (length - 2) / 2;
|
||||
} else {
|
||||
strcpy(buf, value_in);
|
||||
result = 0;
|
||||
}
|
||||
} else {
|
||||
strcpy(buf, value_in);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool str_2_mac(uint8_t *str, uint8_t *dest)
|
||||
{
|
||||
uint8_t loop = 0;
|
||||
uint8_t tmp = 0;
|
||||
uint8_t *src_p = str;
|
||||
|
||||
if (strlen((char *)src_p) != 17) { // must be like 12:34:56:78:90:AB
|
||||
return false;
|
||||
}
|
||||
|
||||
for (loop = 0; loop < 17 ; loop++) {
|
||||
if (loop % 3 == 2) {
|
||||
if (src_p[loop] != ':') {
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((src_p[loop] >= '0') && (src_p[loop] <= '9')) {
|
||||
tmp = tmp * 16 + src_p[loop] - '0';
|
||||
} else if ((src_p[loop] >= 'A') && (src_p[loop] <= 'F')) {
|
||||
tmp = tmp * 16 + src_p[loop] - 'A' + 10;
|
||||
} else if ((src_p[loop] >= 'a') && (src_p[loop] <= 'f')) {
|
||||
tmp = tmp * 16 + src_p[loop] - 'a' + 10;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loop % 3 == 1) {
|
||||
*dest++ = tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BLE_MESH_CONSOLE_LIB_H_
|
||||
#define _BLE_MESH_CONSOLE_LIB_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
bool str_2_mac(uint8_t *str, uint8_t *dest);
|
||||
int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len);
|
||||
int get_value_string(char *value_in, char *buf);
|
||||
|
||||
#endif //_BLE_MESH_CONSOLE_LIB_H_
|
||||
@@ -0,0 +1,215 @@
|
||||
// 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 "esp_vfs_dev.h"
|
||||
#include "driver/uart.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
|
||||
#include "esp_console.h"
|
||||
#include "linenoise/linenoise.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
#include "ble_mesh_console_decl.h"
|
||||
|
||||
#if CONFIG_STORE_HISTORY
|
||||
|
||||
#define MOUNT_PATH "/data"
|
||||
#define HISTORY_PATH MOUNT_PATH "/history.txt"
|
||||
|
||||
static void initialize_filesystem(void)
|
||||
{
|
||||
static wl_handle_t wl_handle;
|
||||
const esp_vfs_fat_mount_config_t mount_config = {
|
||||
.max_files = 4,
|
||||
.format_if_mount_failed = true
|
||||
};
|
||||
esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle);
|
||||
if (err != ESP_OK) {
|
||||
printf("Failed to mount FATFS (0x%x)", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_STORE_HISTORY
|
||||
|
||||
static void initialize_console(void)
|
||||
{
|
||||
/* Disable buffering on stdin and stdout */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
|
||||
256, 0, 0, NULL, 0) );
|
||||
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = {
|
||||
.max_cmdline_args = 20,
|
||||
.max_cmdline_length = 256,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_init(&console_config) );
|
||||
|
||||
/* Configure linenoise line completion library */
|
||||
/* Enable multiline editing. If not set, long commands will scroll within
|
||||
* single line.
|
||||
*/
|
||||
linenoiseSetMultiLine(1);
|
||||
|
||||
/* Tell linenoise where to get command completions and hints */
|
||||
linenoiseSetCompletionCallback(&esp_console_get_completion);
|
||||
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
|
||||
|
||||
/* Set command history size */
|
||||
linenoiseHistorySetMaxLen(100);
|
||||
|
||||
#if CONFIG_STORE_HISTORY
|
||||
/* Load command history from filesystem */
|
||||
linenoiseHistoryLoad(HISTORY_PATH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
printf("%s initialize controller failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
printf("%s enable controller failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
printf("%s init bluetooth failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
printf("%s enable bluetooth failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t res;
|
||||
|
||||
nvs_flash_init();
|
||||
|
||||
// init and enable bluetooth
|
||||
res = bluetooth_init();
|
||||
if (res) {
|
||||
printf("esp32_bluetooth_init failed (ret %d)", res);
|
||||
}
|
||||
|
||||
#if CONFIG_STORE_HISTORY
|
||||
initialize_filesystem();
|
||||
#endif
|
||||
|
||||
initialize_console();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_system();
|
||||
register_bluetooth();
|
||||
ble_mesh_register_mesh_node();
|
||||
ble_mesh_register_server();
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
|
||||
|
||||
printf("\n"
|
||||
"This is an example of ESP-IDF console component.\n"
|
||||
"Type 'help' to get the list of commands.\n"
|
||||
"Use UP/DOWN arrows to navigate through command history.\n"
|
||||
"Press TAB when typing command name to auto-complete.\n");
|
||||
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates success */
|
||||
printf("\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
prompt = "esp32> ";
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
}
|
||||
|
||||
/* Main loop */
|
||||
while (true) {
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
char *line = linenoise(prompt);
|
||||
if (line == NULL) { /* Ignore empty lines */
|
||||
continue;
|
||||
}
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
#if CONFIG_STORE_HISTORY
|
||||
/* Save command history to filesystem */
|
||||
linenoiseHistorySave(HISTORY_PATH);
|
||||
#endif
|
||||
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
printf("Unrecognized command\n");
|
||||
} else if (err == ESP_ERR_INVALID_ARG) {
|
||||
// command was empty
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
printf("\nCommand returned non-zero error code: 0x%x\n", ret);
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: 0x%x\n", err);
|
||||
}
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/* Console example — various system commands
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "ble_mesh_console_decl.h"
|
||||
|
||||
#if CONFIG_IDF_CMAKE
|
||||
#define CONFIG_ESPTOOLPY_PORT "Which is choosen by Users for CMake"
|
||||
#endif
|
||||
|
||||
static void register_free(void);
|
||||
static void register_restart(void);
|
||||
static void register_make(void);
|
||||
|
||||
void register_system(void)
|
||||
{
|
||||
register_free();
|
||||
register_restart();
|
||||
register_make();
|
||||
}
|
||||
|
||||
/** 'restart' command restarts the program */
|
||||
|
||||
static int restart(int argc, char **argv)
|
||||
{
|
||||
printf("%s, %s", __func__, "Restarting");
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
static void register_restart(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "restart",
|
||||
.help = "Restart the program",
|
||||
.hint = NULL,
|
||||
.func = &restart,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
/** 'free' command prints available heap memory */
|
||||
|
||||
static int free_mem(int argc, char **argv)
|
||||
{
|
||||
printf("%d\n", esp_get_free_heap_size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_free(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "free",
|
||||
.help = "Get the total size of heap memory available",
|
||||
.hint = NULL,
|
||||
.func = &free_mem,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
static int make(int argc, char **argv)
|
||||
{
|
||||
int count = REG_READ(RTC_CNTL_STORE0_REG);
|
||||
if (++count >= 3) {
|
||||
printf("This is not the console you are looking for.\n");
|
||||
return 0;
|
||||
}
|
||||
REG_WRITE(RTC_CNTL_STORE0_REG, count);
|
||||
|
||||
const char *make_output =
|
||||
R"(LD build/console.elf
|
||||
esptool.py v2.1-beta1
|
||||
)";
|
||||
|
||||
const char* flash_output[] = {
|
||||
R"(Flashing binaries to serial port )" CONFIG_ESPTOOLPY_PORT R"( (app at offset 0x10000)...
|
||||
esptool.py v2.1-beta1
|
||||
Connecting....
|
||||
)",
|
||||
R"(Chip is ESP32D0WDQ6 (revision 0)
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Changing baud rate to 921600
|
||||
Changed.
|
||||
Configuring flash size...
|
||||
Auto-detected Flash size: 4MB
|
||||
Flash params set to 0x0220
|
||||
Compressed 15712 bytes to 9345...
|
||||
)",
|
||||
R"(Wrote 15712 bytes (9345 compressed) at 0x00001000 in 0.1 seconds (effective 1126.9 kbit/s)...
|
||||
Hash of data verified.
|
||||
Compressed 333776 bytes to 197830...
|
||||
)",
|
||||
R"(Wrote 333776 bytes (197830 compressed) at 0x00010000 in 3.3 seconds (effective 810.3 kbit/s)...
|
||||
Hash of data verified.
|
||||
Compressed 3072 bytes to 82...
|
||||
)",
|
||||
R"(Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 1588.4 kbit/s)...
|
||||
Hash of data verified.
|
||||
Leaving...
|
||||
Hard resetting...
|
||||
)"
|
||||
};
|
||||
|
||||
const char* monitor_output =
|
||||
R"(MONITOR
|
||||
)" LOG_COLOR_W R"(--- idf_monitor on )" CONFIG_ESPTOOLPY_PORT R"( 115200 ---
|
||||
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --
|
||||
)" LOG_RESET_COLOR;
|
||||
|
||||
bool need_make = false;
|
||||
bool need_flash = false;
|
||||
bool need_monitor = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "all") == 0) {
|
||||
need_make = true;
|
||||
} else if (strcmp(argv[i], "flash") == 0) {
|
||||
need_make = true;
|
||||
need_flash = true;
|
||||
} else if (strcmp(argv[i], "monitor") == 0) {
|
||||
need_monitor = true;
|
||||
} else if (argv[i][0] == '-') {
|
||||
/* probably -j option */
|
||||
} else if (isdigit((int) argv[i][0])) {
|
||||
/* might be an argument to -j */
|
||||
} else {
|
||||
printf("make: *** No rule to make target `%s'. Stop.\n", argv[i]);
|
||||
/* Technically this is an error, but let's not spoil the output */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (argc == 1) {
|
||||
need_make = true;
|
||||
}
|
||||
if (need_make) {
|
||||
printf("%s", make_output);
|
||||
}
|
||||
if (need_flash) {
|
||||
size_t n_items = sizeof(flash_output) / sizeof(flash_output[0]);
|
||||
for (int i = 0; i < n_items; ++i) {
|
||||
printf("%s", flash_output[i]);
|
||||
vTaskDelay(200/portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
if (need_monitor) {
|
||||
printf("%s", monitor_output);
|
||||
esp_restart();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_make(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "make",
|
||||
.help = NULL, /* Do not include in 'help' output */
|
||||
.hint = "all | flash | monitor",
|
||||
.func = &make,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,547 @@
|
||||
// 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 "esp_bt.h"
|
||||
#include "soc/soc.h"
|
||||
|
||||
#include "esp_bt_device.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
|
||||
#include "ble_mesh_console_lib.h"
|
||||
#include "ble_mesh_adapter.h"
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *static_val;
|
||||
struct arg_int *static_val_len;
|
||||
struct arg_int *output_size;
|
||||
struct arg_int *output_actions;
|
||||
struct arg_int *input_size;
|
||||
struct arg_int *input_actions;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_prov_t;
|
||||
static ble_mesh_prov_t oob;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *model_type;
|
||||
struct arg_int *config_index;
|
||||
struct arg_str *dev_uuid;
|
||||
struct arg_int *pub_config;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_comp_t;
|
||||
static ble_mesh_comp_t component;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *bearer;
|
||||
struct arg_int *enable;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_bearer_t;
|
||||
static ble_mesh_bearer_t bearer;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *package_num;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_node_statistices_t;
|
||||
ble_mesh_node_statistices_t node_statistices;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *tx_sense_power;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_tx_sense_power;
|
||||
static ble_mesh_tx_sense_power power_set;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *net_key;
|
||||
struct arg_int *net_idx;
|
||||
struct arg_int *unicast_addr;
|
||||
struct arg_str *dev_key;
|
||||
struct arg_str *app_key;
|
||||
struct arg_int *app_idx;
|
||||
struct arg_int *group_addr;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_node_network_info_t;
|
||||
ble_mesh_node_network_info_t node_network_info;
|
||||
|
||||
ble_mesh_node_status node_status = {
|
||||
.previous = 0x0,
|
||||
.current = 0x0,
|
||||
};
|
||||
|
||||
SemaphoreHandle_t ble_mesh_node_sema;
|
||||
|
||||
void ble_mesh_register_node_cmd(void);
|
||||
// Register callback function
|
||||
void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param);
|
||||
void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param);
|
||||
|
||||
|
||||
void ble_mesh_register_mesh_node(void)
|
||||
{
|
||||
ble_mesh_register_node_cmd();
|
||||
}
|
||||
|
||||
int ble_mesh_register_node_cb(int argc, char** argv)
|
||||
{
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
ble_mesh_node_init();
|
||||
esp_ble_mesh_register_prov_callback(ble_mesh_prov_cb);
|
||||
esp_ble_mesh_register_custom_model_callback(ble_mesh_model_cb);
|
||||
ESP_LOGI(TAG, "Node:Reg,OK");
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGD(TAG, "enter %s, event = %d", __func__, event);
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->prov_register_comp.err_code, "Provisioning:Register");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_enable_comp.err_code, "Node:EnBearer");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_disable_comp.err_code, "Node:DisBearer");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "Node:LinkOpen,OK,%d", param->node_prov_link_open.bearer);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "Node:LinkClose,OK,%d", param->node_prov_link_close.bearer);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT:
|
||||
ESP_LOGI(TAG, "Node:OutPut,%d,%d", param->node_prov_output_num.action, param->node_prov_output_num.number);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT:
|
||||
ESP_LOGI(TAG, "Node:OutPutStr,%s", param->node_prov_output_str.string);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_INPUT_EVT:
|
||||
ESP_LOGI(TAG, "Node:InPut,%d,%d", param->node_prov_input.action, param->node_prov_input.size);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "Provisioning:Success,%d", param->node_prov_complete.addr);
|
||||
ble_mesh_set_node_prestore_params(param->node_prov_complete.net_idx, param->node_prov_complete.addr);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
||||
ESP_LOGI(TAG, "Node:Reset");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_input_num_comp.err_code, "Node:InputNum");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_input_str_comp.err_code, "Node:InputStr");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_set_unprov_dev_name_comp.err_code, "Node:SetName");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_proxy_identity_enable_comp.err_code, "Node:ProxyIndentity");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_proxy_gatt_enable_comp.err_code, "Node:EnProxyGatt");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_proxy_gatt_disable_comp.err_code, "Node:DisProxyGatt");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s", __func__);
|
||||
}
|
||||
|
||||
void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param)
|
||||
{
|
||||
uint8_t status;
|
||||
uint16_t result;
|
||||
uint8_t data[4];
|
||||
|
||||
ESP_LOGD(TAG, "enter %s, event=%x\n", __func__, event);
|
||||
printf("enter %s, event=%x\n", __func__, event);
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_MODEL_OPERATION_EVT:
|
||||
if (param->model_operation.model != NULL && param->model_operation.model->op != NULL) {
|
||||
if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) {
|
||||
ESP_LOGI(TAG, "Node:GetStatus,Success");
|
||||
ble_mesh_node_get_state(status);
|
||||
esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(status), &status);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
ESP_LOGI(TAG, "Node:SetAck,Success,%d,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl, param->model_operation.length);
|
||||
ble_mesh_node_set_state(param->model_operation.msg[0]);
|
||||
ble_mesh_node_get_state(status);
|
||||
esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(status), &status);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ble_mesh_node_set_state(param->model_operation.msg[0]);
|
||||
ESP_LOGI(TAG, "Node:SetUnAck,Success,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS) {
|
||||
ESP_LOGI(TAG, "Node:Status,Success,%d", param->model_operation.length);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET) {
|
||||
ESP_LOGI(TAG, "VendorModel:SetAck,Success,%d", param->model_operation.ctx->recv_ttl);
|
||||
data[0] = param->model_operation.msg[0];
|
||||
data[1] = param->model_operation.msg[1];
|
||||
data[2] = param->model_operation.msg[2];
|
||||
data[3] = param->model_operation.ctx->recv_ttl;
|
||||
result = ble_mesh_node_statistics_accumultate(param->model_operation.msg, param->model_operation.length, VENDOR_MODEL_PERF_OPERATION_TYPE_SET);
|
||||
if (result == 0) {
|
||||
esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx,
|
||||
ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, sizeof(data), data);
|
||||
}
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK) {
|
||||
ESP_LOGI(TAG, "VendorModel:SetUnAck,Success,%d,%d", param->model_operation.ctx->recv_ttl, param->model_operation.length);
|
||||
result = ble_mesh_node_statistics_accumultate(param->model_operation.msg, param->model_operation.length, VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK);
|
||||
if (result == 0) {
|
||||
esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx,
|
||||
ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, param->model_operation.length, param->model_operation.msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
|
||||
if (param->model_send_comp.err_code == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Node:ModelSend,OK");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Node:ModelSend,Fail");
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
|
||||
ESP_LOGI(TAG, "PublishSend,OK,0x%x,%d,", param->model_publish_comp.model->model_id, param->model_publish_comp.model->pub->msg->len);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT:
|
||||
ESP_LOGI(TAG, "PublishUpdate,OK");
|
||||
break;
|
||||
case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT:
|
||||
ESP_LOGI(TAG, "Node:TimeOut");
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_EVT_MAX:
|
||||
ESP_LOGI(TAG, "Node:MaxEvt");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
}
|
||||
|
||||
int ble_mesh_power_set(int argc, char **argv)
|
||||
{
|
||||
esp_err_t result = ESP_OK;
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
int nerrors = arg_parse(argc, argv, (void **) &power_set);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, power_set.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(power_set.action_type->sval[0], "tx") == 0) {
|
||||
result = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, power_set.tx_sense_power->ival[0]);
|
||||
} else if (strcmp(power_set.action_type->sval[0], "sense") == 0) {
|
||||
uint32_t *reg = (uint32_t *)(0x6001c07c);
|
||||
int reg_addr = 0x6001c07c;
|
||||
uint32_t flag = 0x00FF0000;
|
||||
uint32_t sense_new = power_set.tx_sense_power->ival[0];
|
||||
uint32_t reg_to_write = ((*reg) &= ~flag) | ((256 - sense_new) << 16);
|
||||
REG_WRITE(reg_addr, reg_to_write);
|
||||
|
||||
}
|
||||
|
||||
if (result == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Node:SetPower,OK\n");
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ble_mesh_load_oob(int argc, char **argv)
|
||||
{
|
||||
uint8_t *static_val;
|
||||
int nerrors = arg_parse(argc, argv, (void **) &oob);
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, oob.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//parsing prov
|
||||
if (oob.static_val->count != 0) {
|
||||
static_val = malloc(oob.static_val_len->ival[0] + 1);
|
||||
get_value_string((char *)oob.static_val->sval[0], (char *)static_val);
|
||||
prov.static_val = static_val;
|
||||
}
|
||||
|
||||
arg_int_to_value(oob.static_val_len, prov.static_val_len, "static_val_len");
|
||||
arg_int_to_value(oob.output_size, prov.output_size, "output_size");
|
||||
arg_int_to_value(oob.output_actions, prov.output_actions, "output_actions");
|
||||
arg_int_to_value(oob.input_size, prov.input_size, "input_size");
|
||||
arg_int_to_value(oob.input_actions, prov.input_actions, "input_action");
|
||||
|
||||
ESP_LOGI(TAG, "OOB:Load,OK\n");
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_mesh_init(int argc, char **argv)
|
||||
{
|
||||
int err;
|
||||
esp_ble_mesh_comp_t *local_component = NULL;
|
||||
uint8_t *device_uuid =NULL;
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &component);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, component.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "enter %s, module %x\n", __func__, component.model_type->ival[0]);
|
||||
local_component = ble_mesh_get_component(component.model_type->ival[0]);
|
||||
|
||||
if (component.dev_uuid->count != 0) {
|
||||
device_uuid = malloc((16 + 1) * sizeof(uint8_t));
|
||||
if (device_uuid == NULL) {
|
||||
ESP_LOGE(TAG, "ble mesh malloc failed, %d\n", __LINE__);
|
||||
}
|
||||
get_value_string((char *)component.dev_uuid->sval[0], (char *) device_uuid);
|
||||
memcpy(dev_uuid, device_uuid, 16);
|
||||
} else {
|
||||
memcpy(dev_uuid, esp_bt_dev_get_address(), 6);
|
||||
}
|
||||
|
||||
err = esp_ble_mesh_init(&prov, local_component);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Initializing mesh failed (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
free(device_uuid);
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_node_enable_bearer(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err = 0;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &bearer);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, bearer.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bearer.enable->count != 0) {
|
||||
if (bearer.enable->ival[0]) {
|
||||
//err = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_N12);
|
||||
err = esp_ble_mesh_node_prov_enable(bearer.bearer->ival[0]);
|
||||
} else {
|
||||
err = esp_ble_mesh_node_prov_disable(bearer.bearer->ival[0]);
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_node_reset(int argc, char** argv)
|
||||
{
|
||||
esp_err_t err;
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
|
||||
err = esp_ble_mesh_node_local_reset();
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_node_statistics_regist(int argc, char **argv)
|
||||
{
|
||||
int result = ESP_OK;
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &node_statistices);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, node_statistices.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
|
||||
if (strcmp(node_statistices.action_type->sval[0], "init") == 0) {
|
||||
result = ble_mesh_node_statistics_init(node_statistices.package_num->ival[0]);
|
||||
ESP_LOGI(TAG, "Node:InitStatistics,OK\n");
|
||||
} else if (strcmp(node_statistices.action_type->sval[0], "get") == 0) {
|
||||
ble_mesh_node_statistics_get();
|
||||
ESP_LOGI(TAG, "Node:GetStatistics,OK\n");
|
||||
} else if (strcmp(node_statistices.action_type->sval[0], "destroy") == 0) {
|
||||
ble_mesh_node_statistics_destroy();
|
||||
ESP_LOGI(TAG, "Node:DestroyStatistics\n");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ble_mesh_node_enter_network_auto(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
struct bt_mesh_device_network_info info = {
|
||||
.flags = 0,
|
||||
.iv_index = 0,
|
||||
};
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &node_network_info);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, node_network_info.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
|
||||
arg_int_to_value(node_network_info.net_idx, info.net_idx, "network key index");
|
||||
arg_int_to_value(node_network_info.unicast_addr, info.unicast_addr, "unicast address");
|
||||
arg_int_to_value(node_network_info.app_idx, info.app_idx, "appkey index");
|
||||
arg_int_to_value(node_network_info.group_addr, info.group_addr, "group address");
|
||||
err = get_value_string((char *)node_network_info.net_key->sval[0], (char *)info.net_key);
|
||||
err = get_value_string((char *)node_network_info.dev_key->sval[0], (char *)info.dev_key);
|
||||
err = get_value_string((char *)node_network_info.app_key->sval[0], (char *)info.app_key);
|
||||
|
||||
err = bt_mesh_device_auto_enter_network(&info);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGD(TAG, "NODE:EnNetwork,OK");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "NODE:EnNetwork,FAIL,%d", err);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ble_mesh_register_node_cmd(void)
|
||||
{
|
||||
const esp_console_cmd_t register_cmd = {
|
||||
.command = "bmreg",
|
||||
.help = "ble mesh: provisioner/node register callback",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_register_node_cb,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(®ister_cmd));
|
||||
|
||||
oob.static_val = arg_str0("s", NULL, "<value>", "Static OOB value");
|
||||
oob.static_val_len = arg_int0("l", NULL, "<length>", "Static OOB value length");
|
||||
oob.output_size = arg_int0("x", NULL, "<size>", "Maximum size of Output OOB");
|
||||
oob.output_actions = arg_int0("o", NULL, "<actions>", "Supported Output OOB Actions");
|
||||
oob.input_size = arg_int0("y", NULL, "<size>", "Maximum size of Input OOB");
|
||||
oob.input_actions = arg_int0("i", NULL, "<actions>", "Supported Input OOB Actions");
|
||||
oob.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t oob_cmd = {
|
||||
.command = "bmoob",
|
||||
.help = "ble mesh: provisioner/node config OOB parameters",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_load_oob,
|
||||
.argtable = &oob,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&oob_cmd) );
|
||||
|
||||
component.model_type = arg_int0("m", NULL, "<model>", "mesh model");
|
||||
component.config_index = arg_int0("c", NULL, "<index>", "mesh model op");
|
||||
component.config_index->ival[0] = 0; // set default value
|
||||
component.pub_config = arg_int0("p", NULL, "<publish>", "publish message buffer");
|
||||
component.dev_uuid = arg_str0("d", NULL, "<uuid>", "device uuid");
|
||||
component.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t model_cmd = {
|
||||
.command = "bminit",
|
||||
.help = "ble mesh: provisioner/node init",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_init,
|
||||
.argtable = &component,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&model_cmd) );
|
||||
|
||||
bearer.bearer = arg_int0("b", NULL, "<bearer>", "supported bearer");
|
||||
bearer.enable = arg_int0("e", NULL, "<enable/disable>", "bearers node supported");
|
||||
bearer.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t bearer_cmd = {
|
||||
.command = "bmnbearer",
|
||||
.help = "ble mesh node: enable/disable different bearer",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_node_enable_bearer,
|
||||
.argtable = &bearer,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&bearer_cmd));
|
||||
|
||||
const esp_console_cmd_t reset_cmd = {
|
||||
.command = "bmnreset",
|
||||
.help = "ble mesh node: reset",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_node_reset,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&reset_cmd));
|
||||
|
||||
node_statistices.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
node_statistices.package_num = arg_int0("p", NULL, "<package>", "package number");
|
||||
node_statistices.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t node_statistices_cmd = {
|
||||
.command = "bmsperf",
|
||||
.help = "ble mesh server: performance statistics",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_node_statistics_regist,
|
||||
.argtable = &node_statistices,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&node_statistices_cmd));
|
||||
|
||||
power_set.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
power_set.tx_sense_power = arg_int0("t", NULL, "<power>", "tx power or sense");
|
||||
power_set.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t power_set_cmd = {
|
||||
.command = "bmtxpower",
|
||||
.help = "ble mesh: set tx power or sense",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_power_set,
|
||||
.argtable = &power_set,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&power_set_cmd));
|
||||
|
||||
node_network_info.net_key = arg_str1("k", NULL, "<net key>", "network key");
|
||||
node_network_info.net_idx = arg_int1("n", NULL, "<net index>", "network key index");
|
||||
node_network_info.unicast_addr = arg_int1("u", NULL, "<unicast address>", "unicast address");
|
||||
node_network_info.dev_key = arg_str1("d", NULL, "<device key>", "device key");
|
||||
node_network_info.app_key = arg_str1("a", NULL, "<appkey>", "app key");
|
||||
node_network_info.app_idx = arg_int1("i", NULL, "<app index>", "appkey index");
|
||||
node_network_info.group_addr = arg_int1("g", NULL, "<group address>", "group address");
|
||||
node_network_info.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t node_network_info_cmd = {
|
||||
.command = "bmnnwk",
|
||||
.help = "ble mesh node: auto join network",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_node_enter_network_auto,
|
||||
.argtable = &node_network_info,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&node_network_info_cmd));
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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 "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
|
||||
#include "ble_mesh_console_lib.h"
|
||||
#include "ble_mesh_adapter.h"
|
||||
|
||||
void ble_mesh_register_server_operation(void);
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *data;
|
||||
struct arg_int *opcode;
|
||||
struct arg_int *model;
|
||||
struct arg_int *role;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_publish_message;
|
||||
ble_mesh_publish_message msg_publish;
|
||||
|
||||
void ble_mesh_register_server(void)
|
||||
{
|
||||
ble_mesh_register_server_operation();
|
||||
}
|
||||
|
||||
int ble_mesh_module_publish_message(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err;
|
||||
esp_ble_mesh_model_t *model = NULL;
|
||||
uint8_t *data = NULL;
|
||||
uint8_t device_role = ROLE_NODE;
|
||||
uint16_t length = 0;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &msg_publish);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, msg_publish.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
data = malloc(strlen(msg_publish.data->sval[0]));
|
||||
get_value_string((char *)msg_publish.data->sval[0], (char *) data);
|
||||
|
||||
arg_int_to_value(msg_publish.role, device_role, "device role");
|
||||
model = ble_mesh_get_model(msg_publish.model->ival[0]);
|
||||
|
||||
err = esp_ble_mesh_model_publish(model, msg_publish.opcode->ival[0], length, data, device_role);
|
||||
|
||||
ESP_LOGD(TAG, "exit %s \n", __func__);
|
||||
free(data);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ble_mesh_register_server_operation(void)
|
||||
{
|
||||
msg_publish.data = arg_str1("d", NULL, "<data>", "message data");
|
||||
msg_publish.opcode = arg_int1("o", NULL, "<opcode>", "operation opcode");
|
||||
msg_publish.model = arg_int1("m", NULL, "<module>", "module published to");
|
||||
msg_publish.role = arg_int1("r", NULL, "<role>", "device role");
|
||||
msg_publish.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t msg_publish_cmd = {
|
||||
.command = "bmpublish",
|
||||
.help = "ble mesh: publish message",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_module_publish_message,
|
||||
.argtable = &msg_publish,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&msg_publish_cmd));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 "esp_bt_device.h"
|
||||
#include "esp_console.h"
|
||||
|
||||
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
void register_ble_address(void);
|
||||
|
||||
void register_bluetooth(void)
|
||||
{
|
||||
register_ble_address();
|
||||
}
|
||||
|
||||
int bt_mac(int argc, char** argv)
|
||||
{
|
||||
const uint8_t *mac = esp_bt_dev_get_address();
|
||||
printf("+BTMAC:"MACSTR"\n", MAC2STR(mac));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void register_ble_address(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "btmac",
|
||||
.help = "get BT mac address",
|
||||
.hint = NULL,
|
||||
.func = &bt_mac,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
|
||||
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
|
||||
CONFIG_BLE_SCAN_DUPLICATE=y
|
||||
CONFIG_SCAN_DUPLICATE_TYPE=2
|
||||
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
|
||||
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
|
||||
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
|
||||
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
|
||||
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
|
||||
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
|
||||
CONFIG_GATTS_ENABLE=y
|
||||
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_HCI_5_0=y
|
||||
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PROV=y
|
||||
CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y
|
||||
CONFIG_BLE_MESH_PROXY=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=y
|
||||
CONFIG_BLE_MESH_NODE_ID_TIMEOUT=60
|
||||
CONFIG_BLE_MESH_PROXY_FILTER_SIZE=1
|
||||
CONFIG_BLE_MESH_SUBNET_COUNT=1
|
||||
CONFIG_BLE_MESH_APP_KEY_COUNT=1
|
||||
CONFIG_BLE_MESH_MODEL_KEY_COUNT=1
|
||||
CONFIG_BLE_MESH_MODEL_GROUP_COUNT=1
|
||||
CONFIG_BLE_MESH_LABEL_COUNT=1
|
||||
CONFIG_BLE_MESH_CRPL=10
|
||||
CONFIG_BLE_MESH_MSG_CACHE_SIZE=10
|
||||
CONFIG_BLE_MESH_ADV_BUF_COUNT=60
|
||||
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1
|
||||
CONFIG_BLE_MESH_RX_SDU_MAX=384
|
||||
CONFIG_BLE_MESH_TX_SEG_MAX=32
|
||||
CONFIG_BLE_MESH_RELAY=y
|
||||
CONFIG_BLE_MESH_LOW_POWER=
|
||||
CONFIG_BLE_MESH_FRIEND=
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
CONFIG_BTU_TASK_STACK_SIZE=4512
|
||||
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_mesh_console_provisioner)
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_mesh_console_provisioner
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,10 @@
|
||||
# ble mesh provisioner demo
|
||||
## Introduction
|
||||
This demo implements ble mesh provisioner basic features.Based on this demo, provisioner can scan and prove unprovisioned device, send set/get message. Also can define new model.
|
||||
|
||||
Demo steps:
|
||||
1. Build the ble mesh provisioner demo with sdkconfig.default
|
||||
2. register provisioner and set oob info, load model to init ble mesh provisioner
|
||||
3. enable bearer, so that it can scan and prove unprovisioned devices
|
||||
4. config appkey and other config info use config client model
|
||||
5. send set/get message to nodes
|
||||
@@ -0,0 +1,15 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_adapter.c"
|
||||
"ble_mesh_cfg_srv_model.c"
|
||||
"ble_mesh_console_lib.c"
|
||||
"ble_mesh_console_main.c"
|
||||
"ble_mesh_console_system.c"
|
||||
"ble_mesh_reg_cfg_client_cmd.c"
|
||||
"ble_mesh_reg_gen_onoff_client_cmd.c"
|
||||
"ble_mesh_reg_test_perf_client_cmd.c"
|
||||
"ble_mesh_register_node_cmd.c"
|
||||
"ble_mesh_register_provisioner_cmd.c"
|
||||
"register_bluetooth.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,300 @@
|
||||
// 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 "esp_ble_mesh_networking_api.h"
|
||||
#include "ble_mesh_adapter.h"
|
||||
|
||||
esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id)
|
||||
{
|
||||
esp_ble_mesh_model_t *model = NULL;
|
||||
|
||||
switch (model_id) {
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_SRV:
|
||||
model = config_server_models;
|
||||
break;
|
||||
#if (CONFIG_BLE_MESH_CFG_CLI)
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI:
|
||||
model = &gen_onoff_cli_models[1];
|
||||
break;
|
||||
#endif
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV:
|
||||
model = &gen_onoff_srv_models[1];
|
||||
break;
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI:
|
||||
model = &gen_onoff_cli_models[2];
|
||||
break;
|
||||
#endif
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI:
|
||||
model = &test_perf_cli_models[0];
|
||||
break;
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV:
|
||||
model = &test_perf_srv_models[0];
|
||||
break;
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id)
|
||||
{
|
||||
esp_ble_mesh_comp_t *comp = NULL;
|
||||
|
||||
switch (model_id) {
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_SRV:
|
||||
comp = &config_server_comp;
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_ID_CONFIG_CLI:
|
||||
comp = &config_client_comp;
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV:
|
||||
comp = &gen_onoff_srv_comp;
|
||||
break;
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
case ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI:
|
||||
comp = &gen_onoff_cli_comp;
|
||||
break;
|
||||
#endif
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI:
|
||||
comp = &test_perf_cli_comp;
|
||||
break;
|
||||
case ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV:
|
||||
comp = &test_perf_srv_comp;
|
||||
break;
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
void ble_mesh_node_init(void)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) {
|
||||
ble_mesh_node_prestore_params[i].net_idx = 0xFFFF;
|
||||
ble_mesh_node_prestore_params[i].unicast_addr = 0xFFFF;
|
||||
}
|
||||
|
||||
ble_mesh_node_sema = xSemaphoreCreateMutex();
|
||||
if (!ble_mesh_node_sema) {
|
||||
ESP_LOGE(TAG, "%s failed to init, failed to create mesh node semaphore", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr)
|
||||
{
|
||||
uint16_t i;
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY);
|
||||
for (i = 0; i < NODE_MAX_GROUP_CONFIG; i++) {
|
||||
if (ble_mesh_node_prestore_params[i].net_idx != 0xFFFF && ble_mesh_node_prestore_params[i].unicast_addr != 0xFFFF) {
|
||||
ble_mesh_node_prestore_params[i].net_idx = netkey_index;
|
||||
ble_mesh_node_prestore_params[i].unicast_addr = unicast_addr;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(ble_mesh_node_sema);
|
||||
}
|
||||
|
||||
void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
// first two bytes are sequence num, third is type
|
||||
data[0] = sequence_num >> 8;
|
||||
data[1] = sequence_num & 0xFF;
|
||||
switch (opcode) {
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET:
|
||||
data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_GET;
|
||||
break;
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET:
|
||||
data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_SET;
|
||||
break;
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK:
|
||||
data[2] = VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 3; i < byte_num; i++) {
|
||||
data[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
void ble_mesh_test_performance_client_model_get(void)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint32_t sum_time = 0;
|
||||
|
||||
xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY);
|
||||
|
||||
for (i = 0, j = 0; i < test_perf_statistics.test_num; i++) {
|
||||
if (test_perf_statistics.time[i] != 0) {
|
||||
sum_time += test_perf_statistics.time[i];
|
||||
j += 1;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (j == test_perf_statistics.test_num - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "VendorModel:Statistics,%d,%d\n",
|
||||
test_perf_statistics.statistics, (sum_time / (j + 1)));
|
||||
|
||||
xSemaphoreGive(ble_mesh_test_perf_sema);
|
||||
}
|
||||
|
||||
void ble_mesh_test_performance_client_model_get_received_percent(void)
|
||||
{
|
||||
uint32_t i, j;
|
||||
uint32_t max_time = 1400;
|
||||
uint32_t min_time = 0;
|
||||
uint32_t time_level_num = 0;
|
||||
typedef struct {
|
||||
uint16_t time_level;
|
||||
uint16_t time_num;
|
||||
} statistics_time_performance;
|
||||
statistics_time_performance *statistics_time_percent;
|
||||
|
||||
xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY);
|
||||
|
||||
time_level_num = ((max_time - min_time) / 50 + 1);
|
||||
statistics_time_percent = malloc(sizeof(statistics_time_performance) * time_level_num);
|
||||
|
||||
for (j = 0; j < time_level_num; j++) {
|
||||
statistics_time_percent[j].time_level = min_time + 50 * j;
|
||||
statistics_time_percent[j].time_num = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < test_perf_statistics.test_num; i++) {
|
||||
for (j = 0; j < time_level_num; j++) {
|
||||
if (test_perf_statistics.time[i] > max_time) {
|
||||
j -= 1;
|
||||
break;
|
||||
}
|
||||
if (test_perf_statistics.time[i] >= min_time + 50 * j
|
||||
&& test_perf_statistics.time[i] < min_time + 50 * (j + 1)) {
|
||||
statistics_time_percent[j].time_num += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for script match
|
||||
ESP_LOGI(TAG, "VendorModel:Statistics");
|
||||
for (j = 0; j < time_level_num; j++) {
|
||||
printf(",%d:%d", statistics_time_percent[j].time_level, statistics_time_percent[j].time_num);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
free(statistics_time_percent);
|
||||
xSemaphoreGive(ble_mesh_test_perf_sema);
|
||||
}
|
||||
|
||||
void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value)
|
||||
{
|
||||
xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY);
|
||||
test_perf_statistics.statistics += value;
|
||||
xSemaphoreGive(ble_mesh_test_perf_sema);
|
||||
}
|
||||
|
||||
int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length)
|
||||
{
|
||||
uint16_t i;
|
||||
uint16_t sequence_num = 0;
|
||||
uint16_t node_received_ttl = 0;
|
||||
xSemaphoreTake(ble_mesh_test_perf_sema, portMAX_DELAY);
|
||||
|
||||
// received fail
|
||||
if (length != test_perf_statistics.test_length) {
|
||||
xSemaphoreGive(ble_mesh_test_perf_sema);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
sequence_num = (data[0] << 8) | data[1];
|
||||
if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET) {
|
||||
node_received_ttl = data[3];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < test_perf_statistics.test_num; i++) {
|
||||
if (test_perf_statistics.package_index[i] == sequence_num) {
|
||||
xSemaphoreGive(ble_mesh_test_perf_sema);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < test_perf_statistics.test_num; i++) {
|
||||
if (test_perf_statistics.package_index[i] == 0) {
|
||||
test_perf_statistics.package_index[i] = sequence_num;
|
||||
if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET) {
|
||||
if (node_received_ttl == test_perf_statistics.ttl && ack_ttl == test_perf_statistics.ttl) {
|
||||
test_perf_statistics.time[i] = time;
|
||||
} else {
|
||||
test_perf_statistics.time[i] = 0;
|
||||
}
|
||||
} else if (data[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK) {
|
||||
test_perf_statistics.time[i] = time;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreGive(ble_mesh_test_perf_sema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
// malloc time
|
||||
test_perf_statistics.time = malloc(test_num * sizeof(uint16_t));
|
||||
if (test_perf_statistics.time == NULL) {
|
||||
ESP_LOGE(TAG, " %s %d, malloc fail\n", __func__, __LINE__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
test_perf_statistics.package_index = malloc(test_num * sizeof(uint16_t));
|
||||
if (test_perf_statistics.package_index == NULL) {
|
||||
ESP_LOGE(TAG, " %s %d, malloc fail\n", __func__, __LINE__);
|
||||
}
|
||||
for (i = 0; i < test_num; i++) {
|
||||
test_perf_statistics.time[i] = 0;
|
||||
test_perf_statistics.package_index[i] = 0;
|
||||
}
|
||||
|
||||
test_perf_statistics.test_num = test_num;
|
||||
test_perf_statistics.node_num = node_num;
|
||||
test_perf_statistics.ttl = ttl;
|
||||
test_perf_statistics.statistics = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_mesh_test_performance_client_model_destroy(void)
|
||||
{
|
||||
if (test_perf_statistics.time != NULL) {
|
||||
free(test_perf_statistics.time);
|
||||
}
|
||||
|
||||
if (test_perf_statistics.package_index != NULL) {
|
||||
free(test_perf_statistics.package_index);
|
||||
}
|
||||
|
||||
test_perf_statistics.test_num = 0;
|
||||
test_perf_statistics.ttl = 0;
|
||||
test_perf_statistics.node_num = 0;
|
||||
test_perf_statistics.statistics = 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BLE_MESH_ADAPTER_H_
|
||||
#define _BLE_MESH_ADAPTER_H_
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "ble_mesh_console_lib.h"
|
||||
#include "ble_mesh_cfg_srv_model.h"
|
||||
|
||||
#define TAG "ble_mesh_prov_console"
|
||||
|
||||
uint64_t start_time;
|
||||
typedef enum {
|
||||
VENDOR_MODEL_PERF_OPERATION_TYPE_GET = 1,
|
||||
VENDOR_MODEL_PERF_OPERATION_TYPE_SET,
|
||||
VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK
|
||||
} ble_mesh_perf_operation_type;
|
||||
|
||||
typedef struct {
|
||||
uint8_t current;
|
||||
uint8_t previous;
|
||||
char *name;
|
||||
} ble_mesh_node_status;
|
||||
|
||||
typedef struct {
|
||||
bool need_ack;
|
||||
uint8_t ttl;
|
||||
uint16_t length;
|
||||
uint16_t test_num;
|
||||
uint16_t address;
|
||||
uint16_t app_idx;
|
||||
uint16_t net_idx;
|
||||
uint32_t opcode;
|
||||
esp_ble_mesh_model_t *model;
|
||||
esp_ble_mesh_dev_role_t device_role;
|
||||
} ble_mesh_test_perf_throughput_data;
|
||||
|
||||
typedef struct {
|
||||
uint32_t statistics;
|
||||
uint32_t test_num;
|
||||
uint16_t test_length;
|
||||
uint16_t node_num;
|
||||
uint16_t *time;
|
||||
uint16_t *package_index;
|
||||
uint8_t ttl;
|
||||
} ble_mesh_performance_statistics_t;
|
||||
ble_mesh_performance_statistics_t test_perf_statistics;
|
||||
|
||||
#define SEND_MESSAGE_TIMEOUT (30000/portTICK_RATE_MS)
|
||||
|
||||
extern SemaphoreHandle_t ble_mesh_node_sema;
|
||||
extern SemaphoreHandle_t ble_mesh_test_perf_send_sema;
|
||||
extern SemaphoreHandle_t ble_mesh_test_perf_sema;
|
||||
|
||||
#define arg_int_to_value(src_msg, dst_msg, message) do { \
|
||||
if (src_msg->count != 0) {\
|
||||
ESP_LOGD(TAG, " %s, %s\n", __func__, message);\
|
||||
dst_msg = src_msg->ival[0];\
|
||||
} \
|
||||
} while(0) \
|
||||
|
||||
#define ble_mesh_node_get_value(index, key, value) do { \
|
||||
uint16_t _index = 0; \
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \
|
||||
for (_index = 0; _index < NODE_MAX_GROUP_CONFIG; _index) { \
|
||||
if (node_set_prestore_params[_index].key == value) { \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
index = _index; \
|
||||
xSemaphoreGive(ble_mesh_node_sema); \
|
||||
} while(0) \
|
||||
|
||||
#define ble_mesh_node_set_state(status) do { \
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \
|
||||
node_status.previous = node_status.current; \
|
||||
node_status.current = status; \
|
||||
xSemaphoreGive(ble_mesh_node_sema); \
|
||||
}while(0) \
|
||||
|
||||
#define ble_mesh_node_get_state(status) do { \
|
||||
xSemaphoreTake(ble_mesh_node_sema, portMAX_DELAY); \
|
||||
status = node_status.previous; \
|
||||
xSemaphoreGive(ble_mesh_node_sema); \
|
||||
}while(0) \
|
||||
|
||||
#define ble_mesh_callback_check_err_code(err_code, message) do { \
|
||||
if (err_code == ESP_OK) { \
|
||||
ESP_LOGI(TAG, "%s,OK\n", message); \
|
||||
} else { \
|
||||
ESP_LOGI(TAG, "%s,Fail,%d\n", message, err_code); \
|
||||
} \
|
||||
}while(0) \
|
||||
|
||||
void ble_mesh_node_init(void);
|
||||
void ble_mesh_set_node_prestore_params(uint16_t netkey_index, uint16_t unicast_addr);
|
||||
|
||||
esp_ble_mesh_model_t *ble_mesh_get_model(uint16_t model_id);
|
||||
esp_ble_mesh_comp_t *ble_mesh_get_component(uint16_t model_id);
|
||||
void ble_mesh_create_send_data(char *data, uint16_t byte_num, uint16_t sequence_num, uint32_t opcode);
|
||||
|
||||
void ble_mesh_test_performance_client_model_get(void);
|
||||
void ble_mesh_test_performance_client_model_get_received_percent(void);
|
||||
void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value);
|
||||
int ble_mesh_test_performance_client_model_accumulate_time(uint16_t time, uint8_t *data, uint8_t ack_ttl, uint16_t length);
|
||||
int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl);
|
||||
void ble_mesh_test_performance_client_model_destroy(void);
|
||||
|
||||
#endif //_BLE_MESH_ADAPTER_H_
|
||||
@@ -0,0 +1,205 @@
|
||||
// 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 "ble_mesh_cfg_srv_model.h"
|
||||
|
||||
uint8_t dev_uuid[16] = {0xdd, 0xdd};
|
||||
|
||||
#if CONFIG_BLE_MESH_NODE
|
||||
esp_ble_mesh_prov_t prov = {
|
||||
.uuid = dev_uuid,
|
||||
};
|
||||
#endif //CONFIG_BLE_MESH_NODE
|
||||
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
esp_ble_mesh_prov_t prov = {
|
||||
.prov_uuid = dev_uuid,
|
||||
.prov_unicast_addr = 0x0001,
|
||||
.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,
|
||||
};
|
||||
#endif //CONFIG_BLE_MESH_PROVISIONER
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(model_pub_config, 2 + 1, ROLE_PROVISIONER);
|
||||
|
||||
esp_ble_mesh_model_pub_t vendor_model_pub_config;
|
||||
|
||||
// configure server module
|
||||
esp_ble_mesh_cfg_srv_t cfg_srv = {
|
||||
.relay = ESP_BLE_MESH_RELAY_ENABLED,
|
||||
.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 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(0, 20),
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t config_server_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t config_server_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_server_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t config_server_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = config_server_elements,
|
||||
.element_count = ARRAY_SIZE(config_server_elements),
|
||||
};
|
||||
|
||||
// config client model
|
||||
esp_ble_mesh_model_t config_client_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t config_client_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_client_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t config_client_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = config_client_elements,
|
||||
.element_count = ARRAY_SIZE(config_client_elements),
|
||||
};
|
||||
|
||||
// configure special module
|
||||
esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t gen_onoff_srv_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_model_op_config, &model_pub_config, NULL),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t gen_onoff_srv_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, gen_onoff_srv_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t gen_onoff_srv_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = gen_onoff_srv_elements,
|
||||
.element_count = ARRAY_SIZE(gen_onoff_srv_elements),
|
||||
};
|
||||
|
||||
// config generic onoff client
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
|
||||
esp_ble_mesh_client_t gen_onoff_cli;
|
||||
|
||||
esp_ble_mesh_model_t gen_onoff_cli_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&model_pub_config, &gen_onoff_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t gen_onoff_cli_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, gen_onoff_cli_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t gen_onoff_cli_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = gen_onoff_cli_elements,
|
||||
.element_count = ARRAY_SIZE(gen_onoff_cli_elements),
|
||||
};
|
||||
#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI
|
||||
|
||||
//CONFIG VENDOR MODEL TEST PERFORMANCE
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001
|
||||
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP)
|
||||
|
||||
esp_ble_mesh_client_op_pair_t test_perf_cli_op_pair[] = {
|
||||
{ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS},
|
||||
{ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS},
|
||||
{ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS},
|
||||
};
|
||||
|
||||
esp_ble_mesh_client_t test_perf_cli = {
|
||||
.op_pair_size = ARRAY_SIZE(test_perf_cli_op_pair),
|
||||
.op_pair = test_perf_cli_op_pair,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_op_t test_perf_srv_op[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET, 1),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET, 1),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK, 1),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_op_t test_perf_cli_op[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS, 1),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t config_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t test_perf_cli_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI,
|
||||
test_perf_cli_op, &vendor_model_pub_config, &test_perf_cli),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t test_perf_cli_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_cli_models),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t test_perf_cli_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = test_perf_cli_elements,
|
||||
.element_count = ARRAY_SIZE(test_perf_cli_elements),
|
||||
};
|
||||
|
||||
esp_ble_mesh_model_t test_perf_srv_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV,
|
||||
test_perf_srv_op, NULL, NULL),
|
||||
};
|
||||
|
||||
esp_ble_mesh_elem_t test_perf_srv_elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, config_models, test_perf_srv_models),
|
||||
};
|
||||
|
||||
esp_ble_mesh_comp_t test_perf_srv_comp = {
|
||||
.cid = CID_ESP,
|
||||
.elements = test_perf_srv_elements,
|
||||
.element_count = ARRAY_SIZE(test_perf_srv_elements),
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BLE_MESH_CFG_SRV_MODEL_H_
|
||||
#define _BLE_MESH_CFG_SRV_MODEL_H_
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI
|
||||
|
||||
#define NODE_MAX_GROUP_CONFIG 3
|
||||
#define CID_ESP 0x02C4
|
||||
|
||||
extern uint8_t dev_uuid[16];
|
||||
|
||||
typedef struct {
|
||||
uint16_t net_idx;
|
||||
uint16_t unicast_addr;
|
||||
} ble_mesh_node_config_params;
|
||||
ble_mesh_node_config_params ble_mesh_node_prestore_params[NODE_MAX_GROUP_CONFIG];
|
||||
|
||||
extern esp_ble_mesh_prov_t prov;
|
||||
|
||||
extern esp_ble_mesh_model_pub_t vendor_model_pub_config;
|
||||
|
||||
// configure server module
|
||||
extern esp_ble_mesh_cfg_srv_t cfg_srv;
|
||||
|
||||
extern esp_ble_mesh_model_t config_server_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t config_server_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t config_server_comp;
|
||||
|
||||
// config client model
|
||||
esp_ble_mesh_client_t cfg_cli;
|
||||
extern esp_ble_mesh_model_t config_client_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t config_client_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t config_client_comp;
|
||||
|
||||
// configure special module
|
||||
extern esp_ble_mesh_model_op_t gen_onoff_srv_model_op_config[];
|
||||
|
||||
extern esp_ble_mesh_model_t gen_onoff_srv_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t gen_onoff_srv_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t gen_onoff_srv_comp;
|
||||
|
||||
// config generic onoff client
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
|
||||
extern esp_ble_mesh_client_t gen_onoff_cli;
|
||||
|
||||
extern esp_ble_mesh_model_t gen_onoff_cli_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t gen_onoff_cli_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t gen_onoff_cli_comp;
|
||||
#endif //CONFIG_BLE_MESH_GENERIC_ONOFF_CLI
|
||||
|
||||
//CONFIG VENDOR MODEL TEST PERFORMANCE
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_SRV 0x2000
|
||||
#define ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI 0x2001
|
||||
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_GET ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET ESP_BLE_MESH_MODEL_OP_3(0x02, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET_UNACK ESP_BLE_MESH_MODEL_OP_3(0x03, CID_ESP)
|
||||
#define ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS ESP_BLE_MESH_MODEL_OP_3(0x04, CID_ESP)
|
||||
|
||||
extern esp_ble_mesh_client_t test_perf_cli;
|
||||
|
||||
extern esp_ble_mesh_model_op_t test_perf_srv_op[];
|
||||
|
||||
extern esp_ble_mesh_model_op_t test_perf_cli_op[];
|
||||
|
||||
extern esp_ble_mesh_model_t config_models[];
|
||||
|
||||
extern esp_ble_mesh_model_t test_perf_cli_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t test_perf_cli_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t test_perf_cli_comp;
|
||||
|
||||
extern esp_ble_mesh_model_t test_perf_srv_models[];
|
||||
|
||||
extern esp_ble_mesh_elem_t test_perf_srv_elements[];
|
||||
|
||||
extern esp_ble_mesh_comp_t test_perf_srv_comp;
|
||||
|
||||
#endif //_BLE_MESH_CFG_SRV_MODEL_H_
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Console example — declarations of command registration functions.
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option).
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
|
||||
// Register system functions
|
||||
void register_system(void);
|
||||
|
||||
// Register bluetooth
|
||||
void register_bluetooth(void);
|
||||
|
||||
// Register mesh node cmd
|
||||
void ble_mesh_register_mesh_node(void);
|
||||
|
||||
// Register Test Perf client cmd
|
||||
void ble_mesh_register_mesh_test_performance_client(void);
|
||||
|
||||
#if (CONFIG_BLE_MESH_CFG_CLI)
|
||||
// Register mesh config client operation cmd
|
||||
void ble_mesh_register_configuration_client_model(void);
|
||||
#endif
|
||||
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
// Register mesh client operation cmd
|
||||
void ble_mesh_register_gen_onoff_client(void);
|
||||
#endif
|
||||
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
// Regitster mesh provisioner cmd
|
||||
void ble_mesh_register_mesh_provisioner(void);
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
// 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 "ble_mesh_console_lib.h"
|
||||
|
||||
static int hex2num(char c);
|
||||
static int hex2byte(const char *hex);
|
||||
|
||||
static int hex2num(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if (c >= 'a' && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
if (c >= 'A' && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int hex2byte(const char *hex)
|
||||
{
|
||||
int a, b;
|
||||
a = hex2num(*hex++);
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
b = hex2num(*hex++);
|
||||
if (b < 0) {
|
||||
return -1;
|
||||
}
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
uint32_t i;
|
||||
int a;
|
||||
const char *ipos = hex;
|
||||
uint8_t *opos = buf;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
a = hex2byte(ipos);
|
||||
if (a < 0) {
|
||||
return -1;
|
||||
}
|
||||
*opos ++ = a;
|
||||
ipos += 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_value_string(char *value_in, char *buf)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
uint16_t length = strlen(value_in);
|
||||
|
||||
if (length > 2) {
|
||||
if (value_in[0] == '0' && value_in[1] == 'x') {
|
||||
buf[(length - 2) / 2] = 0;
|
||||
result = hexstr_2_bin(&value_in[2], (uint8_t *)buf, (length - 2) / 2);
|
||||
length = (length - 2) / 2;
|
||||
} else {
|
||||
strcpy(buf, value_in);
|
||||
result = 0;
|
||||
}
|
||||
} else {
|
||||
strcpy(buf, value_in);
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool str_2_mac(uint8_t *str, uint8_t *dest)
|
||||
{
|
||||
uint8_t loop = 0;
|
||||
uint8_t tmp = 0;
|
||||
uint8_t *src_p = str;
|
||||
|
||||
if (strlen((char *)src_p) != 17) { // must be like 12:34:56:78:90:AB
|
||||
return false;
|
||||
}
|
||||
|
||||
for (loop = 0; loop < 17 ; loop++) {
|
||||
if (loop % 3 == 2) {
|
||||
if (src_p[loop] != ':') {
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((src_p[loop] >= '0') && (src_p[loop] <= '9')) {
|
||||
tmp = tmp * 16 + src_p[loop] - '0';
|
||||
} else if ((src_p[loop] >= 'A') && (src_p[loop] <= 'F')) {
|
||||
tmp = tmp * 16 + src_p[loop] - 'A' + 10;
|
||||
} else if ((src_p[loop] >= 'a') && (src_p[loop] <= 'f')) {
|
||||
tmp = tmp * 16 + src_p[loop] - 'a' + 10;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loop % 3 == 1) {
|
||||
*dest++ = tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BLE_MESH_CONSOLE_LIB_H_
|
||||
#define _BLE_MESH_CONSOLE_LIB_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
bool str_2_mac(uint8_t *str, uint8_t *dest);
|
||||
int hexstr_2_bin(const char *hex, uint8_t *buf, uint32_t len);
|
||||
int get_value_string(char *value_in, char *buf);
|
||||
|
||||
#endif //_BLE_MESH_CONSOLE_LIB_H_
|
||||
@@ -0,0 +1,228 @@
|
||||
// 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 "esp_console.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
#include "driver/uart.h"
|
||||
#include "linenoise/linenoise.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
|
||||
#include "ble_mesh_console_decl.h"
|
||||
|
||||
#define TAG "ble_mesh_test"
|
||||
|
||||
#if CONFIG_STORE_HISTORY
|
||||
|
||||
#define MOUNT_PATH "/data"
|
||||
#define HISTORY_PATH MOUNT_PATH "/history.txt"
|
||||
|
||||
static void initialize_filesystem(void)
|
||||
{
|
||||
static wl_handle_t wl_handle;
|
||||
const esp_vfs_fat_mount_config_t mount_config = {
|
||||
.max_files = 4,
|
||||
.format_if_mount_failed = true
|
||||
};
|
||||
esp_err_t err = esp_vfs_fat_spiflash_mount(MOUNT_PATH, "storage", &mount_config, &wl_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount FATFS (0x%x)", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_STORE_HISTORY
|
||||
|
||||
static void initialize_console(void)
|
||||
{
|
||||
/* Disable buffering on stdin and stdout */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Install UART driver for interrupt-driven reads and writes */
|
||||
ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM,
|
||||
256, 0, 0, NULL, 0) );
|
||||
|
||||
/* Tell VFS to use UART driver */
|
||||
esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
|
||||
/* Initialize the console */
|
||||
esp_console_config_t console_config = {
|
||||
.max_cmdline_args = 20,
|
||||
.max_cmdline_length = 256,
|
||||
#if CONFIG_LOG_COLORS
|
||||
.hint_color = atoi(LOG_COLOR_CYAN)
|
||||
#endif
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_init(&console_config) );
|
||||
|
||||
/* Configure linenoise line completion library */
|
||||
/* Enable multiline editing. If not set, long commands will scroll within
|
||||
* a single line.
|
||||
*/
|
||||
linenoiseSetMultiLine(1);
|
||||
|
||||
/* Tell linenoise where to get command completions and hints */
|
||||
linenoiseSetCompletionCallback(&esp_console_get_completion);
|
||||
linenoiseSetHintsCallback((linenoiseHintsCallback *) &esp_console_get_hint);
|
||||
|
||||
/* Set command history size */
|
||||
linenoiseHistorySetMaxLen(100);
|
||||
|
||||
#if CONFIG_STORE_HISTORY
|
||||
/* Load command history from filesystem */
|
||||
linenoiseHistoryLoad(HISTORY_PATH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s failed to initialize controller\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s failed to enable controller\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s failed to initialize bluetooth\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s failed to enable bluetooth\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t res;
|
||||
|
||||
nvs_flash_init();
|
||||
|
||||
// init and enable bluetooth
|
||||
res = bluetooth_init();
|
||||
if (res) {
|
||||
printf("esp32_bluetooth_init failed (ret %d)", res);
|
||||
}
|
||||
|
||||
#if CONFIG_STORE_HISTORY
|
||||
initialize_filesystem();
|
||||
#endif
|
||||
|
||||
initialize_console();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_system();
|
||||
register_bluetooth();
|
||||
ble_mesh_register_mesh_node();
|
||||
ble_mesh_register_mesh_test_performance_client();
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
ble_mesh_register_gen_onoff_client();
|
||||
#endif
|
||||
#if (CONFIG_BLE_MESH_PROVISIONER)
|
||||
ble_mesh_register_mesh_provisioner();
|
||||
#endif
|
||||
#if (CONFIG_BLE_MESH_CFG_CLI)
|
||||
ble_mesh_register_configuration_client_model();
|
||||
#endif
|
||||
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
const char *prompt = LOG_COLOR_I "esp32> " LOG_RESET_COLOR;
|
||||
|
||||
printf("\n"
|
||||
"This is an example of an ESP-IDF console component.\n"
|
||||
"Type 'help' to get the list of commands.\n"
|
||||
"Use UP/DOWN arrows to navigate through the command history.\n"
|
||||
"Press TAB when typing a command name to auto-complete.\n");
|
||||
|
||||
/* Figure out if the terminal supports escape sequences */
|
||||
int probe_status = linenoiseProbe();
|
||||
if (probe_status) { /* zero indicates OK */
|
||||
printf("\n"
|
||||
"Your terminal application does not support escape sequences.\n"
|
||||
"Line editing and history features are disabled.\n"
|
||||
"On Windows, try using Putty instead.\n");
|
||||
linenoiseSetDumbMode(1);
|
||||
#if CONFIG_LOG_COLORS
|
||||
/* Since the terminal doesn't support escape sequences,
|
||||
* don't use color codes in the prompt.
|
||||
*/
|
||||
prompt = "esp32> ";
|
||||
#endif //CONFIG_LOG_COLORS
|
||||
}
|
||||
|
||||
/* Main loop */
|
||||
while (true) {
|
||||
/* Get a line using linenoise.
|
||||
* The line is returned when ENTER is pressed.
|
||||
*/
|
||||
char *line = linenoise(prompt);
|
||||
if (line == NULL) { /* Ignore empty lines */
|
||||
continue;
|
||||
}
|
||||
/* Add the command to the history */
|
||||
linenoiseHistoryAdd(line);
|
||||
#if CONFIG_STORE_HISTORY
|
||||
/* Save command history to filesystem */
|
||||
linenoiseHistorySave(HISTORY_PATH);
|
||||
#endif
|
||||
|
||||
/* Try to run the command */
|
||||
int ret;
|
||||
esp_err_t err = esp_console_run(line, &ret);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
printf("Unrecognized command\n");
|
||||
} else if (err == ESP_ERR_INVALID_ARG) {
|
||||
// command was empty
|
||||
} else if (err == ESP_OK && ret != ESP_OK) {
|
||||
printf("\nCommand returned non-zero error code: 0x%x\n", ret);
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: 0x%x\n", err);
|
||||
}
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/* Console example — various system commands
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option).
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/rtc_io.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
#include "ble_mesh_console_decl.h"
|
||||
|
||||
#if CONFIG_IDF_CMAKE
|
||||
#define CONFIG_ESPTOOLPY_PORT "Which is choosen by Users for CMake"
|
||||
#endif
|
||||
|
||||
static void register_free(void);
|
||||
static void register_restart(void);
|
||||
static void register_make(void);
|
||||
|
||||
void register_system(void)
|
||||
{
|
||||
register_free();
|
||||
register_restart();
|
||||
register_make();
|
||||
}
|
||||
|
||||
/** 'restart' command restarts the program */
|
||||
|
||||
static int restart(int argc, char **argv)
|
||||
{
|
||||
printf("%s, %s", __func__, "Restarting");
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
static void register_restart(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "restart",
|
||||
.help = "Restart the program",
|
||||
.hint = NULL,
|
||||
.func = &restart,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
/** 'free' command prints available heap memory */
|
||||
|
||||
static int free_mem(int argc, char **argv)
|
||||
{
|
||||
printf("%d\n", esp_get_free_heap_size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_free(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "free",
|
||||
.help = "Get the total size of heap memory available",
|
||||
.hint = NULL,
|
||||
.func = &free_mem,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
static int make(int argc, char **argv)
|
||||
{
|
||||
int count = REG_READ(RTC_CNTL_STORE0_REG);
|
||||
if (++count >= 3) {
|
||||
printf("This is not the console you are looking for.\n");
|
||||
return 0;
|
||||
}
|
||||
REG_WRITE(RTC_CNTL_STORE0_REG, count);
|
||||
|
||||
const char *make_output =
|
||||
R"(LD build/console.elf
|
||||
esptool.py v2.1-beta1
|
||||
)";
|
||||
|
||||
const char* flash_output[] = {
|
||||
R"(Flashing binaries to serial port )" CONFIG_ESPTOOLPY_PORT R"( (app at offset 0x10000)...
|
||||
esptool.py v2.1-beta1
|
||||
Connecting....
|
||||
)",
|
||||
R"(Chip is ESP32D0WDQ6 (revision 0)
|
||||
Uploading stub...
|
||||
Running stub...
|
||||
Stub running...
|
||||
Changing baud rate to 921600
|
||||
Changed.
|
||||
Configuring flash size...
|
||||
Auto-detected Flash size: 4MB
|
||||
Flash params set to 0x0220
|
||||
Compressed 15712 bytes to 9345...
|
||||
)",
|
||||
R"(Wrote 15712 bytes (9345 compressed) at 0x00001000 in 0.1 seconds (effective 1126.9 kbit/s)...
|
||||
Hash of data verified.
|
||||
Compressed 333776 bytes to 197830...
|
||||
)",
|
||||
R"(Wrote 333776 bytes (197830 compressed) at 0x00010000 in 3.3 seconds (effective 810.3 kbit/s)...
|
||||
Hash of data verified.
|
||||
Compressed 3072 bytes to 82...
|
||||
)",
|
||||
R"(Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 1588.4 kbit/s)...
|
||||
Hash of data verified.
|
||||
Leaving...
|
||||
Hard resetting...
|
||||
)"
|
||||
};
|
||||
|
||||
const char* monitor_output =
|
||||
R"(MONITOR
|
||||
)" LOG_COLOR_W R"(--- idf_monitor on )" CONFIG_ESPTOOLPY_PORT R"( 115200 ---
|
||||
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --
|
||||
)" LOG_RESET_COLOR;
|
||||
|
||||
bool need_make = false;
|
||||
bool need_flash = false;
|
||||
bool need_monitor = false;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "all") == 0) {
|
||||
need_make = true;
|
||||
} else if (strcmp(argv[i], "flash") == 0) {
|
||||
need_make = true;
|
||||
need_flash = true;
|
||||
} else if (strcmp(argv[i], "monitor") == 0) {
|
||||
need_monitor = true;
|
||||
} else if (argv[i][0] == '-') {
|
||||
/* probably -j option */
|
||||
} else if (isdigit((int) argv[i][0])) {
|
||||
/* might be an argument to -j */
|
||||
} else {
|
||||
printf("make: *** No rule to make target `%s'. Stop.\n", argv[i]);
|
||||
/* Technically this is an error, but let's not spoil the output */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (argc == 1) {
|
||||
need_make = true;
|
||||
}
|
||||
if (need_make) {
|
||||
printf("%s", make_output);
|
||||
}
|
||||
if (need_flash) {
|
||||
size_t n_items = sizeof(flash_output) / sizeof(flash_output[0]);
|
||||
for (int i = 0; i < n_items; ++i) {
|
||||
printf("%s", flash_output[i]);
|
||||
vTaskDelay(200/portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
if (need_monitor) {
|
||||
printf("%s", monitor_output);
|
||||
esp_restart();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_make(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "make",
|
||||
.help = NULL, /* Do not include in 'help' output */
|
||||
.hint = "all | flash | monitor",
|
||||
.func = &make,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
// 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 "esp_ble_mesh_networking_api.h"
|
||||
#include "ble_mesh_adapter.h"
|
||||
|
||||
#if (CONFIG_BLE_MESH_CFG_CLI)
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_str *set_state;
|
||||
struct arg_int *opcode;
|
||||
struct arg_int *unicast_address;
|
||||
struct arg_int *appkey_index;
|
||||
struct arg_int *mod_id;
|
||||
struct arg_int *addr;
|
||||
struct arg_int *cid;
|
||||
struct arg_int *value;
|
||||
struct arg_int *relay_statue;
|
||||
struct arg_int *relay_transmit;
|
||||
struct arg_int *net_idx;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_client_get_set_state_t;
|
||||
ble_mesh_client_get_set_state_t configuration_client_model_operation;
|
||||
|
||||
void ble_mesh_register_configuration_client_model_command(void);
|
||||
void ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event,
|
||||
esp_ble_mesh_cfg_client_cb_param_t *param);
|
||||
|
||||
void ble_mesh_register_configuration_client_model(void)
|
||||
{
|
||||
ble_mesh_register_configuration_client_model_command();
|
||||
}
|
||||
|
||||
void ble_mesh_configuration_client_model_cb(esp_ble_mesh_cfg_client_cb_event_t event,
|
||||
esp_ble_mesh_cfg_client_cb_param_t *param)
|
||||
{
|
||||
uint32_t opcode;
|
||||
ESP_LOGD(TAG, "enter %s, event = %x\n, error_code = %x\n", __func__, event, param->error_code);
|
||||
|
||||
if (!param->error_code) {
|
||||
opcode = param->params->opcode;
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT:
|
||||
switch (opcode) {
|
||||
case ESP_BLE_MESH_MODEL_OP_BEACON_GET:
|
||||
ESP_LOGI(TAG, "CfgClient:beacon,0x%x", param->status_cb.beacon_status.beacon);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET:
|
||||
ESP_LOGI(TAG, "CfgClient:page,0x%x,len,0x%x", param->status_cb.comp_data_status.page, param->status_cb.comp_data_status.composition_data->len);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_GET:
|
||||
ESP_LOGI(TAG, "CfgClient:ttl,0x%x", param->status_cb.default_ttl_status.default_ttl);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_GET:
|
||||
ESP_LOGI(TAG, "CfgClient:proxy,0x%x", param->status_cb.gatt_proxy_status.gatt_proxy);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_RELAY_GET:
|
||||
ESP_LOGI(TAG, "CfgClient:relay,0x%x,retransmit,0x%x", param->status_cb.relay_status.relay, param->status_cb.relay_status.retransmit);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_GET:
|
||||
if (param->status_cb.model_pub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:PublishGet,OK,0x%x", param->status_cb.model_pub_status.publish_addr);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:PublishGet,Fail");
|
||||
}
|
||||
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_FRIEND_GET:
|
||||
ESP_LOGI(TAG, "CfgClient:friend,0x%x", param->status_cb.friend_status.friend_state);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_GET:
|
||||
if (param->status_cb.heartbeat_pub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatPubGet,OK,destination:0x%x,countlog:0x%x,periodlog:0x%x,ttl:0x%x,features:0x%x,net_idx:0x%x",
|
||||
param->status_cb.heartbeat_pub_status.dst, param->status_cb.heartbeat_pub_status.count, param->status_cb.heartbeat_pub_status.period,
|
||||
param->status_cb.heartbeat_pub_status.ttl, param->status_cb.heartbeat_pub_status.features, param->status_cb.heartbeat_pub_status.net_idx);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatGet,Fail,%d", param->status_cb.heartbeat_pub_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_GET:
|
||||
if (param->status_cb.heartbeat_sub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatSubGet,OK,source:0x%x,destination:0x%x, periodlog:0x%x,countlog:0x%x,minhops:0x%x,maxhops:0x%x",
|
||||
param->status_cb.heartbeat_sub_status.src, param->status_cb.heartbeat_sub_status.dst, param->status_cb.heartbeat_sub_status.period,
|
||||
param->status_cb.heartbeat_sub_status.count, param->status_cb.heartbeat_sub_status.min_hops, param->status_cb.heartbeat_sub_status.max_hops);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatSubGet,Fail,%d", param->status_cb.heartbeat_sub_status.status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Not supported config client get message opcode");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT:
|
||||
switch (opcode) {
|
||||
case ESP_BLE_MESH_MODEL_OP_BEACON_SET:
|
||||
ESP_LOGI(TAG, "CfgClient:beacon,0x%x", param->status_cb.beacon_status.beacon);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_DEFAULT_TTL_SET:
|
||||
ESP_LOGI(TAG, "CfgClient:ttl,0x%x", param->status_cb.default_ttl_status.default_ttl);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_GATT_PROXY_SET:
|
||||
ESP_LOGI(TAG, "CfgClient:proxy,0x%x", param->status_cb.gatt_proxy_status.gatt_proxy);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_RELAY_SET:
|
||||
ESP_LOGI(TAG, "CfgClient:relay,0x%x, retransmit: 0x%x", param->status_cb.relay_status.relay, param->status_cb.relay_status.retransmit);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_PUB_SET:
|
||||
if (param->status_cb.model_pub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:PublishSet,OK,0x%x", param->status_cb.model_pub_status.publish_addr);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:PublishSet,Fail");
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD:
|
||||
if (param->status_cb.model_sub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CnfClient:SubAdd,OK,%x,%x", param->status_cb.model_sub_status.element_addr, param->status_cb.model_sub_status.sub_addr);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CnfClient:SubAdd,Fail,%x", param->status_cb.model_sub_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_DELETE:
|
||||
if (param->status_cb.model_sub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CnfClient:SubDel,OK,%x,%x", param->status_cb.model_sub_status.element_addr, param->status_cb.model_sub_status.sub_addr);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CnfClient:SubDel,Fail,%x", param->status_cb.model_sub_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_OVERWRITE:
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_ADD:
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_DELETE:
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_VIRTUAL_ADDR_OVERWRITE:
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_NET_KEY_ADD:
|
||||
if (param->status_cb.netkey_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:NetKeyAdd,OK");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:NetKeyAdd,Fail,%d", param->status_cb.netkey_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
||||
if (param->status_cb.appkey_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CnfClient:AddAppkey,OK,%x,%x,%x", param->status_cb.appkey_status.net_idx, param->status_cb.appkey_status.app_idx, param->params->ctx.addr);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CnfClient:AddAppkey,Fail,%x", param->status_cb.appkey_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
|
||||
if (param->status_cb.model_app_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CnfClient:AppkeyBind,OK,%x,%x,%x", param->status_cb.model_app_status.app_idx, param->status_cb.model_app_status.model_id, param->params->ctx.addr);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CnfClient:AppkeyBind,Fail,%x", param->status_cb.model_app_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_FRIEND_SET:
|
||||
ESP_LOGI(TAG, "CfgClient:friend: 0x%x", param->status_cb.friend_status.friend_state);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_PUB_SET:
|
||||
if (param->status_cb.heartbeat_pub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatPubSet,OK,destination:0x%x,countlog:0x%x, periodlog:0x%x,ttl:0x%x,features:0x%x,net_idx: 0x%x",
|
||||
param->status_cb.heartbeat_pub_status.dst, param->status_cb.heartbeat_pub_status.count, param->status_cb.heartbeat_pub_status.period,
|
||||
param->status_cb.heartbeat_pub_status.ttl, param->status_cb.heartbeat_pub_status.features, param->status_cb.heartbeat_pub_status.net_idx);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatSet,Fail,%d", param->status_cb.heartbeat_pub_status.status);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_HEARTBEAT_SUB_SET:
|
||||
if (param->status_cb.heartbeat_sub_status.status == ESP_OK) {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatSubSet,OK,source:0x%x,destination:0x%x, periodlog:0x%x,countlog:0x%x,minhops:0x%x,maxhops:0x%x",
|
||||
param->status_cb.heartbeat_sub_status.src, param->status_cb.heartbeat_sub_status.dst, param->status_cb.heartbeat_sub_status.period,
|
||||
param->status_cb.heartbeat_sub_status.count, param->status_cb.heartbeat_sub_status.min_hops, param->status_cb.heartbeat_sub_status.max_hops);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CfgClient:HeartBeatSubSet,Fail,%d", param->status_cb.heartbeat_sub_status.status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "Not supported config client set message opcode");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT:
|
||||
ESP_LOGI(TAG, "CnfClient:Publish,OK");
|
||||
break;
|
||||
case ESP_BLE_MESH_CFG_CLIENT_EVT_MAX:
|
||||
ESP_LOGI(TAG, "CnfClient:MaxEvt");
|
||||
break;
|
||||
case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT:
|
||||
ESP_LOGI(TAG, "CfgClient:TimeOut");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGI(TAG, "CfgClient:InvalidEvent");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGI(TAG, "CnfClient:Fail,%d", param->error_code);
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s \n", __func__);
|
||||
}
|
||||
|
||||
int ble_mesh_configuration_client_model_operation(int argc, char **argv)
|
||||
{
|
||||
int err = ESP_OK;
|
||||
const uint8_t *app_key = NULL;
|
||||
esp_ble_mesh_cfg_default_ttl_set_t ttl_set;
|
||||
esp_ble_mesh_cfg_gatt_proxy_set_t proxy_set;
|
||||
esp_ble_mesh_cfg_app_key_add_t app_key_add;
|
||||
esp_ble_mesh_cfg_model_pub_set_t mod_pub_set = {
|
||||
.company_id = 0xFFFF,
|
||||
.cred_flag = false,
|
||||
.publish_period = 0,
|
||||
.publish_retransmit = 0,
|
||||
};
|
||||
esp_ble_mesh_cfg_model_sub_add_t mod_sub_add = {
|
||||
.company_id = 0xFFFF,
|
||||
};
|
||||
esp_ble_mesh_cfg_model_sub_delete_t mod_sub_del = {
|
||||
.company_id = 0xFFFF,
|
||||
};
|
||||
esp_ble_mesh_cfg_relay_set_t relay_set;
|
||||
esp_ble_mesh_client_common_param_t client_common = {
|
||||
.msg_role = ROLE_PROVISIONER,
|
||||
.msg_timeout = 0,
|
||||
.ctx.send_ttl = 7,
|
||||
};
|
||||
esp_ble_mesh_cfg_client_get_state_t get_state = {
|
||||
.comp_data_get.page = 0,
|
||||
.model_pub_get.company_id = 0xFFFF,
|
||||
};
|
||||
esp_ble_mesh_cfg_model_app_bind_t mod_app_bind = {
|
||||
.company_id = 0xFFFF,
|
||||
};
|
||||
|
||||
client_common.model = ble_mesh_get_model(ESP_BLE_MESH_MODEL_ID_CONFIG_CLI);
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &configuration_client_model_operation);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, configuration_client_model_operation.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.opcode->count != 0) {
|
||||
client_common.opcode = configuration_client_model_operation.opcode->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.net_idx->count != 0) {
|
||||
client_common.ctx.net_idx = configuration_client_model_operation.net_idx->ival[0];
|
||||
app_key_add.net_idx = configuration_client_model_operation.net_idx->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.unicast_address->count != 0) {
|
||||
client_common.ctx.addr = configuration_client_model_operation.unicast_address->ival[0];
|
||||
get_state.model_pub_get.element_addr = configuration_client_model_operation.unicast_address->ival[0];
|
||||
mod_app_bind.element_addr = configuration_client_model_operation.unicast_address->ival[0];
|
||||
mod_sub_add.element_addr = configuration_client_model_operation.unicast_address->ival[0];
|
||||
mod_sub_del.element_addr = configuration_client_model_operation.unicast_address->ival[0];
|
||||
mod_pub_set.element_addr = configuration_client_model_operation.unicast_address->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.appkey_index->count != 0) {
|
||||
client_common.ctx.app_idx = configuration_client_model_operation.appkey_index->ival[0];
|
||||
mod_app_bind.model_app_idx = configuration_client_model_operation.appkey_index->ival[0];
|
||||
app_key_add.app_idx = configuration_client_model_operation.appkey_index->ival[0];
|
||||
mod_pub_set.publish_app_idx = configuration_client_model_operation.appkey_index->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.value->count != 0) {
|
||||
ttl_set.ttl = configuration_client_model_operation.value->ival[0];
|
||||
proxy_set.gatt_proxy = configuration_client_model_operation.value->ival[0];
|
||||
mod_pub_set.publish_ttl = configuration_client_model_operation.value->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.addr->count != 0) {
|
||||
mod_sub_del.sub_addr = configuration_client_model_operation.addr->ival[0];
|
||||
mod_sub_add.sub_addr = configuration_client_model_operation.addr->ival[0];
|
||||
mod_pub_set.publish_addr = configuration_client_model_operation.addr->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.mod_id->count != 0) {
|
||||
mod_app_bind.model_id = configuration_client_model_operation.mod_id->ival[0];
|
||||
mod_sub_add.model_id = configuration_client_model_operation.mod_id->ival[0];
|
||||
mod_sub_del.model_id = configuration_client_model_operation.mod_id->ival[0];
|
||||
get_state.model_pub_get.model_id = configuration_client_model_operation.mod_id->ival[0];;
|
||||
mod_pub_set.model_id = configuration_client_model_operation.mod_id->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.relay_statue->count != 0) {
|
||||
relay_set.relay = configuration_client_model_operation.relay_statue->ival[0];
|
||||
mod_pub_set.publish_period = configuration_client_model_operation.relay_statue->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.relay_transmit->count != 0) {
|
||||
relay_set.relay_retransmit = configuration_client_model_operation.relay_transmit->ival[0];
|
||||
mod_pub_set.publish_retransmit = configuration_client_model_operation.relay_transmit->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.cid->count != 0) {
|
||||
mod_app_bind.company_id = configuration_client_model_operation.cid->ival[0];
|
||||
mod_sub_del.company_id = configuration_client_model_operation.cid->ival[0];
|
||||
mod_sub_add.company_id = configuration_client_model_operation.cid->ival[0];
|
||||
mod_pub_set.company_id = configuration_client_model_operation.cid->ival[0];
|
||||
}
|
||||
|
||||
if (configuration_client_model_operation.action_type->count != 0) {
|
||||
if (strcmp(configuration_client_model_operation.action_type->sval[0], "get") == 0) {
|
||||
err = esp_ble_mesh_config_client_get_state(&client_common, &get_state);
|
||||
} else if (strcmp(configuration_client_model_operation.action_type->sval[0], "set") == 0) {
|
||||
if (configuration_client_model_operation.set_state->count != 0) {
|
||||
if (strcmp(configuration_client_model_operation.set_state->sval[0], "appkey") == 0) {
|
||||
app_key = esp_ble_mesh_provisioner_get_local_app_key(app_key_add.net_idx, app_key_add.app_idx);
|
||||
if (app_key == NULL) {
|
||||
ESP_LOGE(TAG, "CnfClient:AddAppkey,Fail,app key or network key NULL");
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
memcpy(app_key_add.app_key, app_key, 16);
|
||||
}
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&app_key_add);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "appbind") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_app_bind);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "ttl") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&ttl_set);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "proxy") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&proxy_set);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "subadd") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_sub_add);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "subdel") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_sub_del);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "relay") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&relay_set);
|
||||
} else if (strcmp(configuration_client_model_operation.set_state->sval[0], "pubset") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, (esp_ble_mesh_cfg_client_set_state_t *)&mod_pub_set);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(configuration_client_model_operation.action_type->sval[0], "reg") == 0) {
|
||||
err = esp_ble_mesh_register_config_client_callback(ble_mesh_configuration_client_model_cb);
|
||||
}
|
||||
}
|
||||
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "ConfigClient:OK");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "ConfigClient:Fail");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s %d\n", __func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void ble_mesh_register_configuration_client_model_command(void)
|
||||
{
|
||||
configuration_client_model_operation.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
configuration_client_model_operation.set_state = arg_str0("x", NULL, "<state>", "set state");
|
||||
configuration_client_model_operation.opcode = arg_int0("o", NULL, "<opcode>", "message opcode");
|
||||
configuration_client_model_operation.unicast_address = arg_int0("u", NULL, "<address>", "unicast address");
|
||||
configuration_client_model_operation.net_idx = arg_int0("n", NULL, "<network>", "net work index");
|
||||
configuration_client_model_operation.appkey_index = arg_int0("i", NULL, "<index>", "appkey index");
|
||||
configuration_client_model_operation.relay_statue = arg_int0("r", NULL, "<relay>", "relay statue");
|
||||
configuration_client_model_operation.relay_transmit = arg_int0("t", NULL, "<transmit>", "relay transmit");
|
||||
configuration_client_model_operation.cid = arg_int0("c", NULL, "<cid>", "company id");
|
||||
configuration_client_model_operation.value = arg_int0("v", NULL, "<value>", "value");
|
||||
configuration_client_model_operation.addr = arg_int0("a", NULL, "<address>", "address");
|
||||
configuration_client_model_operation.mod_id = arg_int0("m", NULL, "<mod id>", "model id");
|
||||
configuration_client_model_operation.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t client_stconfiguration_client_model_operationate_cmd = {
|
||||
.command = "bmccm",
|
||||
.help = "ble mesh configuration client model",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_configuration_client_model_operation,
|
||||
.argtable = &configuration_client_model_operation,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&client_stconfiguration_client_model_operationate_cmd));
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
// 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 "esp_timer.h"
|
||||
#include "ble_mesh_adapter.h"
|
||||
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *op_en;
|
||||
struct arg_int *unicast_address;
|
||||
struct arg_int *onoff_state;
|
||||
struct arg_int *trans_id;
|
||||
struct arg_int *trans_time;
|
||||
struct arg_int *delay;
|
||||
struct arg_int *opcode;
|
||||
struct arg_int *appkey_idx;
|
||||
struct arg_int *role;
|
||||
struct arg_int *net_idx;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_gen_onoff_state_t;
|
||||
ble_mesh_gen_onoff_state_t gen_onoff_state;
|
||||
|
||||
void ble_mesh_register_gen_onoff_client_command(void);
|
||||
void ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event,
|
||||
esp_ble_mesh_generic_client_cb_param_t *param);
|
||||
|
||||
void ble_mesh_register_gen_onoff_client(void)
|
||||
{
|
||||
ble_mesh_register_gen_onoff_client_command();
|
||||
}
|
||||
|
||||
void ble_mesh_generic_onoff_client_model_cb(esp_ble_mesh_generic_client_cb_event_t event,
|
||||
esp_ble_mesh_generic_client_cb_param_t *param)
|
||||
{
|
||||
uint32_t opcode = param->params->opcode;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s: event is %d, error code is %d, opcode is 0x%x\n",
|
||||
__func__, event, param->error_code, opcode);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT: {
|
||||
switch (opcode) {
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
|
||||
if (param->error_code == ESP_OK) {
|
||||
ESP_LOGI(TAG, "GenOnOffClient:GetStatus,OK,%d", param->status_cb.onoff_status.present_onoff);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "GenOnOffClient:GetStatus,Fail,%d", param->error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT: {
|
||||
switch (opcode) {
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
|
||||
if (param->error_code == ESP_OK) {
|
||||
ESP_LOGI(TAG, "GenOnOffClient:SetStatus,OK,%d", param->status_cb.onoff_status.present_onoff);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "GenOnOffClient:SetStatus,Fail,%d", param->error_code);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK:
|
||||
if (param->error_code == ESP_OK) {
|
||||
ESP_LOGI(TAG, "GenOnOffClient:SetUNACK,OK");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "GenOnOffClient:SetUNACK,Fail,%d", param->error_code);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT: {
|
||||
if (param->error_code == ESP_OK) {
|
||||
ESP_LOGI(TAG, "GenOnOffClient:Publish,OK");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "GenOnOffClient:Publish,Fail,%d", param->error_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT:
|
||||
ESP_LOGE(TAG, "GenOnOffClient:TimeOut,%d", param->error_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_EVT_MAX:
|
||||
ESP_LOGE(TAG, "GenONOFFClient:InvalidEvt,%d", param->error_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s \n", __func__);
|
||||
}
|
||||
|
||||
int ble_mesh_generic_onoff_client_model(int argc, char **argv)
|
||||
{
|
||||
int err = ESP_OK;
|
||||
esp_ble_mesh_generic_client_set_state_t gen_client_set;
|
||||
esp_ble_mesh_generic_client_get_state_t gen_client_get;
|
||||
esp_ble_mesh_client_common_param_t onoff_common = {
|
||||
.msg_timeout = 0,
|
||||
.ctx.send_ttl = 7,
|
||||
};
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &gen_onoff_state);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, gen_onoff_state.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
onoff_common.model = ble_mesh_get_model(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI);
|
||||
|
||||
arg_int_to_value(gen_onoff_state.appkey_idx, onoff_common.ctx.app_idx, "appkey_index");
|
||||
arg_int_to_value(gen_onoff_state.opcode, onoff_common.opcode, "opcode");
|
||||
arg_int_to_value(gen_onoff_state.role, onoff_common.msg_role, "role");
|
||||
arg_int_to_value(gen_onoff_state.unicast_address, onoff_common.ctx.addr, "address");
|
||||
arg_int_to_value(gen_onoff_state.net_idx, onoff_common.ctx.net_idx, "network key index");
|
||||
arg_int_to_value(gen_onoff_state.op_en, gen_client_set.onoff_set.op_en, "op_en");
|
||||
arg_int_to_value(gen_onoff_state.onoff_state, gen_client_set.onoff_set.onoff, "onoff");
|
||||
arg_int_to_value(gen_onoff_state.trans_id, gen_client_set.onoff_set.tid, "tid");
|
||||
arg_int_to_value(gen_onoff_state.trans_time, gen_client_set.onoff_set.trans_time, "trans_time");
|
||||
arg_int_to_value(gen_onoff_state.delay, gen_client_set.onoff_set.delay, "delay");
|
||||
|
||||
if (gen_onoff_state.action_type->count != 0) {
|
||||
if (strcmp(gen_onoff_state.action_type->sval[0], "get") == 0) {
|
||||
err = esp_ble_mesh_generic_client_get_state(&onoff_common, &gen_client_get);
|
||||
} else if (strcmp(gen_onoff_state.action_type->sval[0], "set") == 0) {
|
||||
err = esp_ble_mesh_generic_client_set_state(&onoff_common, &gen_client_set);
|
||||
} else if (strcmp(gen_onoff_state.action_type->sval[0], "reg") == 0) {
|
||||
err = esp_ble_mesh_register_generic_client_callback(ble_mesh_generic_onoff_client_model_cb);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "GenONOFFClient:Reg,OK");
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ble_mesh_register_gen_onoff_client_command(void)
|
||||
{
|
||||
gen_onoff_state.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
gen_onoff_state.opcode = arg_int0("o", NULL, "<opcode>", "message opcode");
|
||||
gen_onoff_state.appkey_idx = arg_int0("a", NULL, "<appkey>", "appkey index");
|
||||
gen_onoff_state.role = arg_int0("r", NULL, "<role>", "role");
|
||||
gen_onoff_state.unicast_address = arg_int0("u", NULL, "<address>", "unicast address");
|
||||
gen_onoff_state.net_idx = arg_int0("n", NULL, "<netkey index>", "network key index");
|
||||
gen_onoff_state.op_en = arg_int0("e", NULL, "<optional>", "whether optional parameters included");
|
||||
gen_onoff_state.onoff_state = arg_int0("s", NULL, "<state>", "present onoff state");
|
||||
gen_onoff_state.trans_id = arg_int0("i", NULL, "<identifier>", "transaction identifier");
|
||||
gen_onoff_state.trans_time = arg_int0("t", NULL, "<time>", "time to complete state transition");
|
||||
gen_onoff_state.delay = arg_int0("d", NULL, "<delay>", "indicate message execution delay");
|
||||
gen_onoff_state.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t gen_onoff_state_cmd = {
|
||||
.command = "bmgocm",
|
||||
.help = "ble mesh generic onoff client model",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_generic_onoff_client_model,
|
||||
.argtable = &gen_onoff_state,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&gen_onoff_state_cmd));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,219 @@
|
||||
// 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
#include "ble_mesh_adapter.h"
|
||||
|
||||
SemaphoreHandle_t ble_mesh_test_perf_send_sema;
|
||||
SemaphoreHandle_t ble_mesh_test_perf_sema;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *playload_byte;
|
||||
struct arg_int *test_num;
|
||||
struct arg_int *opcode;
|
||||
struct arg_int *unicast_address;
|
||||
struct arg_int *ttl;
|
||||
struct arg_int *app_idx;
|
||||
struct arg_int *net_idx;
|
||||
struct arg_int *dev_role;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_test_perf_client_model_t;
|
||||
ble_mesh_test_perf_client_model_t test_perf_client_model;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *test_size;
|
||||
struct arg_int *node_num;
|
||||
struct arg_int *ttl;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_test_perf_client_model_statistics_t;
|
||||
ble_mesh_test_perf_client_model_statistics_t test_perf_client_model_statistics;
|
||||
|
||||
void ble_mesh_performance_client_model_command(void);
|
||||
|
||||
void ble_mesh_register_mesh_test_performance_client(void)
|
||||
{
|
||||
ble_mesh_performance_client_model_command();
|
||||
}
|
||||
|
||||
void ble_mesh_test_performance_client_model_throughput(void *params)
|
||||
{
|
||||
uint16_t i;
|
||||
uint8_t *data = NULL;
|
||||
esp_ble_mesh_msg_ctx_t ctx;
|
||||
ble_mesh_test_perf_throughput_data *profile_context = (ble_mesh_test_perf_throughput_data *)params;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
|
||||
ctx.net_idx = profile_context->net_idx;
|
||||
ctx.app_idx = profile_context->app_idx;
|
||||
ctx.addr = profile_context->address;
|
||||
ctx.send_ttl = profile_context->ttl;
|
||||
ctx.model = profile_context->model;
|
||||
ctx.send_rel = 0;
|
||||
test_perf_statistics.test_length = profile_context->length;
|
||||
|
||||
// create send data
|
||||
data = malloc(profile_context->length);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, " %s, %d, malloc fail\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
ble_mesh_test_perf_send_sema = xSemaphoreCreateMutex();
|
||||
xSemaphoreTake(ble_mesh_test_perf_send_sema, SEND_MESSAGE_TIMEOUT);
|
||||
|
||||
for (i = 1; i <= profile_context->test_num; i++) {
|
||||
ble_mesh_create_send_data((char *)data, profile_context->length, i, profile_context->opcode);
|
||||
start_time = esp_timer_get_time();
|
||||
esp_ble_mesh_client_model_send_msg(profile_context->model, &ctx, profile_context->opcode,
|
||||
profile_context->length, data, 8000, profile_context->need_ack, profile_context->device_role);
|
||||
ble_mesh_test_performance_client_model_accumulate_statistics(profile_context->length);
|
||||
xSemaphoreTake(ble_mesh_test_perf_send_sema, SEND_MESSAGE_TIMEOUT);
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "VendorModel:SendPackage,Finish");
|
||||
free(params);
|
||||
vTaskDelete(NULL);
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
}
|
||||
|
||||
int ble_mesh_test_performance_client_model(int argc, char **argv)
|
||||
{
|
||||
esp_ble_mesh_model_t *model;
|
||||
esp_err_t result = ESP_OK;
|
||||
ble_mesh_test_perf_throughput_data *profile_data = NULL;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
int nerrors = arg_parse(argc, argv, (void **) &test_perf_client_model);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, test_perf_client_model.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
model = ble_mesh_get_model(ESP_BLE_MESH_VND_MODEL_ID_TEST_PERF_CLI);
|
||||
|
||||
if (strcmp(test_perf_client_model.action_type->sval[0], "init") == 0) {
|
||||
ble_mesh_test_perf_sema = xSemaphoreCreateMutex();
|
||||
result = esp_ble_mesh_client_model_init(model);
|
||||
if (result == ESP_OK) {
|
||||
ESP_LOGI(TAG, "VendorClientModel:Init,OK");
|
||||
}
|
||||
} else if (strcmp(test_perf_client_model.action_type->sval[0], "start") == 0) {
|
||||
profile_data = malloc(sizeof(ble_mesh_test_perf_throughput_data));
|
||||
profile_data->model = model;
|
||||
if (profile_data == NULL) {
|
||||
ESP_LOGE(TAG, " %s, %d malloc fail\n", __func__, __LINE__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_int_to_value(test_perf_client_model.playload_byte, profile_data->length, "length");
|
||||
arg_int_to_value(test_perf_client_model.opcode, profile_data->opcode, "opcode");
|
||||
arg_int_to_value(test_perf_client_model.unicast_address, profile_data->address, "publish address");
|
||||
arg_int_to_value(test_perf_client_model.ttl, profile_data->ttl, "model ttl");
|
||||
arg_int_to_value(test_perf_client_model.app_idx, profile_data->app_idx, "appkey index");
|
||||
arg_int_to_value(test_perf_client_model.net_idx, profile_data->net_idx, "network key index");
|
||||
arg_int_to_value(test_perf_client_model.dev_role, profile_data->device_role, "device role");
|
||||
arg_int_to_value(test_perf_client_model.test_num, profile_data->test_num, "test number");
|
||||
|
||||
if (profile_data->opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET) {
|
||||
profile_data->need_ack = true;
|
||||
} else {
|
||||
profile_data->need_ack = false;
|
||||
}
|
||||
|
||||
xTaskCreate(ble_mesh_test_performance_client_model_throughput, "MESHTHROUGHPUTSEND", 4048, profile_data, 1, NULL);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ble_mesh_test_performance_client_model_performance(int argc, char **argv)
|
||||
{
|
||||
uint8_t result = 0;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
int nerrors = arg_parse(argc, argv, (void **) &test_perf_client_model_statistics);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, test_perf_client_model_statistics.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(test_perf_client_model_statistics.action_type->sval[0], "init") == 0) {
|
||||
result = ble_mesh_test_performance_client_model_init(test_perf_client_model_statistics.node_num->ival[0],
|
||||
test_perf_client_model_statistics.test_size->ival[0], test_perf_client_model_statistics.ttl->ival[0]);
|
||||
if (result == 0) {
|
||||
ESP_LOGI(TAG, "VendorPerfTest:InitStatistics,OK\n");
|
||||
}
|
||||
} else if (strcmp(test_perf_client_model_statistics.action_type->sval[0], "get") == 0) {
|
||||
ble_mesh_test_performance_client_model_get();
|
||||
} else if (strcmp(test_perf_client_model_statistics.action_type->sval[0], "destroy") == 0) {
|
||||
ble_mesh_test_performance_client_model_destroy();
|
||||
ESP_LOGI(TAG, "VendorPerfTest:DestroyStatistics,OK\n");
|
||||
} else if (strcmp(test_perf_client_model_statistics.action_type->sval[0], "percent") == 0) {
|
||||
ble_mesh_test_performance_client_model_get_received_percent();
|
||||
ESP_LOGI(TAG, "VendorPerfTest:GetPercent,OK\n");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_mesh_performance_client_model_command(void)
|
||||
{
|
||||
test_perf_client_model.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
test_perf_client_model.playload_byte = arg_int0("p", NULL, "<byte>", "playload byte");
|
||||
test_perf_client_model.test_num = arg_int0("n", NULL, "<number>", "test number");
|
||||
// set test num default to 1000
|
||||
test_perf_client_model.test_num->ival[0] = 1000;
|
||||
test_perf_client_model.opcode = arg_int0("o", NULL, "<opcode>", "opcode");
|
||||
test_perf_client_model.unicast_address = arg_int0("u", NULL, "<address>", "unicast address");
|
||||
test_perf_client_model.ttl = arg_int0("t", NULL, "<ttl>", "ttl");
|
||||
test_perf_client_model.app_idx = arg_int0("a", NULL, "<appkey>", "appkey index");
|
||||
test_perf_client_model.net_idx = arg_int0("i", NULL, "<network key>", "network key index");
|
||||
test_perf_client_model.dev_role = arg_int0("d", NULL, "<role>", "device role");
|
||||
test_perf_client_model.dev_role->ival[0] = ROLE_PROVISIONER;
|
||||
test_perf_client_model.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t test_perf_client_model_cmd = {
|
||||
.command = "bmtpcvm",
|
||||
.help = "ble mesh test performance client vendor model",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_test_performance_client_model,
|
||||
.argtable = &test_perf_client_model,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&test_perf_client_model_cmd));
|
||||
|
||||
test_perf_client_model_statistics.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
test_perf_client_model_statistics.test_size = arg_int0("s", NULL, "<test size>", "test size");
|
||||
test_perf_client_model_statistics.node_num = arg_int0("n", NULL, "<node number>", "node number");
|
||||
test_perf_client_model_statistics.ttl = arg_int0("l", NULL, "<test number>", "ttl");
|
||||
test_perf_client_model_statistics.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t test_perf_client_model_performance_cmd = {
|
||||
.command = "bmcperf",
|
||||
.help = "ble mesh client: test performance",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_test_performance_client_model_performance,
|
||||
.argtable = &test_perf_client_model_statistics,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&test_perf_client_model_performance_cmd));
|
||||
}
|
||||
@@ -0,0 +1,476 @@
|
||||
// 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 "soc/soc.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_device.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 "ble_mesh_adapter.h"
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *static_val;
|
||||
struct arg_int *static_val_len;
|
||||
struct arg_int *output_size;
|
||||
struct arg_int *output_actions;
|
||||
struct arg_int *input_size;
|
||||
struct arg_int *input_actions;
|
||||
struct arg_int *prov_start_address;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_prov_t;
|
||||
static ble_mesh_prov_t oob;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *model_type;
|
||||
struct arg_int *config_index;
|
||||
struct arg_int *pub_config;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_comp_t;
|
||||
static ble_mesh_comp_t component;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *bearer;
|
||||
struct arg_int *enable;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_bearer_t;
|
||||
static ble_mesh_bearer_t bearer;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *tx_sense_power;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_tx_sense_power;
|
||||
static ble_mesh_tx_sense_power power_set;
|
||||
|
||||
ble_mesh_node_status node_status = {
|
||||
.previous = 0x0,
|
||||
.current = 0x0,
|
||||
};
|
||||
|
||||
SemaphoreHandle_t ble_mesh_node_sema;
|
||||
|
||||
void ble_mesh_register_node_cmd(void);
|
||||
// Register callback function
|
||||
void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param);
|
||||
void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param);
|
||||
|
||||
|
||||
void ble_mesh_register_mesh_node(void)
|
||||
{
|
||||
ble_mesh_register_node_cmd();
|
||||
}
|
||||
|
||||
int ble_mesh_register_node_cb(int argc, char** argv)
|
||||
{
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
ble_mesh_node_init();
|
||||
esp_ble_mesh_register_prov_callback(ble_mesh_prov_cb);
|
||||
esp_ble_mesh_register_custom_model_callback(ble_mesh_model_cb);
|
||||
ESP_LOGI(TAG, "Node:Reg,OK");
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event, esp_ble_mesh_prov_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGD(TAG, "enter %s, event = %d", __func__, event);
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->prov_register_comp.err_code, "Provisioning:Register");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_enable_comp.err_code, "Node:EnBearer");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_DISABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_disable_comp.err_code, "Node:DisBearer");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "Node:LinkOpen,OK,%d", param->node_prov_link_open.bearer);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "Node:LinkClose,OK,%d", param->node_prov_link_close.bearer);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT:
|
||||
ESP_LOGI(TAG, "Node:OutPut,%d,%d", param->node_prov_output_num.action, param->node_prov_output_num.number);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT:
|
||||
ESP_LOGI(TAG, "Node:OutPutStr,%s", param->node_prov_output_str.string);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_INPUT_EVT:
|
||||
ESP_LOGI(TAG, "Node:InPut,%d,%d", param->node_prov_input.action, param->node_prov_input.size);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "Node:OK,%d,%d", param->node_prov_complete.net_idx, param->node_prov_complete.addr);
|
||||
ble_mesh_set_node_prestore_params(param->node_prov_complete.net_idx, param->node_prov_complete.addr);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
||||
ESP_LOGI(TAG, "Node:Reset");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_INPUT_NUMBER_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_input_num_comp.err_code, "Node:InputNum");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_INPUT_STRING_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_prov_input_str_comp.err_code, "Node:InputStr");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_set_unprov_dev_name_comp.err_code, "Node:SetName");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_IDENTITY_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_proxy_identity_enable_comp.err_code, "Node:ProxyIndentity");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_GATT_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_proxy_gatt_enable_comp.err_code, "Node:EnProxyGatt");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->node_proxy_gatt_disable_comp.err_code, "Node:DisProxyGatt");
|
||||
break;
|
||||
#if (CONFIG_BLE_MESH_PROVISIONER)
|
||||
case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT:
|
||||
ESP_LOGI(TAG, "Provisioner recv unprovisioned device beacon:");
|
||||
ESP_LOG_BUFFER_HEX("Device UUID %s", param->provisioner_recv_unprov_adv_pkt.dev_uuid, 16);
|
||||
ESP_LOG_BUFFER_HEX("Address %s", param->provisioner_recv_unprov_adv_pkt.addr, 6);
|
||||
ESP_LOGI(TAG, "Address type 0x%x, oob_info 0x%04x, adv_type 0x%x, bearer 0x%x",
|
||||
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, "Provisioner:LinkOpen,OK,%d", param->provisioner_prov_link_open.bearer);
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "Provisioner:LinkClose,OK,%d,%d",
|
||||
param->provisioner_prov_link_close.bearer, param->provisioner_prov_link_close.reason);
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_add_unprov_dev_comp.err_code, "Provisioner:DevAdd");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_DELETE_DEV_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_delete_dev_comp.err_code, "Provisioner:DevDel");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "Provisioner:OK,%d,%d", param->provisioner_prov_complete.netkey_idx, param->provisioner_prov_complete.unicast_addr);
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_prov_enable_comp.err_code, "Provisioner:EnBearer");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_prov_disable_comp.err_code, "Provisioner:DisBearer");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_set_dev_uuid_match_comp.err_code, "Provisioner:UuidMatch");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_SET_PROV_DATA_INFO_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_set_prov_data_info_comp.err_code, "Provisioner:DataInfo");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_set_node_name_comp.err_code, "Provisioner:NodeName");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_add_app_key_comp.err_code, "Provisioner:AppKeyAdd");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_bind_app_key_to_model_comp.err_code, "Provisioner:AppKeyBind");
|
||||
break;
|
||||
case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_NET_KEY_COMP_EVT:
|
||||
ble_mesh_callback_check_err_code(param->provisioner_add_net_key_comp.err_code, "Provisioner:NetKeyAdd");
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
}
|
||||
|
||||
void ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event, esp_ble_mesh_model_cb_param_t *param)
|
||||
{
|
||||
esp_err_t result = ESP_OK;
|
||||
uint8_t status;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s, event=%x\n", __func__, event);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_MODEL_OPERATION_EVT:
|
||||
if (param->model_operation.model != NULL && param->model_operation.model->op != NULL) {
|
||||
if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) {
|
||||
ESP_LOGI(TAG, "Node:GetStatus,OK");
|
||||
ble_mesh_node_get_state(status);
|
||||
result = esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(status), &status);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
ble_mesh_node_set_state(param->model_operation.msg[0]);
|
||||
ESP_LOGI(TAG, "Node:SetAck,OK,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl);
|
||||
result = esp_ble_mesh_server_model_send_msg(param->model_operation.model, param->model_operation.ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(status), param->model_operation.msg);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ble_mesh_node_set_state(param->model_operation.msg[0]);
|
||||
ESP_LOGI(TAG, "Node:SetUnAck,OK,%d,%d", param->model_operation.msg[0], param->model_operation.ctx->recv_ttl);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS) {
|
||||
ESP_LOGI(TAG, "Node:Status,Success,%d", param->model_operation.length);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_SET) {
|
||||
ESP_LOGI(TAG, "VendorModel:SetAck,OK,%d", param->model_operation.ctx->recv_ttl);
|
||||
} else if (param->model_operation.opcode == ESP_BLE_MESH_VND_MODEL_OP_TEST_PERF_STATUS) {
|
||||
uint64_t current_time = esp_timer_get_time();
|
||||
result = ble_mesh_test_performance_client_model_accumulate_time(((uint32_t)(current_time - start_time) / 1000), param->model_operation.msg, param->model_operation.ctx->recv_ttl, param->model_operation.length);
|
||||
ESP_LOGI(TAG, "VendorModel:Status,OK,%d", param->model_operation.ctx->recv_ttl);
|
||||
if (ble_mesh_test_perf_send_sema != NULL && result == ESP_OK) {
|
||||
xSemaphoreGive(ble_mesh_test_perf_send_sema);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
|
||||
if (param->model_send_comp.err_code == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Node:ModelSend,OK");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Node:ModelSend,Fail,%d,0x%X,0x%04X", param->model_send_comp.err_code, param->model_send_comp.model->model_id, param->model_send_comp.model->op->opcode);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
|
||||
ESP_LOGI(TAG, "Node:PublishSend,OK,0x%X,%d", param->model_publish_comp.model->model_id, param->model_publish_comp.model->pub->msg->len);
|
||||
break;
|
||||
case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT:
|
||||
ESP_LOGI(TAG, "Node:PublishReceive,OK,0x%04X,%d,%d", param->client_recv_publish_msg.opcode, param->client_recv_publish_msg.length, param->client_recv_publish_msg.msg[1]);
|
||||
uint64_t current_time = esp_timer_get_time();
|
||||
result = ble_mesh_test_performance_client_model_accumulate_time(((uint32_t)(current_time - start_time) / 2000), param->client_recv_publish_msg.msg, param->client_recv_publish_msg.ctx->recv_ttl, param->client_recv_publish_msg.length);
|
||||
if (ble_mesh_test_perf_send_sema != NULL && param->client_recv_publish_msg.msg[2] == VENDOR_MODEL_PERF_OPERATION_TYPE_SET_UNACK && result == ESP_OK) {
|
||||
xSemaphoreGive(ble_mesh_test_perf_send_sema);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_PUBLISH_UPDATE_EVT:
|
||||
ESP_LOGI(TAG, "Node:PublishUpdate,OK");
|
||||
break;
|
||||
case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT:
|
||||
ESP_LOGI(TAG, "Node:TimeOut, 0x%04X", param->client_send_timeout.opcode);
|
||||
if (ble_mesh_test_perf_send_sema != NULL) {
|
||||
xSemaphoreGive(ble_mesh_test_perf_send_sema);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_EVT_MAX:
|
||||
ESP_LOGI(TAG, "Node:MaxEvt");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
}
|
||||
|
||||
int ble_mesh_power_set(int argc, char **argv)
|
||||
{
|
||||
esp_err_t result = ESP_OK;
|
||||
int nerrors = arg_parse(argc, argv, (void **) &power_set);
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, power_set.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(power_set.action_type->sval[0], "tx") == 0) {
|
||||
result = esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, power_set.tx_sense_power->ival[0]);
|
||||
} else if (strcmp(power_set.action_type->sval[0], "sense") == 0) {
|
||||
uint32_t *reg = (uint32_t *)(0x6001c07c);
|
||||
int reg_addr = 0x6001c07c;
|
||||
uint32_t flag = 0x00FF0000;
|
||||
uint32_t sense_new = power_set.tx_sense_power->ival[0];
|
||||
uint32_t reg_to_write = ((*reg) &= ~flag) | ((256 - sense_new) << 16);
|
||||
REG_WRITE(reg_addr, reg_to_write);
|
||||
|
||||
}
|
||||
|
||||
if (result == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Node:SetPower,OK\n");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ble_mesh_load_oob(int argc, char **argv)
|
||||
{
|
||||
uint8_t *static_val;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &oob);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, oob.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//parsing prov
|
||||
#if CONFIG_BLE_MESH_NODE
|
||||
prov.uuid = dev_uuid;
|
||||
memcpy(dev_uuid, esp_bt_dev_get_address(), 6);
|
||||
if (oob.static_val->count != 0) {
|
||||
static_val = malloc(oob.static_val_len->ival[0] + 1);
|
||||
if (static_val == NULL) {
|
||||
ESP_LOGE(TAG, "malloc fail,%s,%d\n", __func__, __LINE__);
|
||||
}
|
||||
get_value_string((char *)oob.static_val->sval[0], (char *)static_val);
|
||||
prov.static_val = static_val;
|
||||
}
|
||||
|
||||
arg_int_to_value(oob.static_val_len, prov.static_val_len, "static value length");
|
||||
arg_int_to_value(oob.output_size, prov.output_size, "output size");
|
||||
arg_int_to_value(oob.output_actions, prov.output_actions, "output actions");
|
||||
arg_int_to_value(oob.input_size, prov.input_size, "input size");
|
||||
arg_int_to_value(oob.input_actions, prov.input_actions, "input actions");
|
||||
#endif
|
||||
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
if (oob.static_val->count != 0) {
|
||||
static_val = malloc(oob.static_val_len->ival[0] + 1);
|
||||
if (static_val == NULL) {
|
||||
ESP_LOGE(TAG, "malloc fail,%s,%d\n", __func__, __LINE__);
|
||||
}
|
||||
get_value_string((char *)oob.static_val->sval[0], (char *)static_val);
|
||||
prov.prov_static_oob_val = static_val;
|
||||
}
|
||||
arg_int_to_value(oob.prov_start_address, prov.prov_start_address, "provisioner start address");
|
||||
arg_int_to_value(oob.static_val_len, prov.prov_static_oob_len, "provisioner static value length");
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "OOB:Load,OK\n");
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ble_mesh_init(int argc, char **argv)
|
||||
{
|
||||
int err;
|
||||
esp_ble_mesh_comp_t *local_component = NULL;
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &component);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, component.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "enter %s, module %x\n", __func__, component.model_type->ival[0]);
|
||||
local_component = ble_mesh_get_component(component.model_type->ival[0]);
|
||||
|
||||
|
||||
err = esp_ble_mesh_init(&prov, local_component);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Initializing mesh failed (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_provisioner_enable_bearer(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err = 0;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &bearer);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, bearer.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (bearer.enable->count != 0) {
|
||||
if (bearer.enable->ival[0]) {
|
||||
err = esp_ble_mesh_provisioner_prov_enable(bearer.bearer->ival[0]);
|
||||
} else {
|
||||
err = esp_ble_mesh_provisioner_prov_disable(bearer.bearer->ival[0]);
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ble_mesh_register_node_cmd(void)
|
||||
{
|
||||
const esp_console_cmd_t register_cmd = {
|
||||
.command = "bmreg",
|
||||
.help = "ble mesh: provisioner/node register callback",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_register_node_cb,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(®ister_cmd));
|
||||
oob.static_val = arg_str0("s", NULL, "<value>", "Static OOB value");
|
||||
oob.static_val_len = arg_int0("l", NULL, "<length>", "Static OOB value length");
|
||||
oob.output_size = arg_int0("x", NULL, "<size>", "Maximum size of Output OOB");
|
||||
oob.output_actions = arg_int0("o", NULL, "<actions>", "Supported Output OOB Actions");
|
||||
oob.input_size = arg_int0("y", NULL, "<size>", "Maximum size of Input OOB");
|
||||
oob.input_actions = arg_int0("i", NULL, "<actions>", "Supported Input OOB Actions");
|
||||
oob.prov_start_address = arg_int0("p", NULL, "<address>", "start address assigned by provisioner");
|
||||
oob.prov_start_address->ival[0] = 0x0005;
|
||||
oob.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t oob_cmd = {
|
||||
.command = "bmoob",
|
||||
.help = "ble mesh: provisioner/node config OOB parameters",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_load_oob,
|
||||
.argtable = &oob,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&oob_cmd) );
|
||||
|
||||
component.model_type = arg_int0("m", NULL, "<model>", "mesh model");
|
||||
component.config_index = arg_int0("c", NULL, "<index>", "mesh model op");
|
||||
component.config_index->ival[0] = 0; // set default value
|
||||
component.pub_config = arg_int0("p", NULL, "<publish>", "publish message buffer");
|
||||
component.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t model_cmd = {
|
||||
.command = "bminit",
|
||||
.help = "ble mesh: provisioner/node init",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_init,
|
||||
.argtable = &component,
|
||||
};
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&model_cmd) );
|
||||
|
||||
bearer.bearer = arg_int0("b", NULL, "<bearer>", "supported bearer");
|
||||
bearer.enable = arg_int0("e", NULL, "<enable/disable>", "bearers node supported");
|
||||
bearer.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t bearer_cmd = {
|
||||
.command = "bmpbearer",
|
||||
.help = "ble mesh provisioner: enable/disable different bearers",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_provisioner_enable_bearer,
|
||||
.argtable = &bearer,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&bearer_cmd));
|
||||
|
||||
power_set.tx_sense_power = arg_int0("t", NULL, "<power>", "tx power or sense");
|
||||
power_set.action_type = arg_str1("z", NULL, "<action>", "action type");
|
||||
power_set.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t power_set_cmd = {
|
||||
.command = "bmtxpower",
|
||||
.help = "ble mesh: set tx power or sense",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_power_set,
|
||||
.argtable = &power_set,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&power_set_cmd));
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
// 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 "esp_bt_defs.h"
|
||||
|
||||
#include "provisioner_prov.h"
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
|
||||
#include "ble_mesh_adapter.h"
|
||||
#include "ble_mesh_console_decl.h"
|
||||
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *bearer;
|
||||
struct arg_int *enable;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_provisioner_bearer_t;
|
||||
ble_mesh_provisioner_bearer_t provisioner_bearer;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *add_del;
|
||||
struct arg_str *device_addr;
|
||||
struct arg_str *device_uuid;
|
||||
struct arg_int *addr_type;
|
||||
struct arg_int *bearer;
|
||||
struct arg_int *oob_info;
|
||||
struct arg_int *flag;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_provisioner_addr_t;
|
||||
ble_mesh_provisioner_addr_t provisioner_addr;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *unicast_addr;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_provisioner_get_node_t;
|
||||
ble_mesh_provisioner_get_node_t provisioner_get_node;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *oob_info;
|
||||
struct arg_int *unicast_addr;
|
||||
struct arg_int *element_num;
|
||||
struct arg_int *net_idx;
|
||||
struct arg_str *dev_key;
|
||||
struct arg_str *uuid;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_provisioner_add_node_t;
|
||||
ble_mesh_provisioner_add_node_t provisioner_add_node;
|
||||
|
||||
typedef struct {
|
||||
struct arg_int *appkey_index;
|
||||
struct arg_int *element_address;
|
||||
struct arg_int *network_index;
|
||||
struct arg_int *mod_id;
|
||||
struct arg_int *cid;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_provisioner_bind_model_t;
|
||||
ble_mesh_provisioner_bind_model_t provisioner_local_bind;
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *action_type;
|
||||
struct arg_int *net_idx;
|
||||
struct arg_int *app_idx;
|
||||
struct arg_str *key;
|
||||
struct arg_end *end;
|
||||
} ble_mesh_provisioner_add_key_t;
|
||||
ble_mesh_provisioner_add_key_t provisioner_add_key;
|
||||
|
||||
void ble_mesh_regist_provisioner_cmd(void);
|
||||
|
||||
void ble_mesh_prov_adv_cb(const esp_ble_mesh_bd_addr_t addr, const esp_ble_mesh_addr_type_t addr_type, const uint8_t adv_type,
|
||||
const uint8_t *dev_uuid, uint16_t oob_info, esp_ble_mesh_prov_bearer_t bearer);
|
||||
|
||||
void ble_mesh_register_mesh_provisioner(void)
|
||||
{
|
||||
ble_mesh_regist_provisioner_cmd();
|
||||
}
|
||||
|
||||
void ble_mesh_prov_adv_cb(const esp_ble_mesh_bd_addr_t addr, const esp_ble_mesh_addr_type_t addr_type, const uint8_t adv_type,
|
||||
const uint8_t *dev_uuid, uint16_t oob_info, esp_ble_mesh_prov_bearer_t bearer)
|
||||
{
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
ESP_LOGI(TAG, "scan device address:");
|
||||
esp_log_buffer_hex(TAG, addr, sizeof(esp_ble_mesh_bd_addr_t));
|
||||
ESP_LOGI(TAG, "scan device uuid:");
|
||||
esp_log_buffer_hex(TAG, dev_uuid, 16);
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
}
|
||||
|
||||
int ble_mesh_provisioner_register(int argc, char** argv)
|
||||
{
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
// esp_ble_mesh_register_unprov_adv_pkt_callback(ble_mesh_prov_adv_cb);
|
||||
ESP_LOGI(TAG, "Provisioner:Reg,OK");
|
||||
ESP_LOGD(TAG, "exit %s \n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_mesh_provision_address(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
esp_ble_mesh_unprov_dev_add_t device_addr = {0};
|
||||
uint8_t preset_addr_uuid[16] = {0x01, 0x02};
|
||||
esp_ble_mesh_device_delete_t del_dev = {
|
||||
.flag = BIT(0),
|
||||
};
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &provisioner_addr);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, provisioner_addr.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (provisioner_addr.device_addr->count != 0) {
|
||||
if (provisioner_addr.device_uuid->count != 0) {
|
||||
del_dev.flag = BIT(0) | BIT(1);
|
||||
str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], device_addr.uuid);
|
||||
str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], del_dev.uuid);
|
||||
} else {
|
||||
del_dev.flag = BIT(0);
|
||||
memcpy(device_addr.uuid, preset_addr_uuid, 16);
|
||||
memcpy(del_dev.uuid, preset_addr_uuid, 16);
|
||||
}
|
||||
str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], device_addr.addr);
|
||||
str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], del_dev.addr);
|
||||
arg_int_to_value(provisioner_addr.addr_type, device_addr.addr_type, "address type");
|
||||
arg_int_to_value(provisioner_addr.addr_type, del_dev.addr_type, "address type");
|
||||
} else if (provisioner_addr.device_uuid->count != 0) {
|
||||
del_dev.flag = BIT(1);
|
||||
memcpy(device_addr.addr, preset_addr_uuid, 6);
|
||||
memcpy(del_dev.addr, preset_addr_uuid, 6);
|
||||
str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], device_addr.uuid);
|
||||
str_2_mac((uint8_t *)provisioner_addr.device_addr->sval[0], del_dev.uuid);
|
||||
}
|
||||
|
||||
if (strcmp(provisioner_addr.add_del->sval[0], "add") == 0) {
|
||||
arg_int_to_value(provisioner_addr.bearer, device_addr.bearer, "bearer");
|
||||
arg_int_to_value(provisioner_addr.oob_info, device_addr.oob_info, "oob information");
|
||||
err = esp_ble_mesh_provisioner_add_unprov_dev(&device_addr, provisioner_addr.flag->ival[0]);
|
||||
} else if (strcmp(provisioner_addr.add_del->sval[0], "del") == 0) {
|
||||
err = esp_ble_mesh_provisioner_delete_dev(&del_dev);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s \n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_provisioner_bearer(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s \n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &provisioner_bearer);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, provisioner_bearer.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (provisioner_bearer.enable->count != 0) {
|
||||
if (provisioner_bearer.enable->ival[0]) {
|
||||
err = esp_ble_mesh_provisioner_prov_enable(provisioner_bearer.bearer->ival[0]);
|
||||
} else {
|
||||
err = esp_ble_mesh_provisioner_prov_disable(provisioner_bearer.bearer->ival[0]);
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s \n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_provisioner_get_node(int argc, char **argv)
|
||||
{
|
||||
uint16_t unicast_addr = 0;
|
||||
uint16_t i = 0;
|
||||
struct bt_mesh_node *node_info;
|
||||
|
||||
ESP_LOGD(TAG, "enter %s\n", __func__);
|
||||
int nerrors = arg_parse(argc, argv, (void **) &provisioner_get_node);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, provisioner_get_node.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_int_to_value(provisioner_get_node.unicast_addr, unicast_addr, "unicast address");
|
||||
node_info = bt_mesh_provisioner_get_node_info(unicast_addr);
|
||||
|
||||
if (node_info == NULL) {
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
printf("OobInfo:0x%x,Address:0x%x,EleNum:0x%x,NetIdx:0x%x,DevKey:",
|
||||
node_info->oob_info, node_info->unicast_addr, node_info->element_num, node_info->net_idx);
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%02x", node_info->dev_key[i]);
|
||||
}
|
||||
printf(",DevUuid:");
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("%02x", node_info->dev_uuid[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int ble_mesh_provisioner_add_node(int argc, char **argv)
|
||||
{
|
||||
struct bt_mesh_node node_info;
|
||||
esp_err_t result;
|
||||
ESP_LOGD(TAG, " enter %s\n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &provisioner_add_node);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, provisioner_add_node.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_int_to_value(provisioner_add_node.oob_info, node_info.oob_info, "oob information");
|
||||
arg_int_to_value(provisioner_add_node.unicast_addr, node_info.unicast_addr, "unicast address");
|
||||
arg_int_to_value(provisioner_add_node.element_num, node_info.element_num, "element number");
|
||||
arg_int_to_value(provisioner_add_node.net_idx, node_info.net_idx, "network index");
|
||||
if (provisioner_add_node.dev_key->count != 0) {
|
||||
get_value_string((char *)provisioner_add_node.dev_key->sval[0], (char *)node_info.dev_key);
|
||||
}
|
||||
if (provisioner_add_node.uuid->count != 0) {
|
||||
get_value_string((char *)provisioner_add_node.uuid->sval[0], (char *)node_info.dev_uuid);
|
||||
get_value_string((char *)provisioner_add_node.uuid->sval[0], (char *)node_info.dev_uuid);
|
||||
}
|
||||
|
||||
result = bt_mesh_provisioner_store_node_info(&node_info);
|
||||
if (result == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Provisioner:AddNodeInfo,OK\n");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return result;
|
||||
}
|
||||
|
||||
int ble_mesh_provisioner_add_key(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
uint8_t key[16] = {0};
|
||||
esp_ble_mesh_prov_data_info_t info = {
|
||||
.net_idx = 1,
|
||||
.flag = NET_IDX_FLAG,
|
||||
};
|
||||
ESP_LOGD(TAG, " enter %s\n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &provisioner_add_key);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, provisioner_add_key.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
err = get_value_string((char *)provisioner_add_key.key->sval[0], (char *) key);
|
||||
if (strcmp(provisioner_add_key.action_type->sval[0], "appkey") == 0) {
|
||||
err = esp_ble_mesh_provisioner_add_local_app_key(key, provisioner_add_key.net_idx->ival[0], provisioner_add_key.app_idx->ival[0]);
|
||||
} else if (strcmp(provisioner_add_key.action_type->sval[0], "netkey") == 0) {
|
||||
// choose network key
|
||||
info.net_idx = provisioner_add_key.net_idx->ival[0];
|
||||
err = esp_ble_mesh_provisioner_add_local_net_key(key, provisioner_add_key.net_idx->ival[0]);
|
||||
err = err | esp_ble_mesh_provisioner_set_prov_data_info(&info);
|
||||
}
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGI(TAG, "Provisioner:KeyAction,Fail");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Provisioner:KeyAction,OK");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ble_mesh_provision_bind_local_model(int argc, char **argv)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint16_t element_addr = 0;
|
||||
uint16_t app_idx = 0;
|
||||
uint16_t model_id = 0;
|
||||
uint16_t company_id = 0xFFFF;
|
||||
|
||||
ESP_LOGD(TAG, " enter %s\n", __func__);
|
||||
|
||||
int nerrors = arg_parse(argc, argv, (void **) &provisioner_local_bind);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, provisioner_local_bind.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg_int_to_value(provisioner_local_bind.element_address, element_addr, "element address");
|
||||
arg_int_to_value(provisioner_local_bind.appkey_index, app_idx, "appkey index");
|
||||
arg_int_to_value(provisioner_local_bind.mod_id, model_id, "model id");
|
||||
arg_int_to_value(provisioner_local_bind.cid, company_id, "company id");
|
||||
err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(element_addr, app_idx, model_id, company_id);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Provisioner:BindModel,Fail,%x\n", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Provisioner:BindModel,OK\n");
|
||||
}
|
||||
ESP_LOGD(TAG, "exit %s\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ble_mesh_regist_provisioner_cmd(void)
|
||||
{
|
||||
const esp_console_cmd_t prov_register = {
|
||||
.command = "bmpreg",
|
||||
.help = "ble mesh provisioner: register callback",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_provisioner_register,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&prov_register));
|
||||
|
||||
provisioner_addr.add_del = arg_str1("z", NULL, "<add/delete>", "action type");
|
||||
provisioner_addr.device_addr = arg_str0("d", NULL, "<address>", "device address");
|
||||
provisioner_addr.device_uuid = arg_str0("u", NULL, "<uuid>", "device uuid");
|
||||
provisioner_addr.addr_type = arg_int0("a", NULL, "<type>", "address type");
|
||||
provisioner_addr.flag = arg_int0("f", NULL, "<flag>", "address flag");
|
||||
provisioner_addr.flag->ival[0] = ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG;
|
||||
provisioner_addr.bearer = arg_int0("b", NULL, "<bearer>", "used bearer");
|
||||
provisioner_addr.oob_info = arg_int0("o", NULL, "<oob info>", "oob information");
|
||||
provisioner_addr.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t provisioner_addr_cmd = {
|
||||
.command = "bmpdev",
|
||||
.help = "ble mesh provisioner: add/delete unprovisioned device",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_provision_address,
|
||||
.argtable = &provisioner_addr,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_addr_cmd));
|
||||
|
||||
provisioner_bearer.bearer = arg_int0("b", NULL, "<bearer>", "bearer supported provisioner");
|
||||
provisioner_bearer.enable = arg_int0("e", NULL, "<enable/disable>", "enable or disable bearer");
|
||||
provisioner_bearer.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t provisioner_bearer_cmd = {
|
||||
.command = "bmpbearer",
|
||||
.help = "ble mesh provisioner: enable/disable provisioner different bearer",
|
||||
.hint = NULL,
|
||||
.func = &ble_mesh_provisioner_bearer,
|
||||
.argtable = &provisioner_bearer,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_bearer_cmd));
|
||||
|
||||
provisioner_get_node.unicast_addr = arg_int1("u", NULL, "<address>", "get node by unicast address");
|
||||
provisioner_get_node.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t provisioner_get_node_cmd = {
|
||||
.command = "bmpgetn",
|
||||
.help = "ble mesh provisioner: get node",
|
||||
.func = &ble_mesh_provisioner_get_node,
|
||||
.argtable = &provisioner_get_node,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_get_node_cmd));
|
||||
|
||||
provisioner_add_node.oob_info = arg_int0("o", NULL, "<oob info>", "oob information");
|
||||
provisioner_add_node.unicast_addr = arg_int0("a", NULL, "<unicast address>", "unicast address");
|
||||
provisioner_add_node.element_num = arg_int0("e", NULL, "<element num>", "element num");
|
||||
provisioner_add_node.net_idx = arg_int0("n", NULL, "<net index>", "net index");
|
||||
provisioner_add_node.dev_key = arg_str0("d", NULL, "<device key>", "device key");
|
||||
provisioner_add_node.uuid = arg_str0("u", NULL, "<device uuid>", "device uuid");
|
||||
provisioner_add_node.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t provisioner_add_node_cmd = {
|
||||
.command = "bmpaddn",
|
||||
.help = "ble mesh provisioner: add node",
|
||||
.func = &ble_mesh_provisioner_add_node,
|
||||
.argtable = &provisioner_add_node,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_add_node_cmd));
|
||||
|
||||
provisioner_local_bind.appkey_index = arg_int1("a", NULL, "<appkey index>", "appkey index");
|
||||
provisioner_local_bind.element_address = arg_int1("e", NULL, "<element address>", "element address");
|
||||
provisioner_local_bind.network_index = arg_int1("n", NULL, "<network index>", "network index");
|
||||
provisioner_local_bind.mod_id = arg_int1("m", NULL, "<model id>", "model id");
|
||||
provisioner_local_bind.cid = arg_int0("c", NULL, "<model id>", "company id");
|
||||
provisioner_local_bind.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t provisioner_local_bind_cmd = {
|
||||
.command = "bmpbind",
|
||||
.help = "ble mesh provisioner: bind local model",
|
||||
.func = &ble_mesh_provision_bind_local_model,
|
||||
.argtable = &provisioner_local_bind,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_local_bind_cmd));
|
||||
|
||||
provisioner_add_key.action_type = arg_str1("z", NULL, "<action type>", "add appkey or network key");
|
||||
provisioner_add_key.net_idx = arg_int1("n", NULL, "<net key index>", "network key index");
|
||||
provisioner_add_key.key = arg_str1("k", NULL, "<key>", "appkey or network");
|
||||
provisioner_add_key.app_idx = arg_int0("a", NULL, "<app key index>", "appkey index");
|
||||
provisioner_add_key.end = arg_end(1);
|
||||
|
||||
const esp_console_cmd_t provisioner_add_key_cmd = {
|
||||
.command = "bmpkey",
|
||||
.help = "ble mesh provisioner: key",
|
||||
.func = &ble_mesh_provisioner_add_key,
|
||||
.argtable = &provisioner_add_key,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&provisioner_add_key_cmd));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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 "esp_bt_device.h"
|
||||
#include "esp_console.h"
|
||||
|
||||
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
|
||||
void register_ble_address(void);
|
||||
|
||||
void register_bluetooth(void)
|
||||
{
|
||||
register_ble_address();
|
||||
}
|
||||
|
||||
int bt_mac(int argc, char** argv)
|
||||
{
|
||||
const uint8_t *mac = esp_bt_dev_get_address();
|
||||
printf("+BTMAC:"MACSTR"\n", MAC2STR(mac));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void register_ble_address(void)
|
||||
{
|
||||
const esp_console_cmd_t cmd = {
|
||||
.command = "btmac",
|
||||
.help = "BLE address",
|
||||
.hint = NULL,
|
||||
.func = (esp_console_cmd_func_t)&bt_mac,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
|
||||
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
|
||||
CONFIG_BLE_SCAN_DUPLICATE=y
|
||||
CONFIG_SCAN_DUPLICATE_TYPE=2
|
||||
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
|
||||
CONFIG_DUPLICATE_SCAN_CACHE_SIZE=200
|
||||
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
|
||||
CONFIG_MESH_DUPLICATE_SCAN_CACHE_SIZE=200
|
||||
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
|
||||
CONFIG_BLE_ADV_REPORT_FLOW_CONTROL_SUPPORTED=y
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_HCI_5_0=y
|
||||
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
|
||||
CONFIG_BLE_MESH_PROV=y
|
||||
CONFIG_BLE_MESH_PROVISIONER=y
|
||||
CONFIG_BLE_MESH_WAIT_FOR_PROV_MAX_DEV_NUM=20
|
||||
CONFIG_BLE_MESH_MAX_PROV_NODES=20
|
||||
CONFIG_BLE_MESH_PBA_SAME_TIME=10
|
||||
CONFIG_BLE_MESH_PBG_SAME_TIME=3
|
||||
CONFIG_BLE_MESH_PROVISIONER_SUBNET_COUNT=3
|
||||
CONFIG_BLE_MESH_PROVISIONER_APP_KEY_COUNT=9
|
||||
CONFIG_BLE_MESH_PB_ADV=y
|
||||
CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=y
|
||||
CONFIG_BLE_MESH_RELAY=y
|
||||
CONFIG_BLE_MESH_LOW_POWER=
|
||||
CONFIG_BLE_MESH_FRIEND=
|
||||
CONFIG_BLE_MESH_MSG_CACHE_SIZE=10
|
||||
CONFIG_BLE_MESH_ADV_BUF_COUNT=60
|
||||
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1
|
||||
CONFIG_BLE_MESH_RX_SDU_MAX=384
|
||||
CONFIG_BLE_MESH_TX_SEG_MAX=32
|
||||
CONFIG_BTU_TASK_STACK_SIZE=4512
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_mesh_fast_prov_client)
|
||||
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_mesh_fast_prov_client
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,6 @@
|
||||
ESP BLE Mesh Fast Provisioning Client example
|
||||
========================
|
||||
|
||||
This example shows how a BLE Mesh device functions as a Fast Provisioning Client.
|
||||
|
||||
Please check the [tutorial](tutorial/ble_mesh_fast_provision_client.md) for more information about this example.
|
||||
@@ -0,0 +1,6 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
|
||||
"ble_mesh_demo_init.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,143 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sdkconfig.h>
|
||||
/* BLE */
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid, esp_bt_dev_get_address(), BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
static SemaphoreHandle_t mesh_sem;
|
||||
static uint8_t own_addr_type;
|
||||
void ble_store_config_init(void);
|
||||
static uint8_t addr_val[6] = {0};
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
static void mesh_on_reset(int reason)
|
||||
{
|
||||
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
|
||||
}
|
||||
|
||||
static void mesh_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
xSemaphoreGive(mesh_sem);
|
||||
}
|
||||
|
||||
void mesh_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
mesh_sem = xSemaphoreCreateBinary();
|
||||
if (mesh_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create mesh semaphore");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
|
||||
|
||||
nimble_port_init();
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = mesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = mesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(mesh_host_task);
|
||||
|
||||
xSemaphoreTake(mesh_sem, portMAX_DELAY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_MESH_DEMO_INIT_H_
|
||||
#define _BLE_MESH_DEMO_INIT_H_
|
||||
|
||||
#define TAG "FAST_PROV_CLIENT_DEMO"
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
|
||||
|
||||
esp_err_t bluetooth_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,601 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,28 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
|
||||
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
|
||||
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
|
||||
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
|
||||
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
|
||||
CONFIG_BLUEDROID_ENABLED=y
|
||||
CONFIG_BLE_SMP_ENABLE=n
|
||||
CONFIG_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
# Override some defaults of ESP BLE Mesh
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_PROVISIONER=y
|
||||
CONFIG_BLE_MESH_PROV=y
|
||||
CONFIG_BLE_MESH_PBA_SAME_TIME=1
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_CRPL=10
|
||||
CONFIG_BLE_MESH_ADV_BUF_COUNT=100
|
||||
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_TX_SEG_MAX=32
|
||||
CONFIG_BLE_MESH_TRACE_LEVEL_WARNING=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,218 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
This demo completes the following functions:
|
||||
|
||||
1. Provisioning an unprovisioned device and change it to a node.
|
||||
2. Binding the provisioner's Appkey to its own models.
|
||||
3. Sending messages to the node about the Appkey and the fast provisioning information.
|
||||
4. Getting the addresses of all the nodes in the fast provisioning network.
|
||||
5. Controlling the nodes by their group address.
|
||||
|
||||
**Note: The demo's functionality is similar to that of the EspBleMesh app.**
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, in which the following four models are implemented:
|
||||
|
||||
- The **Configuration Server** model is used to represent a mesh network configuration of a device.
|
||||
- The **Configuration Client** model is used to represent an element that can control and monitor the configuration of a node.
|
||||
- The **Generic OnOff Client** model controls a Generic OnOff Server via messages defined by the **Generic OnOff** model (turning on and off the lights in this demo).
|
||||
- The **Vendor Client** model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node.
|
||||
|
||||
**Note: For detailed information about these models, please refer to other BLE Mesh demos.**
|
||||
|
||||
## 2. Code Analysis
|
||||
|
||||
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
|
||||
### 2.1 Data Structure
|
||||
|
||||
`example_prov_info_t` is used to define the keys, the address range can be assigned by a node, and the maximum number of nodes supported by the mesh network.
|
||||
|
||||
| Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `net_idx` | Netkey index value |
|
||||
| `app_idx` | AppKey index value |
|
||||
| `app_key[16]` | Appkey, which is used throughout the network |
|
||||
| `node_addr_cnt`| The maximum number of nodes supported in the mesh network,which serves the same purpose of the `Fast provisioning count` parameter in the EspBleMesh app|
|
||||
| `unicast_min` | Minimum unicast address to be assigned to the nodes in the mesh network |
|
||||
| `unicast_max` | Maximum unicast address to be assigned to the nodes in the mesh network |
|
||||
| `group_addr`| The group address, which is used to control the on/off state of all nodes in the mesh network, that is said, turning on and off the lights in this demo|
|
||||
| `match_val[16]`| The value used by the Fast Provisioning Provisioner to filter the devices to be provisioned |
|
||||
| `match_len` | The maximum length of `match_val[16]` |
|
||||
| `max_node_num` | The maximum number of nodes can be provisioned by the client |
|
||||
|
||||
### 2.2 Code Flow
|
||||
|
||||
The events and APIs in this section are presented in the same order with code execution.
|
||||
|
||||
### 2.2.1 Initialization
|
||||
|
||||
#### 2.2.1.1 Set the UUID Filter
|
||||
|
||||
The `esp_ble_mesh_provisioner_set_dev_uuid_match` API is called by the provisioner to set the part of the device UUID to be compared before starting to provision.
|
||||
|
||||
```
|
||||
/**
|
||||
* @brief This function is called by Provisioner to set the part of the device UUID
|
||||
* to be compared before starting to provision.
|
||||
*
|
||||
* @param[in] match_val: Value to be compared with the part of the device UUID.
|
||||
* @param[in] match_len: Length of the compared match value.
|
||||
* @param[in] offset: Offset of the device UUID to be compared (based on zero).
|
||||
* @param[in] prov_after_match: Flag used to indicate whether provisioner should start to provision
|
||||
* the device immediately if the part of the UUID matches.
|
||||
*
|
||||
* @return ESP_OK on success or error code otherwise.
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_ble_mesh_provisioner_set_dev_uuid_match(const uint8_t *match_val, uint8_t match_len,
|
||||
uint8_t offset, bool prov_after_match);
|
||||
```
|
||||
|
||||
```c
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2.2.1.2 Add local Appkey
|
||||
|
||||
The provisioner has no Appkey right after it has been initialized. Therefore, you have to add a local Appkey for the provisioner by calling the `esp_ble_mesh_provisioner_add_local_app_key`.
|
||||
|
||||
```c
|
||||
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;
|
||||
}
|
||||
```
|
||||
Please check the return value of the API calling and the return value of `ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT`, and make sure that the Appkey has been added to this provisioner.
|
||||
|
||||
#### 2.2.1.3 Bind Appkey to local model
|
||||
|
||||
To control the server model, the client model uses messages to control the server model and these message must be encrypted by the Appkey. To that end, users must bind the Appkey of the provisioner to its local models, which are the **Generic OnOff Client** model and the **Vendor Client** model, by calling the `esp_ble_mesh_provisioner_add_local_app_key` api.
|
||||
|
||||
```c
|
||||
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;
|
||||
}
|
||||
```
|
||||
Please check the return value of the API calling and the return value of the `ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT` event, and make sure that the Appkey has been binded to the local models.
|
||||
|
||||
|
||||
### 2.2.2 Provisioning a device
|
||||
|
||||
The unprovisioned devices continuously send the **Unprovisioned Device** beacon, which contains the value of its UUID.
|
||||
|
||||
* If the UUID matched, a `ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT` event will be triggered, which will add the unprovisioned device information to the queue of to-be-provisioned devices.
|
||||
|
||||
```c
|
||||
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--;
|
||||
}
|
||||
}
|
||||
```
|
||||
* If not, this device will be ignored.
|
||||
|
||||
After that, all the devices in the queue will be provisioned automatically.
|
||||
|
||||
### 2.2.3 Sending cache data
|
||||
|
||||
Appkey is among the cache required for this node to become a provisioner.
|
||||
|
||||
When the provisioning completes, an `ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT` event will be triggered, which will add the Appkey to the node's **Config Server** model by calling the `esp_ble_mesh_config_client_set_state` API:
|
||||
|
||||
```c
|
||||
common.opcode = ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD;
|
||||
common.model = model;
|
||||
common.ctx.net_idx = info->net_idx;
|
||||
common.ctx.app_idx = 0x0000; /* not used for config messages */
|
||||
common.ctx.addr = info->dst;
|
||||
common.ctx.send_rel = false;
|
||||
common.ctx.send_ttl = 0;
|
||||
common.msg_timeout = info->timeout;
|
||||
common.msg_role = info->role;
|
||||
|
||||
return esp_ble_mesh_config_client_set_state(&common, &set);
|
||||
```
|
||||
|
||||
* If API calling succeeds, an `ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT` event will be triggered, which sends other cache information (`example_fast_prov_info_set_t`) to the node's **Vendor Server** model by calling the `example_send_fast_prov_info_set` function;
|
||||
* If API calling (`example_send_fast_prov_info_set`) succeeded, a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` will be sent, whose acknowledgement (with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS`) will further trigger an `ESP_BLE_MESH_MODEL_OPERATION_EVT` event
|
||||
```c
|
||||
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;
|
||||
}
|
||||
```
|
||||
* If API calling (`example_send_fast_prov_info_set`) times out, an `ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT` event will be triggered.
|
||||
* If API calling times out, an `ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT` event is triggered.
|
||||
|
||||
After that, this node has the ability to provisioning other nodes as a provisioner, and further controls other nodes.
|
||||
|
||||
**Note: The message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` contains the group address of all the nodes. When a node receives this message, it will automatically subscribe the Onoff Server model of this address.**
|
||||
|
||||
### 2.2.4 Controlling the node
|
||||
|
||||
When the `ESP_BLE_MESH_MODEL_OPERATION_EVT` event is triggered, the provisioner starts a timer.
|
||||
|
||||
```c
|
||||
ESP_LOG_BUFFER_HEX("fast prov info status", data, len);
|
||||
#if !defined(CONFIG_BLE_MESH_FAST_PROV)
|
||||
prim_prov_addr = ctx->addr;
|
||||
k_delayed_work_init(&get_all_node_addr_timer, example_get_all_node_addr);
|
||||
k_delayed_work_submit(&get_all_node_addr_timer, GET_ALL_NODE_ADDR_TIMEOUT);
|
||||
#endif
|
||||
break;
|
||||
```
|
||||
After the timers times out, the provisioner starts to get the addresses of all nodes in the mesh network by calling the `example_send_fast_prov_all_node_addr_get` function, which sends a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET`.
|
||||
|
||||
```c
|
||||
err = example_send_fast_prov_all_node_addr_get(model, &info);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send Fast Prov Node Address Get message", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
After that, the provisioner will receive an acknowledgement, which is a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS`, which triggers the `ESP_BLE_MESH_MODEL_OPERATION_EVT` event.
|
||||
|
||||
Then, the provisioner is able to turn on all the nodes (which are lights in this demo) by calling the `example_send_generic_onoff_set` function using the group address.
|
||||
|
||||
```c
|
||||
example_msg_common_info_t info = {
|
||||
.net_idx = node->net_idx,
|
||||
.app_idx = node->app_idx,
|
||||
.dst = node->group_addr,
|
||||
.timeout = 0,
|
||||
.role = ROLE_PROVISIONER,
|
||||
};
|
||||
err = example_send_generic_onoff_set(cli_model, &info, LED_ON, 0x00, false);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send Generic OnOff Set Unack message", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,8 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_mesh_fast_prov_server)
|
||||
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_mesh_fast_prov_server
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,6 @@
|
||||
ESP BLE Mesh Fast Provisioning Server example
|
||||
========================
|
||||
|
||||
This example shows how a BLE Mesh device functions as a Fast Provisioning Server.
|
||||
|
||||
Please check the [tutorial](tutorial/ble_mesh_fast_provision_server.md) for more information about this example.
|
||||
@@ -0,0 +1,7 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
|
||||
"ble_mesh_demo_init.c"
|
||||
"board.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,16 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice BLE_MESH_EXAMPLE_BOARD
|
||||
prompt "Board selection for BLE Mesh"
|
||||
default BLE_MESH_ESP_WROOM_32
|
||||
help
|
||||
Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32
|
||||
|
||||
config BLE_MESH_ESP_WROOM_32
|
||||
bool "ESP32-WROOM-32"
|
||||
|
||||
config BLE_MESH_ESP_WROVER
|
||||
bool "ESP32-WROVER"
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,143 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sdkconfig.h>
|
||||
/* BLE */
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
static SemaphoreHandle_t mesh_sem;
|
||||
static uint8_t own_addr_type;
|
||||
void ble_store_config_init(void);
|
||||
static uint8_t addr_val[6] = {0};
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
static void mesh_on_reset(int reason)
|
||||
{
|
||||
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
|
||||
}
|
||||
|
||||
static void mesh_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
xSemaphoreGive(mesh_sem);
|
||||
}
|
||||
|
||||
void mesh_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
mesh_sem = xSemaphoreCreateBinary();
|
||||
if (mesh_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create mesh semaphore");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
|
||||
|
||||
nimble_port_init();
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = mesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = mesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(mesh_host_task);
|
||||
|
||||
xSemaphoreTake(mesh_sem, portMAX_DELAY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_MESH_DEMO_INIT_H_
|
||||
#define _BLE_MESH_DEMO_INIT_H_
|
||||
|
||||
#define TAG "FAST_PROV_SERVER_DEMO"
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
|
||||
|
||||
esp_err_t bluetooth_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,764 @@
|
||||
// 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_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
#include "esp_ble_mesh_local_data_operation_api.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "esp_fast_prov_operation.h"
|
||||
#include "esp_fast_prov_client_model.h"
|
||||
#include "esp_fast_prov_server_model.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
|
||||
extern struct _led_state led_state[3];
|
||||
extern struct k_delayed_work send_self_prov_node_addr_timer;
|
||||
extern bt_mesh_atomic_t fast_prov_cli_flags;
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
static uint8_t prov_start_num = 0;
|
||||
static bool prov_start = false;
|
||||
|
||||
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, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS },
|
||||
};
|
||||
|
||||
/* Configuration Client Model user_data */
|
||||
esp_ble_mesh_client_t config_client;
|
||||
|
||||
/* Configuration Server Model user_data */
|
||||
esp_ble_mesh_cfg_srv_t config_server = {
|
||||
.relay = ESP_BLE_MESH_RELAY_ENABLED,
|
||||
.beacon = ESP_BLE_MESH_BEACON_DISABLED,
|
||||
#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 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
/* Fast Prov Client Model user_data */
|
||||
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,
|
||||
};
|
||||
|
||||
/* Fast Prov Server Model user_data */
|
||||
example_fast_prov_server_t fast_prov_server = {
|
||||
.primary_role = false,
|
||||
.max_node_num = 6,
|
||||
.prov_node_cnt = 0x0,
|
||||
.unicast_min = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_max = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_cur = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_step = 0x0,
|
||||
.flags = 0x0,
|
||||
.iv_index = 0x0,
|
||||
.net_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.app_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.group_addr = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.prim_prov_addr = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.match_len = 0x0,
|
||||
.pend_act = FAST_PROV_ACT_NONE,
|
||||
.state = STATE_IDLE,
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 3, ROLE_FAST_PROV);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_op_t fast_prov_srv_op[] = {
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, 2),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, 0),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_ADD, 2),
|
||||
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_DELETE, 2),
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
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_ACK, 0),
|
||||
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_SRV(&onoff_pub, &onoff_server),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t vnd_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV,
|
||||
fast_prov_srv_op, NULL, &fast_prov_server),
|
||||
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 = {
|
||||
.uuid = dev_uuid,
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
.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,
|
||||
};
|
||||
|
||||
static void example_change_led_state(uint8_t onoff)
|
||||
{
|
||||
struct _led_state *led = &led_state[1];
|
||||
|
||||
board_led_operation(led->pin, onoff);
|
||||
|
||||
/* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will
|
||||
* start the timer used to disable fast provisioning functionality.
|
||||
*/
|
||||
if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) {
|
||||
k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
static void node_prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
||||
{
|
||||
ESP_LOGI(TAG, "net_idx: 0x%04x, unicast_addr: 0x%04x", net_idx, addr);
|
||||
ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index);
|
||||
board_prov_complete();
|
||||
/* Updates the net_idx used by Fast Prov Server model, and it can also
|
||||
* be updated if the Fast Prov Info Set message contains a valid one.
|
||||
*/
|
||||
fast_prov_server.net_idx = net_idx;
|
||||
}
|
||||
|
||||
static void provisioner_prov_link_open(esp_ble_mesh_prov_bearer_t bearer)
|
||||
{
|
||||
ESP_LOGI(TAG, "%s: bearer %s", __func__, 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: bearer %s, reason 0x%02x", __func__,
|
||||
bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", reason);
|
||||
if (prov_start_num) {
|
||||
prov_start_num--;
|
||||
}
|
||||
}
|
||||
|
||||
static void provisioner_prov_complete(int node_idx, const uint8_t uuid[16], uint16_t unicast_addr,
|
||||
uint8_t element_num, uint16_t net_idx)
|
||||
{
|
||||
example_node_info_t *node = NULL;
|
||||
esp_err_t err;
|
||||
|
||||
if (example_is_node_exist(uuid) == false) {
|
||||
fast_prov_server.prov_node_cnt++;
|
||||
}
|
||||
|
||||
ESP_LOG_BUFFER_HEX("Device uuid", uuid + 2, 6);
|
||||
ESP_LOGI(TAG, "Unicast address 0x%04x", unicast_addr);
|
||||
|
||||
/* Sets node info */
|
||||
err = example_store_node_info(uuid, unicast_addr, element_num, net_idx,
|
||||
fast_prov_server.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;
|
||||
}
|
||||
|
||||
if (fast_prov_server.primary_role == true) {
|
||||
/* If the Provisioner is the primary one (i.e. provisioned by the phone), it shall
|
||||
* store self-provisioned node addresses;
|
||||
* If the node_addr_cnt configured by the phone is small than or equal to the
|
||||
* maximum number of nodes it can provision, it shall reset the timer which is used
|
||||
* to send all node addresses to the phone.
|
||||
*/
|
||||
err = example_store_remote_node_address(unicast_addr);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to store node address 0x%04x", __func__, unicast_addr);
|
||||
return;
|
||||
}
|
||||
if (fast_prov_server.node_addr_cnt != FAST_PROV_NODE_COUNT_MIN &&
|
||||
fast_prov_server.node_addr_cnt <= fast_prov_server.max_node_num) {
|
||||
if (bt_mesh_atomic_test_and_clear_bit(fast_prov_server.srv_flags, GATT_PROXY_ENABLE_START)) {
|
||||
k_delayed_work_cancel(&fast_prov_server.gatt_proxy_enable_timer);
|
||||
}
|
||||
if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, GATT_PROXY_ENABLE_START)) {
|
||||
k_delayed_work_submit(&fast_prov_server.gatt_proxy_enable_timer, GATT_PROXY_ENABLE_TIMEOUT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* When a device is provisioned, the non-primary Provisioner shall reset the timer
|
||||
* which is used to send node addresses to the primary Provisioner.
|
||||
*/
|
||||
if (bt_mesh_atomic_test_and_clear_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) {
|
||||
k_delayed_work_cancel(&send_self_prov_node_addr_timer);
|
||||
}
|
||||
if (!bt_mesh_atomic_test_and_set_bit(&fast_prov_cli_flags, SEND_SELF_PROV_NODE_ADDR_START)) {
|
||||
k_delayed_work_submit(&send_self_prov_node_addr_timer, SEND_SELF_PROV_NODE_ADDR_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
if (bt_mesh_atomic_test_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) {
|
||||
/* When a device is provisioned, and the stop_prov flag of the Provisioner has been
|
||||
* set, the Provisioner shall reset the timer which is used to stop the provisioner
|
||||
* functionality.
|
||||
*/
|
||||
k_delayed_work_cancel(&fast_prov_server.disable_fast_prov_timer);
|
||||
k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT);
|
||||
}
|
||||
|
||||
/* 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_FAST_PROV,
|
||||
};
|
||||
err = example_send_config_appkey_add(config_client.model, &info, NULL);
|
||||
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;
|
||||
|
||||
/* In Fast Provisioning, the Provisioner should only use PB-ADV to provision devices. */
|
||||
if (prov_start && (bearer & ESP_BLE_MESH_PROV_ADV)) {
|
||||
/* Checks if the device is a reprovisioned one. */
|
||||
if (example_is_node_exist(dev_uuid) == false) {
|
||||
if ((prov_start_num >= fast_prov_server.max_node_num) ||
|
||||
(fast_prov_server.prov_node_cnt >= fast_prov_server.max_node_num)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
add_dev.addr_type = (uint8_t)addr_type;
|
||||
add_dev.oob_info = oob_info;
|
||||
add_dev.bearer = (uint8_t)bearer;
|
||||
memcpy(add_dev.uuid, dev_uuid, 16);
|
||||
memcpy(add_dev.addr, addr, BLE_MESH_ADDR_LEN);
|
||||
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 device", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If adding unprovisioned device successfully, increase prov_start_num */
|
||||
prov_start_num++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
|
||||
esp_ble_mesh_prov_cb_param_t *param)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
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_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code: %d",
|
||||
param->node_prov_enable_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer: %s",
|
||||
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer: %s",
|
||||
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
|
||||
node_prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
|
||||
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROXY_GATT_DISABLE_COMP_EVT");
|
||||
if (fast_prov_server.primary_role == true) {
|
||||
config_server.relay = ESP_BLE_MESH_RELAY_DISABLED;
|
||||
}
|
||||
prov_start = true;
|
||||
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");
|
||||
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");
|
||||
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_SET_FAST_PROV_INFO_COMP_EVT: {
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT");
|
||||
ESP_LOGI(TAG, "status_unicast: 0x%02x, status_net_idx: 0x%02x, status_match 0x%02x",
|
||||
param->set_fast_prov_info_comp.status_unicast,
|
||||
param->set_fast_prov_info_comp.status_net_idx,
|
||||
param->set_fast_prov_info_comp.status_match);
|
||||
err = example_handle_fast_prov_info_set_comp_evt(fast_prov_server.model,
|
||||
param->set_fast_prov_info_comp.status_unicast,
|
||||
param->set_fast_prov_info_comp.status_net_idx,
|
||||
param->set_fast_prov_info_comp.status_match);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to handle Fast Prov Info Set complete event", __func__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, status_action 0x%02x",
|
||||
param->set_fast_prov_action_comp.status_action);
|
||||
err = example_handle_fast_prov_action_set_comp_evt(fast_prov_server.model,
|
||||
param->set_fast_prov_action_comp.status_action);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to handle Fast Prov Action Set complete event", __func__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void example_ble_mesh_custom_model_cb(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_SET:
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD:
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR:
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET:
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_ADD:
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_GROUP_DELETE: {
|
||||
ESP_LOGI(TAG, "%s: Fast prov server receives msg, opcode 0x%04x", __func__, opcode);
|
||||
struct net_buf_simple buf = {
|
||||
.len = param->model_operation.length,
|
||||
.data = param->model_operation.msg,
|
||||
};
|
||||
err = example_fast_prov_server_recv_msg(param->model_operation.model,
|
||||
param->model_operation.ctx, &buf);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to handle fast prov client message", __func__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
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_ACK: {
|
||||
ESP_LOGI(TAG, "%s: Fast prov client receives msg, 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 server 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);
|
||||
switch (param->model_send_comp.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_ACK:
|
||||
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS:
|
||||
err = example_handle_fast_prov_status_send_comp_evt(param->model_send_comp.err_code,
|
||||
param->model_send_comp.opcode,
|
||||
param->model_send_comp.model,
|
||||
param->model_send_comp.ctx);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to handle fast prov status send complete event", __func__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
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: Faield to resend fast prov client message", __func__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_config_client_cb(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 == false) {
|
||||
/* After sending Config AppKey Add successfully, start to send Fast Prov Info Set */
|
||||
if (fast_prov_server.unicast_cur >= fast_prov_server.unicast_max) {
|
||||
/* TODO:
|
||||
* 1. If unicast_cur is >= unicast_max, we can also send the message to enable
|
||||
* the Provisioner functionality on the node, and need to add another vendor
|
||||
* message used by the node to require a new unicast address range from primary
|
||||
* Provisioner, and before get the correct response, the node should pend
|
||||
* the fast provisioning functionality.
|
||||
* 2. Currently if address is not enough, the Provisioner will only add the group
|
||||
* address to the node.
|
||||
*/
|
||||
ESP_LOGW(TAG, "%s: Not enough address to be assigned", __func__);
|
||||
node->lack_of_addr = true;
|
||||
} else {
|
||||
/* Send fast_prov_info_set message to node */
|
||||
node->lack_of_addr = false;
|
||||
node->unicast_min = fast_prov_server.unicast_cur;
|
||||
if (fast_prov_server.unicast_cur + fast_prov_server.unicast_step >= fast_prov_server.unicast_max) {
|
||||
node->unicast_max = fast_prov_server.unicast_max;
|
||||
} else {
|
||||
node->unicast_max = fast_prov_server.unicast_cur + fast_prov_server.unicast_step;
|
||||
}
|
||||
node->flags = fast_prov_server.flags;
|
||||
node->iv_index = fast_prov_server.iv_index;
|
||||
node->fp_net_idx = fast_prov_server.net_idx;
|
||||
node->group_addr = fast_prov_server.group_addr;
|
||||
node->prov_addr = fast_prov_server.prim_prov_addr;
|
||||
node->match_len = fast_prov_server.match_len;
|
||||
memcpy(node->match_val, fast_prov_server.match_val, fast_prov_server.match_len);
|
||||
node->action = FAST_PROV_ACT_ENTER;
|
||||
fast_prov_server.unicast_cur = node->unicast_max + 1;
|
||||
}
|
||||
}
|
||||
if (node->lack_of_addr == false) {
|
||||
set.ctx_flags = 0x03FE;
|
||||
memcpy(&set.unicast_min, &node->unicast_min,
|
||||
sizeof(example_node_info_t) - offsetof(example_node_info_t, unicast_min));
|
||||
} else {
|
||||
set.ctx_flags = BIT(6);
|
||||
set.group_addr = fast_prov_server.group_addr;
|
||||
}
|
||||
example_msg_common_info_t info = {
|
||||
.net_idx = node->net_idx,
|
||||
.app_idx = node->app_idx,
|
||||
.dst = node->unicast_addr,
|
||||
.timeout = 0,
|
||||
.role = ROLE_FAST_PROV,
|
||||
};
|
||||
err = example_send_fast_prov_info_set(fast_prov_client.model, &info, &set);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send 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_FAST_PROV,
|
||||
};
|
||||
err = example_send_config_appkey_add(config_client.model, &info, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to send Config AppKey Add message", __func__);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
|
||||
esp_ble_mesh_cfg_server_cb_param_t *param)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "%s, event = 0x%02x, opcode = 0x%04x, addr: 0x%04x",
|
||||
__func__, event, param->ctx.recv_op, param->ctx.addr);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT:
|
||||
switch (param->ctx.recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
||||
ESP_LOGI(TAG, "Config Server get Config AppKey Add");
|
||||
err = example_handle_config_app_key_add_evt(param->value.state_change.appkey_add.app_idx);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to bind app_idx 0x%04x with non-config models",
|
||||
__func__, param->value.state_change.appkey_add.app_idx);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event,
|
||||
esp_ble_mesh_generic_server_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04x, src 0x%04x, dst 0x%04x",
|
||||
event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
|
||||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff);
|
||||
example_change_led_state(param->value.state_change.onoff_set.onoff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unknown Generic Server event 0x%02x", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
|
||||
esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb);
|
||||
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
||||
esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb);
|
||||
|
||||
err = esp_ble_mesh_init(&prov, &comp);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize BLE Mesh", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = example_fast_prov_server_init(&vnd_models[0]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize fast prov server model", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_ble_mesh_client_model_init(&vnd_models[1]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize fast prov client model", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
k_delayed_work_init(&send_self_prov_node_addr_timer, example_send_self_prov_node_addr);
|
||||
|
||||
err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to enable node provisioning", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "BLE Mesh Fast Prov Node initialized");
|
||||
|
||||
board_led_operation(LED_B, LED_ON);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing...");
|
||||
|
||||
err = board_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "board_init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
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, "Bluetooth mesh init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
// 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 "driver/gpio.h"
|
||||
#include "board.h"
|
||||
#include "esp_fast_prov_common.h"
|
||||
|
||||
#define TAG "BOARD"
|
||||
|
||||
struct _led_state led_state[3] = {
|
||||
{ LED_OFF, LED_OFF, LED_R, "red" },
|
||||
{ LED_OFF, LED_OFF, LED_G, "green" },
|
||||
{ LED_OFF, LED_OFF, LED_B, "blue" },
|
||||
};
|
||||
|
||||
void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number)
|
||||
{
|
||||
ESP_LOGI(TAG, "Board output number %d", number);
|
||||
}
|
||||
|
||||
void board_prov_complete(void)
|
||||
{
|
||||
board_led_operation(LED_B, LED_OFF);
|
||||
}
|
||||
|
||||
void board_led_operation(uint8_t pin, uint8_t onoff)
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (led_state[i].pin != pin) {
|
||||
continue;
|
||||
}
|
||||
if (onoff == led_state[i].previous) {
|
||||
ESP_LOGW(TAG, "led %s is already %s",
|
||||
led_state[i].name, (onoff ? "on" : "off"));
|
||||
return;
|
||||
}
|
||||
gpio_set_level(pin, onoff);
|
||||
led_state[i].previous = onoff;
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGE(TAG, "LED is not found!");
|
||||
}
|
||||
|
||||
static void board_led_init(void)
|
||||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
gpio_pad_select_gpio(led_state[i].pin);
|
||||
gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(led_state[i].pin, LED_OFF);
|
||||
led_state[i].previous = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t board_init(void)
|
||||
{
|
||||
board_led_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
|
||||
#ifdef CONFIG_BLE_MESH_ESP_WROOM_32
|
||||
#define LED_R GPIO_NUM_25
|
||||
#define LED_G GPIO_NUM_26
|
||||
#define LED_B GPIO_NUM_27
|
||||
#elif defined(CONFIG_BLE_MESH_ESP_WROVER)
|
||||
#define LED_R GPIO_NUM_0
|
||||
#define LED_G GPIO_NUM_2
|
||||
#define LED_B GPIO_NUM_4
|
||||
#endif
|
||||
|
||||
struct _led_state {
|
||||
uint8_t current;
|
||||
uint8_t previous;
|
||||
uint8_t pin;
|
||||
char *name;
|
||||
};
|
||||
|
||||
void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number);
|
||||
|
||||
void board_prov_complete(void);
|
||||
|
||||
void board_led_operation(uint8_t pin, uint8_t onoff);
|
||||
|
||||
esp_err_t board_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,30 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
|
||||
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
|
||||
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
|
||||
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
|
||||
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
|
||||
CONFIG_BLUEDROID_ENABLED=y
|
||||
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BLE_SMP_ENABLE=n
|
||||
CONFIG_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
# Override some defaults of ESP BLE Mesh
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_FAST_PROV=y
|
||||
CONFIG_BLE_MESH_MAX_PROV_NODES=6
|
||||
CONFIG_BLE_MESH_PBA_SAME_TIME=3
|
||||
CONFIG_BLE_MESH_PBG_SAME_TIME=3
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_CRPL=60
|
||||
CONFIG_BLE_MESH_MSG_CACHE_SIZE=60
|
||||
CONFIG_BLE_MESH_ADV_BUF_COUNT=200
|
||||
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_TX_SEG_MAX=32
|
||||
CONFIG_BLE_MESH_TRACE_LEVEL_ERROR=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
@@ -0,0 +1,93 @@
|
||||
# Demo Function
|
||||
|
||||
This demo demonstrates the fast provisioning of ESP BLE Mesh network and how to use the EspBleMesh app to control an individual provisioned node or all the provisioned nodes.
|
||||
|
||||
A video of this demo can be seen
|
||||
[here](http://download.espressif.com/BLE_MESH/BLE_Mesh_Demo/V0.4_Demo_Fast_Provision/ESP32_BLE_Mesh_Fast_Provision.mp4)
|
||||
|
||||
# What You Need
|
||||
|
||||
* [EspBleMesh App for Android](http://download.espressif.com/BLE_MESH/BLE_Mesh_Tools/BLE_Mesh_App/EspBleMesh-0.9.4.apk)
|
||||
* [ESP BLE Mesh SDK v0.6(Beta Version)](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6)
|
||||
* ESP32 Development Boards
|
||||
|
||||
> Note:
|
||||
>
|
||||
> 1. Please flash the [`ble_mesh_fast_prov_server`](https://glab.espressif.cn/ble_mesh/esp-ble-mesh-v0.6/tree/ble_mesh_release/esp-ble-mesh-v0.6/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server) to your boards first;
|
||||
> 2. To have a better understanding of the performance of the BLE Mesh network, we recommend that at least 3 devices should be added in your network.
|
||||
> 3. We recommend that you solder LED indicators if your development board does not come with lights.
|
||||
> 4. Please check the type of board and LED pin definition enabled in `Example BLE Mesh Config` by running `idf.py menuconfig`
|
||||
|
||||

|
||||
|
||||
|
||||
# Flash and Monitor
|
||||
|
||||
1. Enter the directory:
|
||||
examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server
|
||||
2. Make sure that the `IDF_PATH` environment variable was set in accordance with your current IDF path
|
||||
3. Check the version of your toolchain. Version 4.1 or newer should be used.
|
||||
|
||||

|
||||
|
||||
4. Run `idf.py -p PORT flash` to compile codes and flash the codes to the device.
|
||||
|
||||

|
||||
|
||||
> Note:
|
||||
>
|
||||
> Please click on the Exit button if you see the following windows.
|
||||
|
||||
|
||||
5. Please establish a connection between your device and PC, using the correct serial number, if you want to monitor the operation of this device on PC.
|
||||
|
||||
# How to Use the App
|
||||
|
||||
Please launch the `EspBleMesh` app, and follow the steps described below to establish a BLE Mesh network and control any individual node or all the nodes.
|
||||
|
||||

|
||||
1. Click on the upper left corner to see more options;
|
||||
2. Click on **Provisioning** to scan nearby unprovisioned devices;
|
||||
3. Choose any unprovisioned devices in the scanned list;
|
||||
4. Enter the number of devices you want to add in your mesh network;
|
||||
> Note:
|
||||
>
|
||||
> If you only want to use the normal provisioning feature,You don't check the option for fast provisioning.
|
||||
5. Wait until all the devices are provisioned;
|
||||
6. Click on the upper left corner to see more options;
|
||||
7. Click on **Fast Provisioned** to see all the provisioned devices;
|
||||
8. Control your devices.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Please disable your Bluetooth function on your phone, enable it and try again, if you have encountered any connection issues.
|
||||
|
||||
|
||||
# Procedure
|
||||
|
||||
## Role
|
||||
|
||||
* Phone - Top Provisioner
|
||||
* The device that has been provisioned by Phone - Primary Provisioner
|
||||
* Devices that have been provisioned and changed to the role of a provisioner - Temporary Provisioner
|
||||
* Devices that have been provisioned but not changed to the role of a provisioner - Node
|
||||
|
||||
## Interaction
|
||||
|
||||

|
||||
1. The Top Provisioner configures the first device to access the network with the GATT bearer.
|
||||
2. The Top Provisioner sends the `send_config_appkey_add` message to allocate the Appkey to this device.
|
||||
3. The Top Provisioner sends the `send_fast_prov_info_set` message to provide the necessary information so the device can be changed to a Primary Provisioner.
|
||||
4. The device calls the `esp_ble_mesh_set_fast_prov_action` API to change itself into the role of a Primary Provisioner and disconnects with the Top Provisioner.
|
||||
5. The Primary Provisioner sends the `send_config_appkey_add` message to allocate the Appkey to an other device.
|
||||
6. The Primary Provisioner sends the `send_fast_prov_info_set` message to provide the necessary information so the device can be changed to a Temporary Provisioner.
|
||||
7. The device calls the `esp_ble_mesh_set_fast_prov_action` API to change itself into the role of a Temporary Provisioner and starts its address timer.
|
||||
8. The Temporary Provisioner collects the addresses of nodes that it has provisioned and sends these addresses to the Primary Provisioner, when its address timer times out, which indicates the Temporary Provisioner hasn't provisioned any devices for 10s.
|
||||
9. The Primary Provisioner reconnects to the Top Provisioner when its address timer times out, which indicates the Primary Provisioner hasn't received any messages from the Temporary Provisioners for 10s.
|
||||
10. The Top Provisioner sends the `node_adress_Get` message automatically after reconnecting with the Primary Provisioner.
|
||||
11. At this point, the Top Provisioner is able to control any nodes in the BLE Mesh Network.
|
||||
|
||||
> Note:
|
||||
>
|
||||
> The nodes in the BLE Mesh Network only disable its provisioner functionality after it has been controlled by the Top Provisioner for at least one time.
|
||||
|
||||
@@ -0,0 +1,409 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
This demo is used for fast provisioning networks. It takes no more than 60 seconds to provisioning 100 devices in this demo.
|
||||
|
||||
This demo must be used with the EspBleMesh app. For details about how to use the EspBleMesh app, please click [here](EspBleMesh.md).
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, where the following five Models are implemented:
|
||||
|
||||
- The **Configuration Server** Model is used to represent a mesh network configuration of a device.
|
||||
- The **Configuration Client** Model is used to represent an element that can control and monitor the configuration of a node.
|
||||
- The **Generic OnOff Server** Model implements the node's Onoff state.
|
||||
- The **Vendor Server** Model implements the node's `fast_prov_server` state.
|
||||
- The **Vendor Client** Model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node.
|
||||
|
||||
|
||||
## 2. Code Analysis
|
||||
|
||||
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
|
||||
### 2.1 Data Structure
|
||||
|
||||
This section introduces the `example_fast_prov_server_t` strut for this demo, and its variables in groups.
|
||||
|
||||
```
|
||||
typedef struct {
|
||||
esp_ble_mesh_model_t *model; /* Fast Prov Server Model pointer */
|
||||
ATOMIC_DEFINE(srv_flags, SRV_MAX_FLAGS);
|
||||
|
||||
bool primary_role; /* Indicate if the device is a Primary Provisioner */
|
||||
uint8_t max_node_num; /* The maximum number of devices can be provisioned by the Provisioner */
|
||||
uint8_t prov_node_cnt; /* Number of self-provisioned nodes */
|
||||
uint16_t app_idx; /* AppKey index of the application key added by other Provisioner */
|
||||
uint16_t top_address; /* Address of the device(e.g. phone) which triggers fast provisioning */
|
||||
|
||||
esp_ble_mesh_msg_ctx_t ctx; /* the context stored for sending fast prov status message */
|
||||
struct fast_prov_info_set *set_info; /* Used to store received fast prov info set context */
|
||||
|
||||
uint16_t node_addr_cnt; /* Number of node address shall be received */
|
||||
uint16_t unicast_min; /* Minimum unicast address can be send to other nodes */
|
||||
uint16_t unicast_max; /* Maximum unicast address can be send to other nodes */
|
||||
uint16_t unicast_cur; /* Current unicast address can be assigned */
|
||||
uint16_t unicast_step; /* Unicast address change step */
|
||||
uint8_t flags; /* Flags state */
|
||||
uint32_t iv_index; /* Iv_index state */
|
||||
uint16_t net_idx; /* Netkey index state */
|
||||
uint16_t group_addr; /* Subscribed group address */
|
||||
uint16_t prim_prov_addr; /* Unicast address of Primary Provisioner */
|
||||
uint8_t match_val[16]; /* Match value to be compared with unprovisioned device UUID */
|
||||
uint8_t match_len; /* Length of match value to be compared */
|
||||
|
||||
uint8_t pend_act; /* Pending action to be performed */
|
||||
uint8_t state; /* Fast prov state -> 0: idle, 1: pend, 2: active */
|
||||
|
||||
struct k_delayed_work disable_fast_prov_timer; /* Used to disable fast provisioning */
|
||||
struct k_delayed_work gatt_proxy_enable_timer; /* Used to Mesh GATT Proxy functionality */
|
||||
} __attribute__((packed)) example_fast_prov_server_t;
|
||||
```
|
||||
|
||||
|
||||
#### 2.1.1 Provisioner Role and State
|
||||
|
||||
Different provisioners have different behaviors and it’s helpful to understand the concepts of different roles so you can better understand the codes.
|
||||
|
||||
In the struct, there are three variables that are related to roles and states, which are described in the following table:
|
||||
|
||||
| Variable Name |Description |
|
||||
| ---------------------|------------------------- |
|
||||
| `primary_role` | Provisioner identity |
|
||||
| `state` | Fast provisioner state (0: idle, 1: pend, 2: active) |
|
||||
| `srv_flags` | Flags (`DISABLE_FAST_PROV_START`,`GATT_PROXY_ENABLE_START`,`RELAY_PROXY_DISABLED`,`SRV_MAX_FLAGS`) |
|
||||
|
||||
Among which, there are four roles in this demo (`primary_role`):
|
||||
|
||||
* Phone - Top Provisioner
|
||||
* The device that has been provisioned by Phone - Primary Provisioner
|
||||
* Devices that have been provisioned and changed to the role of a provisioner - Temporary Provisioner
|
||||
* Devices that have been provisioned but not changed to the role of a provisioner - Node
|
||||
|
||||
|
||||
#### 2.1.2 Provisioner Address Management
|
||||
|
||||
The provisioner address management is used to assign a unicast address to each node, so as to prevent address conflicts by allocating address in an equally manner. Each provisioner has its own address range and a maximum number of the nodes it can provisioned. The provisioner will allocate a subset of its address range to the nodes it has provisioned.
|
||||
|
||||
Example: A top provisioner's address range is 0 to 100 and the maximum number of nodes it can provisioned is 5. The provisioner address management will assign subsets of address range to these 5 nodes, which are 1 to 20, 21 to 40, 41 to 60, 61 to 80 and 81 to 100.
|
||||
|
||||
The variables that are related to the address management are described in the following table:
|
||||
|
||||
| Variable Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `unicast_min` | Minimum unicast address can be allocated to other nodes |
|
||||
| `unicast_max` | Maximum unicast address can be allocated to other nodes |
|
||||
| `unicast_cur` | Current unicast address |
|
||||
| `unicast_step` | Unicast address change step Offset|
|
||||
|
||||
#### 2.1.3 Provisioner Cache Data
|
||||
|
||||
The cache data is required, so a node can change its role to become a provisioner. During this process, the `esp_ble_mesh_set_fast_prov_info` and `esp_ble_mesh_set_fast_prov_action` APIs are called.
|
||||
|
||||
The node's cache data, which are described in the following table, is sent by the provisioner.
|
||||
|
||||
| Variable Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `flags` |Flags state|
|
||||
| `iv_index` |Iv_index state|
|
||||
| `net_idx` |Netkey index state |
|
||||
| `group_addr` |Subscribed group address |
|
||||
| `prim_prov_addr` |Unicast address of Primary Provisioner |
|
||||
| `match_val[16]` |Match value to be compared with unprovisioned device UUID |
|
||||
| `match_len` | Length of match value to be compared |
|
||||
| `max_node_num` | The maximum number of devices can be provisioned by the Provisioner |
|
||||
| `prov_node_cnt` | Number of self-provisioned nodes |
|
||||
| `app_idx` | AppKey index of the application key added by other Provisioner |
|
||||
| `top_address` | Address of the device(e.g. phone) which triggers fast provisioning |
|
||||
|
||||
|
||||
#### 2.1.4 Provisioner Timer
|
||||
|
||||
There are two timers in this demo, which are:
|
||||
|
||||
1. `gatt_proxy_enable_timer` is used to enable Mesh GATT Proxy functionality.
|
||||
* The timer starts or resets and starts when a Temporary Provisioner provisions an unprovisioned device.
|
||||
* The Temporary Provisioner will send a message (Address information) to the Primary Provisioner.
|
||||
2. `disable_fast_prov_timer` is used to disable the provisioning capabilities.
|
||||
* The node starts the timer when it receives a **Generic OnOff Get/Set/Set Unack** message sent by the EspBleMesh app. The group address should be used if you want to disable the provisioning capabilities of all nodes.
|
||||
|
||||
The variables that are related to these two timers are described below:
|
||||
|
||||
| Variable Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `disable_fast_prov_timer` |Used to disable fast provisioning|
|
||||
| `gatt_proxy_enable_timer` |Used to enable Mesh GATT Proxy functionality|
|
||||
|
||||
### 2.2 Model Definition
|
||||
|
||||
#### 2.2.1 Vendor Server Model
|
||||
|
||||
The **Vendor Server** Model implements the node's `fast_prov_server` state, which has been covered in the previous section.
|
||||
|
||||
```c
|
||||
example_fast_prov_server_t fast_prov_server = {
|
||||
.primary_role = false,
|
||||
.max_node_num = 6,
|
||||
.prov_node_cnt = 0x0,
|
||||
.unicast_min = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_max = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_cur = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.unicast_step = 0x0,
|
||||
.flags = 0x0,
|
||||
.iv_index = 0x0,
|
||||
.net_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.app_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.group_addr = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.prim_prov_addr = ESP_BLE_MESH_ADDR_UNASSIGNED,
|
||||
.match_len = 0x0,
|
||||
.pend_act = FAST_PROV_ACT_NONE,
|
||||
.state = STATE_IDLE,
|
||||
};
|
||||
```
|
||||
|
||||
The `fast_prov_srv_op` is used to register the minimum length of messages. For example, the minimum length of the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message is registered as 3 octets.
|
||||
|
||||
```c
|
||||
static esp_ble_mesh_model_op_t fast_prov_srv_op[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR, 2, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, 0, NULL },
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
```
|
||||
The `example_fast_prov_server_init` function is used to register the callback function triggered when the timers timeout, and initializes the Model-related variables in the data struct.
|
||||
|
||||
```c
|
||||
err = example_fast_prov_server_init(&vnd_models[0]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize fast prov server model", __func__);
|
||||
return err;
|
||||
}
|
||||
```
|
||||
|
||||
The `fast_prov_server` struct represents the Vendor server's states. The `CID_ESP` and `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV` constants, which consist of the vendor server Model's Model id `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV`, are used to identity the Vendor server Model.
|
||||
|
||||
|
||||
```c
|
||||
static esp_ble_mesh_model_t vnd_models[] = {
|
||||
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_SRV,
|
||||
fast_prov_srv_op, NULL, &fast_prov_server),
|
||||
};
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
#### 2.2.2 Vendor Client Model
|
||||
|
||||
The **Vendor Client** Model is used to control the `fast_prov_server` state, which defines the fast provisioning behavior of a node.
|
||||
|
||||
The `fast_prov_cli_op_pair` struct is used to register the corresponding message acknowledgements.
|
||||
|
||||
```c
|
||||
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, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS },
|
||||
};
|
||||
```
|
||||
|
||||
Example: The **Vendor Client** Model sends message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET`, which requires the **Vendor Server** Model to respond with a message with an opcode of `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS`. After that, the **Vendor Client** Model times out if it receives no corresponding acknowledgement.
|
||||
|
||||
```c
|
||||
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 },
|
||||
};
|
||||
```
|
||||
Note that you can also use the code below if you don't want the **Vendor Client** Model to wait for acknowledgement from the server Model, which means the client Model will never time out.
|
||||
|
||||
```c
|
||||
static const esp_ble_mesh_client_op_pair_t fast_prov_cli_op_pair[] = {
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, NULL },
|
||||
};
|
||||
```
|
||||
|
||||
The `esp_ble_mesh_client_model_init` API is used to register the callback function triggered when the timers timeout, and initializes the Model-related variables in the data struct.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_client_model_init(&vnd_models[1]);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Failed to initialize fast prov client Model", __func__);
|
||||
return err;
|
||||
}
|
||||
```
|
||||
|
||||
The `CID_ESP` and `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI` constants, which consist of the vendor client Model's Model id `ESP_BLE_MESH_VND_MODEL_ID_FAST_PROV_CLI`, are used to identity the Vendor client Model.
|
||||
|
||||
```c
|
||||
|
||||
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_VND_MODEL_OP_FAST_PROV_INFO_STATUS, 1, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS, 2, NULL },
|
||||
{ ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK, 0, NULL },
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
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),
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 2.3 Message Opcode
|
||||
|
||||
"Opcode-send" represents the message that the client sends to the server.
|
||||
|
||||
"Opcode-ack" represents the message that the server sends to the client.
|
||||
|
||||
* INFO_SET
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS` |
|
||||
|Function| This message contains all the information as a Provisioner |Checks each field of the Provisioner information and set the corresponding flag bit. The returned status is variable.|
|
||||
|Parameter|structfast_prov_info_set|status_bit_mask, status_ctx_flag, status_unicast, status_net_idx, status_group, status_pri_prov, status_match, status_action|
|
||||
|
||||
|
||||
* NODE_ADDR
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK` |
|
||||
|Function| Temporary Provisioner reports the address of the node it has provisioned. |Used to check if the message was sent successfully. |
|
||||
|Parameter| Address array |NA |
|
||||
|
||||
* ADDR_GET
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode| `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_STATUS` |
|
||||
|Function|Top Provisioner gets the address of all nodes obtained from Primary Provisioner. | Returns the address of all nodes, but does not contain its own. |
|
||||
|Parameter|NA |Address array |
|
||||
|
||||
* NET_KEY_ADD
|
||||
|
||||
|Meaning | Opcode-send | Opcode-ack |
|
||||
| -----| ------------- | -------------|
|
||||
|Opcode | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD` | `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS` |
|
||||
|Function| Reserved for later use | Reserved for later use |
|
||||
|Parameter| NA | NA |
|
||||
|
||||
|
||||
### 2.4 Callback Function
|
||||
#### 2.4.1 The Callback function for the Vendor Server Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
```
|
||||
|
||||
1. The callback function will be triggered when the **Vendor Server** Model:
|
||||
* Receives a message that indicates the Onoff state of the client Model; or
|
||||
* Calls any APIs that send messages.
|
||||
|
||||
2. The events that this callback function handle:
|
||||
|
||||
* Generic Onoff Server Model
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT|ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | This event is triggered when the **Generic Onoff Server** model receives the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT|ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK| This event is triggered when the **Generic Onoff Server** model receives the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK` message. |
|
||||
|
||||
* Vendor Server Model
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET | This event is triggered when the **Vendor Server** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_GET` message.|
|
||||
|
||||
* The **Configuration Client** Model
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
|ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT| NA| This event is triggered when the `esp_ble_mesh_set_fast_prov_info` API is called. |
|
||||
|ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT| NA| This event is triggered when the `esp_ble_mesh_set_fast_prov_action` API is called. |
|
||||
|ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT|ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD|This event is triggered when the **Configuration Server** model receives and further triggers an API calling to send `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET` message. |
|
||||
|ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT|ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD|This event is triggered when the API `example_send_config_appkey_add` times out.|
|
||||
|
||||
#### 2.4.2 The Vendor Client Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
|
||||
```
|
||||
|
||||
1. The callback function will be triggered when the **Vendor Client** model:
|
||||
* Receives any message sent by the vendor server Model; or
|
||||
* Calls any APIs that send messages.
|
||||
|
||||
2. The events that this callback function handle:
|
||||
|
||||
| Event Name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_STATUS` message.|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK | This event is triggered when the **Vendor Client** model receives the `ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR_ACK` message |
|
||||
| ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT | client_send_timeout.opcode | This event is triggered when the API `esp_ble_mesh_client_model_send_msg` times out.|
|
||||
|
||||
### 2.5 Message Sending
|
||||
#### 2.5.1 The Vendor Client sends messages
|
||||
|
||||
The Vendor Client Model calls the `esp_ble_mesh_client_model_send_msg` API to send messages to the Vendor Server Model.
|
||||
|
||||
| Parameter Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `model` | The pointer to the client Model struct |
|
||||
| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent |
|
||||
| `ctx.app_idx` | The AppKey Index for the message encryption |
|
||||
| `ctx.addr` | The address of the destination nodes |
|
||||
| `ctx.send_ttl`| The TTL State, which determines how many times a message can be relayed|
|
||||
| `ctx.send_rel`| This parameter determines whether the Model will wait for an acknowledgment after sending a message |
|
||||
| `opcode` | The message opcode |
|
||||
| `msg->len` | The length of the `msg->data`|
|
||||
| `msg->data` | The pointer to sent data|
|
||||
| `msg_timeout` | The maximum duration (4000 ms by default) that the Model waits for an acknowledgment. |
|
||||
|`true` | True: an acknowledgement is required; False: no acknowledgement is required |
|
||||
| `msg_role` | The role of a message (node/provisioner) |
|
||||
|
||||
```c
|
||||
esp_ble_mesh_msg_ctx_t ctx = {
|
||||
.net_idx = info->net_idx,
|
||||
.app_idx = info->app_idx,
|
||||
.addr = info->dst,
|
||||
.send_rel = false,
|
||||
.send_ttl = 0,
|
||||
};
|
||||
err = esp_ble_mesh_client_model_send_msg(model, &ctx,
|
||||
ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET,
|
||||
msg->len, msg->data, info->timeout, true, info->role);
|
||||
```
|
||||
|
||||
#### 2.5.2 The Vendor Server sends messages
|
||||
|
||||
The **Vendor Server** Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message.
|
||||
|
||||
```c
|
||||
esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_STATUS,
|
||||
msg->len ,msg->data );
|
||||
```
|
||||
The **Vendor Server** Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages.
|
||||
|
||||
```c
|
||||
esp_err_t esp_ble_mesh_model_publish(esp_ble_mesh_model_t *model, uint32_t opcode,
|
||||
uint16_t length, uint8_t *data,
|
||||
esp_ble_mesh_dev_role_t device_role);
|
||||
```
|
||||
|
After Width: | Height: | Size: 178 KiB |
|
After Width: | Height: | Size: 348 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(onoff_client)
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := onoff_client
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,14 @@
|
||||
ESP BLE Mesh Client Model Demo
|
||||
========================
|
||||
|
||||
This demo shows how to use the Generic OnOff Client Model to get/set the generic on/off state. The basic procedures are as follows:
|
||||
|
||||
1. Download and run this demo.
|
||||
2. Use any app for BLE Mesh to provision this device as well as the device running the Generic OnOff Server demo.
|
||||
3. After both onoff client and server devices are provisioned, use UART1 to input the unicast address of the element within the server device.
|
||||
4. The Generic OnOff Client will start to get and set Generic OnOff states periodically.
|
||||
|
||||
>**Notes:**
|
||||
>
|
||||
>1. The NetKey index and AppKey index are fixed to 0x0000 in this demo.
|
||||
>2. If the client device is re-provisioned, but the server device is not, the first few get/set messages from the client will be treated as replay attacks. To avoid this, both devices should be re-provisioned prior to transmitting messages.
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
set(COMPONENT_SRCS "button.c"
|
||||
"button_obj.cpp")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ". include")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,21 @@
|
||||
menu "Button"
|
||||
|
||||
choice BUTTON_TIMER_IMPLEMENT
|
||||
bool "Button Timer Mode"
|
||||
default BUTTON_USE_ESP_TIMER
|
||||
help
|
||||
Choose a implementation of timer for button instance.
|
||||
|
||||
config BUTTON_USE_RTOS_TIMER
|
||||
bool "Use FreeRTOS Timer"
|
||||
|
||||
config BUTTON_USE_ESP_TIMER
|
||||
bool "Use ESP Timer"
|
||||
endchoice
|
||||
|
||||
config BUTTON_IO_GLITCH_FILTER_TIME_MS
|
||||
int "IO glitch filter timer ms (10~100)"
|
||||
range 10 100
|
||||
default 50
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,47 @@
|
||||
# Component: Button
|
||||
|
||||
* This component defines a button as a well encapsulated object.
|
||||
* A button device is defined by:
|
||||
* GPIO number on which the button is attached.
|
||||
* Active level which decided by peripheral hardware.
|
||||
* Trigger mode which decides whether to call serial trigger callback during pressing
|
||||
* Serial threshold seconds which decides that serial trigger callback will be called after how many seconds' pressing
|
||||
* A button device can provide:
|
||||
* One push event callback
|
||||
* One release event callback
|
||||
* One short-time tap event callback
|
||||
* One serial trigger event callback
|
||||
* Several long-time press event callback
|
||||
We can set different jitter filters for all the events.
|
||||
Once any of the long press callback is triggered, the short tap event will not be triggered.
|
||||
This components are based on GPIO provided by idf and soft timer provided by FreeRTOS.
|
||||
|
||||
* To use the button device, you need to :
|
||||
* create a button object returned by iot_button_create().
|
||||
* Then hook different event callbacks to the button object.
|
||||
* To free the object, you can call iot_button_delete to delete the button object and free the memory that used.
|
||||
|
||||
* Todo:
|
||||
* Add hardware timer mode(because sometimes soft-timer callback function is limited)
|
||||
|
||||
### NOTE:
|
||||
> All the event callback function are realized by FreeRTOS soft timer APIs, the callback must follow the rule:
|
||||
|
||||
|
||||
|
||||
```
|
||||
Button callback functions execute in the context of the timer service task.
|
||||
It is therefore essential that button callback functions never attempt to block.
|
||||
For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(), or specify a non zero block time when accessing a queue or a semaphore.
|
||||
```
|
||||
|
||||
> In addition:
|
||||
> You can adjust the following macros within FreeRTOS to adjust the stack depth/queue length/task priority of the timer service.
|
||||
|
||||
|
||||
```
|
||||
#define configUSE_TIMERS //enable soft-timer
|
||||
#define configTIMER_TASK_PRIORITY // priority of the timers service task
|
||||
#define configQueue_LENGTH // length of timer command queue
|
||||
#define configTIMER_TASK_STACK_DEPTH // stack depth of the soft-timer
|
||||
```
|
||||
@@ -0,0 +1,434 @@
|
||||
// Copyright 2015-2016 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "iot_button.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define USE_ESP_TIMER CONFIG_BUTTON_USE_ESP_TIMER
|
||||
#if USE_ESP_TIMER
|
||||
#define STOP_TIMER(tmr) esp_timer_stop(tmr)
|
||||
#define DELETE_TIMER(tmr) esp_timer_delete(tmr)
|
||||
#else
|
||||
#define STOP_TIMER(tmr) xTimerStop(tmr, portMAX_DELAY)
|
||||
#define DELETE_TIMER(tmr) xTimerDelete(tmr, portMAX_DELAY);
|
||||
#endif
|
||||
|
||||
#define IOT_CHECK(tag, a, ret) if(!(a)) { \
|
||||
ESP_LOGE(tag,"%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__); \
|
||||
return (ret); \
|
||||
}
|
||||
#define ERR_ASSERT(tag, param) IOT_CHECK(tag, (param) == ESP_OK, ESP_FAIL)
|
||||
#define POINT_ASSERT(tag, param, ret) IOT_CHECK(tag, (param) != NULL, (ret))
|
||||
|
||||
typedef enum {
|
||||
BUTTON_STATE_IDLE = 0,
|
||||
BUTTON_STATE_PUSH,
|
||||
BUTTON_STATE_PRESSED,
|
||||
} button_status_t;
|
||||
|
||||
typedef struct button_dev button_dev_t;
|
||||
typedef struct btn_cb button_cb_t;
|
||||
|
||||
struct btn_cb{
|
||||
TickType_t interval;
|
||||
button_cb cb;
|
||||
void* arg;
|
||||
#if !USE_ESP_TIMER
|
||||
TimerHandle_t tmr;
|
||||
#else
|
||||
esp_timer_handle_t tmr;
|
||||
#endif
|
||||
button_dev_t *pbtn;
|
||||
button_cb_t *next_cb;
|
||||
};
|
||||
|
||||
struct button_dev{
|
||||
uint8_t io_num;
|
||||
uint8_t active_level;
|
||||
uint32_t serial_thres_sec;
|
||||
button_status_t state;
|
||||
button_cb_t tap_short_cb;
|
||||
button_cb_t tap_psh_cb;
|
||||
button_cb_t tap_rls_cb;
|
||||
button_cb_t press_serial_cb;
|
||||
button_cb_t* cb_head;
|
||||
};
|
||||
|
||||
#define BUTTON_GLITCH_FILTER_TIME_MS CONFIG_BUTTON_IO_GLITCH_FILTER_TIME_MS
|
||||
static const char* TAG = "button";
|
||||
|
||||
// static void button_press_cb(xTimerHandle tmr)
|
||||
static void button_press_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_cb_t* btn_cb = (button_cb_t*)(tmr);
|
||||
#endif
|
||||
|
||||
button_dev_t* btn = btn_cb->pbtn;
|
||||
// low, then restart
|
||||
if (btn->active_level == gpio_get_level(btn->io_num)) {
|
||||
btn->state = BUTTON_STATE_PRESSED;
|
||||
if (btn_cb->cb) {
|
||||
btn_cb->cb(btn_cb->arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static void button_tap_psh_cb(xTimerHandle tmr)
|
||||
static void button_tap_psh_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_cb_t* btn_cb = (button_cb_t*)(tmr);
|
||||
#endif
|
||||
|
||||
button_dev_t* btn = btn_cb->pbtn;
|
||||
STOP_TIMER(btn->tap_rls_cb.tmr);
|
||||
|
||||
int lv = gpio_get_level(btn->io_num);
|
||||
|
||||
if (btn->active_level == lv) {
|
||||
// high, then key is up
|
||||
btn->state = BUTTON_STATE_PUSH;
|
||||
if (btn->press_serial_cb.tmr) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
|
||||
xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
|
||||
#else
|
||||
esp_timer_stop(btn->press_serial_cb.tmr);
|
||||
esp_timer_start_once(btn->press_serial_cb.tmr, btn->serial_thres_sec * 1000 * 1000);
|
||||
#endif
|
||||
|
||||
}
|
||||
if (btn->tap_psh_cb.cb) {
|
||||
btn->tap_psh_cb.cb(btn->tap_psh_cb.arg);
|
||||
}
|
||||
} else {
|
||||
// 50ms, check if this is a real key up
|
||||
if (btn->tap_rls_cb.tmr) {
|
||||
STOP_TIMER(btn->tap_rls_cb.tmr);
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerReset(btn->tap_rls_cb.tmr, portMAX_DELAY);
|
||||
#else
|
||||
esp_timer_start_once(btn->tap_rls_cb.tmr, btn->tap_rls_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void button_tap_rls_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_cb_t* btn_cb = (button_cb_t*)(tmr);
|
||||
#endif
|
||||
button_dev_t* btn = btn_cb->pbtn;
|
||||
STOP_TIMER(btn->tap_rls_cb.tmr);
|
||||
|
||||
if (btn->active_level == gpio_get_level(btn->io_num)) {
|
||||
|
||||
} else {
|
||||
// high, then key is up
|
||||
button_cb_t *pcb = btn->cb_head;
|
||||
while (pcb != NULL) {
|
||||
if (pcb->tmr != NULL) {
|
||||
STOP_TIMER(pcb->tmr);
|
||||
}
|
||||
pcb = pcb->next_cb;
|
||||
}
|
||||
if (btn->press_serial_cb.tmr && btn->press_serial_cb.tmr != NULL) {
|
||||
STOP_TIMER(btn->press_serial_cb.tmr);
|
||||
}
|
||||
if (btn->tap_short_cb.cb && btn->state == BUTTON_STATE_PUSH) {
|
||||
btn->tap_short_cb.cb(btn->tap_short_cb.arg);
|
||||
}
|
||||
if(btn->tap_rls_cb.cb && btn->state != BUTTON_STATE_IDLE) {
|
||||
btn->tap_rls_cb.cb(btn->tap_rls_cb.arg);
|
||||
}
|
||||
btn->state = BUTTON_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void button_press_serial_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_dev_t* btn = (button_dev_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_dev_t* btn = (button_dev_t*)(tmr);
|
||||
#endif
|
||||
|
||||
if (btn->press_serial_cb.cb) {
|
||||
btn->press_serial_cb.cb(btn->press_serial_cb.arg);
|
||||
}
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->press_serial_cb.interval, portMAX_DELAY);
|
||||
xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
|
||||
#else
|
||||
esp_timer_stop(btn->press_serial_cb.tmr);
|
||||
esp_timer_start_once(btn->press_serial_cb.tmr, btn->press_serial_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void button_gpio_isr_handler(void* arg)
|
||||
{
|
||||
button_dev_t* btn = (button_dev_t*) arg;
|
||||
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
||||
int level = gpio_get_level(btn->io_num);
|
||||
if (level == btn->active_level) {
|
||||
if (btn->tap_psh_cb.tmr) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerStopFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
|
||||
xTimerResetFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
|
||||
#else
|
||||
esp_timer_stop(btn->tap_psh_cb.tmr);
|
||||
esp_timer_start_once(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
button_cb_t *pcb = btn->cb_head;
|
||||
while (pcb != NULL) {
|
||||
if (pcb->tmr != NULL) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerStopFromISR(pcb->tmr, &HPTaskAwoken);
|
||||
xTimerResetFromISR(pcb->tmr, &HPTaskAwoken);
|
||||
#else
|
||||
esp_timer_stop(pcb->tmr);
|
||||
esp_timer_start_once(pcb->tmr, pcb->interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
pcb = pcb->next_cb;
|
||||
}
|
||||
} else {
|
||||
// 50ms, check if this is a real key up
|
||||
if (btn->tap_rls_cb.tmr) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerStopFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
|
||||
xTimerResetFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
|
||||
#else
|
||||
esp_timer_stop(btn->tap_rls_cb.tmr);
|
||||
esp_timer_start_once(btn->tap_rls_cb.tmr, btn->tap_rls_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
#if !USE_ESP_TIMER
|
||||
static void button_free_tmr(xTimerHandle* tmr)
|
||||
#else
|
||||
static void button_free_tmr(esp_timer_handle_t *tmr)
|
||||
#endif
|
||||
{
|
||||
if (tmr && *tmr) {
|
||||
STOP_TIMER(*tmr);
|
||||
DELETE_TIMER(*tmr);
|
||||
*tmr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t iot_button_delete(button_handle_t btn_handle)
|
||||
{
|
||||
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
gpio_set_intr_type(btn->io_num, GPIO_INTR_DISABLE);
|
||||
gpio_isr_handler_remove(btn->io_num);
|
||||
|
||||
button_free_tmr(&btn->tap_rls_cb.tmr);
|
||||
button_free_tmr(&btn->tap_psh_cb.tmr);
|
||||
button_free_tmr(&btn->tap_short_cb.tmr);
|
||||
button_free_tmr(&btn->press_serial_cb.tmr);
|
||||
|
||||
button_cb_t *pcb = btn->cb_head;
|
||||
while (pcb != NULL) {
|
||||
button_cb_t *cb_next = pcb->next_cb;
|
||||
button_free_tmr(&pcb->tmr);
|
||||
free(pcb);
|
||||
pcb = cb_next;
|
||||
}
|
||||
free(btn);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level)
|
||||
{
|
||||
#if USE_ESP_TIMER
|
||||
ets_printf("use esp timer !!!\n");
|
||||
esp_timer_init();
|
||||
#endif
|
||||
|
||||
IOT_CHECK(TAG, gpio_num < GPIO_NUM_MAX, NULL);
|
||||
button_dev_t* btn = (button_dev_t*) calloc(1, sizeof(button_dev_t));
|
||||
POINT_ASSERT(TAG, btn, NULL);
|
||||
btn->active_level = active_level;
|
||||
btn->io_num = gpio_num;
|
||||
btn->state = BUTTON_STATE_IDLE;
|
||||
btn->tap_rls_cb.arg = NULL;
|
||||
btn->tap_rls_cb.cb = NULL;
|
||||
btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
|
||||
btn->tap_rls_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
btn->tap_rls_cb.tmr = xTimerCreate("btn_rls_tmr", btn->tap_rls_cb.interval, pdFALSE,
|
||||
&btn->tap_rls_cb, button_tap_rls_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_rls;
|
||||
tmr_param_rls.arg = &btn->tap_rls_cb;
|
||||
tmr_param_rls.callback = button_tap_rls_cb;
|
||||
tmr_param_rls.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_rls.name = "btn_rls_tmr";
|
||||
esp_timer_create(&tmr_param_rls, &btn->tap_rls_cb.tmr);
|
||||
#endif
|
||||
|
||||
btn->tap_psh_cb.arg = NULL;
|
||||
btn->tap_psh_cb.cb = NULL;
|
||||
btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
|
||||
btn->tap_psh_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
btn->tap_psh_cb.tmr = xTimerCreate("btn_psh_tmr", btn->tap_psh_cb.interval, pdFALSE,
|
||||
&btn->tap_psh_cb, button_tap_psh_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_psh;
|
||||
tmr_param_psh.arg = &btn->tap_psh_cb;
|
||||
tmr_param_psh.callback = button_tap_psh_cb;
|
||||
tmr_param_psh.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_psh.name = "btn_psh_tmr";
|
||||
esp_timer_create(&tmr_param_psh, &btn->tap_psh_cb.tmr);
|
||||
#endif
|
||||
gpio_install_isr_service(0);
|
||||
gpio_config_t gpio_conf;
|
||||
gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
|
||||
gpio_conf.mode = GPIO_MODE_INPUT;
|
||||
gpio_conf.pin_bit_mask = (1ULL << gpio_num);
|
||||
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&gpio_conf);
|
||||
gpio_isr_handler_add(gpio_num, button_gpio_isr_handler, btn);
|
||||
return (button_handle_t) btn;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type)
|
||||
{
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
button_cb_t* btn_cb = NULL;
|
||||
if (type == BUTTON_CB_PUSH) {
|
||||
btn_cb = &btn->tap_psh_cb;
|
||||
} else if (type == BUTTON_CB_RELEASE) {
|
||||
btn_cb = &btn->tap_rls_cb;
|
||||
} else if (type == BUTTON_CB_TAP) {
|
||||
btn_cb = &btn->tap_short_cb;
|
||||
} else if (type == BUTTON_CB_SERIAL) {
|
||||
btn_cb = &btn->press_serial_cb;
|
||||
}
|
||||
btn_cb->cb = NULL;
|
||||
btn_cb->arg = NULL;
|
||||
btn_cb->pbtn = btn;
|
||||
button_free_tmr(&btn_cb->tmr);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg)
|
||||
{
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
btn->serial_thres_sec = start_after_sec;
|
||||
|
||||
if (btn->press_serial_cb.tmr == NULL) {
|
||||
#if !USE_ESP_TIMER
|
||||
btn->press_serial_cb.tmr = xTimerCreate("btn_serial_tmr", btn->serial_thres_sec*1000 / portTICK_PERIOD_MS,
|
||||
pdFALSE, btn, button_press_serial_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_ser;
|
||||
tmr_param_ser.arg = btn;
|
||||
tmr_param_ser.callback = button_press_serial_cb;
|
||||
tmr_param_ser.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_ser.name = "btn_serial_tmr";
|
||||
esp_timer_create(&tmr_param_ser, &btn->press_serial_cb.tmr);
|
||||
#endif
|
||||
}
|
||||
btn->press_serial_cb.arg = arg;
|
||||
btn->press_serial_cb.cb = cb;
|
||||
btn->press_serial_cb.interval = interval_tick;
|
||||
btn->press_serial_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg)
|
||||
{
|
||||
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
if (type == BUTTON_CB_PUSH) {
|
||||
btn->tap_psh_cb.arg = arg;
|
||||
btn->tap_psh_cb.cb = cb;
|
||||
btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
|
||||
btn->tap_psh_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
|
||||
#endif
|
||||
} else if (type == BUTTON_CB_RELEASE) {
|
||||
btn->tap_rls_cb.arg = arg;
|
||||
btn->tap_rls_cb.cb = cb;
|
||||
btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
|
||||
btn->tap_rls_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->tap_rls_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
|
||||
#endif
|
||||
} else if (type == BUTTON_CB_TAP) {
|
||||
btn->tap_short_cb.arg = arg;
|
||||
btn->tap_short_cb.cb = cb;
|
||||
btn->tap_short_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
|
||||
btn->tap_short_cb.pbtn = btn;
|
||||
} else if (type == BUTTON_CB_SERIAL) {
|
||||
iot_button_set_serial_cb(btn_handle, 1, 1000 / portTICK_RATE_MS, cb, arg);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg)
|
||||
{
|
||||
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
|
||||
IOT_CHECK(TAG, press_sec != 0, ESP_ERR_INVALID_ARG);
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
button_cb_t* cb_new = (button_cb_t*) calloc(1, sizeof(button_cb_t));
|
||||
POINT_ASSERT(TAG, cb_new, ESP_FAIL);
|
||||
cb_new->arg = arg;
|
||||
cb_new->cb = cb;
|
||||
cb_new->interval = press_sec * 1000 / portTICK_PERIOD_MS;
|
||||
cb_new->pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
cb_new->tmr = xTimerCreate("btn_press_tmr", cb_new->interval, pdFALSE, cb_new, button_press_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_cus;
|
||||
tmr_param_cus.arg = cb_new;
|
||||
tmr_param_cus.callback = button_press_cb;
|
||||
tmr_param_cus.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_cus.name = "btn_press_custom_tmr";
|
||||
esp_timer_create(&tmr_param_cus, &cb_new->tmr);
|
||||
#endif
|
||||
cb_new->next_cb = btn->cb_head;
|
||||
btn->cb_head = cb_new;
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015-2016 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "iot_button.h"
|
||||
|
||||
CButton::CButton(gpio_num_t gpio_num, button_active_t active_level)
|
||||
{
|
||||
m_btn_handle = iot_button_create(gpio_num, active_level);
|
||||
}
|
||||
|
||||
CButton::~CButton()
|
||||
{
|
||||
iot_button_delete(m_btn_handle);
|
||||
m_btn_handle = NULL;
|
||||
}
|
||||
|
||||
esp_err_t CButton::set_evt_cb(button_cb_type_t type, button_cb cb, void* arg)
|
||||
{
|
||||
return iot_button_set_evt_cb(m_btn_handle, type, cb, arg);
|
||||
}
|
||||
|
||||
esp_err_t CButton::set_serial_cb(button_cb cb, void* arg, TickType_t interval_tick, uint32_t start_after_sec)
|
||||
{
|
||||
return iot_button_set_serial_cb(m_btn_handle, start_after_sec, interval_tick, cb, arg);
|
||||
}
|
||||
|
||||
esp_err_t CButton::add_custom_cb(uint32_t press_sec, button_cb cb, void* arg)
|
||||
{
|
||||
return iot_button_add_custom_cb(m_btn_handle, press_sec, cb, arg);
|
||||
}
|
||||
|
||||
esp_err_t CButton::rm_cb(button_cb_type_t type)
|
||||
{
|
||||
return iot_button_rm_cb(m_btn_handle, type);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,230 @@
|
||||
// Copyright 2015-2016 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.
|
||||
#ifndef _IOT_BUTTON_H_
|
||||
#define _IOT_BUTTON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/portmacro.h"
|
||||
typedef void (* button_cb)(void*);
|
||||
typedef void* button_handle_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_ACTIVE_HIGH = 1, /*!<button active level: high level*/
|
||||
BUTTON_ACTIVE_LOW = 0, /*!<button active level: low level*/
|
||||
} button_active_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_CB_PUSH = 0, /*!<button push callback event */
|
||||
BUTTON_CB_RELEASE, /*!<button release callback event */
|
||||
BUTTON_CB_TAP, /*!<button quick tap callback event(will not trigger if there already is a "PRESS" event) */
|
||||
BUTTON_CB_SERIAL, /*!<button serial trigger callback event */
|
||||
} button_cb_type_t;
|
||||
|
||||
/**
|
||||
* @brief Init button functions
|
||||
*
|
||||
* @param gpio_num GPIO index of the pin that the button uses
|
||||
* @param active_level button hardware active level.
|
||||
* For "BUTTON_ACTIVE_LOW" it means when the button pressed, the GPIO will read low level.
|
||||
*
|
||||
* @return A button_handle_t handle to the created button object, or NULL in case of error.
|
||||
*/
|
||||
button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level);
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a serial trigger event.
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @start_after_sec define the time after which to start serial trigger action
|
||||
* @interval_tick serial trigger interval
|
||||
* @cb callback function for "TAP" action.
|
||||
* @arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a button_cb_type_t action.
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @param type callback function type
|
||||
* @param cb callback function for "TAP" action.
|
||||
* @param arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @param press_sec the callback function would be called if you press the button for a specified period of time
|
||||
* @param cb callback function for "PRESS" action.
|
||||
* @param arg Parameter for callback function
|
||||
*
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Delete button object and free memory
|
||||
* @param btn_handle handle of the button object
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_delete(button_handle_t btn_handle);
|
||||
|
||||
/**
|
||||
* @brief Remove callback
|
||||
*
|
||||
* @param btn_handle The handle of the button object
|
||||
* @param type callback function event type
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/**
|
||||
* class of button
|
||||
* simple usage:
|
||||
* CButton* btn = new CButton(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL, BUTTON_SERIAL_TRIGGER, 3);
|
||||
* btn->add_cb(BUTTON_CB_PUSH, button_tap_cb, (void*) push, 50 / portTICK_PERIOD_MS);
|
||||
* btn->add_custom_cb(5, button_press_5s_cb, NULL);
|
||||
* ......
|
||||
* delete btn;
|
||||
*/
|
||||
class CButton
|
||||
{
|
||||
private:
|
||||
button_handle_t m_btn_handle;
|
||||
|
||||
/**
|
||||
* prevent copy constructing
|
||||
*/
|
||||
CButton(const CButton&);
|
||||
CButton& operator = (const CButton&);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor of CButton
|
||||
*
|
||||
* @param gpio_num GPIO index of the pin that the button uses
|
||||
* @param active_level button hardware active level.
|
||||
* For "BUTTON_ACTIVE_LOW" it means when the button pressed, the GPIO will read low level.
|
||||
*/
|
||||
CButton(gpio_num_t gpio_num, button_active_t active_level = BUTTON_ACTIVE_LOW);
|
||||
|
||||
~CButton();
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a button_cb_type_t action.
|
||||
*
|
||||
* @param type callback function type
|
||||
* @param cb callback function for "TAP" action.
|
||||
* @param arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t set_evt_cb(button_cb_type_t type, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a serial trigger event.
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @start_after_sec define the time after which to start serial trigger action
|
||||
* @interval_tick serial trigger interval
|
||||
* @cb callback function for "TAP" action.
|
||||
* @arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t set_serial_cb(button_cb cb, void* arg, TickType_t interval_tick, uint32_t start_after_sec);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param press_sec the callback function would be called if you press the button for a specified period of time
|
||||
* @param cb callback function for "PRESS" action.
|
||||
* @param arg Parameter for callback function
|
||||
*
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t add_custom_cb(uint32_t press_sec, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Remove callback
|
||||
*
|
||||
* @param type callback function event type
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rm_cb(button_cb_type_t type);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
|
||||
"ble_mesh_demo_init.c"
|
||||
"board.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,22 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice BLE_MESH_EXAMPLE_BOARD
|
||||
prompt "Board selection for BLE Mesh"
|
||||
default BLE_MESH_ESP_WROOM_32
|
||||
help
|
||||
Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32
|
||||
|
||||
config BLE_MESH_ESP_WROOM_32
|
||||
bool "ESP32-WROOM-32"
|
||||
|
||||
config BLE_MESH_ESP_WROVER
|
||||
bool "ESP32-WROVER"
|
||||
endchoice
|
||||
|
||||
config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0
|
||||
bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0"
|
||||
default y
|
||||
help
|
||||
It is an ad hoc solution and needs further modifications.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,143 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sdkconfig.h>
|
||||
/* BLE */
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
static SemaphoreHandle_t mesh_sem;
|
||||
static uint8_t own_addr_type;
|
||||
void ble_store_config_init(void);
|
||||
static uint8_t addr_val[6] = {0};
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
static void mesh_on_reset(int reason)
|
||||
{
|
||||
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
|
||||
}
|
||||
|
||||
static void mesh_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
xSemaphoreGive(mesh_sem);
|
||||
}
|
||||
|
||||
void mesh_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
mesh_sem = xSemaphoreCreateBinary();
|
||||
if (mesh_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create mesh semaphore");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
|
||||
|
||||
nimble_port_init();
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = mesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = mesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(mesh_host_task);
|
||||
|
||||
xSemaphoreTake(mesh_sem, portMAX_DELAY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_MESH_DEMO_INIT_H_
|
||||
#define _BLE_MESH_DEMO_INIT_H_
|
||||
|
||||
#define TAG "onoff_client"
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
|
||||
|
||||
esp_err_t bluetooth_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,272 @@
|
||||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.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 "board.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
|
||||
#define CID_ESP 0x02E5
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
static uint16_t node_net_idx = ESP_BLE_MESH_KEY_UNUSED;
|
||||
static uint16_t node_app_idx = ESP_BLE_MESH_KEY_UNUSED;
|
||||
static uint8_t remote_onoff = LED_OFF;
|
||||
static uint8_t msg_tid = 0x0;
|
||||
|
||||
/* The remote node address shall be input through UART1, see board.c */
|
||||
uint16_t remote_addr = ESP_BLE_MESH_ADDR_UNASSIGNED;
|
||||
|
||||
static esp_ble_mesh_client_t onoff_client;
|
||||
|
||||
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 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, ROLE_NODE);
|
||||
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_comp_t composition = {
|
||||
.cid = CID_ESP,
|
||||
.elements = elements,
|
||||
.element_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
static esp_ble_mesh_prov_t provision = {
|
||||
.uuid = dev_uuid,
|
||||
#if 0
|
||||
.output_size = 4,
|
||||
.output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
|
||||
.input_actions = ESP_BLE_MESH_PUSH,
|
||||
.input_size = 4,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
||||
{
|
||||
ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr);
|
||||
ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index);
|
||||
board_led_operation(LED_G, LED_OFF);
|
||||
node_net_idx = net_idx;
|
||||
}
|
||||
|
||||
static void example_ble_mesh_provisioning_cb(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_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
|
||||
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
|
||||
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
|
||||
prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
|
||||
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void example_ble_mesh_send_gen_onoff_set(void)
|
||||
{
|
||||
esp_ble_mesh_generic_client_set_state_t set = {0};
|
||||
esp_ble_mesh_client_common_param_t common = {0};
|
||||
esp_err_t err;
|
||||
|
||||
common.opcode = ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK;
|
||||
common.model = onoff_client.model;
|
||||
common.ctx.net_idx = node_net_idx;
|
||||
common.ctx.app_idx = node_app_idx;
|
||||
common.ctx.addr = 0xFFFF; /* to all nodes */
|
||||
common.ctx.send_ttl = 3;
|
||||
common.ctx.send_rel = false;
|
||||
common.msg_timeout = 0; /* 0 indicates that timeout value from menuconfig will be used */
|
||||
common.msg_role = ROLE_NODE;
|
||||
|
||||
set.onoff_set.op_en = false;
|
||||
set.onoff_set.onoff = remote_onoff;
|
||||
set.onoff_set.tid = msg_tid++;
|
||||
|
||||
err = esp_ble_mesh_generic_client_set_state(&common, &set);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
|
||||
} else {
|
||||
remote_onoff = !remote_onoff;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event,
|
||||
esp_ble_mesh_generic_client_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "%s: event is %d, error code is %d, opcode is 0x%x",
|
||||
__func__, event, param->error_code, param->params->opcode);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT");
|
||||
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) {
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, onoff %d", param->status_cb.onoff_status.present_onoff);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT");
|
||||
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, onoff %d", param->status_cb.onoff_status.present_onoff);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT");
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT");
|
||||
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
/* If failed to get the response of Generic OnOff Set, resend Generic OnOff Set */
|
||||
example_ble_mesh_send_gen_onoff_set();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
|
||||
esp_ble_mesh_cfg_server_cb_param_t *param)
|
||||
{
|
||||
if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
|
||||
switch (param->ctx.recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
|
||||
ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
|
||||
param->value.state_change.appkey_add.net_idx,
|
||||
param->value.state_change.appkey_add.app_idx);
|
||||
ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
|
||||
ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
||||
param->value.state_change.mod_app_bind.element_addr,
|
||||
param->value.state_change.mod_app_bind.app_idx,
|
||||
param->value.state_change.mod_app_bind.company_id,
|
||||
param->value.state_change.mod_app_bind.model_id);
|
||||
if (param->value.state_change.mod_app_bind.company_id == 0xFFFF &&
|
||||
param->value.state_change.mod_app_bind.model_id == ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI) {
|
||||
node_app_idx = param->value.state_change.mod_app_bind.app_idx;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err = 0;
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
esp_ble_mesh_register_generic_client_callback(example_ble_mesh_generic_client_cb);
|
||||
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
||||
|
||||
err = esp_ble_mesh_init(&provision, &composition);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
||||
|
||||
ESP_LOGI(TAG, "BLE Mesh Node initialized");
|
||||
|
||||
board_led_operation(LED_G, LED_ON);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing...");
|
||||
|
||||
board_init();
|
||||
|
||||
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, "Bluetooth mesh init failed (err %d)", err);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/* board.c - Board-specific hooks */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "iot_button.h"
|
||||
#include "board.h"
|
||||
|
||||
#define TAG "BOARD"
|
||||
|
||||
#define BUTTON_IO_NUM 0
|
||||
#define BUTTON_ACTIVE_LEVEL 0
|
||||
|
||||
extern void example_ble_mesh_send_gen_onoff_set(void);
|
||||
|
||||
struct _led_state led_state[3] = {
|
||||
{ LED_OFF, LED_OFF, LED_R, "red" },
|
||||
{ LED_OFF, LED_OFF, LED_G, "green" },
|
||||
{ LED_OFF, LED_OFF, LED_B, "blue" },
|
||||
};
|
||||
|
||||
void board_led_operation(uint8_t pin, uint8_t onoff)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(led_state); i++) {
|
||||
if (led_state[i].pin != pin) {
|
||||
continue;
|
||||
}
|
||||
if (onoff == led_state[i].previous) {
|
||||
ESP_LOGW(TAG, "led %s is already %s",
|
||||
led_state[i].name, (onoff ? "on" : "off"));
|
||||
return;
|
||||
}
|
||||
gpio_set_level(pin, onoff);
|
||||
led_state[i].previous = onoff;
|
||||
return;
|
||||
}
|
||||
ESP_LOGE(TAG, "LED is not found!");
|
||||
}
|
||||
|
||||
static void board_led_init(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(led_state); i++) {
|
||||
gpio_pad_select_gpio(led_state[i].pin);
|
||||
gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(led_state[i].pin, LED_OFF);
|
||||
led_state[i].previous = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void button_tap_cb(void* arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "tap cb (%s)", (char *)arg);
|
||||
|
||||
example_ble_mesh_send_gen_onoff_set();
|
||||
}
|
||||
|
||||
static void board_button_init(void)
|
||||
{
|
||||
button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL);
|
||||
if (btn_handle) {
|
||||
iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE");
|
||||
}
|
||||
}
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
board_led_init();
|
||||
board_button_init();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* board.h - Board-specific hooks */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
|
||||
#if defined(CONFIG_BLE_MESH_ESP_WROOM_32)
|
||||
#define LED_R GPIO_NUM_25
|
||||
#define LED_G GPIO_NUM_26
|
||||
#define LED_B GPIO_NUM_27
|
||||
#elif defined(CONFIG_BLE_MESH_ESP_WROVER)
|
||||
#define LED_R GPIO_NUM_0
|
||||
#define LED_G GPIO_NUM_2
|
||||
#define LED_B GPIO_NUM_4
|
||||
#endif
|
||||
|
||||
#define LED_ON 1
|
||||
#define LED_OFF 0
|
||||
|
||||
struct _led_state {
|
||||
uint8_t current;
|
||||
uint8_t previous;
|
||||
uint8_t pin;
|
||||
char *name;
|
||||
};
|
||||
|
||||
void board_led_operation(uint8_t pin, uint8_t onoff);
|
||||
|
||||
void board_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
@@ -0,0 +1,24 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=
|
||||
CONFIG_BTDM_CONTROLLER_MODE_BTDM=
|
||||
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
|
||||
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
|
||||
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
|
||||
CONFIG_BTDM_CONTROLLER_FULL_SCAN_SUPPORTED=y
|
||||
CONFIG_BLUEDROID_ENABLED=y
|
||||
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BLE_SMP_ENABLE=n
|
||||
CONFIG_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
# Override some defaults of ESP BLE Mesh
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
|
||||
CONFIG_BLE_MESH_TX_SEG_MAX=32
|
||||
CONFIG_BLE_MESH_TRACE_LEVEL_WARNING=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,252 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
1. This demo forwards the message sent by the nRF Mesh app.
|
||||
2. The user enters the address of the destination node and use it to forwarded packet.
|
||||
3. The types of the forwarded message include:
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET`,
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET`,
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK`.
|
||||
4. The destination node reports its Onoff state with the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS` message.
|
||||
|
||||
Example: The nRF Mesh app sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the node that runs the `ble_mesh_client_model` project. Then this node sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the destination node that runs the `ble_mesh_node` project. The address of the destination node is entered by the user via the serial port.
|
||||
|
||||
## 1.1.1 What You Need
|
||||
|
||||
* 1 x Device that runs the `ble_mesh_client_model` project.
|
||||
* 1 x Device that runs the `ble_mesh_node` project.
|
||||
* 1 x Phone that installs the nRF Mesh app for controlling these two devices
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, in which the following three Models are implemented:
|
||||
|
||||
- **Configuration Server Model** is mainly to represent a mesh network configuration, such as its AppKey, Relay State, TTL State, Subscription List State, etc.
|
||||
- **Generic OnOff Client Model** controls a Generic OnOff Server via messages defined by the Generic OnOff Model, that is, turning on and off the lights.
|
||||
- **Generic OnOff Server Model** implements the nodes' Onoff state.
|
||||
|
||||
## 1.3 Message Sequence
|
||||
|
||||
You can choose from the 4 message sequences described below:
|
||||
|
||||
1. Acknowledged Get
|
||||
2. Acknowledged Set
|
||||
3. Unacknowledged Set
|
||||
4. Acknowledged Set with Periodic Publishing
|
||||
|
||||

|
||||
|
||||
## 2. Code Analysis
|
||||
|
||||
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
|
||||
|
||||
### 2.1 Model Definition
|
||||
|
||||
#### 2.1.1 Generic OnOff Server Model
|
||||
|
||||
```c
|
||||
//Allocating memory for publishing messages.
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_srv_pub, 2 + 1, MSG_ROLE);
|
||||
//Registering the minimum length of messages. For example, the minimum length of the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message is registered as 2 octets.
|
||||
static esp_ble_mesh_model_op_t onoff_op[] = {
|
||||
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0, 0},
|
||||
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2, 0},
|
||||
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, 0},
|
||||
ESP_BLE_MESH_MODEL_OP_END,
|
||||
};
|
||||
//Registering the Generic Onoff Server Model.
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
//onoff server's onoff state init
|
||||
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
|
||||
&onoff_srv_pub, &led_state[0]),
|
||||
};
|
||||
```
|
||||
#### 2.1.2 Generic OnOff Client Model
|
||||
|
||||
```c
|
||||
//Allocating memory for publishing messages.
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, MSG_ROLE);
|
||||
//Registering the Generic Onoff Client Model.
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client),
|
||||
};
|
||||
```
|
||||
|
||||
### 2.2 Model Callback Function
|
||||
|
||||
#### 2.2.1 The Callback function for the Generic Onoff Client Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb);
|
||||
|
||||
```
|
||||
1. The callback function will be triggered when the Client Model:
|
||||
|
||||
* Receives a message that indicates the Onoff state of the Sever Model; Or
|
||||
* Calls any APIs that the Server Model send messages.
|
||||
|
||||
2. The events that the callback function handle:
|
||||
|
||||
| Event name | Opcode |Description |
|
||||
| ------------- | ------------|------------------------------------------- |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET |The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET` message |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT | NA | The event triggered when the Generic Onoff Client Model receives publishing messages. |
|
||||
| ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when API (that send messages) calling times out |
|
||||
|
||||
|
||||
#### 2.2.2 The Callback function for the Generic Onoff Server Model
|
||||
|
||||
```c
|
||||
esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb);
|
||||
|
||||
```
|
||||
1. The callback function will be triggered when the Server Model:
|
||||
|
||||
* Receives a message that indicates operating the Onoff state of the Server Model from the Generic Onoff Client Model; Or
|
||||
* Calls any APIs that the Server Model send messages.
|
||||
|
||||
2. The events of the callback function:
|
||||
|
||||
| Event Name | Opcode | Description |
|
||||
|-------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET message that **gets** the Onoff state of the server from the Client Model |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message that **sets** the Onoff state of the server from the Client Model |
|
||||
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK message that **sets** the Onoff state of the server from the Client Model |
|
||||
| ESP_BLE_MESH_MODEL_SEND_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_server_model_send_msg` API calling completes |
|
||||
| ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_model_publish` API calling completes |
|
||||
|
||||
|
||||
### 2.3 Model that Sends Message
|
||||
#### 2.3.1 Message Control
|
||||
|
||||
The `esp_ble_mesh_set_msg_common` function is used to set the message controlling parameters.
|
||||
|
||||
| Parameter Name |Description |
|
||||
| ----------------------|------------------------- |
|
||||
| `opcode` | The message opcode |
|
||||
| `model` | The pointer to the client Model struct |
|
||||
| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent |
|
||||
| `ctx.app_idx` | The AppKey Index for message encryption |
|
||||
| `ctx.addr` | The address of the destination nodes |
|
||||
| `ctx.send_ttl`| The TTL State, which determines how many times a message will be relayed |
|
||||
| `ctx.send_rel`| This parameter determines if the Model will wait for an acknowledgement after sending a message |
|
||||
| `msg_timeout` | The maximum time the Model will wait for an acknowledgement |
|
||||
| `msg_role` | The role of message (node/provisioner) |
|
||||
|
||||
> Note:
|
||||
>
|
||||
> Please check the `ESP_BLE_MESH_MODEL_SEND_COMP_EVT` event to see if the message is sent successfully.
|
||||
> This event is just for sending sig Model and vendor Model messages, not for all Models.
|
||||
|
||||
#### 2.3.2 The Generic Onoff Client sends message
|
||||
|
||||
The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_get_state` API to get the state of the server Model, such as the Onoff state.
|
||||
|
||||
```c
|
||||
esp_ble_mesh_generic_client_get_state_t get_state = {0};
|
||||
esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET);
|
||||
err = esp_ble_mesh_generic_client_get_state(&common, &get_state);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_set_state` API to set the state of the server Model, such as the Onoff state.
|
||||
|
||||
```c
|
||||
esp_ble_mesh_generic_client_set_state_t set_state = {0};
|
||||
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
|
||||
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
|
||||
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3.3 The Generic Onoff Server sends message
|
||||
|
||||
The Generic Onoff Server Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(send_data), &send_data);
|
||||
```
|
||||
The Generic Onoff Server Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages.
|
||||
|
||||
```c
|
||||
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(led->current), &led->current, ROLE_NODE);
|
||||
```
|
||||
|
||||
### 2.4 Users Enter the Address of the Destination Node via Serial Port
|
||||
|
||||
Please connect your devices and enters the address of the destination node via the serial port.
|
||||
|
||||
Users can adjust the address of the destination node.
|
||||
|
||||
|
||||
> Note:
|
||||
> Please connect the pin 16 and pin 17 of the device that runs the `ble_mesh_client_model` project to the USB-to-UART tool.
|
||||
|
||||
```c
|
||||
#define UART1_TX_PIN GPIO_NUM_16
|
||||
#define UART1_RX_PIN GPIO_NUM_17
|
||||
```
|
||||
|
||||
The `board_uart_task` task is used to receive commands sent via the serial port, among which, the`remote_addr` represents the address of destination node that the message is forwarded to. Please enters hexadecimal string, such as 5, for this parameter. The address will be converted to 0x05 automatically.
|
||||
|
||||
```c
|
||||
static void board_uart_task(void *p)
|
||||
{
|
||||
uint8_t *data = calloc(1, UART_BUF_SIZE);
|
||||
uint32_t input;
|
||||
|
||||
while (1) {
|
||||
int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS);
|
||||
if (len > 0) {
|
||||
input = strtoul((const char *)data, NULL, 16);
|
||||
remote_addr = input & 0xFFFF;
|
||||
ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr);
|
||||
memset(data, 0, UART_BUF_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 3. Timing Sequence Diagram
|
||||
|
||||
The steps for this demo:
|
||||
|
||||
1. The nRF Mesh App provisionings the unprovisioned devices into nodes;
|
||||
2. The nRF Mesh App adds a Appkey to these nodes, and bind the Models of these nodes to this Appkey.
|
||||
3. The nRF Mesh App sends a controlling message to the Generic Onoff Client Model. Then the Client Model forwards this message to the server Model of the other node.
|
||||
|
||||
The timing sequence diagram of this demo is shown below:
|
||||
|
||||
 <div align=center></div>
|
||||
|
||||
>Note:
|
||||
>
|
||||
>The node **only forwards the message after it receives the controlling message sent by the app**. That is said, the node will **not** forwards messages to the other nodes every time the user enters the address of the destination node through the serial port.
|
||||
|
||||
|
||||
# 4. The nRF Mesh App
|
||||
|
||||

|
||||
|
||||
1. Scan the unprovisioned devices.
|
||||
2. Identity the the capability of the unprovisioned devices.
|
||||
3. Provisioning the unprovisioned devices.
|
||||
4. Check if the Mesh node has been configured successful.
|
||||
5. Configure the Models of the nodes.
|
||||
6. Click on the Generic On Off Client option.
|
||||
7. Bind the Generic On Off Client Model to the Appkey.
|
||||
8. Check if the binding is successfully.
|
||||
9. Bind the Generic On Off Server Model to the Appkey.
|
||||
10. Send controlling messages.
|
||||
|
After Width: | Height: | Size: 433 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 26 KiB |
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(onoff_server)
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := onoff_server
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,16 @@
|
||||
ESP BLE Mesh Node demo
|
||||
==========================
|
||||
|
||||
This demo shows how BLE Mesh device can be set up as a node with the following features:
|
||||
|
||||
- One element
|
||||
- Two SIG models
|
||||
- **Configuration Server model**: The role of this model is mainly to configure Provisioner device’s AppKey and set up its relay function, TTL size, subscription, etc.
|
||||
- **OnOff Server model**: This model implements the most basic function of turning the lights on and off.
|
||||
|
||||
The default purpose of this demo is to enable the advertising function with 20-ms non-connectable interval in BLE 5.0. You can disable this function through menuconfig: `idf.py menuconfig --> Example Configuration --> This option facilitates sending with 20ms non-connectable interval...`
|
||||
|
||||
For a better demonstration effect, an RGB LED can be soldered onto the ESP32-DevKitC board, by connecting their corresponding GPIO pins are GPIO\_NUM\_25, GPIO\_NUM\_26, GPIO\_NUM\_27. Then you need to select the following option in menuconfig:
|
||||
`idf.py menuconfig --> Example Configuration --> Board selection for BLE Mesh --> ESP-WROOM-32`
|
||||
|
||||
Please check the [tutorial](tutorial/Ble_Mesh_Node_Example_Walkthrough.md) for more information about this example.
|
||||
@@ -0,0 +1,7 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
|
||||
"ble_mesh_demo_init.c"
|
||||
"board.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,22 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice BLE_MESH_EXAMPLE_BOARD
|
||||
prompt "Board selection for BLE Mesh"
|
||||
default BLE_MESH_ESP_WROOM_32
|
||||
help
|
||||
Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32
|
||||
|
||||
config BLE_MESH_ESP_WROOM_32
|
||||
bool "ESP32-WROOM-32"
|
||||
|
||||
config BLE_MESH_ESP_WROVER
|
||||
bool "ESP32-WROVER"
|
||||
endchoice
|
||||
|
||||
config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0
|
||||
bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0"
|
||||
default y
|
||||
help
|
||||
It is an ad hoc solution and needs further modifications
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,143 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sdkconfig.h>
|
||||
/* BLE */
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "console/console.h"
|
||||
#endif
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
|
||||
#ifdef CONFIG_BLUEDROID_ENABLED
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
ret = esp_bt_controller_init(&bt_cfg);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable controller failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
static SemaphoreHandle_t mesh_sem;
|
||||
static uint8_t own_addr_type;
|
||||
void ble_store_config_init(void);
|
||||
static uint8_t addr_val[6] = {0};
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
|
||||
{
|
||||
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
|
||||
}
|
||||
|
||||
static void mesh_on_reset(int reason)
|
||||
{
|
||||
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
|
||||
}
|
||||
|
||||
static void mesh_on_sync(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
xSemaphoreGive(mesh_sem);
|
||||
}
|
||||
|
||||
void mesh_host_task(void *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "BLE Host Task Started");
|
||||
/* This function will return only when nimble_port_stop() is executed */
|
||||
nimble_port_run();
|
||||
|
||||
nimble_port_freertos_deinit();
|
||||
}
|
||||
|
||||
esp_err_t bluetooth_init(void)
|
||||
{
|
||||
mesh_sem = xSemaphoreCreateBinary();
|
||||
if (mesh_sem == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create mesh semaphore");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
|
||||
|
||||
nimble_port_init();
|
||||
/* Initialize the NimBLE host configuration. */
|
||||
ble_hs_cfg.reset_cb = mesh_on_reset;
|
||||
ble_hs_cfg.sync_cb = mesh_on_sync;
|
||||
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_config_init();
|
||||
|
||||
nimble_port_freertos_init(mesh_host_task);
|
||||
|
||||
xSemaphoreTake(mesh_sem, portMAX_DELAY);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_MESH_DEMO_INIT_H_
|
||||
#define _BLE_MESH_DEMO_INIT_H_
|
||||
|
||||
#define TAG "onoff_server"
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
|
||||
|
||||
esp_err_t bluetooth_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,332 @@
|
||||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.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_networking_api.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
#include "esp_ble_mesh_local_data_operation_api.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
|
||||
#define CID_ESP 0x02E5
|
||||
|
||||
extern struct _led_state led_state[3];
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
|
||||
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 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_0, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server_0 = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_1, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server_1 = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_2, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server_2 = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server_0),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t extend_model_0[] = {
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_1, &onoff_server_1),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t extend_model_1[] = {
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_2, &onoff_server_2),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
ESP_BLE_MESH_ELEMENT(0, extend_model_0, ESP_BLE_MESH_MODEL_NONE),
|
||||
ESP_BLE_MESH_ELEMENT(0, extend_model_1, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_comp_t composition = {
|
||||
.cid = CID_ESP,
|
||||
.elements = elements,
|
||||
.element_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
static esp_ble_mesh_prov_t provision = {
|
||||
.uuid = dev_uuid,
|
||||
#if 0
|
||||
.output_size = 4,
|
||||
.output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
|
||||
.input_actions = ESP_BLE_MESH_PUSH,
|
||||
.input_size = 4,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
||||
{
|
||||
ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr);
|
||||
ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index);
|
||||
board_led_operation(LED_G, LED_OFF);
|
||||
}
|
||||
|
||||
static void example_change_led_state(esp_ble_mesh_model_t *model,
|
||||
esp_ble_mesh_msg_ctx_t *ctx, uint8_t onoff)
|
||||
{
|
||||
uint16_t primary_addr = esp_ble_mesh_get_primary_element_address();
|
||||
uint8_t elem_count = esp_ble_mesh_get_element_count();
|
||||
struct _led_state *led = NULL;
|
||||
uint8_t i;
|
||||
|
||||
if (ESP_BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
|
||||
for (i = 0; i < elem_count; i++) {
|
||||
if (ctx->recv_dst == (primary_addr + i)) {
|
||||
led = &led_state[i];
|
||||
board_led_operation(led->pin, onoff);
|
||||
}
|
||||
}
|
||||
} else if (ESP_BLE_MESH_ADDR_IS_GROUP(ctx->recv_dst)) {
|
||||
if (esp_ble_mesh_is_model_subscribed_to_group(model, ctx->recv_dst)) {
|
||||
led = &led_state[model->element->element_addr - primary_addr];
|
||||
board_led_operation(led->pin, onoff);
|
||||
}
|
||||
} else if (ctx->recv_dst == 0xFFFF) {
|
||||
led = &led_state[model->element->element_addr - primary_addr];
|
||||
board_led_operation(led->pin, onoff);
|
||||
}
|
||||
}
|
||||
|
||||
static void example_handle_gen_onoff_msg(esp_ble_mesh_model_t *model,
|
||||
esp_ble_mesh_msg_ctx_t *ctx,
|
||||
esp_ble_mesh_server_recv_gen_onoff_set_t *set)
|
||||
{
|
||||
esp_ble_mesh_gen_onoff_srv_t *srv = model->user_data;
|
||||
|
||||
switch (ctx->recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
|
||||
esp_ble_mesh_server_model_send_msg(model, ctx,
|
||||
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK:
|
||||
if (set->op_en == false) {
|
||||
srv->state.onoff = set->onoff;
|
||||
} else {
|
||||
/* TODO: Delay and state transition */
|
||||
srv->state.onoff = set->onoff;
|
||||
}
|
||||
if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
esp_ble_mesh_server_model_send_msg(model, ctx,
|
||||
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff);
|
||||
}
|
||||
esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(srv->state.onoff), &srv->state.onoff, ROLE_NODE);
|
||||
example_change_led_state(model, ctx, srv->state.onoff);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_provisioning_cb(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_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
|
||||
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
|
||||
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
|
||||
prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
|
||||
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event,
|
||||
esp_ble_mesh_generic_server_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04x, src 0x%04x, dst 0x%04x",
|
||||
event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
|
||||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff);
|
||||
example_change_led_state(param->model, ¶m->ctx, param->value.state_change.onoff_set.onoff);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) {
|
||||
example_handle_gen_onoff_msg(param->model, ¶m->ctx, NULL);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
|
||||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ESP_LOGI(TAG, "onoff 0x%02x, tid 0x%02x", param->value.set.onoff.onoff, param->value.set.onoff.tid);
|
||||
if (param->value.set.onoff.op_en) {
|
||||
ESP_LOGI(TAG, "trans_time 0x%02x, delay 0x%02x",
|
||||
param->value.set.onoff.trans_time, param->value.set.onoff.delay);
|
||||
}
|
||||
example_handle_gen_onoff_msg(param->model, ¶m->ctx, ¶m->value.set.onoff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown Generic Server event 0x%02x", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
|
||||
esp_ble_mesh_cfg_server_cb_param_t *param)
|
||||
{
|
||||
if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
|
||||
switch (param->ctx.recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
|
||||
ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
|
||||
param->value.state_change.appkey_add.net_idx,
|
||||
param->value.state_change.appkey_add.app_idx);
|
||||
ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
|
||||
ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
||||
param->value.state_change.mod_app_bind.element_addr,
|
||||
param->value.state_change.mod_app_bind.app_idx,
|
||||
param->value.state_change.mod_app_bind.company_id,
|
||||
param->value.state_change.mod_app_bind.model_id);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD");
|
||||
ESP_LOGI(TAG, "elem_addr 0x%04x, sub_addr 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
||||
param->value.state_change.mod_sub_add.element_addr,
|
||||
param->value.state_change.mod_sub_add.sub_addr,
|
||||
param->value.state_change.mod_sub_add.company_id,
|
||||
param->value.state_change.mod_sub_add.model_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
||||
esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb);
|
||||
|
||||
err = esp_ble_mesh_init(&provision, &composition);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
||||
|
||||
ESP_LOGI(TAG, "BLE Mesh Node initialized");
|
||||
|
||||
board_led_operation(LED_G, LED_ON);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing...");
|
||||
|
||||
board_init();
|
||||
|
||||
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, "Bluetooth mesh init failed (err %d)", err);
|
||||
}
|
||||
}
|
||||