ble_mesh: update ble mesh examples

This commit is contained in:
lly
2019-10-21 22:48:05 +08:00
parent 547081cc3c
commit dfcfe467c9
44 changed files with 1632 additions and 1301 deletions
@@ -1,7 +0,0 @@
# 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)
set(SUPPORTED_TARGETS esp32)
project(ble_mesh_client_model)
@@ -1,10 +0,0 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := ble_mesh_client_model
COMPONENT_ADD_INCLUDEDIRS := components/include
include $(IDF_PATH)/make/project.mk
@@ -1,14 +0,0 @@
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.
@@ -1,7 +0,0 @@
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
"ble_mesh_demo_init.c"
"board.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
@@ -1,22 +0,0 @@
menu "Example Configuration"
choice BLE_MESH_EXAMPLE_BOARD
prompt "Board selection for BLE Mesh"
default BLE_MESH_ESP_WROOM_32
help
Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32
config BLE_MESH_ESP_WROOM_32
bool "ESP32-WROOM-32"
config BLE_MESH_ESP_WROVER
bool "ESP32-WROVER"
endchoice
config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0
bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0"
default y
help
It is an ad hoc solution and needs further modifications.
endmenu
@@ -1,143 +0,0 @@
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
/* BLE */
#ifdef CONFIG_BT_BLUEDROID_ENABLED
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#endif
#ifdef CONFIG_BT_NIMBLE_ENABLED
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#endif
#include "esp_ble_mesh_defs.h"
#include "ble_mesh_demo_init.h"
#include "esp_ble_mesh_common_api.h"
#ifdef CONFIG_BT_BLUEDROID_ENABLED
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
{
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), BD_ADDR_LEN);
}
esp_err_t bluetooth_init(void)
{
esp_err_t ret;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
return ret;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(TAG, "%s enable controller failed", __func__);
return ret;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
return ret;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
return ret;
}
return ret;
}
#endif
#ifdef CONFIG_BT_NIMBLE_ENABLED
static SemaphoreHandle_t mesh_sem;
static uint8_t own_addr_type;
void ble_store_config_init(void);
static uint8_t addr_val[6] = {0};
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
{
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
}
static void mesh_on_reset(int reason)
{
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
}
static void mesh_on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Figure out address to use while advertising (no privacy for now) */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
return;
}
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
xSemaphoreGive(mesh_sem);
}
void mesh_host_task(void *param)
{
ESP_LOGI(TAG, "BLE Host Task Started");
/* This function will return only when nimble_port_stop() is executed */
nimble_port_run();
nimble_port_freertos_deinit();
}
esp_err_t bluetooth_init(void)
{
mesh_sem = xSemaphoreCreateBinary();
if (mesh_sem == NULL) {
ESP_LOGE(TAG, "Failed to create mesh semaphore");
return ESP_FAIL;
}
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
nimble_port_init();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = mesh_on_reset;
ble_hs_cfg.sync_cb = mesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* XXX Need to have template for store */
ble_store_config_init();
nimble_port_freertos_init(mesh_host_task);
xSemaphoreTake(mesh_sem, portMAX_DELAY);
return ESP_OK;
}
#endif
@@ -1,18 +0,0 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef _BLE_MESH_DEMO_INIT_H_
#define _BLE_MESH_DEMO_INIT_H_
#define TAG "ble_mesh_client"
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
esp_err_t bluetooth_init(void);
#endif
@@ -1,496 +0,0 @@
/* main.c - Application main entry point */
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_networking_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "esp_ble_mesh_generic_model_api.h"
#include "board.h"
#include "ble_mesh_demo_init.h"
#define CID_ESP 0x02E5
#define MSG_SEND_TTL 3
#define MSG_SEND_REL false
#define MSG_TIMEOUT 0 /* 0 indicates that timeout value from menuconfig will be used */
#define MSG_ROLE ROLE_NODE
extern struct _led_state led_state[3];
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
static uint16_t node_net_idx = ESP_BLE_MESH_KEY_UNUSED;
static uint16_t node_app_idx = ESP_BLE_MESH_KEY_UNUSED;
static uint8_t remote_onoff = LED_OFF;
/* The remote node address shall be input through UART1, see board.c */
uint16_t remote_addr = ESP_BLE_MESH_ADDR_UNASSIGNED;
static esp_ble_mesh_client_t onoff_client;
static esp_ble_mesh_cfg_srv_t config_server = {
.relay = ESP_BLE_MESH_RELAY_DISABLED,
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
#if defined(CONFIG_BLE_MESH_FRIEND)
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
#else
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
#endif
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
#else
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
};
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_srv_pub, 2 + 1, MSG_ROLE);
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, MSG_ROLE);
static esp_ble_mesh_model_op_t onoff_op[] = {
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0),
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2),
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2),
/* Each model operation struct array must use this terminator
* as the end tag of the operation uint. */
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_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
&onoff_srv_pub, &led_state[0]),
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 int output_number(esp_ble_mesh_output_action_t action, uint32_t number)
{
board_output_number(action, number);
return 0;
}
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_prov_complete();
node_net_idx = net_idx;
}
static void gen_onoff_get_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t length, uint8_t *data)
{
struct _led_state *led = (struct _led_state *)model->user_data;
uint8_t send_data;
esp_err_t err;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
send_data = led->current;
/* Send Generic OnOff Status as a response to Generic OnOff Get */
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__);
return;
}
}
static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t length, uint8_t *data)
{
struct _led_state *led = (struct _led_state *)model->user_data;
uint8_t prev_onoff;
esp_err_t err;
prev_onoff = led->previous;
led->current = data[0];
remote_onoff = led->current;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
/* If Generic OnOff state is changed, and the publish address of Generic OnOff Server
* model is valid, Generic OnOff Status will be published.
*/
if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) {
ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current);
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(led->current), &led->current, ROLE_NODE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__);
return;
}
}
}
static void gen_onoff_set_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t length, uint8_t *data)
{
struct net_buf_simple *msg = model->pub->msg;
struct _led_state *led = (struct _led_state *)model->user_data;
uint8_t prev_onoff, send_data;
esp_err_t err;
prev_onoff = led->previous;
led->current = data[0];
remote_onoff = led->current;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
send_data = led->current;
/* Send Generic OnOff Status as a response to Generic OnOff Get */
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__);
return;
}
/* If Generic OnOff state is changed, and the publish address of Generic OnOff Server
* model is valid, Generic OnOff Status will be published.
*/
if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) {
ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current);
bt_mesh_model_msg_init(msg, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS);
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data, ROLE_NODE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__);
return;
}
}
}
static char *esp_ble_mesh_prov_event_to_str(esp_ble_mesh_prov_cb_event_t event)
{
switch (event) {
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
return "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT";
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
return "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT";
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
return "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT";
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
return "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT";
case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT:
return "ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT";
case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT:
return "ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT";
case ESP_BLE_MESH_NODE_PROV_INPUT_EVT:
return "ESP_BLE_MESH_NODE_PROV_INPUT_EVT";
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
return "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT";
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
return "ESP_BLE_MESH_NODE_PROV_RESET_EVT";
default:
return "Invalid BLE Mesh provision event";
}
return NULL;
}
static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event,
esp_ble_mesh_prov_cb_param_t *param)
{
ESP_LOGI(TAG, "%s, event = %s", __func__, esp_ble_mesh_prov_event_to_str(event));
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_OUTPUT_NUMBER_EVT:
output_number(param->node_prov_output_num.action, param->node_prov_output_num.number);
break;
case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT:
break;
case ESP_BLE_MESH_NODE_PROV_INPUT_EVT:
break;
case 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;
}
return;
}
static esp_err_t esp_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common,
esp_ble_mesh_generic_client_set_state_t *set,
esp_ble_mesh_model_t *model, uint32_t opcode,
uint8_t onoff)
{
if (!common || !set || !model) {
return ESP_ERR_INVALID_ARG;
}
common->opcode = opcode;
common->model = model;
common->ctx.net_idx = node_net_idx;
common->ctx.app_idx = node_app_idx;
common->ctx.addr = remote_addr;
common->ctx.send_ttl = MSG_SEND_TTL;
common->ctx.send_rel = MSG_SEND_REL;
common->msg_timeout = MSG_TIMEOUT;
common->msg_role = MSG_ROLE;
set->onoff_set.op_en = false;
set->onoff_set.onoff = onoff;
set->onoff_set.tid = 0x0;
return ESP_OK;
}
static void esp_ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event,
esp_ble_mesh_model_cb_param_t *param)
{
esp_ble_mesh_client_common_param_t common = {0};
int 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, "ESP_BLE_MESH_MODEL_OPERATION_EVT parameter is NULL");
return;
}
if (node_app_idx == ESP_BLE_MESH_KEY_UNUSED) {
/* Generic OnOff Server/Client Models need to bind with the same app key */
node_app_idx = param->model_operation.ctx->app_idx;
}
switch (param->model_operation.opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
gen_onoff_get_handler(param->model_operation.model, param->model_operation.ctx,
param->model_operation.length, param->model_operation.msg);
break;
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: {
esp_ble_mesh_generic_client_set_state_t set_state = {0};
gen_onoff_set_handler(param->model_operation.model, param->model_operation.ctx,
param->model_operation.length, param->model_operation.msg);
/* This node has a Generic OnOff Client and Server Model.
* When Generic OnOff Server Model receives a Generic OnOff Set message, after
* this message is been handled, the Generic OnOff Client Model will send the
* Generic OnOff Set message to another node(contains Generic OnOff Server Model)
* identified by the remote_addr.
*/
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
return;
}
break;
}
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: {
esp_ble_mesh_generic_client_set_state_t set_state = {0};
gen_onoff_set_unack_handler(param->model_operation.model, param->model_operation.ctx,
param->model_operation.length, param->model_operation.msg);
/* This node has a Generic OnOff Client and Server Model.
* When Generic OnOff Client Model receives a Generic OnOff Set Unack message,
* after this message is been handled, the Generic OnOff Client Model will send
* the Generic OnOff Set Unack message to another node(contains Generic OnOff
* Server Model) identified by the remote_addr.
*/
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set Unack failed", __func__);
return;
}
break;
}
default:
break;
}
break;
}
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
break;
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
break;
default:
break;
}
return;
}
static void esp_ble_mesh_generic_cb(esp_ble_mesh_generic_client_cb_event_t event,
esp_ble_mesh_generic_client_cb_param_t *param)
{
uint32_t opcode;
int err;
ESP_LOGI(TAG, "%s: event is %d, error code is %d, opcode is 0x%x",
__func__, event, param->error_code, param->params->opcode);
opcode = 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");
switch (opcode) {
case 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;
default:
break;
}
break;
case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT");
switch (opcode) {
case 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;
default:
break;
}
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");
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: {
esp_ble_mesh_client_common_param_t common = {0};
esp_ble_mesh_generic_client_set_state_t set_state = {0};
/* If failed to get the response of Generic OnOff Set, resend Generic OnOff Set */
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
return;
}
break;
}
default:
break;
}
break;
}
default:
break;
}
return;
}
static int ble_mesh_init(void)
{
int err = 0;
esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb);
esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb);
esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb);
err = esp_ble_mesh_init(&provision, &composition);
if (err) {
ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err);
return err;
}
esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
ESP_LOGI(TAG, "BLE Mesh Node initialized");
board_led_operation(LED_G, LED_ON);
return err;
}
void app_main(void)
{
int err;
ESP_LOGI(TAG, "Initializing...");
board_init();
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
err = bluetooth_init();
if (err) {
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
return;
}
ble_mesh_get_dev_uuid(dev_uuid);
/* Initialize the Bluetooth Mesh Subsystem */
err = ble_mesh_init();
if (err) {
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
}
}
@@ -1,115 +0,0 @@
/* 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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "board.h"
#define TAG "BOARD"
#define MESH_UART_NUM UART_NUM_1
#define MESH_UART (&UART1)
#define UART_BUF_SIZE 128
#define UART1_TX_PIN GPIO_NUM_16
#define UART1_RX_PIN GPIO_NUM_17
extern uint16_t remote_addr;
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_G, LED_OFF);
}
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_uart_task(void *p)
{
uint8_t *data = calloc(1, UART_BUF_SIZE);
uint32_t input;
while (1) {
int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS);
if (len > 0) {
input = strtoul((const char *)data, NULL, 16);
remote_addr = input & 0xFFFF;
ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr);
memset(data, 0, UART_BUF_SIZE);
}
}
vTaskDelete(NULL);
}
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 board_uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(MESH_UART_NUM, &uart_config);
uart_set_pin(MESH_UART_NUM, UART1_TX_PIN, UART1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_driver_install(MESH_UART_NUM, UART_BUF_SIZE * 2, 0, 0, NULL, 0);
}
void board_init(void)
{
board_led_init();
board_uart_init();
xTaskCreate(board_uart_task, "board_uart_task", 2048, NULL, 5, NULL);
}
@@ -1,42 +0,0 @@
/* board.h - Board-specific hooks */
/*
* Copyright (c) 2017 Intel Corporation
*
* 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_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);
void board_init(void);
#endif
@@ -1,4 +0,0 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
@@ -1,47 +0,0 @@
# 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=
CONFIG_BTDM_CTRL_MODE_BTDM=
CONFIG_BTDM_MODEM_SLEEP=n
CONFIG_BTDM_BLE_SCAN_DUPL=y
CONFIG_BTDM_SCAN_DUPL_TYPE=2
CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE=y
CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE=200
CONFIG_BTDM_BLE_MESH_SCAN_DUPL_EN=y
CONFIG_BTDM_MESH_DUPL_SCAN_CACHE_SIZE=200
CONFIG_BTDM_CTRL_FULL_SCAN_SUPPORTED=y
CONFIG_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
CONFIG_BT_GATTS_ENABLE=y
CONFIG_BT_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_HCI_5_0=y
CONFIG_BLE_MESH_USE_DUPLICATE_SCAN=y
CONFIG_BLE_MESH_NODE=y
CONFIG_BLE_MESH_PROV=y
CONFIG_BLE_MESH_NET_BUF_POOL_USAGE=y
CONFIG_BLE_MESH_PROXY=y
CONFIG_BLE_MESH_PB_GATT=y
CONFIG_BLE_MESH_GATT_PROXY_SERVER=y
CONFIG_BLE_MESH_NODE_ID_TIMEOUT=60
CONFIG_BLE_MESH_PROXY_FILTER_SIZE=1
CONFIG_BLE_MESH_IV_UPDATE_TEST=
CONFIG_BLE_MESH_SUBNET_COUNT=1
CONFIG_BLE_MESH_APP_KEY_COUNT=1
CONFIG_BLE_MESH_MODEL_KEY_COUNT=1
CONFIG_BLE_MESH_MODEL_GROUP_COUNT=1
CONFIG_BLE_MESH_LABEL_COUNT=1
CONFIG_BLE_MESH_CRPL=10
CONFIG_BLE_MESH_MSG_CACHE_SIZE=10
CONFIG_BLE_MESH_ADV_BUF_COUNT=60
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=6
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=1
CONFIG_BLE_MESH_RX_SDU_MAX=384
CONFIG_BLE_MESH_TX_SEG_MAX=32
CONFIG_BLE_MESH_RELAY=y
CONFIG_BLE_MESH_LOW_POWER=
CONFIG_BLE_MESH_FRIEND=
CONFIG_BLE_MESH_CFG_CLI=
CONFIG_BLE_MESH_GENERIC_ONOFF_CLI=y
CONFIG_BT_BTU_TASK_STACK_SIZE=4512
@@ -1,252 +0,0 @@
# 1. Introduction
## 1.1 Demo Function
1. This demo forwards the message sent by the nRF Mesh app.
2. The user enters the address of the destination node and use it to forwarded packet.
3. The types of the forwarded message include:
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET`,
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET`,
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK`.
4. The destination node reports its Onoff state with the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS` message.
Example: The nRF Mesh app sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the node that runs the `ble_mesh_client_model` project. Then this node sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the destination node that runs the `ble_mesh_node` project. The address of the destination node is entered by the user via the serial port.
## 1.1.1 What You Need
* 1 x Device that runs the `ble_mesh_client_model` project.
* 1 x Device that runs the `ble_mesh_node` project.
* 1 x Phone that installs the nRF Mesh app for controlling these two devices
## 1.2 Node Composition
This demo has only one element, in which the following three Models are implemented:
- **Configuration Server Model** is mainly to represent a mesh network configuration, such as its AppKey, Relay State, TTL State, Subscription List State, etc.
- **Generic OnOff Client Model** controls a Generic OnOff Server via messages defined by the Generic OnOff Model, that is, turning on and off the lights.
- **Generic OnOff Server Model** implements the nodes' Onoff state.
## 1.3 Message Sequence
You can choose from the 4 message sequences described below:
1. Acknowledged Get
2. Acknowledged Set
3. Unacknowledged Set
4. Acknowledged Set with Periodic Publishing
![Packet interaction](images/message.png)
## 2. Code Analysis
Code initialization part reference [Initializing the Bluetooth and Initializing the BLE Mesh](../../ble_mesh_wifi_coexist/tutorial%20%20%20%20%20%20/ble_mesh_wifi_coexist.md)
### 2.1 Model Definition
#### 2.1.1 Generic OnOff Server Model
```c
//Allocating memory for publishing messages.
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_srv_pub, 2 + 1, MSG_ROLE);
//Registering the minimum length of messages. For example, the minimum length of the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message is registered as 2 octets.
static esp_ble_mesh_model_op_t onoff_op[] = {
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0, 0},
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2, 0},
{ ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, 0},
ESP_BLE_MESH_MODEL_OP_END,
};
//Registering the Generic Onoff Server Model.
static esp_ble_mesh_model_t root_models[] = {
//onoff server's onoff state init
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
&onoff_srv_pub, &led_state[0]),
};
```
#### 2.1.2 Generic OnOff Client Model
```c
//Allocating memory for publishing messages.
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, MSG_ROLE);
//Registering the Generic Onoff Client Model.
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client),
};
```
### 2.2 Model Callback Function
#### 2.2.1 The Callback function for the Generic Onoff Client Model
```c
esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb);
```
1. The callback function will be triggered when the Client Model:
* Receives a message that indicates the Onoff state of the Sever Model; Or
* Calls any APIs that the Server Model send messages.
2. The events that the callback function handle:
| Event name | Opcode |Description |
| ------------- | ------------|------------------------------------------- |
| ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET |The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET` message |
| ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Client Model receives acknowledgment after sending the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message |
| ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT | NA | The event triggered when the Generic Onoff Client Model receives publishing messages. |
| ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when API (that send messages) calling times out |
#### 2.2.2 The Callback function for the Generic Onoff Server Model
```c
esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb);
```
1. The callback function will be triggered when the Server Model:
* Receives a message that indicates operating the Onoff state of the Server Model from the Generic Onoff Client Model; Or
* Calls any APIs that the Server Model send messages.
2. The events of the callback function:
| Event Name | Opcode | Description |
|-------------------------------------|-------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET message that **gets** the Onoff state of the server from the Client Model |
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET message that **sets** the Onoff state of the server from the Client Model |
| ESP_BLE_MESH_MODEL_OPERATION_EVT | ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK | The event triggered when the Generic Onoff Server Model receives the ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK message that **sets** the Onoff state of the server from the Client Model |
| ESP_BLE_MESH_MODEL_SEND_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_server_model_send_msg` API calling completes |
| ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT | NA | The event triggered when the `esp_ble_mesh_model_publish` API calling completes |
### 2.3 Model that Sends Message
#### 2.3.1 Message Control
The `esp_ble_mesh_set_msg_common` function is used to set the message controlling parameters.
| Parameter Name |Description |
| ----------------------|------------------------- |
| `opcode` | The message opcode |
| `model` | The pointer to the client Model struct |
| `ctx.net_idx` | The NetKey Index of the subnet through which the message is sent |
| `ctx.app_idx` | The AppKey Index for message encryption |
| `ctx.addr` | The address of the destination nodes |
| `ctx.send_ttl`| The TTL State, which determines how many times a message will be relayed |
| `ctx.send_rel`| This parameter determines if the Model will wait for an acknowledgement after sending a message |
| `msg_timeout` | The maximum time the Model will wait for an acknowledgement |
| `msg_role` | The role of message (node/provisioner) |
> Note:
>
> Please check the `ESP_BLE_MESH_MODEL_SEND_COMP_EVT` event to see if the message is sent successfully.
> This event is just for sending sig Model and vendor Model messages, not for all Models.
#### 2.3.2 The Generic Onoff Client sends message
The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_get_state` API to get the state of the server Model, such as the Onoff state.
```c
esp_ble_mesh_generic_client_get_state_t get_state = {0};
esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET);
err = esp_ble_mesh_generic_client_get_state(&common, &get_state);
if (err) {
ESP_LOGE(TAG, "%s: Generic OnOff Get failed", __func__);
return;
}
```
The Generic Onoff Client Model calls the `esp_ble_mesh_generic_client_set_state` API to set the state of the server Model, such as the Onoff state.
```c
esp_ble_mesh_generic_client_set_state_t set_state = {0};
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
return;
}
```
#### 2.3.3 The Generic Onoff Server sends message
The Generic Onoff Server Model has to bind its Appkey before calling the `esp_ble_mesh_server_model_send_msg` API to send a message.
```c
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data);
```
The Generic Onoff Server Model calls the `esp_ble_mesh_model_publish` API to publish messages. Only the Models that have subscribed to this destination address receive the published messages.
```c
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(led->current), &led->current, ROLE_NODE);
```
### 2.4 Users Enter the Address of the Destination Node via Serial Port
Please connect your devices and enters the address of the destination node via the serial port.
Users can adjust the address of the destination node.
> Note:
> Please connect the pin 16 and pin 17 of the device that runs the `ble_mesh_client_model` project to the USB-to-UART tool.
```c
#define UART1_TX_PIN GPIO_NUM_16
#define UART1_RX_PIN GPIO_NUM_17
```
The `board_uart_task` task is used to receive commands sent via the serial port, among which, the`remote_addr` represents the address of destination node that the message is forwarded to. Please enters hexadecimal string, such as 5, for this parameter. The address will be converted to 0x05 automatically.
```c
static void board_uart_task(void *p)
{
uint8_t *data = calloc(1, UART_BUF_SIZE);
uint32_t input;
while (1) {
int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS);
if (len > 0) {
input = strtoul((const char *)data, NULL, 16);
remote_addr = input & 0xFFFF;
ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr);
memset(data, 0, UART_BUF_SIZE);
}
}
vTaskDelete(NULL);
}
```
# 3. Timing Sequence Diagram
The steps for this demo:
1. The nRF Mesh App provisionings the unprovisioned devices into nodes;
2. The nRF Mesh App adds a Appkey to these nodes, and bind the Models of these nodes to this Appkey.
3. The nRF Mesh App sends a controlling message to the Generic Onoff Client Model. Then the Client Model forwards this message to the server Model of the other node.
The timing sequence diagram of this demo is shown below
![Packet interaction](images/picture5.png) <div align=center></div>
>Note:
>
>The node **only forwards the message after it receives the controlling message sent by the app**. That is said, the node will **not** forwards messages to the other nodes every time the user enters the address of the destination node through the serial port.
# 4. The nRF Mesh App
![Packet interaction](images/app.png)
1. Scan the unprovisioned devices.
2. Identity the the capability of the unprovisioned devices.
3. Provisioning the unprovisioned devices.
4. Check if the Mesh node has been configured successful.
5. Configure the Models of the nodes.
6. Click on the Generic On Off Client option.
7. Bind the Generic On Off Client Model to the Appkey.
8. Check if the binding is successfully.
9. Bind the Generic On Off Server Model to the Appkey.
10. Send controlling messages.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB