mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-19 17:35:54 +08:00
添加智能灯固件代码
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# ESP-BLE-MESH Examples
|
||||
|
||||
[ESP-BLE-MESH](../../../components/bt/esp_ble_mesh/) is the official Bluetooth® 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 either Bluedroid or NimBLE can be selected as the host stack.
|
||||
|
||||
# Example Layout
|
||||
|
||||
This directory includes examples to demonstrate ESP-BLE-MESH functionality based on [Zephyr Bluetooth Mesh stack](https://github.com/zephyrproject-rtos/zephyr/tree/master/subsys/bluetooth/mesh).
|
||||
|
||||
## 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 [ble_mesh_node](ble_mesh_console/ble_mesh_node) folder for more details.
|
||||
|
||||
#### ble_mesh_provisioner
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Provisioner and sends vendor messages for testing.
|
||||
|
||||
See [ble_mesh_provisioner](ble_mesh_console/ble_mesh_provisioner) folder for more details.
|
||||
|
||||
## ble_mesh_fast_provision
|
||||
|
||||
This example illustrates the solution of ESP-BLE-MESH Fast Provisioning.
|
||||
|
||||
#### fast_prov_client
|
||||
|
||||
This example shows how ESP32, acting as a BLE Mesh Fast Provisioning Client, provisions other unprovisioned devices and then controls the nodes.
|
||||
|
||||
See [fast_prov_client](ble_mesh_fast_provision/fast_prov_client) folder for more details.
|
||||
|
||||
#### fast_prov_server
|
||||
|
||||
This example illustrates the process that:
|
||||
1. ESP32 as a BLE Mesh Fast Provisioning Server is provisioned into a node;
|
||||
2. ESP32 as a Temporary Provisioner provisions other unprovisioned devices.
|
||||
|
||||
See [fast_prov_server](ble_mesh_fast_provision/fast_prov_server) folder for more details.
|
||||
|
||||
## ble_mesh_node
|
||||
|
||||
This example demonstrates how ESP32 acts as a BLE Mesh node with Generic OnOff Server model or Generic OnOff Client model on board.
|
||||
|
||||
#### onoff_client
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Node with Generic OnOff Client model in the Primary Element.
|
||||
|
||||
See [onoff_client](ble_mesh_node/onoff_client) folder for more details.
|
||||
|
||||
#### onoff_server
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Node with only Generic OnOff Server model in the Primary Element.
|
||||
|
||||
See [onoff_server](ble_mesh_node/onoff_server) folder for more details.
|
||||
|
||||
## ble_mesh_provisioner
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Provisioner and provisions other unprovisioned devices.
|
||||
|
||||
See [ble_mesh_provisioner](ble_mesh_provisioner) folder for more details.
|
||||
|
||||
## ble_mesh_vendor_model
|
||||
|
||||
This example demonstrates how ESP32 acts as a BLE Mesh Provisioner with vendor client model or as a BLE Mesh node with vendor server model.
|
||||
|
||||
#### vendor_client
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Provisioner with a vendor client model in the Primary Element.
|
||||
|
||||
See [vendor_client](ble_mesh_vendor_model/vendor_client) folder for more details.
|
||||
|
||||
#### vendor_server
|
||||
|
||||
This example shows how ESP32 acts as a BLE Mesh Node with a vendor server model in the Primary Element.
|
||||
|
||||
See [vendor_server](ble_mesh_vendor_model/vendor_server) folder for more details.
|
||||
|
||||
## 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 [ble_mesh_wifi_coexist](ble_mesh_wifi_coexist) folder for more details.
|
||||
|
||||
# More
|
||||
|
||||
See the [README.md](../../README.md) file in the upper level [examples](../../) directory for more information about examples.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# 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_coex_test)
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_mesh_coex_test
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,110 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# Example of BLE Mesh and TCP Server/Client Coexistence
|
||||
|
||||
This example introduces how to test the basic functions of `BLE Mesh data interface` and `TCP Server/Client Coexistence`. `BLE Mesh data interface` is GAP scanning and advertising.
|
||||
|
||||
There are two working modes here:
|
||||
|
||||
* In automatic mode, the program coordinates three development boards working through a synchronization mechanism.
|
||||
|
||||
* In manual mode, you will work with three development boards via commands
|
||||
|
||||
|
||||
## Test Preparation
|
||||
|
||||
* Before running the test, you need to prepare a router and three ESP32 development boards. This Example of BLE Mesh and TCP Server/Client Coexistence has the following three items, and any of the three development boards is for running one specific item.
|
||||
|
||||
* ble_dev : Run only the BLE program.
|
||||
* coex_dev: Run BLE and Wi-Fi program.
|
||||
* wifi_dev: Run only the Wi-Fi program.
|
||||
|
||||
``Note: If you want better performance in BLE and WiFi coexistence, you should use a development board with PSRAM that could run a coexistence program. Such as ESP32_LyraT, ESP32-WROVER-B and etc.``
|
||||
|
||||
* The following structure shows the parameters you need to configure. And usually, there are two methods for configuration, i.e. configuring during initialization or configuring with the command `env`.
|
||||
|
||||
```c
|
||||
coex_test_env_t test_env = {
|
||||
#if defined(CONFIG_EXAMPLE_MANAUL)
|
||||
.ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
|
||||
.ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
|
||||
#endif
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
.ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
|
||||
.ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
|
||||
#endif
|
||||
.test_port = "8080",
|
||||
.server_ip = "192.168.3.32",
|
||||
.duration = "120000",
|
||||
.is_start = false,
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Run Test Case Manually
|
||||
Configure to Manual Mode via `Example Configuration --->run mode (manual) `
|
||||
|
||||
The meaning of the numeric argument of the command `run_tc` is as follows:
|
||||
|
||||
| id | case name | description |
|
||||
|:-:|:-|:-|
|
||||
| 0 | wifi_tcp_tx_throughput| Test the case of Wi-Fi tcp tx, which will create a tcp client that will continuously send data to the tcp server. |
|
||||
| 1 |wifi_tcp_rx_throughput| Test the case of Wi-Fi tcp rx, which will create a tcp server that will continuously receive data from the tcp client. |
|
||||
| 2 | ble_adv | Test the case of BLE advertising. |
|
||||
| 3 | ble_scan| Test the case of BLE Scan.|
|
||||
|
||||
|
||||
### Case 1: tcp tx + scan
|
||||
1. wifi_dev: run_tc -w 1
|
||||
2. coex_dev: env -s -k server_ip -v 192.168.3.34 run_tc -w 0 -b 3
|
||||
3. ble_dev : run_tc -b 2
|
||||
|
||||
|
||||
### Case 2: tcp rx + scan
|
||||
1. coex_dev: run_tc -w 1 -b 3
|
||||
2. wifi_dev: env -s -k server_ip -v 192.168.3.34 run_tc -w 0
|
||||
3. ble_dev : run_tc -b 2
|
||||
|
||||
### Case 3: tcp tx + adv
|
||||
1. wifi_dev: run_tc -w 1
|
||||
2. coex_dev: env -s -k server_ip -v 192.168.3.13 run_tc -w 0 -b 2
|
||||
3. ble_dev : run_tc -b 3
|
||||
|
||||
|
||||
### Case 4: tcp rx + adv
|
||||
1. coex_dev: run_tc -w 1 -b 2
|
||||
2. wifi_dev: env -s -k server_ip -v 192.168.3.34 run_tc -w 0
|
||||
3. ble_dev : run_tc -b 3
|
||||
|
||||
## Run Test Case By Automation
|
||||
Configure to Automatic Mode via `Example Configuration --->run mode (auto) `
|
||||
|
||||
### Coexistence device configuration
|
||||
1. Select a development board as coexistence role by `Example Configuration --->select role (run device as coex role) `
|
||||
2. Select a test case by `Example Configuration --->select case `.
|
||||
* There are four types of cases:
|
||||
* TCP TX and BLE ADV: The TCP client will be created on the coexistence device, and bluetooth will start advertising when the Wi-Fi is running tx throughput program.
|
||||
* TCP RX and BLE ADV: The TCP server will be created on the coexistence device, and bluetooth will start advertising when the Wi-Fi is running rx throughput program.
|
||||
* TCP TX and BLE SCAN: The TCP client will be created on the coexistence device, and bluetooth will start scanning when the Wi-Fi is running tx throughput program.
|
||||
* TCP RX and BLE SCAN: The TCP server will be created on the coexistence device, and bluetooth will start scanning when the Wi-Fi is running rx throughput program.
|
||||
|
||||
### Bluetooth device configuration
|
||||
1. Select a development board as bluetooth role by `select role (run device as bluetooth role) `
|
||||
|
||||
### Wi-Fi device configuration
|
||||
1. Select a development board as bluetooth role by `select role (run device as wifi role) `
|
||||
|
||||
|
||||
## Coexistence Configuration
|
||||
In theory, the performance of BLE and Wi-Fi coexistence will drop to half of the performance in BLE Only mode or Wi-Fi Only mode.
|
||||
|
||||
* ESP32 working frequency:
|
||||
* Component config ---> ESP32-specific ---> CPU frequency (240 MHz)
|
||||
|
||||
* ESP32 external PSRAM
|
||||
* Component config ---> ESP32-specific ---> Support for external, SPI-connected RAM
|
||||
* Devices that do not support PSRAM cannot open this option!
|
||||
|
||||
* ESP32 coexistence mode
|
||||
* Component config ---> Wi-Fi ---> WiFi/Bluetooth coexistence performance preference (Balance)
|
||||
@@ -0,0 +1,11 @@
|
||||
set(srcs "ble_unit.c"
|
||||
"run_tc.c"
|
||||
"sync.c"
|
||||
"test_env.c"
|
||||
"wifi_connect.c"
|
||||
"wifi_unit.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES console nvs_flash bt
|
||||
REQUIRED_IDF_TARGETS esp32)
|
||||
@@ -0,0 +1,253 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "ble_unit.h"
|
||||
#include "sync.h"
|
||||
#define TAG "BLE_UINT"
|
||||
|
||||
#define GAP_TRANS_DEFAULT_SHORT_TO 50 // 50ms for events expected to reported as soon as API called
|
||||
|
||||
static uint8_t default_adv_data[] = {
|
||||
0x02, 0x01, 0x06,
|
||||
0x02, 0x0a, 0xeb, 0x03, 0x03, 0xab, 0xcd
|
||||
};
|
||||
static uint8_t default_scan_rsp_data[] = {
|
||||
0x0f, 0x09, 0x45, 0x53, 0x50, 0x5f, 0x47, 0x41, 0x54, 0x54, 0x53, 0x5f, 0x43,
|
||||
0x4f, 0x45, 0x58
|
||||
};
|
||||
|
||||
esp_ble_scan_params_t default_scan_param = {
|
||||
.scan_type = BLE_SCAN_TYPE_ACTIVE,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
|
||||
.scan_interval = 0x100,
|
||||
.scan_window = 0x100
|
||||
};
|
||||
|
||||
esp_ble_adv_params_t default_adv_param = {
|
||||
.adv_int_min = 0x40,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
ble_util_scan_count_t scan_count;
|
||||
|
||||
static void ble_gap_event_default_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
|
||||
if (param->scan_param_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "set scan parameter failed, error status = %x", param->scan_param_cmpl.status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: {
|
||||
if (param->adv_data_raw_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "set row data failed, error status = %x", param->adv_data_raw_cmpl.status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: {
|
||||
if (param->scan_rsp_data_raw_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "set scan response data failed, error status = %x", param->scan_rsp_data_raw_cmpl.status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: {
|
||||
if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Advertising start failed\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
|
||||
if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Advertising stop failed\n");
|
||||
}
|
||||
break;
|
||||
case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: {
|
||||
if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "scan start failed, error status = %x", param->scan_start_cmpl.status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
|
||||
if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "scan stop failed, error status = %x", param->scan_stop_cmpl.status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ble_gap_util_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
if (sync_obj.cmd_recv != NULL) {
|
||||
sync_obj.cmd_recv(param->scan_rst.ble_adv, param->scan_rst.adv_data_len);
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_SCAN_RESULT_EVT:
|
||||
switch (param->scan_rst.search_evt) {
|
||||
case ESP_GAP_SEARCH_INQ_RES_EVT:
|
||||
if (param->scan_rst.adv_data_len > 0 \
|
||||
&& (memcmp(default_adv_data, param->scan_rst.ble_adv, sizeof(default_adv_data)) == 0)) {
|
||||
scan_count.adv_count += 1;
|
||||
if (scan_count.adv_count % 10 == 0) {
|
||||
ESP_LOGI(TAG, "adv count:%d scan_res count %d\n", scan_count.adv_count, scan_count.scan_res_count);
|
||||
}
|
||||
}
|
||||
|
||||
if (param->scan_rst.scan_rsp_len > 0 \
|
||||
&& (memcmp(default_scan_rsp_data, (param->scan_rst.ble_adv + param->scan_rst.adv_data_len), sizeof(default_scan_rsp_data)) == 0)) {
|
||||
scan_count.scan_res_count += 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ble_gap_event_default_handler(event, param);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
esp_err_t ble_gap_util_set_adv_data(uint8_t *adv_data, uint32_t adv_data_len, uint8_t *scan_rsp_data, uint32_t scan_rsp_data_len)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ret = esp_ble_gap_config_adv_data_raw(adv_data, adv_data_len);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = esp_ble_gap_config_scan_rsp_data_raw(scan_rsp_data, scan_rsp_data_len);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_config_scan_rsp_data_raw error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_set_default_adv_data(void)
|
||||
{
|
||||
return ble_gap_util_set_adv_data(default_adv_data, sizeof(default_adv_data), default_scan_rsp_data, sizeof(default_scan_rsp_data));
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_start_adv(esp_ble_adv_params_t *adv_param)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_ble_gap_start_advertising(adv_param);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_start_advertising error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_start_adv_default(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
ret = esp_ble_gap_start_advertising(&default_adv_param);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_start_advertising error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_stop_adv(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_ble_gap_stop_advertising();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_stop_advertising error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_set_scan_param(esp_ble_scan_params_t *scan_param)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_ble_gap_set_scan_params(scan_param);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_set_scan_params error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_set_default_scan_param(void)
|
||||
{
|
||||
return ble_gap_util_set_scan_param(&default_scan_param);
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_start_scan(uint32_t duration)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_ble_gap_start_scanning(duration);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_start_scanning error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t ble_gap_util_stop_scan(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_ble_gap_stop_scanning();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_stop_scanning error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ble_gap_util_stop(void)
|
||||
{
|
||||
ble_gap_util_stop_adv();
|
||||
ble_gap_util_stop_scan();
|
||||
}
|
||||
|
||||
esp_err_t init_ble_gap_test_util(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
ret = esp_ble_gap_register_callback(ble_gap_util_handler);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "gap register error, error code = %x", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void bt_test_init(void)
|
||||
{
|
||||
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();
|
||||
ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
|
||||
ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
|
||||
ESP_ERROR_CHECK(esp_bluedroid_init());
|
||||
ESP_ERROR_CHECK(esp_bluedroid_enable());
|
||||
}
|
||||
|
||||
void bt_test_deinit(void)
|
||||
{
|
||||
esp_bluedroid_disable();
|
||||
esp_bluedroid_deinit();
|
||||
esp_bt_controller_disable();
|
||||
esp_bt_controller_deinit();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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_UNIT_H_
|
||||
#define _BLE_UNIT_H_
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_bt.h"
|
||||
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gatts_api.h"
|
||||
#include "esp_gattc_api.h"
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
|
||||
#define BLE_TC_SCAN_REPORT_PERIOD 10000
|
||||
|
||||
typedef struct {
|
||||
uint32_t adv_count;
|
||||
uint32_t scan_res_count;
|
||||
} ble_util_scan_count_t;
|
||||
|
||||
|
||||
extern esp_bd_addr_t bt_addr;
|
||||
extern ble_util_scan_count_t scan_count;
|
||||
extern esp_ble_adv_params_t default_adv_param;
|
||||
extern esp_ble_scan_params_t default_scan_param;
|
||||
|
||||
void bt_test_init(void);
|
||||
void bt_test_deinit(void);
|
||||
void ble_gap_util_stop(void);
|
||||
|
||||
esp_err_t ble_gap_util_set_adv_data(uint8_t *adv_data, uint32_t adv_data_len, uint8_t *scan_rsp_data, uint32_t scan_rsp_data_len);
|
||||
esp_err_t ble_gap_util_set_default_adv_data(void);
|
||||
esp_err_t ble_gap_util_start_adv(esp_ble_adv_params_t *adv_param);
|
||||
esp_err_t ble_gap_util_start_adv_default(void);
|
||||
esp_err_t ble_gap_util_stop_adv(void);
|
||||
|
||||
esp_err_t ble_gap_util_set_scan_param(esp_ble_scan_params_t *scan_param);
|
||||
esp_err_t ble_gap_util_set_default_scan_param(void);
|
||||
esp_err_t ble_gap_util_start_scan(uint32_t duration);
|
||||
esp_err_t ble_gap_util_stop_scan(void);
|
||||
|
||||
esp_err_t init_ble_gap_test_util(void);
|
||||
|
||||
#endif /* _BLE_UNIT_H_ */
|
||||
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS = .
|
||||
@@ -0,0 +1,291 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "run_tc.h"
|
||||
#include "test_env.h"
|
||||
#include "wifi_unit.h"
|
||||
#include "ble_unit.h"
|
||||
#include "sync.h"
|
||||
#include "wifi_connect.h"
|
||||
|
||||
#define TAG "CASE"
|
||||
|
||||
xQueueHandle xTaskQueue = 0;
|
||||
|
||||
static const char *coex_get_case_env(coex_test_env_t *test_env, const char *keyword)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
if (!strcmp(keyword, "ap_ssid")) {
|
||||
ret = test_env->ap_ssid;
|
||||
} else if (!strcmp(keyword, "ap_password")) {
|
||||
ret = test_env->ap_password;
|
||||
} else if (!strcmp(keyword, "test_port")) {
|
||||
ret = test_env->test_port;
|
||||
} else if (!strcmp(keyword, "server_ip")) {
|
||||
ret = test_env->server_ip;
|
||||
} else if (!strcmp(keyword, "duration")) {
|
||||
ret = test_env->duration;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void wifi_tc_sta_throughput_timeout(void *arg)
|
||||
{
|
||||
static uint32_t statistic_count = 0;
|
||||
static uint64_t accumulate_speed = 0;
|
||||
|
||||
uint32_t now = utils_get_system_ts();
|
||||
uint32_t *report = (uint32_t *) arg;
|
||||
uint32_t last_timestamp = report[0];
|
||||
|
||||
if (now > last_timestamp) {
|
||||
uint32_t speed = report[1] * 8 / (now - last_timestamp);
|
||||
accumulate_speed += speed;
|
||||
statistic_count += 1;
|
||||
printf("speed: %d kbps average speed: %lld kbps\n", speed, accumulate_speed / statistic_count );
|
||||
report[1] = 0;
|
||||
report[0] = now;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t create_statistic_timer(esp_timer_handle_t *timer_hdl , uint32_t statistic_date[])
|
||||
{
|
||||
esp_err_t ret;
|
||||
esp_timer_create_args_t tca = {
|
||||
.callback = (esp_timer_cb_t)wifi_tc_sta_throughput_timeout,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "TCP_STATISTIC",
|
||||
};
|
||||
tca.arg = statistic_date;
|
||||
ret = esp_timer_create(&tca, timer_hdl);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "statistic_timer create failed");
|
||||
return ret;
|
||||
}
|
||||
esp_timer_start_periodic(*timer_hdl, 1000000); //1000ms
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void wifi_tcp_tx_throught_start(void *param)
|
||||
{
|
||||
esp_timer_handle_t timer_hdl = NULL;
|
||||
esp_err_t ret;
|
||||
int sock = -1;
|
||||
uint32_t statistic_date[2] = {0};
|
||||
|
||||
const char *ssid = coex_get_case_env(param, "ap_ssid");
|
||||
const char *passwd = coex_get_case_env(param, "ap_password");
|
||||
|
||||
|
||||
wifi_util_init();
|
||||
// wifi_unit_connect_ap(ssid, passwd);
|
||||
example_connect(ssid, passwd);
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_AUTO)
|
||||
if (((coex_test_env_t *)param)->run_mutex != NULL) {
|
||||
//This will be blocked by the sync timer.
|
||||
xSemaphoreTake(((coex_test_env_t *)param)->run_mutex, portMAX_DELAY);
|
||||
xSemaphoreGive(((coex_test_env_t *)param)->run_mutex);
|
||||
}
|
||||
#endif
|
||||
const char *ip = coex_get_case_env(param, "server_ip");
|
||||
const char *port = coex_get_case_env(param, "test_port");
|
||||
const char *duration = coex_get_case_env(param, "duration");
|
||||
wifi_unit_client_establish(&sock, ip, port);
|
||||
|
||||
ret = create_statistic_timer(&timer_hdl, statistic_date);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "statistic_timer create failed");
|
||||
goto _stop;
|
||||
}
|
||||
|
||||
ret = wifi_util_tcp_send(sock, 1460, 0, &statistic_date[1], atoi(duration));
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "send failed, %x", ret);
|
||||
}
|
||||
|
||||
_stop:
|
||||
if (timer_hdl) {
|
||||
esp_timer_stop(timer_hdl);
|
||||
esp_timer_delete(timer_hdl);
|
||||
}
|
||||
|
||||
if (sock > 0) {
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
void wifi_tcp_tx_throught_end(void)
|
||||
{
|
||||
esp_wifi_disconnect();
|
||||
}
|
||||
|
||||
void wifi_tcp_rx_throught_start(void *param)
|
||||
{
|
||||
esp_timer_handle_t timer_hdl = NULL;
|
||||
esp_err_t ret;
|
||||
int sock = -1;
|
||||
uint32_t statistic_date[2] = {0};
|
||||
|
||||
const char *ssid = coex_get_case_env(param, "ap_ssid");
|
||||
const char *passwd = coex_get_case_env(param, "ap_password");
|
||||
const char *port = coex_get_case_env(param, "test_port");
|
||||
const char *duration = coex_get_case_env(param, "duration");
|
||||
|
||||
wifi_util_init();
|
||||
// wifi_unit_connect_ap(ssid, passwd);
|
||||
example_connect(ssid, passwd);
|
||||
wifi_unit_server_establish( &sock, port);
|
||||
|
||||
ret = create_statistic_timer(&timer_hdl, statistic_date);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "statistic_timer create failed");
|
||||
goto _stop;
|
||||
}
|
||||
ret = wifi_unit_tcp_recv(sock, duration, statistic_date);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "tcp receive failed");
|
||||
goto _stop;
|
||||
}
|
||||
_stop:
|
||||
if (timer_hdl) {
|
||||
esp_timer_stop(timer_hdl);
|
||||
esp_timer_delete(timer_hdl);
|
||||
}
|
||||
|
||||
if (sock > 0) {
|
||||
close(sock);
|
||||
}
|
||||
}
|
||||
|
||||
void wifi_tcp_rx_throught_end(void)
|
||||
{
|
||||
esp_wifi_disconnect();
|
||||
}
|
||||
|
||||
void ble_adv_start(void *param)
|
||||
{
|
||||
esp_err_t ret;
|
||||
const char *duration = coex_get_case_env(param, "duration");
|
||||
#if defined(CONFIG_EXAMPLE_MANAUL)
|
||||
bt_test_init();
|
||||
#endif
|
||||
ret = ble_gap_util_set_default_adv_data();
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to set adv data");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ble_gap_util_start_adv(&default_adv_param);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to start adv");
|
||||
return;
|
||||
}
|
||||
|
||||
vTaskDelay(atoi(duration) / portTICK_PERIOD_MS);
|
||||
|
||||
}
|
||||
|
||||
void ble_adv_end(void)
|
||||
{
|
||||
ble_gap_util_stop();
|
||||
}
|
||||
|
||||
|
||||
void ble_scan_start(void *param)
|
||||
{
|
||||
esp_err_t ret;
|
||||
#if defined(CONFIG_EXAMPLE_MANAUL)
|
||||
bt_test_init();
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
init_ble_gap_test_util();
|
||||
#endif
|
||||
|
||||
|
||||
ret = ble_gap_util_set_scan_param(&default_scan_param);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "set scan param fail");
|
||||
return;
|
||||
}
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
scan_count.adv_count = 0;
|
||||
scan_count.scan_res_count = 0;
|
||||
|
||||
ret = esp_ble_gap_start_scanning(BLE_TC_SCAN_REPORT_PERIOD);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_start_scanning error, %d", ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ble_scan_end(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "%s \n", __func__);
|
||||
}
|
||||
|
||||
tc_t tc_case[] = {
|
||||
DECLARE_TC(TC_WIFI_COEX_TCP_TX_THROUGHPUT, 0, wifi_tcp_tx_throught_start, wifi_tcp_tx_throught_end, (void *)&test_env),
|
||||
DECLARE_TC(TC_WIFI_COEX_TCP_RX_THROUGHPUT, 1, wifi_tcp_rx_throught_start, wifi_tcp_rx_throught_end, (void *)&test_env),
|
||||
DECLARE_TC(TC_BLE_COEX_ADV, 2, ble_adv_start, ble_adv_end, (void *)&test_env),
|
||||
DECLARE_TC(TC_BLE_COEX_SCAN, 3, ble_scan_start, ble_scan_end, (void *)&test_env),
|
||||
};
|
||||
|
||||
static void excute_case(void *arg)
|
||||
{
|
||||
tc_t *run_case = (tc_t *) arg;
|
||||
if (run_case && run_case->func_start != NULL) {
|
||||
run_case->func_start(run_case->param_list);
|
||||
}
|
||||
|
||||
if (run_case && run_case->func_stop != NULL ) {
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
run_case->func_stop();
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void run_task(void *arg)
|
||||
{
|
||||
tc_t *tc_case_table = (tc_t *) arg;
|
||||
run_task_msg_t msg;
|
||||
|
||||
for (;;) {
|
||||
if (pdTRUE == xQueueReceive(xTaskQueue, &msg, (portTickType)portMAX_DELAY)) {
|
||||
if ( msg.case_id < sizeof(tc_case) / sizeof(tc_case[0]) ) {
|
||||
xTaskCreatePinnedToCore(excute_case, tc_case_table->name, 4096, &tc_case_table[msg.case_id], RUN_TASK_PRIORITY, NULL, 0);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "msg.case_id %d\n", msg.case_id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
void run_tc_init(void)
|
||||
{
|
||||
xTaskQueue = xQueueCreate(RUN_TASK_QUEUE_LEN, sizeof(run_task_msg_t));
|
||||
if (!xTaskQueue) {
|
||||
ESP_LOGE(TAG, "xTaskQueue create failed");
|
||||
return;
|
||||
}
|
||||
xTaskCreatePinnedToCore(run_task, "run_task", 4096, tc_case, RUN_TASK_PRIORITY, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 __RUN_TC_H__
|
||||
#define __RUN_TC_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#define TC_NAME_LEN 63
|
||||
typedef void (*tc_func_start_t)(void *param);
|
||||
typedef void (*tc_func_end_t)(void);
|
||||
|
||||
|
||||
typedef struct tc {
|
||||
char name[TC_NAME_LEN + 1];
|
||||
uint8_t case_id;
|
||||
tc_func_start_t func_start;
|
||||
tc_func_end_t func_stop;
|
||||
void *param_list;
|
||||
} tc_t;
|
||||
|
||||
|
||||
#define TC_WIFI_COEX_TCP_TX_THROUGHPUT "TCP_COEX_TX_THROUGHPUT"
|
||||
#define TC_WIFI_COEX_TCP_RX_THROUGHPUT "TCP_COEX_RX_THROUGHPUT"
|
||||
#define TC_BLE_COEX_ADV "BLE_COEX_ADVERTISING"
|
||||
#define TC_BLE_COEX_SCAN "BLE_COEX_SCAN"
|
||||
|
||||
// run_task queue size
|
||||
#define RUN_TASK_QUEUE_LEN 6
|
||||
#define RUN_TASK_PRIORITY 18
|
||||
|
||||
#define DECLARE_TC(name, id, start_func, stop_func, param_list) \
|
||||
{name, id, start_func, stop_func, param_list}
|
||||
|
||||
typedef struct run_task_msg {
|
||||
uint8_t case_id;
|
||||
} run_task_msg_t;
|
||||
|
||||
extern xQueueHandle xTaskQueue ;
|
||||
|
||||
void run_tc_init(void);
|
||||
|
||||
#endif /* __RUN_TC_H__ */
|
||||
@@ -0,0 +1,542 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "sync.h"
|
||||
#include "run_tc.h"
|
||||
#include "wifi_unit.h"
|
||||
#define TAG "SYNC"
|
||||
|
||||
SemaphoreHandle_t client_mutex;
|
||||
|
||||
struct sync_t sync_obj = {
|
||||
.except_recv_wifi_id = false,
|
||||
.except_recv_bt_id = false,
|
||||
.recv_param_bit = 0x0,
|
||||
.start_time = 0x0,
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
.state = ASSIGN_CASE,
|
||||
#else
|
||||
.state = WAIT_CASE,
|
||||
#endif
|
||||
#if defined(CONFIG_EXAMPLE_COEX_TX_ADV)
|
||||
.own_wifi_case = WIFI_TCP_TX_CASE,
|
||||
.own_ble_case = BLE_ADV_CASE,
|
||||
#elif defined(CONFIG_EXAMPLE_COEX_RX_ADV)
|
||||
.own_wifi_case = WIFI_TCP_RX_CASE,
|
||||
.own_ble_case = BLE_ADV_CASE,
|
||||
#elif defined(CONFIG_EXAMPLE_COEX_TX_SCAN)
|
||||
.own_wifi_case = WIFI_TCP_TX_CASE,
|
||||
.own_ble_case = BLE_SCAN_CASE,
|
||||
#elif defined(CONFIG_EXAMPLE_COEX_RX_SCAN)
|
||||
.own_wifi_case = WIFI_TCP_RX_CASE,
|
||||
.own_ble_case = BLE_SCAN_CASE,
|
||||
#else
|
||||
.own_wifi_case = NOT_CASE,
|
||||
.own_ble_case = NOT_CASE,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
auto_tc auto_tb[6] = {
|
||||
{WIFI_TCP_TX_CASE, PARAMTER(0b011011)}, //need paramter: wifi_case_id ssid password server ip
|
||||
{WIFI_TCP_RX_CASE, PARAMTER(0b010011)}, //need paramter: wifi_case_id ssid password
|
||||
{BLE_ADV_CASE, PARAMTER(0b100000)}, //need paramter: ble_case_id
|
||||
{BLE_SCAN_CASE, PARAMTER(0b100000)}, //need paramter: ble_case_id
|
||||
};
|
||||
|
||||
|
||||
esp_err_t send_adv(uint8_t *raw_data, uint32_t raw_data_len)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
esp_ble_adv_params_t adv_param = {
|
||||
.adv_int_min = 0x40,
|
||||
.adv_int_max = 0x40,
|
||||
.adv_type = ADV_TYPE_NONCONN_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
ret = esp_ble_gap_config_adv_data_raw(raw_data, raw_data_len);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_config_adv_data_raw error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_ble_gap_start_advertising(&adv_param);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_start_advertising error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS); //every 30ms send one packet
|
||||
|
||||
ret = esp_ble_gap_stop_advertising();
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_stop_advertising error, %d", ret);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
esp_err_t send_adv_data(sync_msg *msg)
|
||||
{
|
||||
send_adv((uint8_t *)msg, sizeof(sync_msg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void send_start_msg(uint8_t start_time)
|
||||
{
|
||||
sync_msg msg = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = 0x4,
|
||||
.ctl = MSG_CONTINUE,
|
||||
.param_bit = 0b000100 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data = {start_time},
|
||||
};
|
||||
send_adv_data(&msg);
|
||||
}
|
||||
void send_start_countdown(void)
|
||||
{
|
||||
if (sync_obj.except_recv_bt_id == true && sync_obj.except_recv_wifi_id == true) {
|
||||
esp_timer_stop(sync_obj.sync_timer);
|
||||
esp_timer_start_once(sync_obj.sync_timer, 1000000);
|
||||
sync_obj.state = START_CASE;
|
||||
}
|
||||
}
|
||||
void send_tcp_rx_inited_msg(void)
|
||||
{
|
||||
uint8_t hex_ip[4];
|
||||
uint32_t ip = wifi_util_get_ip();
|
||||
memcpy(hex_ip, &ip, sizeof(hex_ip));
|
||||
if (hex_ip[0] == 0x0) {
|
||||
return;
|
||||
}
|
||||
sync_msg msg = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = MSG_ID_WIFI_DEV_INIT_FINISH,
|
||||
.ctl = MSG_CONTINUE,
|
||||
.param_bit = 0b001000 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data = {hex_ip[0], hex_ip[1], hex_ip[2], hex_ip[3]},
|
||||
};
|
||||
send_adv_data(&msg);
|
||||
}
|
||||
void send_case_inited_msg(uint8_t msg_id)
|
||||
{
|
||||
sync_msg msg = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = msg_id,
|
||||
.ctl = MSG_CONTINUE,
|
||||
.param_bit = 0b000000 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data = {0},
|
||||
};
|
||||
send_adv_data(&msg);
|
||||
}
|
||||
|
||||
void assign_case_to_dev(uint8_t ble_id, uint8_t wifi_id)
|
||||
{
|
||||
if ( sync_obj.own_wifi_case == WIFI_TCP_RX_CASE ) {
|
||||
uint8_t hex_ip[4];
|
||||
uint32_t ip = wifi_util_get_ip();
|
||||
ESP_LOGI(TAG, "ip:%s", inet_ntoa(ip));
|
||||
memcpy(hex_ip, &ip, sizeof(hex_ip));
|
||||
if (hex_ip[0] == 0x0) {
|
||||
return;
|
||||
}
|
||||
sync_msg msg = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = 0x1,
|
||||
.ctl = MSG_CONTINUE,
|
||||
.param_bit = 0b111000 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data = {ble_id, wifi_id, hex_ip[0], hex_ip[1], hex_ip[2], hex_ip[3]},
|
||||
};
|
||||
send_adv_data(&msg);
|
||||
} else if ( sync_obj.own_wifi_case == WIFI_TCP_TX_CASE ) {
|
||||
sync_msg msg1 = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = 0x1,
|
||||
.ctl = MSG_CONTINUE,
|
||||
.param_bit = 0b110000 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data = {ble_id, wifi_id},
|
||||
};
|
||||
send_adv_data(&msg1);
|
||||
}
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
if (strlen(CONFIG_EXAMPLE_WIFI_SSID) < 20) {
|
||||
sync_msg msg = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = 0x1,
|
||||
.ctl = MSG_CONTINUE,
|
||||
.param_bit = 0b000010 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data[0] = strlen(CONFIG_EXAMPLE_WIFI_SSID),
|
||||
};
|
||||
for (uint8_t i = 0 ; i < strlen(CONFIG_EXAMPLE_WIFI_SSID); i++) {
|
||||
msg.data[i + 1] = CONFIG_EXAMPLE_WIFI_SSID[i] - '0';
|
||||
}
|
||||
send_adv_data(&msg);
|
||||
}
|
||||
|
||||
if (strlen(CONFIG_EXAMPLE_WIFI_PASSWORD) < 20) {
|
||||
sync_msg msg = {
|
||||
.length = 30,
|
||||
.type = MSG_TYPE,
|
||||
.head = MSG_HEAD,
|
||||
.msg_id = 0x1,
|
||||
.ctl = MSG_END,
|
||||
.param_bit = 0b000001 << PARAM_MAX,
|
||||
.reserve = 0xff,
|
||||
.data[0] = strlen(CONFIG_EXAMPLE_WIFI_PASSWORD),
|
||||
};
|
||||
for (int i = 0 ; i < strlen(CONFIG_EXAMPLE_WIFI_PASSWORD); i++) {
|
||||
msg.data[i + 1] = CONFIG_EXAMPLE_WIFI_PASSWORD[i] - '0';
|
||||
}
|
||||
send_adv_data(&msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void excute_case(uint8_t run_case)
|
||||
{
|
||||
run_task_msg_t msg;
|
||||
msg.case_id = run_case;
|
||||
if (xQueueSend(xTaskQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "xTaskQueue Post failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void assign_test_case(void)
|
||||
{
|
||||
#if defined(CONFIG_EXAMPLE_COEX_TX_ADV)
|
||||
assign_case_to_dev(BLE_SCAN_CASE, WIFI_TCP_RX_CASE);
|
||||
#elif defined(CONFIG_EXAMPLE_COEX_RX_ADV)
|
||||
assign_case_to_dev(BLE_SCAN_CASE, WIFI_TCP_TX_CASE);
|
||||
#elif defined(CONFIG_EXAMPLE_COEX_TX_SCAN)
|
||||
assign_case_to_dev(BLE_ADV_CASE, WIFI_TCP_RX_CASE);
|
||||
#elif defined(CONFIG_EXAMPLE_COEX_RX_SCAN)
|
||||
assign_case_to_dev(BLE_ADV_CASE, WIFI_TCP_TX_CASE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void analys_param(uint16_t param_bit, uint8_t data[], uint16_t *recv_param_bit)
|
||||
{
|
||||
|
||||
uint8_t data_ptr = 0;
|
||||
|
||||
for (int i = 0 ; i < PARAM_MAX; i++ ) {
|
||||
switch (GET_PARAM(param_bit, 0x1000 >> i)) {
|
||||
case BLE_CASE_ID:
|
||||
ESP_LOGD(TAG, "BLE_CASE_ID\n");
|
||||
#if defined(CONFIG_EXAMPLE_BT_ROLE)
|
||||
sync_obj.own_ble_case = data[data_ptr];
|
||||
(*recv_param_bit) |= BLE_CASE_ID;
|
||||
#endif
|
||||
data_ptr += 1;
|
||||
break;
|
||||
case WIFI_CASE_ID:
|
||||
ESP_LOGD(TAG, "WIFI_CASE_ID\n");
|
||||
#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
|
||||
sync_obj.own_wifi_case = data[data_ptr];
|
||||
(*recv_param_bit) |= WIFI_CASE_ID;
|
||||
#endif
|
||||
data_ptr += 1;
|
||||
break;
|
||||
case START_TIME:
|
||||
ESP_LOGD(TAG, "START_TIME\n");
|
||||
sync_obj.start_time = data[data_ptr];
|
||||
data_ptr += 1;
|
||||
break;
|
||||
case SERVER_IP: {
|
||||
ESP_LOGD(TAG, "SERVER_IP\n");
|
||||
char server_ip[16];
|
||||
memset(server_ip, '0', sizeof(server_ip));
|
||||
sprintf(server_ip, "%d.%d.%d.%d", data[data_ptr], data[data_ptr + 1], data[data_ptr + 2], data[data_ptr + 3]); // size conversion
|
||||
coex_set_test_env("server_ip", server_ip, sizeof(server_ip));
|
||||
coex_print_test_env();
|
||||
data_ptr += 4;
|
||||
(*recv_param_bit) |= SERVER_IP;
|
||||
break;
|
||||
}
|
||||
case WIFI_SSID: {
|
||||
ESP_LOGD(TAG, "WIFI_SSID\n");
|
||||
uint8_t length = data[data_ptr];
|
||||
data_ptr += 1;
|
||||
if ( length > 20) {
|
||||
ESP_LOGE(TAG, "ssid length error");
|
||||
break;
|
||||
}
|
||||
char *ssid = malloc(length + 1);
|
||||
if (ssid == NULL) {
|
||||
ESP_LOGE(TAG, "%s malloc fail\n", __func__);
|
||||
return ;
|
||||
}
|
||||
memset(ssid, '0', sizeof(length + 1));
|
||||
|
||||
for (int i = length - 1 ; i >= 0 ; i--) {
|
||||
ssid[i] = data[data_ptr + i] + '0';
|
||||
}
|
||||
ssid[length] = '\n';
|
||||
coex_set_test_env("ap_ssid", ssid, length);
|
||||
coex_print_test_env();
|
||||
(*recv_param_bit) |= WIFI_SSID;
|
||||
free(ssid);
|
||||
break;
|
||||
}
|
||||
case WIFI_PASSWIRD: {
|
||||
ESP_LOGD(TAG, "WIFI_PASSWIRD\n");
|
||||
uint8_t length = data[data_ptr];
|
||||
data_ptr += 1;
|
||||
if ( length > 20) {
|
||||
ESP_LOGE(TAG, "password length error");
|
||||
break;
|
||||
}
|
||||
char *password = malloc(length + 1);
|
||||
if (password == NULL) {
|
||||
ESP_LOGE(TAG, "%s malloc fail\n", __func__);
|
||||
return ;
|
||||
}
|
||||
memset(password, '0', sizeof(length + 1));
|
||||
for (int i = length - 1 ; i >= 0 ; i--) {
|
||||
password[i] = data[data_ptr + i] + '0';
|
||||
}
|
||||
password[length] = '\n';
|
||||
coex_set_test_env("ap_password", password, length);
|
||||
coex_print_test_env();
|
||||
(*recv_param_bit) |= WIFI_PASSWIRD;
|
||||
free(password);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sync_cmd_recv(uint8_t *raw_data, uint32_t raw_data_len)
|
||||
{
|
||||
if (raw_data_len < MSG_MIN_LEN) {
|
||||
ESP_LOGD(TAG, "msg length is low");
|
||||
}
|
||||
sync_msg_head msg_head = {0};
|
||||
memcpy(&msg_head, raw_data, sizeof(sync_msg_head));
|
||||
|
||||
if (msg_head.type != MSG_TYPE || msg_head.head != MSG_HEAD) {
|
||||
ESP_LOGD(TAG, "msg is unknown");
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "msg_id: %x\n", msg_head.msg_id);
|
||||
// ESP_LOG_BUFFER_HEX("sync recv:", raw_data, raw_data_len);
|
||||
switch (sync_obj.state) {
|
||||
#if defined(CONFIG_EXAMPLE_WIFI_ROLE) || defined(CONFIG_EXAMPLE_BT_ROLE)
|
||||
case WAIT_CASE: {
|
||||
ESP_LOGD(TAG, "WAIT_CASE\n");
|
||||
if (msg_head.msg_id == MSG_ID_ASSIGN_CASE) {
|
||||
analys_param(msg_head.param_bit, raw_data + MSG_DATA_BASE, &sync_obj.recv_param_bit );
|
||||
#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
|
||||
if (sync_obj.own_wifi_case != NOT_CASE) {
|
||||
if ((sync_obj.recv_param_bit & auto_tb[sync_obj.own_wifi_case].excpet_param_bit) == auto_tb[sync_obj.own_wifi_case].excpet_param_bit) {
|
||||
excute_case(sync_obj.own_wifi_case);
|
||||
sync_obj.state = WAIT_START;
|
||||
esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_EXAMPLE_BT_ROLE)
|
||||
if (sync_obj.own_ble_case != NOT_CASE) {
|
||||
if ((sync_obj.recv_param_bit & auto_tb[sync_obj.own_ble_case].excpet_param_bit) == auto_tb[sync_obj.own_ble_case].excpet_param_bit) {
|
||||
sync_obj.state = WAIT_START;
|
||||
esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WAIT_START:
|
||||
ESP_LOGD(TAG, "WAIT_START\n");
|
||||
ESP_LOGD(TAG, "WAIT_START %x\n", msg_head.msg_id);
|
||||
if (msg_head.msg_id == MSG_ID_START_CASE) {
|
||||
analys_param(msg_head.param_bit, raw_data + MSG_DATA_BASE, &sync_obj.recv_param_bit );
|
||||
sync_obj.state = START_CASE;
|
||||
ble_gap_util_stop();
|
||||
#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
|
||||
bt_test_deinit();
|
||||
#endif
|
||||
esp_timer_stop(sync_obj.sync_timer);
|
||||
esp_timer_start_once(sync_obj.sync_timer, sync_obj.start_time * 1000000);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
case ASSIGN_CASE:
|
||||
ESP_LOGD(TAG, "ASSIGN_CASE\n");
|
||||
switch (msg_head.msg_id) {
|
||||
case MSG_ID_WIFI_DEV_INIT_FINISH:
|
||||
if (msg_head.param_bit != 0x0) {
|
||||
analys_param(msg_head.param_bit, raw_data + MSG_DATA_BASE, &sync_obj.recv_param_bit );
|
||||
}
|
||||
sync_obj.except_recv_wifi_id = true;
|
||||
break;
|
||||
case MSG_ID_BT_DEV_INIT_FINISH:
|
||||
sync_obj.except_recv_bt_id = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
send_start_countdown();
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ESP_LOGD(TAG, "state is unknown %s", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_sync_timeout(void *arg)
|
||||
{
|
||||
static bool run_first = true;
|
||||
if (run_first == true) {
|
||||
xSemaphoreTake((SemaphoreHandle_t)arg, (portTickType)portMAX_DELAY);
|
||||
esp_timer_start_periodic( (SemaphoreHandle_t)arg, 1000000);
|
||||
run_first = false;
|
||||
}
|
||||
switch (sync_obj.state) {
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
case ASSIGN_CASE:
|
||||
ESP_LOGD(TAG, "ASSIGN_CASE\n");
|
||||
assign_test_case();
|
||||
esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_WIFI_ROLE) || defined(CONFIG_EXAMPLE_BT_ROLE)
|
||||
case WAIT_START: {
|
||||
ESP_LOGD(TAG, "WAIT_START\n");
|
||||
#if defined(CONFIG_EXAMPLE_WIFI_ROLE)
|
||||
if ( WIFI_TCP_RX_CASE == sync_obj.own_wifi_case ) {
|
||||
send_tcp_rx_inited_msg();
|
||||
} else {
|
||||
send_case_inited_msg(MSG_ID_WIFI_DEV_INIT_FINISH);
|
||||
}
|
||||
#elif defined(CONFIG_EXAMPLE_BT_ROLE)
|
||||
send_case_inited_msg(MSG_ID_BT_DEV_INIT_FINISH);
|
||||
#endif
|
||||
esp_timer_start_periodic(sync_obj.sync_timer, SYNC_TIMEOUT);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
case START_CASE: {
|
||||
ESP_LOGD(TAG, "START_CASE\n");
|
||||
#if defined(CONFIG_EXAMPLE_BT_ROLE)
|
||||
excute_case(sync_obj.own_ble_case);
|
||||
|
||||
#elif defined(CONFIG_EXAMPLE_WIFI_ROLE)
|
||||
ESP_LOGD(TAG, "START_CASE\n");
|
||||
if (arg != NULL) {
|
||||
xSemaphoreGive((SemaphoreHandle_t)arg);
|
||||
run_first = true;
|
||||
esp_timer_stop(sync_obj.sync_timer);
|
||||
|
||||
}
|
||||
#else
|
||||
static uint8_t send_start_count = 10;
|
||||
if (send_start_count == 0) {
|
||||
excute_case(sync_obj.own_ble_case);
|
||||
xSemaphoreGive((SemaphoreHandle_t)arg);
|
||||
run_first = true;
|
||||
esp_timer_stop(sync_obj.sync_timer);
|
||||
break;
|
||||
}
|
||||
|
||||
send_start_msg(send_start_count);
|
||||
send_start_count -= 1;
|
||||
esp_timer_start_once(sync_obj.sync_timer, 1000000);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGD(TAG, "state is unknown%s", __func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t create_sync_timer(esp_timer_handle_t *timer_hdl)
|
||||
{
|
||||
esp_err_t ret;
|
||||
esp_timer_create_args_t tca = {
|
||||
.callback = (esp_timer_cb_t)handle_sync_timeout,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "SYNC_TIMER",
|
||||
};
|
||||
tca.arg = client_mutex;
|
||||
|
||||
ret = esp_timer_create(&tca, timer_hdl);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "timer create failed %d %x\n", __LINE__, ret);
|
||||
return ret;
|
||||
}
|
||||
esp_timer_start_once( *timer_hdl, 10);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void sync_init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
sync_obj.cmd_recv = &sync_cmd_recv;
|
||||
client_mutex = xSemaphoreCreateMutex();
|
||||
if (!client_mutex) {
|
||||
ESP_LOGE(TAG, "client_mutex Create failed ");
|
||||
return;
|
||||
}
|
||||
coex_set_test_env("mutex", NULL, 0);
|
||||
|
||||
bt_test_init();
|
||||
init_ble_gap_test_util();
|
||||
ret = esp_ble_gap_start_scanning(BLE_TC_SCAN_REPORT_PERIOD);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_ble_gap_start_scanning error, %d", ret);
|
||||
return ;
|
||||
}
|
||||
ret = create_sync_timer(&sync_obj.sync_timer);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "sync timer create failed");
|
||||
return ;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
excute_case(sync_obj.own_wifi_case);
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 __SYNC_H__
|
||||
#define __SYNC_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "ble_unit.h"
|
||||
#include "test_env.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "mesh_util.h"
|
||||
#define PARAM_MAX 7
|
||||
|
||||
#define SYNC_TIMEOUT 500000 //500ms
|
||||
#define PARAMTER(value) (((uint32_t)value) << 7)
|
||||
|
||||
#define WIFI_TCP_TX_CASE 0x0
|
||||
#define WIFI_TCP_RX_CASE 0x1
|
||||
#define BLE_ADV_CASE 0x2
|
||||
#define BLE_SCAN_CASE 0x3
|
||||
#define NOT_CASE 0xff
|
||||
|
||||
#define MSG_HEAD 0xcbb3
|
||||
#define MSG_TYPE 0xff
|
||||
#define MSG_CONTINUE 0x0
|
||||
#define MSG_END 0x1
|
||||
#define MSG_DATA_BASE 0x8
|
||||
#define MSG_ID_ASSIGN_CASE 0x1
|
||||
#define MSG_ID_WIFI_DEV_INIT_FINISH 0x2
|
||||
#define MSG_ID_BT_DEV_INIT_FINISH 0x3
|
||||
#define MSG_ID_START_CASE 0x4
|
||||
|
||||
#define BLE_CASE_ID 0b100000 << PARAM_MAX
|
||||
#define WIFI_CASE_ID 0b010000 << PARAM_MAX
|
||||
#define SERVER_IP 0b001000 << PARAM_MAX
|
||||
#define START_TIME 0b000100 << PARAM_MAX
|
||||
#define WIFI_SSID 0b000010 << PARAM_MAX
|
||||
#define WIFI_PASSWIRD 0b000001 << PARAM_MAX
|
||||
|
||||
|
||||
#define GET_PARAM(value,bit) (((value) & (bit)) ? bit:0x0)
|
||||
|
||||
#define MSG_MIN_LEN 8
|
||||
|
||||
typedef void (*sync_recv)(uint8_t *raw_data, uint32_t raw_data_len);
|
||||
|
||||
typedef struct {
|
||||
uint8_t length;
|
||||
uint8_t type;
|
||||
uint16_t head;
|
||||
uint8_t msg_id;
|
||||
uint16_t ctl: 3,
|
||||
param_bit: 13;
|
||||
} __attribute__((packed)) sync_msg_head;
|
||||
|
||||
typedef struct {
|
||||
uint8_t length;
|
||||
uint8_t type;
|
||||
uint16_t head;
|
||||
uint8_t msg_id;
|
||||
uint16_t ctl: 3,
|
||||
param_bit: 13;
|
||||
uint8_t reserve; //reserved for extend param_bit
|
||||
uint8_t data[23];
|
||||
} __attribute__((packed)) sync_msg;
|
||||
|
||||
typedef struct {
|
||||
uint8_t case_id;
|
||||
const uint16_t excpet_param_bit;
|
||||
} auto_tc;
|
||||
auto_tc auto_tb[6];
|
||||
|
||||
|
||||
typedef enum {
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
ASSIGN_CASE,
|
||||
#else
|
||||
WAIT_CASE,
|
||||
WAIT_START,
|
||||
#endif
|
||||
START_CASE,
|
||||
} sync_state;
|
||||
|
||||
struct sync_t {
|
||||
sync_state state;
|
||||
uint8_t own_wifi_case;
|
||||
uint8_t own_ble_case;
|
||||
uint8_t start_time;
|
||||
|
||||
uint16_t recv_param_bit;
|
||||
|
||||
bool except_recv_wifi_id;
|
||||
bool except_recv_bt_id;
|
||||
|
||||
esp_timer_handle_t sync_timer;
|
||||
sync_recv cmd_recv;
|
||||
};
|
||||
struct sync_t sync_obj;
|
||||
|
||||
extern SemaphoreHandle_t client_mutex;
|
||||
void sync_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "test_env.h"
|
||||
#include "sync.h"
|
||||
|
||||
#define TAG "ENV"
|
||||
|
||||
coex_test_env_t test_env = {
|
||||
#if defined(CONFIG_EXAMPLE_MANAUL)
|
||||
.ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
|
||||
.ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
|
||||
#endif
|
||||
#if defined(CONFIG_EXAMPLE_COEX_ROLE)
|
||||
.ap_ssid = CONFIG_EXAMPLE_WIFI_SSID,
|
||||
.ap_password = CONFIG_EXAMPLE_WIFI_PASSWORD,
|
||||
#endif
|
||||
.test_port = "8080",
|
||||
.server_ip = "192.168.3.32",
|
||||
.duration = "120000",
|
||||
.is_start = false,
|
||||
};
|
||||
|
||||
esp_err_t coex_set_test_env(const char *keyword, const char *value, uint8_t length)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (!strcmp(keyword, "ap_ssid")) {
|
||||
memset(test_env.ap_ssid, '\0', sizeof(test_env.ap_ssid));
|
||||
strncpy(test_env.ap_ssid, value, length);
|
||||
} else if (!strcmp(keyword, "ap_password")) {
|
||||
memset(test_env.ap_password, '\0', sizeof(test_env.ap_password));
|
||||
strncpy(test_env.ap_password, value, length);
|
||||
} else if (!strcmp( keyword, "test_port")) {
|
||||
memset(test_env.test_port, '\0', sizeof(test_env.test_port));
|
||||
strncpy(test_env.test_port, value, length);
|
||||
} else if (!strcmp(keyword, "server_ip")) {
|
||||
memset(test_env.server_ip, '\0', sizeof(test_env.server_ip));
|
||||
strncpy(test_env.server_ip, value, length);
|
||||
} else if (!strcmp(keyword, "duration")) {
|
||||
strncpy(test_env.duration, value, length);
|
||||
} else if (!strcmp(keyword, "mutex")) {
|
||||
test_env.run_mutex = client_mutex;
|
||||
|
||||
} else {
|
||||
ret = ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *coex_get_test_env(const char *keyword)
|
||||
{
|
||||
const char *ret = NULL;
|
||||
if (!strcmp(keyword, "ap_ssid")) {
|
||||
ret = test_env.ap_ssid;
|
||||
} else if (!strcmp(keyword, "ap_password")) {
|
||||
ret = test_env.ap_password;
|
||||
} else if (!strcmp(keyword, "test_port")) {
|
||||
ret = test_env.test_port;
|
||||
} else if (!strcmp(keyword, "server_ip")) {
|
||||
ret = test_env.server_ip;
|
||||
} else if (!strcmp(keyword, "duration")) {
|
||||
ret = test_env.duration;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void coex_print_test_env(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "current test env:");
|
||||
ESP_LOGI(TAG, "\tap_ssid: %s", test_env.ap_ssid);
|
||||
ESP_LOGI(TAG, "\tap_password: %s", test_env.ap_password);
|
||||
ESP_LOGI(TAG, "\ttest_port: %s", test_env.test_port);
|
||||
ESP_LOGI(TAG, "\tserver_ip: %s", test_env.server_ip);
|
||||
ESP_LOGI(TAG, "\tduration: %s", test_env.duration);
|
||||
}
|
||||
|
||||
bool coex_env_str_to_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
|
||||
ESP_LOGE(TAG, "wrong format");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (loop = 0; loop < 17 ; loop++) {
|
||||
if (loop % 3 == 2) {
|
||||
if (src_p[loop] != ':') {
|
||||
ESP_LOGE(TAG, "wrong format");
|
||||
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 {
|
||||
ESP_LOGE(TAG, "wrong format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (loop % 3 == 1) {
|
||||
*dest++ = tmp;
|
||||
tmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 __TEST_ENV_H__
|
||||
#define __TEST_ENV_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#define MAX_SSID_LEN 32
|
||||
#define MAX_PASSWORD_LEN 64
|
||||
#define MAX_IP_STR_LEN 15
|
||||
#define MAX_PORT_STR_LEN 5
|
||||
#define MAX_MAC_ADDR_LEN 17
|
||||
#define INVALID_REMOTE_BT_MAC "ff:ff:ff:ff:ff:ff"
|
||||
#define DURATION_MAX_LEN 10
|
||||
|
||||
typedef struct {
|
||||
char ap_ssid[MAX_SSID_LEN + 1];
|
||||
char ap_password[MAX_PASSWORD_LEN + 1];
|
||||
char test_port[MAX_PORT_STR_LEN + 1];
|
||||
char server_ip[MAX_IP_STR_LEN + 1];
|
||||
char duration[DURATION_MAX_LEN + 1];
|
||||
bool is_start;
|
||||
SemaphoreHandle_t run_mutex;
|
||||
} coex_test_env_t;
|
||||
|
||||
extern coex_test_env_t test_env;
|
||||
|
||||
esp_err_t coex_set_test_env(const char *keyword, const char *value, uint8_t length);
|
||||
const char *coex_get_test_env(const char *keyword);
|
||||
void coex_print_test_env(void);
|
||||
bool coex_env_str_to_mac(uint8_t *str, uint8_t *dest);
|
||||
|
||||
#endif /* __TEST_ENV_H__ */
|
||||
@@ -0,0 +1,158 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "wifi_connect.h"
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_wifi_default.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_netif.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#define GOT_IPV4_BIT BIT(0)
|
||||
|
||||
#define CONNECTED_BITS (GOT_IPV4_BIT)
|
||||
|
||||
|
||||
static EventGroupHandle_t s_connect_event_group;
|
||||
static esp_ip4_addr_t s_ip_addr;
|
||||
static const char *s_connection_name;
|
||||
static esp_netif_t *s_example_esp_netif = NULL;
|
||||
|
||||
|
||||
|
||||
static const char *TAG = "example_connect";
|
||||
|
||||
/* set up connection, Wi-Fi or Ethernet */
|
||||
static void start(const char *ssid, const char *passwd);
|
||||
|
||||
/* tear down connection, release resources */
|
||||
static void stop(void);
|
||||
|
||||
static void on_got_ip(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGI(TAG, "Got IP event!");
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr));
|
||||
xEventGroupSetBits(s_connect_event_group, GOT_IPV4_BIT);
|
||||
}
|
||||
|
||||
esp_err_t example_connect(const char *ssid, const char *passwd)
|
||||
{
|
||||
if (s_connect_event_group != NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
s_connect_event_group = xEventGroupCreate();
|
||||
start(ssid, passwd);
|
||||
ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop));
|
||||
ESP_LOGI(TAG, "Waiting for IP");
|
||||
xEventGroupWaitBits(s_connect_event_group, CONNECTED_BITS, true, true, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Connected to %s", s_connection_name);
|
||||
ESP_LOGI(TAG, "IPv4 address: " IPSTR, IP2STR(&s_ip_addr));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t example_disconnect(void)
|
||||
{
|
||||
if (s_connect_event_group == NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
vEventGroupDelete(s_connect_event_group);
|
||||
s_connect_event_group = NULL;
|
||||
stop();
|
||||
ESP_LOGI(TAG, "Disconnected from %s", s_connection_name);
|
||||
s_connection_name = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static void on_wifi_disconnect(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
ESP_LOGI(TAG, "Wi-Fi disconnected, trying to reconnect...");
|
||||
esp_err_t err = esp_wifi_connect();
|
||||
if (err == ESP_ERR_WIFI_NOT_STARTED) {
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
static void start(const char *ssid, const char *passwd)
|
||||
{
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_WIFI_STA();
|
||||
|
||||
esp_netif_t *netif = esp_netif_new(&netif_config);
|
||||
|
||||
assert(netif);
|
||||
|
||||
esp_netif_attach_wifi_station(netif);
|
||||
esp_wifi_set_default_wifi_sta_handlers();
|
||||
|
||||
s_example_esp_netif = netif;
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip, NULL));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
|
||||
|
||||
wifi_config_t wifi_config;
|
||||
memset(&wifi_config, 0, sizeof(wifi_config));
|
||||
if (ssid) {
|
||||
strncpy((char *)wifi_config.sta.ssid, ssid, strlen(ssid));
|
||||
}
|
||||
if (passwd) {
|
||||
strncpy((char *)wifi_config.sta.password, passwd, strlen(passwd));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Connecting to %s...", wifi_config.sta.ssid);
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
ESP_ERROR_CHECK(esp_wifi_connect());
|
||||
s_connection_name = ssid;
|
||||
}
|
||||
|
||||
static void stop(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect));
|
||||
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip));
|
||||
esp_err_t err = esp_wifi_stop();
|
||||
if (err == ESP_ERR_WIFI_NOT_INIT) {
|
||||
return;
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
ESP_ERROR_CHECK(esp_wifi_deinit());
|
||||
ESP_ERROR_CHECK(esp_wifi_clear_default_wifi_driver_and_handlers(s_example_esp_netif));
|
||||
esp_netif_destroy(s_example_esp_netif);
|
||||
s_example_esp_netif = NULL;
|
||||
}
|
||||
|
||||
esp_netif_t *get_example_netif(void)
|
||||
{
|
||||
return s_example_esp_netif;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 __WIFI_CONNECT_H__
|
||||
#define __WIFI_CONNECT_H__
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
esp_err_t example_connect(const char *ssid, const char *passwd);
|
||||
esp_err_t example_disconnect(void);
|
||||
esp_err_t example_configure_stdin_stdout(void);
|
||||
esp_netif_t *get_example_netif(void);
|
||||
|
||||
#endif /* __WIFI_CONNECT_H__ */
|
||||
@@ -0,0 +1,187 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "wifi_unit.h"
|
||||
#include "wifi_connect.h"
|
||||
#define TAG "WIFI_UINT"
|
||||
|
||||
uint32_t utils_get_system_ts(void)
|
||||
{
|
||||
return esp_log_timestamp();
|
||||
}
|
||||
|
||||
esp_err_t wifi_unit_client_establish(int *sock, const char *ip, const char *port)
|
||||
{
|
||||
esp_err_t ret = 0;
|
||||
uint32_t start_ts;
|
||||
uint32_t timeout = 10000;
|
||||
struct sockaddr_in sock_addr;
|
||||
int s;
|
||||
|
||||
memset(&sock_addr, 0, sizeof(sock_addr));
|
||||
sock_addr.sin_family = AF_INET;
|
||||
sock_addr.sin_addr.s_addr = ipaddr_addr(ip);
|
||||
sock_addr.sin_port = htons(atoi(port));
|
||||
|
||||
start_ts = utils_get_system_ts();
|
||||
do {
|
||||
s = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (s < 0) {
|
||||
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
||||
}
|
||||
ret = connect(s, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
|
||||
if (ret == 0) {
|
||||
*sock = s;
|
||||
break;
|
||||
} else if (s > 0) {
|
||||
close(s);
|
||||
}
|
||||
} while (utils_get_system_ts() - start_ts < timeout);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t wifi_unit_server_establish(int *socket_id, const char *port)
|
||||
{
|
||||
esp_err_t ret = -1;
|
||||
struct sockaddr_in local_addr;
|
||||
uint32_t local_ip;
|
||||
|
||||
static int ls_sock = -1;
|
||||
|
||||
local_ip = wifi_util_get_ip();
|
||||
|
||||
if (ls_sock < 0) {
|
||||
ls_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
if (ls_sock < 0) {
|
||||
ESP_LOGE(TAG, "create socket failed");
|
||||
return ls_sock;
|
||||
}
|
||||
|
||||
local_addr.sin_family = AF_INET;
|
||||
local_addr.sin_port = htons(atoi(port));
|
||||
local_addr.sin_addr.s_addr = local_ip;
|
||||
ret = bind(ls_sock, (struct sockaddr *)&local_addr, sizeof(local_addr));
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "socket bind failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = listen(ls_sock, 1);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "socket listen failed");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6
|
||||
socklen_t addrLen = sizeof(sourceAddr);
|
||||
*socket_id = accept(ls_sock, (struct sockaddr *)&sourceAddr, &addrLen);
|
||||
if (*socket_id < 0) {
|
||||
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
|
||||
return -1;
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket accepted");
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t wifi_unit_tcp_recv(int socket_id, const char *duration, uint32_t user_date[])
|
||||
{
|
||||
esp_err_t ret = -1;
|
||||
uint32_t start_ts;
|
||||
uint8_t *buffer;
|
||||
struct timeval tv_t;
|
||||
uint32_t *recv_len = &user_date[1];
|
||||
tv_t.tv_sec = 1;
|
||||
tv_t.tv_usec = 0;
|
||||
ret = setsockopt(socket_id, SOL_SOCKET, SO_RCVTIMEO, &tv_t, sizeof(tv_t));
|
||||
|
||||
buffer = malloc(2920);
|
||||
|
||||
if (buffer == NULL) {
|
||||
ESP_LOGE(TAG, "%s malloc fail\n", __func__);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
start_ts = utils_get_system_ts();
|
||||
|
||||
while (utils_get_system_ts() - start_ts < atoi(duration)) {
|
||||
ret = recv(socket_id, buffer, 2920, 0);
|
||||
if (ret > 0) {
|
||||
*recv_len = *recv_len + ret;
|
||||
} else if (ret == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(buffer);
|
||||
if (ret > 0 ) {
|
||||
ret = ESP_OK;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t wifi_util_tcp_send(int socket_id, uint32_t len, uint32_t delay, uint32_t *sent_len, uint32_t timeout)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t start_ts;
|
||||
uint8_t *buffer;
|
||||
|
||||
if ( len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
buffer = malloc(len);
|
||||
if (buffer == NULL) {
|
||||
ESP_LOGE(TAG, "%s malloc fail\n", __func__);
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
start_ts = utils_get_system_ts();
|
||||
|
||||
while (utils_get_system_ts() - start_ts < timeout) {
|
||||
ret = send(socket_id, buffer, len, 0);
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "recv failed: errno %d", errno);
|
||||
break;
|
||||
}
|
||||
*sent_len = *sent_len + ret;
|
||||
|
||||
if (delay) {
|
||||
vTaskDelay(delay / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
if (ret == len) {
|
||||
ret = ESP_OK;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "tcp send error, %d", ret);
|
||||
ret = -2;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t wifi_util_get_ip(void)
|
||||
{
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_t *netif = get_example_netif();
|
||||
esp_netif_get_ip_info(netif, &ip_info);
|
||||
return ip_info.ip.addr;
|
||||
}
|
||||
|
||||
void wifi_util_init(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 _WIFI_UNIT_H
|
||||
#define _WIFI_UNIT_H
|
||||
|
||||
#include "esp_wifi_types.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_netif.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/dns.h"
|
||||
|
||||
uint32_t utils_get_system_ts(void);
|
||||
|
||||
void wifi_util_init(void);
|
||||
|
||||
uint32_t wifi_util_get_ip(void);
|
||||
esp_err_t wifi_unit_client_establish(int *sock, const char *ip, const char *port);
|
||||
esp_err_t wifi_unit_server_establish(int *socket_id, const char *port);
|
||||
|
||||
esp_err_t wifi_unit_tcp_recv(int socket_id, const char *duration, uint32_t user_date[]);
|
||||
esp_err_t wifi_util_tcp_send(int socket_id, uint32_t len, uint32_t delay, uint32_t *sent_len, uint32_t timeout);
|
||||
#endif /* _WIFI_UNIT_H */
|
||||
@@ -0,0 +1,3 @@
|
||||
idf_component_register(SRCS "main.c" "coex_cmd.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRED_IDF_TARGETS esp32)
|
||||
@@ -0,0 +1,70 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_RUN_MODE
|
||||
prompt "select run mode"
|
||||
help
|
||||
select run mode
|
||||
|
||||
config EXAMPLE_AUTO
|
||||
bool "auto"
|
||||
help
|
||||
In automatic mode, the program coordinates three development board work
|
||||
through a synchronization mechanism.
|
||||
|
||||
config EXAMPLE_MANAUL
|
||||
bool "manual"
|
||||
help
|
||||
In manual mode, you will work with three development boards via commands.
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_WIFI_SSID
|
||||
depends on EXAMPLE_MANAUL
|
||||
string "WiFi SSID"
|
||||
help
|
||||
SSID (network name) for the example to connect to. The length cannot exceed 20 bytes.
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
depends on EXAMPLE_MANAUL
|
||||
string "WiFi Password"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
Can be left blank if the network has no security set.
|
||||
The length cannot exceed 20 bytes.
|
||||
|
||||
choice EXAMPLE_SELECT_ROLE
|
||||
prompt "select role"
|
||||
depends on EXAMPLE_AUTO
|
||||
config EXAMPLE_COEX_ROLE
|
||||
bool "run device as coex role"
|
||||
config EXAMPLE_WIFI_ROLE
|
||||
bool "run device as wifi role"
|
||||
config EXAMPLE_BT_ROLE
|
||||
bool "run device as bluetooth role"
|
||||
endchoice
|
||||
|
||||
choice EXAMPLE_SELECT_CASE
|
||||
prompt "select case"
|
||||
depends on EXAMPLE_COEX_ROLE
|
||||
config EXAMPLE_COEX_TX_ADV
|
||||
bool "TCP TX and BLE ADV"
|
||||
config EXAMPLE_COEX_RX_ADV
|
||||
bool "TCP RX and BLE ADV"
|
||||
config EXAMPLE_COEX_TX_SCAN
|
||||
bool "TCP TX and BLE SCAN"
|
||||
config EXAMPLE_COEX_RX_SCAN
|
||||
bool "TCP RX and BLE SCAN"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_WIFI_SSID
|
||||
depends on EXAMPLE_COEX_ROLE
|
||||
string "WiFi SSID"
|
||||
help
|
||||
SSID (network name) for the example to connect to. The length cannot exceed 20 bytes.
|
||||
config EXAMPLE_WIFI_PASSWORD
|
||||
depends on EXAMPLE_COEX_ROLE
|
||||
string "WiFi Password"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
Can be left blank if the network has no security set.
|
||||
The length cannot exceed 20 bytes.
|
||||
|
||||
endmenu #"Example Configuration End"
|
||||
@@ -0,0 +1,168 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "esp_log.h"
|
||||
#include "esp_console.h"
|
||||
#include "argtable3/argtable3.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
|
||||
#include "run_tc.h"
|
||||
#include "test_env.h"
|
||||
|
||||
|
||||
#define TAG_CNSL "CNSL"
|
||||
|
||||
typedef struct {
|
||||
struct arg_str *wifi_tc_idx;
|
||||
struct arg_str *bt_tc_idx;
|
||||
struct arg_end *end;
|
||||
} tc_run_args_t;
|
||||
|
||||
typedef struct {
|
||||
struct arg_lit *set;
|
||||
struct arg_lit *get;
|
||||
struct arg_str *key;
|
||||
struct arg_str *value;
|
||||
struct arg_end *end;
|
||||
} env_param_cmd_args_t;
|
||||
|
||||
static tc_run_args_t tc_run_args;
|
||||
static env_param_cmd_args_t env_param_cmd_args;
|
||||
|
||||
static int process_env_parameter_cmd(int argc, char **argv)
|
||||
{
|
||||
int nerrors = arg_parse(argc, argv, (void **) &env_param_cmd_args);
|
||||
int ret;
|
||||
const char *env_value = "";
|
||||
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, env_param_cmd_args.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (env_param_cmd_args.set->count == 1) {
|
||||
if (env_param_cmd_args.key->count == 1) {
|
||||
if (env_param_cmd_args.value->count == 1) {
|
||||
env_value = env_param_cmd_args.value->sval[0];
|
||||
}
|
||||
ret = coex_set_test_env(env_param_cmd_args.key->sval[0], env_value, strlen(env_param_cmd_args.value->sval[0]));
|
||||
if (ret == ESP_ERR_NOT_SUPPORTED) {
|
||||
ESP_LOGE(TAG_CNSL, "Not supported env key");
|
||||
} else if (ret == ESP_ERR_INVALID_ARG) {
|
||||
ESP_LOGE(TAG_CNSL, "Invalid value");
|
||||
}
|
||||
ESP_LOGI(TAG_CNSL, "env set done");
|
||||
} else {
|
||||
ESP_LOGE(TAG_CNSL, "env key not set correctly");
|
||||
}
|
||||
} else if (env_param_cmd_args.get->count == 1) {
|
||||
coex_print_test_env();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_restart_cmd(int argc, char **argv)
|
||||
{
|
||||
ESP_LOGI(TAG_CNSL, "restarting...");
|
||||
esp_restart();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int process_run_tc_cmd(int argc, char **argv)
|
||||
{
|
||||
run_task_msg_t msg;
|
||||
int nerrors = arg_parse(argc, argv, (void **) &tc_run_args);
|
||||
if (nerrors != 0) {
|
||||
arg_print_errors(stderr, tc_run_args.end, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (tc_run_args.wifi_tc_idx->count == 1) {
|
||||
msg.case_id = atoi(tc_run_args.wifi_tc_idx->sval[0]);
|
||||
if (xQueueSend(xTaskQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG_CNSL, "xTaskQueue Post failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (tc_run_args.bt_tc_idx->count == 1) {
|
||||
msg.case_id = atoi(tc_run_args.bt_tc_idx->sval[0]);
|
||||
if (xQueueSend(xTaskQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG_CNSL, "xTaskQueue Post failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_get_mac_addr_cmd(int argc, char **argv)
|
||||
{
|
||||
const uint8_t *mac = esp_bt_dev_get_address();
|
||||
|
||||
if (mac != NULL) {
|
||||
ESP_LOGI(TAG_CNSL, "+BTMAC:"MACSTR"\n", MAC2STR(mac));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void register_coex_cmd(void)
|
||||
{
|
||||
const esp_console_cmd_t restart_cmd = {
|
||||
.command = "restart",
|
||||
.help = "restart cmd",
|
||||
.hint = NULL,
|
||||
.func = &process_restart_cmd,
|
||||
.argtable = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&restart_cmd) );
|
||||
|
||||
const esp_console_cmd_t get_mac_cmd = {
|
||||
.command = "mac",
|
||||
.help = "Get DUT mac address",
|
||||
.hint = NULL,
|
||||
.func = &process_get_mac_addr_cmd,
|
||||
.argtable = NULL
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&get_mac_cmd) );
|
||||
|
||||
tc_run_args.wifi_tc_idx = arg_str0("w", "wifi", "<str>", "0 : wifi_tcp_tx_throught 1 : wifi_tcp_rx_throught\n");
|
||||
tc_run_args.bt_tc_idx = arg_str0("b", "bluetooth", "<str>", "2 :ble_adv 3 : ble_scan\n");
|
||||
tc_run_args.end = arg_end(2);
|
||||
|
||||
const esp_console_cmd_t run_tc_cmd = {
|
||||
.command = "run_tc",
|
||||
.help = "run wifi bt test case command",
|
||||
.hint = NULL,
|
||||
.func = &process_run_tc_cmd,
|
||||
.argtable = &tc_run_args
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&run_tc_cmd) );
|
||||
|
||||
env_param_cmd_args.set = arg_lit0("s", "set", "set env parameter");
|
||||
env_param_cmd_args.get = arg_lit0("g", "get", "get env parameter");
|
||||
env_param_cmd_args.key = arg_str0("k", "key", "<str>", "env parameter key");
|
||||
env_param_cmd_args.value = arg_str0("v", "value", "<str>", "env parameter value (only used with set)");
|
||||
env_param_cmd_args.end = arg_end(4);
|
||||
|
||||
const esp_console_cmd_t env_cmd = {
|
||||
.command = "env",
|
||||
.help = "Set or get test environment parameters",
|
||||
.hint = NULL,
|
||||
.func = &process_env_parameter_cmd,
|
||||
.argtable = &env_param_cmd_args,
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( esp_console_cmd_register(&env_cmd) );
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 MAIN_COEX_CMD_H_
|
||||
#define MAIN_COEX_CMD_H_
|
||||
|
||||
#define CNSL_CMD_OUTPUT_PREFIX "COEX_CNSL_OUTPUT"
|
||||
void register_coex_cmd(void);
|
||||
|
||||
#endif /* MAIN_COEX_CMD_H_ */
|
||||
@@ -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,145 @@
|
||||
/* ESP BLE Mesh Example
|
||||
|
||||
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 "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_coexist.h"
|
||||
#include "coex_cmd.h"
|
||||
#include "run_tc.h"
|
||||
#include "sync.h"
|
||||
|
||||
static void initialize_nvs(void)
|
||||
{
|
||||
esp_err_t err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK( nvs_flash_erase() );
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
static void initialize_console(void)
|
||||
{
|
||||
/* Disable buffering on stdin and stdout */
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
|
||||
/* Minicom, screen, idf_monitor send CR when ENTER key is pressed */
|
||||
esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR);
|
||||
/* Move the caret to the beginning of the next line on '\n' */
|
||||
esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF);
|
||||
|
||||
/* Configure UART. Note that REF_TICK is used so that the baud rate remains
|
||||
* correct while APB frequency is changing in light sleep mode.
|
||||
*/
|
||||
const uart_config_t uart_config = {
|
||||
.baud_rate = CONFIG_CONSOLE_UART_BAUDRATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.use_ref_tick = true
|
||||
};
|
||||
ESP_ERROR_CHECK( uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config) );
|
||||
|
||||
/* 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 = 8,
|
||||
.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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
initialize_nvs();
|
||||
|
||||
initialize_console();
|
||||
run_tc_init();
|
||||
|
||||
/* Register commands */
|
||||
esp_console_register_help_command();
|
||||
register_coex_cmd();
|
||||
|
||||
#if defined(CONFIG_EXAMPLE_AUTO)
|
||||
sync_init();
|
||||
#endif
|
||||
|
||||
/* Prompt to be printed before each line.
|
||||
* This can be customized, made dynamic, etc.
|
||||
*/
|
||||
printf("esp-idf version: %s\n\n", esp_get_idf_version());
|
||||
printf("coexist version: %s\n\n", esp_coex_version_get());
|
||||
const char *prompt = "esp32> ";
|
||||
linenoiseSetDumbMode(1);
|
||||
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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("Command returned non-zero error code: 0x%x (%s)\n", ret, esp_err_to_name(err));
|
||||
} else if (err != ESP_OK) {
|
||||
printf("Internal error: %s\n", esp_err_to_name(err));
|
||||
}
|
||||
/* linenoise allocates line buffer on the heap, so need to free it */
|
||||
linenoiseFree(line);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 0x1F0000,
|
||||
|
@@ -0,0 +1,110 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Espressif IoT Development Framework Configuration
|
||||
#
|
||||
|
||||
#
|
||||
# SDK tool configuration
|
||||
#
|
||||
CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES=y
|
||||
#
|
||||
# Partition Table
|
||||
#
|
||||
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
|
||||
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_APP_OFFSET=0x10000
|
||||
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_BAUD_921600B=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
|
||||
#
|
||||
# Component config
|
||||
#
|
||||
#
|
||||
# Bluetooth
|
||||
#
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_PINNED_TO_CORE=1
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_BLE_SCAN_DUPL=y
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_BLUEDROID_ENABLED=y
|
||||
CONFIG_BT_BLUEDROID_PINNED_TO_CORE_1=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST=y
|
||||
CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY=y
|
||||
CONFIG_BT_SMP_ENABLE=y
|
||||
CONFIG_BT_RESERVE_DRAM=0x10000
|
||||
|
||||
#
|
||||
# ESP32-specific
|
||||
#
|
||||
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
|
||||
CONFIG_MEMMAP_SMP=y
|
||||
CONFIG_ESP32_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096
|
||||
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
|
||||
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=6
|
||||
CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
|
||||
CONFIG_SPIRAM_IGNORE_NOTFOUND=y
|
||||
|
||||
#
|
||||
# Wi-Fi
|
||||
#
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE=y
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_BALANCE=y
|
||||
CONFIG_ESP32_WIFI_SW_COEXIST_PREFERENCE_VALUE=2
|
||||
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=64
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
|
||||
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
|
||||
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
|
||||
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_TX_BA_WIN=16
|
||||
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_RX_BA_WIN=16
|
||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||
CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=6
|
||||
|
||||
#
|
||||
# FreeRTOS
|
||||
#
|
||||
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=1536
|
||||
CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=5
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
#
|
||||
# LWIP
|
||||
#
|
||||
CONFIG_LWIP_IP_FRAG=y
|
||||
CONFIG_LWIP_IP_REASSEMBLY=y
|
||||
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
|
||||
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534
|
||||
CONFIG_LWIP_TCP_WND_DEFAULT=65534
|
||||
CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
|
||||
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
|
||||
CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0=y
|
||||
CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x0
|
||||
|
||||
#
|
||||
# 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_GENERIC_ONOFF_CLI=y
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,12 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# 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,166 @@
|
||||
# The Document of ESP32 BLE_MESH Commands
|
||||
|
||||
## Overall Command
|
||||
|
||||
|
||||
* `bmreg`: Provisioner/node register callback
|
||||
* Example: `bmreg`
|
||||
* Result: `Bm:Reg,OK`
|
||||
|
||||
* `bminit`: Provisioner/node initialize
|
||||
* `-m`: `mesh modle`
|
||||
* Example: `bminit -m 0x0001`
|
||||
* Result: `Bm:Init,OK`
|
||||
|
||||
* `bmpbind`: Provisioner binds Appkey with local model
|
||||
* `-a`: `<appkey index>:appkey index`
|
||||
* `-e`: `<element address>:element address`
|
||||
* `-n`: `<network index>:network index`
|
||||
* `-m`: `<model id>:model id`
|
||||
* `-c`: `<model id>:company id`
|
||||
* Example: `bmpbind -a 0 -e 0x01 -m 0x1001 -n 0x00`
|
||||
* Result: `provisioning:AppKeyBind,OK`
|
||||
|
||||
* `bmpdev`: Provisioner add/delete unprovisioned device
|
||||
* `-z`: `action type <add/delete>`
|
||||
* `-d`: `device address`
|
||||
* `-u`: `device uuid`
|
||||
* `-a`: `address type`
|
||||
* `-f`: `address flag`
|
||||
* `-b`: `used bearer`
|
||||
* `-o`: `oob information`
|
||||
* Example: `bmpdev -z add -d bt_mac -b -1 -a 0`
|
||||
* Result: `provisioner:DevAdd/Del,OK`
|
||||
|
||||
* `bmoob`: Provisioner/node config OOB parameters
|
||||
* `-s`: `Static OOB value`
|
||||
* `-l`: `Static OOB value length`
|
||||
* `-x`: `Maximum size of Output OOB`
|
||||
* `-o`: `Supported Output OOB Actions`
|
||||
* `-y`: `Maximum size of Input OOB`
|
||||
* `-i`: `Supported Input OOB Actions`
|
||||
* `-p`: `start address assigned by provisioner`
|
||||
* Example: `bmoob -o -0 -x 0`
|
||||
* Result: `OOB:Load,OK`
|
||||
|
||||
* `bmpbearer`: Enable/disable provisioner different bearer
|
||||
* `-b`: `bearer supported`
|
||||
* `-e`: `enable or disable bearer`
|
||||
* Example: `bmpbearer -b 1 -e 1`
|
||||
* Result: `provisioner:EnBearer,OK`
|
||||
|
||||
* `bmnbearer`: Enable/disable node different bearer
|
||||
* `-b`: `bearer supported`
|
||||
* `-e`: `enable or disable bearer`
|
||||
* Example: `bmnbearer -b 1 -e 1`
|
||||
* Result: `Node:EnBearer,OK`
|
||||
|
||||
* `bmpkey`: Add/Delete NetKey and AppKey of Provisioner
|
||||
* `-z`: `<action type>:add app key or network key`
|
||||
* `-n`: `<net key index>:network key index`
|
||||
* `-k`: `<key>:appkey or network`
|
||||
* `-a`: `<app key index>:appkey index`
|
||||
* Example: `bmpkey -z netkey -n 1 -k <network_key>`
|
||||
* Result: `provisioner:NetKeyAdd,OK`
|
||||
|
||||
* `bmccm`: BLE Mesh configuration client model operations
|
||||
* `-z`: `<action>:action type`:add or del client model
|
||||
* `-x`: `<state>:set state`
|
||||
* `-o`: `<opcode>:message opcode`
|
||||
* `-u`: `<address>:unicast address`
|
||||
* `-n`: `<network>:net work index`
|
||||
* `-i`: `<index>:appkey index`
|
||||
* `-r`: `<relay>:relay statue`
|
||||
* `-t`: `<transmit>:relay transmit`
|
||||
* `-c`: `<cid>:company id`
|
||||
* `-v`: `<value>:value`
|
||||
* `-a`: `<address>:address`
|
||||
* `-m`: `<mod id>:model id`
|
||||
* Example: `bmccm -z reg`
|
||||
* Result: `ConfigClient:OK`
|
||||
|
||||
* `bmgocm`: BLE Mesh onoff client model operations
|
||||
* `-z`: `<action>:action type`: on or off client model
|
||||
* `-o`: `<opcode>:message opcode`
|
||||
* `-u`: `<address>:unicast address`
|
||||
* `-n`: `<netkey index>:network key index`
|
||||
* `-a`: `<index>:appkey index`
|
||||
* `-r`: `<role>:role`
|
||||
* `-t`: `<time>:time to complete state transition`
|
||||
* `-e`: `<optional>:whether optional parameters included`
|
||||
* `-s` : `<state>:present onoff state`
|
||||
* `-a`: `<address>:address`
|
||||
* `-i`: `<identifier>:transaction identifier`
|
||||
* `-d`: `<delay>:indicate message execution delay`
|
||||
* Example: `bmgocm -z reg`
|
||||
* Result: `GenONOFFClient:Reg,OK`
|
||||
|
||||
* `bmnreset`: Reset node to become an unprovisioned device
|
||||
* Example: `bmnreset`
|
||||
* Result: `Node:Reset`
|
||||
|
||||
* `bmpublish`: BLE Mesh model publication
|
||||
* `-d`: `<data>:message data`
|
||||
* `-o`: `<opcode>:operation opcode`
|
||||
* `-m`: `<module>:module published to`
|
||||
* `-r`: `<role>:device role`
|
||||
* `-a`: `<address>:unicast address`
|
||||
* `-i`: `<app key>:app key index`
|
||||
* `-p`: `<period>:period`
|
||||
* Example: `bmpublish -d 1 -o 0x8204 -m 0x1000 -r 0 -a 1 -p 0 -i 0`
|
||||
* Result: `PublishSend,OK`
|
||||
|
||||
* `bmnnwk`: An unprovisioned device enters the mesh network and becomes a node without the provisioning procedure
|
||||
* `-k`: `<net key>:network key`
|
||||
* `-n`: `<net index>:network key index`
|
||||
* `-u`: `<unicast address>:unicast address`
|
||||
* `-d`: `<device key>:device key`
|
||||
* `-a`: `<appkey>:app key`
|
||||
* `-i`: `<app key>:app key index`
|
||||
* `-g`: `<group address>:group address`
|
||||
* Example: `bnnnwk -k 0x1000 -n 1 -u 0x0010 -a 0x%s -d0x%s -i 0 -g 0xC000`
|
||||
* Result: `Provisioning:Success,%d`
|
||||
|
||||
* `bmpaddn`: Provisioner add device's information into the mesh database while unprovisioned device enter mesh network automatically
|
||||
* `-o`: `<oob info>:oob information`
|
||||
* `-a`: `<unicast address>:unicast address`
|
||||
* `-e`: `<element num>:element num`
|
||||
* `-n`: `<net index>:net index`
|
||||
* `-d`: `<device key>:device key`
|
||||
* `-u`: `<device uuid>:device uuid`
|
||||
* Example: `bmpaddn -o -0x0 -a %s -e 1 -n 1 -d 0x%s -u 0x%s`
|
||||
* Result: `Provisioner:AddNodeInfo,OK`
|
||||
|
||||
* `bmcperf`: BLE Mesh client test performance
|
||||
* `-z`: `<action>:action type`:init/get/destroy/percent
|
||||
* `-s`: `<test size>:test size`
|
||||
* `-n`: `<node number>:node number`
|
||||
* `-l`: `<test number>:ttl`
|
||||
* Example: `bmcperf -z init -n 1 -s %d -l 7`
|
||||
* Result: `VendorPerfTest:InitStatistics,OK`
|
||||
|
||||
* `bmperf`: BLE Mesh vendor server model performance test
|
||||
* `-z`: `<action>:action type`:init/get/destroy/percent
|
||||
* `-p`: `<package>:package number`
|
||||
* Example: `bmsperf -z init -p %d`
|
||||
* Result: `Node:InitStatistics,OK`
|
||||
|
||||
* `bmtpcvm`: BLE Mesh vendor client model performance test
|
||||
* `-z`: `<action>:action type`:init or start
|
||||
* `-p`: `<byte>:playload byte`
|
||||
* `-n`: `<number>:test number`
|
||||
* `-o`: `<opcode>:opcode`
|
||||
* `-u`: `<address>:unicast address`
|
||||
* `-t`: `<ttl>:ttl`
|
||||
* `-a`: `<appkey>:appkey index`
|
||||
* `-i`: `<network key>:network key index`
|
||||
* `-d`: `<role>:device role`
|
||||
* Example: `bmtpcvm -z start -p %d -n %d -o 0xC302C4 -u %s -t 7 -a 0 -i 1 -d 1`
|
||||
* Result: `VendorModel:SendPackage,Finish`
|
||||
|
||||
* `bmtxpower`: Provisioner/node set tx power or rx sensitivity"
|
||||
* `-z`: `<action>:action type`:set tx power or rx sensitivity
|
||||
* `-t`: `<power>:tx power or sense`
|
||||
* Example: `bmtxpower -z tx -t %d`
|
||||
* Result: `Node:SetPower,OK`
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
set(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_cmd.c"
|
||||
"ble_mesh_reg_cfg_client_cmd.c"
|
||||
"ble_mesh_register_server_cmd.c"
|
||||
"ble_mesh_reg_gen_onoff_client_cmd.c"
|
||||
"ble_mesh_reg_test_perf_client_cmd.c"
|
||||
"transaction.c"
|
||||
"register_bluetooth.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,344 @@
|
||||
// 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[0];
|
||||
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 = ESP_BLE_MESH_KEY_UNUSED;
|
||||
ble_mesh_node_prestore_params[i].unicast_addr = ESP_BLE_MESH_ADDR_UNASSIGNED;
|
||||
}
|
||||
|
||||
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 != ESP_BLE_MESH_KEY_UNUSED && ble_mesh_node_prestore_params[i].unicast_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) {
|
||||
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_accumulate(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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
time_level_num = ((max_time - min_time) / 50 + 1);
|
||||
statistics_time_percent = malloc(sizeof(statistics_time_performance) * time_level_num);
|
||||
if (statistics_time_percent == NULL) {
|
||||
ESP_LOGI(TAG, "malloc error");
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
free(statistics_time_percent);
|
||||
}
|
||||
|
||||
void ble_mesh_test_performance_client_model_accumulate_statistics(uint32_t value)
|
||||
{
|
||||
test_perf_statistics.statistics += value;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// receive failed
|
||||
if (length != test_perf_statistics.test_length) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ble_mesh_test_performance_client_model_init(uint16_t node_num, uint32_t test_num, uint8_t ttl)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
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,134 @@
|
||||
// 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_console"
|
||||
|
||||
#define TRANS_TYPE_MESH_PERF 0x01
|
||||
#define TRANS_MESH_SEND_MESSAGE 0x01
|
||||
#define TRANS_MESH_SEND_MESSAGE_EVT 0x01
|
||||
|
||||
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;
|
||||
|
||||
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 SEND_MESSAGE_TIMEOUT (30000/portTICK_RATE_MS)
|
||||
|
||||
#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_accumulate(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);
|
||||
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_ADAOTER_H_
|
||||
@@ -0,0 +1,202 @@
|
||||
// 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"
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
uint8_t dev_uuid[16] = {0xdd, 0xdd};
|
||||
|
||||
|
||||
esp_ble_mesh_prov_t prov = {
|
||||
#if CONFIG_BLE_MESH_NODE
|
||||
.uuid = dev_uuid,
|
||||
#endif //CONFIG_BLE_MESH_NODE
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
.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_t vendor_model_pub_config;
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(model_pub_config, 2 + 1, ROLE_NODE);
|
||||
|
||||
// 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(2, 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 model
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_0, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server = {
|
||||
.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_t gen_onoff_srv_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server),
|
||||
};
|
||||
|
||||
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_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server),
|
||||
};
|
||||
|
||||
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,41 @@
|
||||
/* 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 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
|
||||
|
||||
// Register mesh config server and generic server operation cmd
|
||||
void ble_mesh_register_server(void);
|
||||
|
||||
#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_CFG_CLI)
|
||||
// Register mesh config client operation cmd
|
||||
void ble_mesh_register_configuration_client_model(void);
|
||||
#endif
|
||||
@@ -0,0 +1,132 @@
|
||||
// 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;
|
||||
uint8_t loop = 0;
|
||||
uint16_t length = strlen(value_in);
|
||||
|
||||
// address string, need sepcial test
|
||||
for (loop = 0; loop < 17 ; loop++) {
|
||||
if (loop % 3 == 2) {
|
||||
if (value_in[loop] == ':') {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,119 @@
|
||||
// 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 "esp_vfs_dev.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_vfs_fat.h"
|
||||
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
|
||||
#include "esp_console.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) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_STORE_HISTORY
|
||||
|
||||
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) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_init();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
ret = esp_bluedroid_enable();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_log_level_set("*", ESP_LOG_ERROR);
|
||||
esp_log_level_set("ble_mesh_console", ESP_LOG_INFO);
|
||||
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);
|
||||
}
|
||||
|
||||
esp_console_repl_t *repl = NULL;
|
||||
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
|
||||
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
|
||||
#if CONFIG_STORE_HISTORY
|
||||
initialize_filesystem();
|
||||
repl_config.history_save_path = HISTORY_PATH;
|
||||
#endif
|
||||
repl_config.prompt = "esp32>";
|
||||
// init console REPL environment
|
||||
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
|
||||
|
||||
/* Register commands */
|
||||
register_system();
|
||||
register_bluetooth();
|
||||
ble_mesh_register_mesh_node();
|
||||
ble_mesh_register_mesh_test_performance_client();
|
||||
ble_mesh_register_server();
|
||||
#if (CONFIG_BLE_MESH_GENERIC_ONOFF_CLI)
|
||||
ble_mesh_register_gen_onoff_client();
|
||||
#endif
|
||||
#if (CONFIG_BLE_MESH_CFG_CLI)
|
||||
ble_mesh_register_configuration_client_model();
|
||||
#endif
|
||||
|
||||
// start console REPL
|
||||
ESP_ERROR_CHECK(esp_console_start_repl(repl));
|
||||
}
|
||||
@@ -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,391 @@
|
||||
// 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.set_state->sval[0], "reset") == 0) {
|
||||
err = esp_ble_mesh_config_client_set_state(&client_common, NULL);
|
||||
}
|
||||
}
|
||||
} 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,184 @@
|
||||
// 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;
|
||||
static 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);
|
||||
if (onoff_common.model == NULL) {
|
||||
ESP_LOGI(TAG, "GenONOFFClient:LoadModel,Fail");
|
||||
}
|
||||
|
||||
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,218 @@
|
||||
// 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"
|
||||
#include "transaction.h"
|
||||
|
||||
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;
|
||||
uint64_t start_time;
|
||||
esp_ble_mesh_msg_ctx_t ctx;
|
||||
transaction_t *trans = NULL;
|
||||
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__);
|
||||
}
|
||||
|
||||
TRANSACTION_INIT(&trans, TRANS_TYPE_MESH_PERF, TRANS_MESH_SEND_MESSAGE,
|
||||
TRANS_MESH_SEND_MESSAGE_EVT, SEND_MESSAGE_TIMEOUT, &start_time, NULL);
|
||||
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);
|
||||
transaction_run(trans);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
init_transactions();
|
||||
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));
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
// 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_int *pub_addr;
|
||||
struct arg_int *app_index;
|
||||
struct arg_int *period;
|
||||
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]);
|
||||
if (msg_publish.role->count != 0) {
|
||||
device_role = msg_publish.role->ival[0];
|
||||
}
|
||||
|
||||
if (msg_publish.pub_addr->count != 0) {
|
||||
model->pub->publish_addr = msg_publish.pub_addr->ival[0];
|
||||
}
|
||||
|
||||
if (msg_publish.period->count != 0) {
|
||||
model->pub->period = msg_publish.period->ival[0];
|
||||
}
|
||||
|
||||
if (msg_publish.app_index->count != 0) {
|
||||
model->pub->app_idx = msg_publish.app_index->ival[0];
|
||||
}
|
||||
|
||||
if (msg_publish.data->count != 0) {
|
||||
length = strlen(msg_publish.data->sval[0]);
|
||||
data = malloc((length + 1) * sizeof(uint8_t));
|
||||
if (data != NULL) {
|
||||
err = get_value_string((char *)msg_publish.data->sval[0], (char *) data);
|
||||
}
|
||||
}
|
||||
|
||||
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.pub_addr = arg_int1("a", NULL, "<address>", "unicast address");
|
||||
msg_publish.app_index = arg_int1("i", NULL, "<app key>", "app key index");
|
||||
msg_publish.period = arg_int1("p", NULL, "<period>", "period");
|
||||
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,266 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "transaction.h"
|
||||
|
||||
|
||||
#define TAG "TRANS"
|
||||
|
||||
static transaction_t transactions[MAX_TRANSACTION_COUNT];
|
||||
static SemaphoreHandle_t trans_mutex;
|
||||
|
||||
static uint32_t utils_get_system_ts(void)
|
||||
{
|
||||
return esp_log_timestamp();
|
||||
}
|
||||
|
||||
static void transaction_reset(transaction_t *trans)
|
||||
{
|
||||
EventBits_t bits;
|
||||
|
||||
ESP_LOGV(TAG, "transaction reset: %x", (uint32_t) trans);
|
||||
// set to inactive state and clear all bits of the transaction
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
trans->type = 0;
|
||||
trans->sub_type = 0;
|
||||
trans->current_bits = 0;
|
||||
bits = xEventGroupGetBits(trans->event_group);
|
||||
xEventGroupClearBits(trans->event_group, bits);
|
||||
trans->state = TRANSACTION_INACTIVE;
|
||||
trans->ret = ESP_OK;
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
}
|
||||
|
||||
void transaction_deinit(transaction_t *trans)
|
||||
{
|
||||
if (trans != NULL) {
|
||||
transaction_reset(trans);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t transaction_set_events(transaction_t *trans, EventBits_t events)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
if (trans) {
|
||||
if (trans->state == TRANSACTION_INACTIVE) {
|
||||
ret = TRANS_RET_STATE_ERR;
|
||||
} else {
|
||||
// if the task (task A) setting current bits is with higher priority than the task (task B) run transaction,
|
||||
// current_bits might not be updated until task A yield (not it's only update in run_transaction function).
|
||||
// If task A set events and immediately use current_bits, current_bits is not correct.
|
||||
// update current_bits here to make sure it's updated
|
||||
trans->current_bits |= events;
|
||||
xEventGroupSetBits(trans->event_group, events);
|
||||
}
|
||||
ESP_LOGD(TAG, "transactions set events: %x, %x, %x, %x; ret: %x", (uint32_t) trans, trans->type, trans->sub_type, events, ret);
|
||||
} else {
|
||||
ret = TRANS_RET_INVALID_TRNSACTION;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t transaction_test_events(transaction_t *trans, EventBits_t events)
|
||||
{
|
||||
esp_err_t ret = TRANS_RET_TEST_EVENT_FAILED;
|
||||
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
if (trans) {
|
||||
if (trans->state == TRANSACTION_INACTIVE) {
|
||||
ret = TRANS_RET_STATE_ERR;
|
||||
} else {
|
||||
if ((trans->current_bits & events) == events) {
|
||||
ret = ESP_OK;
|
||||
}
|
||||
}
|
||||
ESP_LOGV(TAG, "transactions test events: %x, %x; ret: %x", (uint32_t) trans, events, ret);
|
||||
} else {
|
||||
ret = TRANS_RET_INVALID_TRNSACTION;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t transaction_clear_events(transaction_t *trans, EventBits_t events)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
if (trans) {
|
||||
if (trans->state == TRANSACTION_INACTIVE) {
|
||||
ret = TRANS_RET_STATE_ERR;
|
||||
} else {
|
||||
trans->current_bits &= ~events;
|
||||
xEventGroupClearBits(trans->event_group, events);
|
||||
}
|
||||
ESP_LOGD(TAG, "transactions clear events: %x, %x, %x, %x; ret: %x", (uint32_t) trans, trans->type, trans->sub_type, events, ret);
|
||||
} else {
|
||||
ret = TRANS_RET_INVALID_TRNSACTION;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t transaction_abort(transaction_t *trans, esp_err_t reason)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
if (trans) {
|
||||
if (trans->state == TRANSACTION_INACTIVE) {
|
||||
ret = TRANS_RET_STATE_ERR;
|
||||
} else {
|
||||
trans->ret = reason;
|
||||
xEventGroupSetBits(trans->event_group, TRANSACTION_ABORT_EVENT);
|
||||
}
|
||||
ESP_LOGD(TAG, "transactions abort: %x, %x, %x, %x; ret: %x", (uint32_t) trans, trans->type, trans->sub_type, reason, ret);
|
||||
} else {
|
||||
ret = TRANS_RET_INVALID_TRNSACTION;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t transaction_init(transaction_t **trans, uint8_t type, uint32_t sub_type, EventBits_t wait_events, uint32_t timeout, void *input, void *output)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint8_t i;
|
||||
|
||||
if ((wait_events & TRANSACTION_EVENT_MASK)
|
||||
&& wait_events != TRANSACTION_TIMEOUT_EVENT) {
|
||||
ret = TRANS_RET_EVENTS_CONFLICT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
for (i = 0; i < MAX_TRANSACTION_COUNT; i++) {
|
||||
if ( transactions[i].state == TRANSACTION_INACTIVE ) {
|
||||
transactions[i].state = TRANSACTION_ACTIVE;
|
||||
*trans = &transactions[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( i == MAX_TRANSACTION_COUNT ) {
|
||||
ret = TRANS_RET_FAILED_TO_ALLOCATE;
|
||||
} else {
|
||||
// init transaction
|
||||
transactions[i].type = type;
|
||||
transactions[i].wait_events = wait_events;
|
||||
transactions[i].sub_type = sub_type;
|
||||
transactions[i].timeout = timeout;
|
||||
transactions[i].ret = ESP_OK;
|
||||
transactions[i].input = input;
|
||||
transactions[i].output = output;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGD(TAG, "transaction created: %x, %x, %x; ret: %x", type, sub_type, (uint32_t) *trans, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t transaction_run(transaction_t *trans)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t start_time;
|
||||
int32_t wait_time;
|
||||
EventBits_t current_bits;
|
||||
|
||||
if (trans) {
|
||||
start_time = utils_get_system_ts();
|
||||
|
||||
// wait for wait events
|
||||
while (1) {
|
||||
//TODO: we didn't handle ts overflow
|
||||
wait_time = start_time + trans->timeout - utils_get_system_ts();
|
||||
|
||||
if ( wait_time < 0 ) {
|
||||
ESP_LOGI(TAG, "transaction timeout: %x, %x, %x, %x, %x", (uint32_t) trans, trans->type, trans->sub_type, trans->wait_events, trans->current_bits);
|
||||
ret = TRANS_RET_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
// trans->event_group and trans->wait_events will not be changed once trans is created, so we don't need protect them
|
||||
current_bits = xEventGroupWaitBits(trans->event_group, trans->wait_events | TRANSACTION_ABORT_EVENT,
|
||||
1, 0, wait_time/portTICK_RATE_MS);
|
||||
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
trans->current_bits |= current_bits;
|
||||
|
||||
if (trans->current_bits == trans->wait_events) {
|
||||
// wait succeeded, we copy the trans->ret as ret of run transaction. This value could be changed by
|
||||
ret = trans->ret;
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
break;
|
||||
} else if ( trans->current_bits & TRANSACTION_ABORT_EVENT ) {
|
||||
if ( trans->ret ) {
|
||||
// copy user defined ret value if it's set
|
||||
ret = trans->ret;
|
||||
} else {
|
||||
ret = TRANS_RET_ABORTED;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
break;
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
}
|
||||
ESP_LOGD(TAG, "transaction run: %x, %x, %x; ret: %x", (uint32_t) trans, trans->type, trans->sub_type, ret);
|
||||
// reset after it's finished
|
||||
transaction_reset(trans);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "transaction run: %x; ret: %x", (uint32_t) trans, ret);
|
||||
ret = TRANS_RET_INVALID_TRNSACTION;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
transaction_t *transaction_get(uint8_t type, uint32_t sub_type, transaction_t *start)
|
||||
{
|
||||
uint8_t i, start_index;
|
||||
transaction_t *trans = NULL;
|
||||
|
||||
if ( start == NULL ) {
|
||||
start_index = 0;
|
||||
} else {
|
||||
start_index = (start - transactions) + 1;
|
||||
}
|
||||
|
||||
xSemaphoreTakeRecursive(trans_mutex, portMAX_DELAY);
|
||||
for (i = start_index; i < MAX_TRANSACTION_COUNT; i++) {
|
||||
if ( transactions[i].state == TRANSACTION_ACTIVE ) {
|
||||
if ( (transactions[i].type == type) && (transactions[i].sub_type & sub_type) ) {
|
||||
trans = &transactions[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
xSemaphoreGiveRecursive(trans_mutex);
|
||||
|
||||
ESP_LOGV(TAG, "transaction get: %x, %x, %x, %x", type, sub_type, (uint32_t) start, (uint32_t) trans);
|
||||
return trans;
|
||||
}
|
||||
|
||||
void init_transactions(void)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
ESP_LOGI(TAG, "init transactions");
|
||||
|
||||
trans_mutex = xSemaphoreCreateRecursiveMutex();
|
||||
|
||||
for (i = 0; i < MAX_TRANSACTION_COUNT; i++) {
|
||||
transactions[i].event_group = xEventGroupCreate();
|
||||
transaction_reset(&transactions[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#ifndef __SSC_NIMBLE_TRANSACTION_H__
|
||||
#define __SSC_NIMBLE_TRANSACTION_H__
|
||||
|
||||
/* In esp-idf, bluetooth and wifi stack APIs are async (using callbacks).
|
||||
* transaction module provides a common method to let user transfer async APIs to sync transactions.
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#define MAX_TRANSACTION_COUNT 5
|
||||
|
||||
#define TRANSACTION_TYPE_ALL 0xFF
|
||||
|
||||
#define TRANSACTION_SUB_TYPE_ALL 0xFFFFFFFF
|
||||
|
||||
// The higher 12 bits of event is reversed for event group or transaction module.
|
||||
// Application can only use lower 20 bits of the event.
|
||||
#define TRANSACTION_TIMEOUT_EVENT 0x00100000UL // only wait for timeout
|
||||
#define TRANSACTION_ABORT_EVENT 0x00800000UL // this event is reserved for internal use only
|
||||
#define TRANSACTION_EVENT_MASK 0xFFF00000UL
|
||||
|
||||
|
||||
enum {
|
||||
TRANS_RET_ERROR_START = 0x10000,
|
||||
TRANS_RET_FAILED_TO_ALLOCATE,
|
||||
TRANS_RET_STATE_ERR,
|
||||
TRANS_RET_TEST_EVENT_FAILED,
|
||||
TRANS_RET_EVENTS_CONFLICT, // events bit conflicts with TRANSACTION_ABORT_EVENT
|
||||
TRANS_RET_INVALID_TRNSACTION,
|
||||
TRANS_RET_TIMEOUT,
|
||||
TRANS_RET_ABORTED
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
TRANSACTION_INACTIVE,
|
||||
TRANSACTION_ACTIVE,
|
||||
} transaction_state_t;
|
||||
|
||||
typedef struct {
|
||||
/* input data passed to callback */
|
||||
void *input;
|
||||
/* output data from callback */
|
||||
void *output;
|
||||
/* retrun value, can be set by callback or transaction module (like timeout, or other common errors)
|
||||
* transaction_run will return this member by default. */
|
||||
esp_err_t ret;
|
||||
// private member
|
||||
transaction_state_t state;
|
||||
uint8_t type;
|
||||
uint32_t sub_type;
|
||||
uint32_t timeout;
|
||||
EventBits_t wait_events;
|
||||
EventGroupHandle_t event_group;
|
||||
EventBits_t current_bits;
|
||||
} transaction_t;
|
||||
|
||||
|
||||
void init_transactions(void);
|
||||
|
||||
esp_err_t transaction_init(transaction_t **trans, uint8_t type, uint32_t sub_type, EventBits_t wait_events, uint32_t timeout, void *input, void *output);
|
||||
esp_err_t transaction_run(transaction_t *trans);
|
||||
|
||||
transaction_t *transaction_get(uint8_t type, uint32_t sub_type, transaction_t *start);
|
||||
|
||||
esp_err_t transaction_set_events(transaction_t *trans, EventBits_t events);
|
||||
esp_err_t transaction_test_events(transaction_t *trans, EventBits_t events);
|
||||
esp_err_t transaction_clear_events(transaction_t *trans, EventBits_t events);
|
||||
|
||||
esp_err_t transaction_abort(transaction_t *trans, esp_err_t reason);
|
||||
|
||||
#define TRANSACTION_INIT(trans, type, sub_type, wait_events, timeout, input, output) \
|
||||
ESP_ERROR_CHECK(transaction_init(trans, type, sub_type, wait_events, timeout, input, output))
|
||||
|
||||
|
||||
#define transaction_get_first(type, sub_type) transaction_get(type, sub_type, NULL)
|
||||
|
||||
|
||||
/* We declare all transaction type / sub type below */
|
||||
#define TRANS_TYPE_BLE_GAP 0x01
|
||||
#define TRANS_TYPE_BLE_GATTC 0x02
|
||||
#define TRANS_TYPE_BLE_GATTS 0x03
|
||||
#define TRANS_TYPE_WIFI 0x04
|
||||
#define TRANS_TYPE_BT 0x05
|
||||
|
||||
|
||||
#endif /* __SSC_NIMBLE_TRANSACTION_H__ */
|
||||
@@ -0,0 +1,4 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 2M,
|
||||
|
@@ -0,0 +1,29 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_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=3
|
||||
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=3
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
CONFIG_BLE_MESH_PROVISIONER=y
|
||||
CONFIG_BLE_MESH_SELF_TEST=y
|
||||
CONFIG_BLE_MESH_TEST_AUTO_ENTER_NETWORK=y
|
||||
|
||||
# partitions
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="4MB"
|
||||
@@ -0,0 +1,9 @@
|
||||
# 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/common_components/example_init
|
||||
$ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(fast_prov_client)
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := fast_prov_client
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/example_init \
|
||||
$(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,9 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
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_Prov_Client_Example_Walkthrough.md) for more information about this example.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -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,603 @@
|
||||
// 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 "ble_mesh_fast_prov_common.h"
|
||||
#include "ble_mesh_fast_prov_operation.h"
|
||||
#include "ble_mesh_fast_prov_client_model.h"
|
||||
#include "ble_mesh_example_init.h"
|
||||
|
||||
#define TAG "EXAMPLE"
|
||||
|
||||
#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[11] = {0};
|
||||
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, ESP_BLE_MESH_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,15 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_PROVISIONER=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,15 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_PROVISIONER=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,21 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
# Override some defaults of ESP BLE Mesh
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_PROVISIONER=y
|
||||
CONFIG_BLE_MESH_PBA_SAME_TIME=1
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
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_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 Bluetooth and BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial/BLE_Mesh_WiFi_Coexist_Example_Walkthrough.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, ESP_BLE_MESH_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,9 @@
|
||||
# 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/common_components/example_init
|
||||
$ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(fast_prov_server)
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := fast_prov_server
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/example_init \
|
||||
$(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/fast_provisioning
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,9 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
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_Prov_Server_Example_Walkthrough.md) for more information about this example.
|
||||
@@ -0,0 +1,5 @@
|
||||
set(srcs "main.c"
|
||||
"board.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -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,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 "ble_mesh_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,766 @@
|
||||
// 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 "ble_mesh_fast_prov_operation.h"
|
||||
#include "ble_mesh_fast_prov_client_model.h"
|
||||
#include "ble_mesh_fast_prov_server_model.h"
|
||||
#include "ble_mesh_example_init.h"
|
||||
|
||||
#define TAG "EXAMPLE"
|
||||
|
||||
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,15 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_FAST_PROV=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
@@ -0,0 +1,21 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_FAST_PROV=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
|
||||
CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY=y
|
||||
CONFIG_BLE_MESH_MEM_ALLOC_MODE_IRAM_8BIT=y
|
||||
CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC=y
|
||||
CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_IRAM_8BIT=y
|
||||
@@ -0,0 +1,14 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_FAST_PROV=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
@@ -0,0 +1,20 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_FAST_PROV=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
|
||||
CONFIG_ESP32_SPIRAM_SUPPORT=y
|
||||
CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y
|
||||
CONFIG_BLE_MESH_MEM_ALLOC_MODE_EXTERNAL=y
|
||||
CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC=y
|
||||
CONFIG_BLE_MESH_FREERTOS_STATIC_ALLOC_EXTERNAL=y
|
||||
@@ -0,0 +1,25 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_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_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_TRACE_LEVEL_ERROR=y
|
||||
CONFIG_BLE_MESH_CFG_CLI=y
|
||||
@@ -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 Bluetooth and BLE Mesh](../../../ble_mesh_wifi_coexist/tutorial/BLE_Mesh_WiFi_Coexist_Example_Walkthrough.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);
|
||||
```
|
||||
@@ -0,0 +1,92 @@
|
||||
# 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 example can be seen from [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](https://github.com/EspressifApp/EspBLEMeshForAndroid/releases/tag/v1.1.0)
|
||||
* [esp-idf](https://github.com/espressif/esp-idf)
|
||||
* ESP32 Development Boards
|
||||
|
||||
> Note:
|
||||
>
|
||||
> 1. Please flash the [`fast_prov_server`](https://github.com/espressif/esp-idf/tree/release/v4.2/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/fast_prov_server) to the development 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/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.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 178 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 348 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,10 @@
|
||||
# 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/common_components/button
|
||||
$ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_init
|
||||
$ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_components/example_nvs)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(onoff_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 := onoff_client
|
||||
|
||||
EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/button \
|
||||
$(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/example_init \
|
||||
$(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_components/example_nvs
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,17 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
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,5 @@
|
||||
set(srcs "main.c"
|
||||
"board.c")
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -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,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/gpio.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,327 @@
|
||||
/* 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_example_init.h"
|
||||
#include "ble_mesh_example_nvs.h"
|
||||
|
||||
#define TAG "EXAMPLE"
|
||||
|
||||
#define CID_ESP 0x02E5
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
|
||||
static struct example_info_store {
|
||||
uint16_t net_idx; /* NetKey Index */
|
||||
uint16_t app_idx; /* AppKey Index */
|
||||
uint8_t onoff; /* Remote OnOff */
|
||||
uint8_t tid; /* Message TID */
|
||||
} __attribute__((packed)) store = {
|
||||
.net_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.app_idx = ESP_BLE_MESH_KEY_UNUSED,
|
||||
.onoff = LED_OFF,
|
||||
.tid = 0x0,
|
||||
};
|
||||
|
||||
static nvs_handle_t NVS_HANDLE;
|
||||
static const char * NVS_KEY = "onoff_client";
|
||||
|
||||
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 mesh_example_info_store(void)
|
||||
{
|
||||
ble_mesh_nvs_store(NVS_HANDLE, NVS_KEY, &store, sizeof(store));
|
||||
}
|
||||
|
||||
static void mesh_example_info_restore(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
bool exist = false;
|
||||
|
||||
err = ble_mesh_nvs_restore(NVS_HANDLE, NVS_KEY, &store, sizeof(store), &exist);
|
||||
if (err != ESP_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (exist) {
|
||||
ESP_LOGI(TAG, "Restore, net_idx 0x%04x, app_idx 0x%04x, onoff %u, tid 0x%02x",
|
||||
store.net_idx, store.app_idx, store.onoff, store.tid);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
store.net_idx = net_idx;
|
||||
/* mesh_example_info_store() shall not be invoked here, because if the device
|
||||
* is restarted and goes into a provisioned state, then the following events
|
||||
* will come:
|
||||
* 1st: ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT
|
||||
* 2nd: ESP_BLE_MESH_PROV_REGISTER_COMP_EVT
|
||||
* So the store.net_idx will be updated here, and if we store the mesh example
|
||||
* info here, the wrong app_idx (initialized with 0xFFFF) will be stored in nvs
|
||||
* just before restoring it.
|
||||
*/
|
||||
}
|
||||
|
||||
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);
|
||||
mesh_example_info_restore(); /* Restore proper mesh example info */
|
||||
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 = ESP_OK;
|
||||
|
||||
common.opcode = ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK;
|
||||
common.model = onoff_client.model;
|
||||
common.ctx.net_idx = store.net_idx;
|
||||
common.ctx.app_idx = store.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 = store.onoff;
|
||||
set.onoff_set.tid = store.tid++;
|
||||
|
||||
err = esp_ble_mesh_generic_client_set_state(&common, &set);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Send Generic OnOff Set Unack failed");
|
||||
return;
|
||||
}
|
||||
|
||||
store.onoff = !store.onoff;
|
||||
mesh_example_info_store(); /* Store proper mesh example info */
|
||||
}
|
||||
|
||||
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, "Generic client, event %u, error code %d, opcode is 0x%04x",
|
||||
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) {
|
||||
store.app_idx = param->value.state_change.mod_app_bind.app_idx;
|
||||
mesh_example_info_store(); /* Store proper mesh example info */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
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_OK) {
|
||||
ESP_LOGE(TAG, "Failed to initialize mesh stack (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to enable mesh node (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Open nvs namespace for storing/restoring mesh example info */
|
||||
err = ble_mesh_nvs_open(&NVS_HANDLE);
|
||||
if (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,17 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Enable | Enable | Enable | Disable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,14 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_SETTINGS=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,17 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Enable | Disable | Disable | Disable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=n
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=n
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,16 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Enable | Disable | Enable | Disable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=n
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,18 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Enable | Disable | Disable | Enable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=n
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=n
|
||||
CONFIG_BLE_MESH_GATT_PROXY_CLIENT=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,17 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Enable | Enable | Disable | Disable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=n
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,18 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Enable | Enable | Disable | Enable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=y
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=n
|
||||
CONFIG_BLE_MESH_GATT_PROXY_CLIENT=y
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,18 @@
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
|
||||
|
||||
#| Proxy | PB-GATT | Proxy Server | Proxy Client |
|
||||
#| Disable | Disable | Disable | Disable |
|
||||
CONFIG_BLE_MESH=y
|
||||
CONFIG_BLE_MESH_NODE=y
|
||||
CONFIG_BLE_MESH_PB_GATT=n
|
||||
CONFIG_BLE_MESH_GATT_PROXY_SERVER=n
|
||||
CONFIG_BLE_MESH_PROXY=n
|
||||
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
|
||||
@@ -0,0 +1,19 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BTDM_MODEM_SLEEP=n
|
||||
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
|
||||
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
|
||||
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
|
||||
CONFIG_BT_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_GENERIC_ONOFF_CLI=y
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user