ble_mesh: update ble mesh examples
This commit is contained in:
@@ -1,358 +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_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 "board.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
|
||||
#define CID_ESP 0x02E5
|
||||
|
||||
extern struct _led_state led_state[3];
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
|
||||
static esp_ble_mesh_cfg_srv_t config_server = {
|
||||
.relay = ESP_BLE_MESH_RELAY_DISABLED,
|
||||
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
|
||||
#if defined(CONFIG_BLE_MESH_FRIEND)
|
||||
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
|
||||
#else
|
||||
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
|
||||
#endif
|
||||
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
|
||||
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
.default_ttl = 7,
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 1, ROLE_NODE);
|
||||
|
||||
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_pub, &led_state[0]),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t extend_model_0[] = {
|
||||
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
|
||||
&onoff_pub, &led_state[1]),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t extend_model_1[] = {
|
||||
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
|
||||
&onoff_pub, &led_state[2]),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
ESP_BLE_MESH_ELEMENT(0, extend_model_0, ESP_BLE_MESH_MODEL_NONE),
|
||||
ESP_BLE_MESH_ELEMENT(0, extend_model_1, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_comp_t composition = {
|
||||
.cid = CID_ESP,
|
||||
.elements = elements,
|
||||
.element_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
static esp_ble_mesh_prov_t provision = {
|
||||
.uuid = dev_uuid,
|
||||
#if 0
|
||||
.output_size = 4,
|
||||
.output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
|
||||
.input_actions = ESP_BLE_MESH_PUSH,
|
||||
.input_size = 4,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static 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();
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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 _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];
|
||||
|
||||
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);
|
||||
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 void esp_ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event,
|
||||
esp_ble_mesh_model_cb_param_t *param)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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:
|
||||
gen_onoff_set_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_UNACK:
|
||||
gen_onoff_set_unack_handler(param->model_operation.model, param->model_operation.ctx,
|
||||
param->model_operation.length, param->model_operation.msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t 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);
|
||||
|
||||
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,130 +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/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "board.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
|
||||
#define TAG "BOARD"
|
||||
|
||||
#define INTR_FLAG_DEFAULT 0
|
||||
|
||||
static xQueueHandle s_evt_queue;
|
||||
|
||||
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 < 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;
|
||||
}
|
||||
}
|
||||
|
||||
static void IRAM_ATTR switch_isr_handler(void *arg)
|
||||
{
|
||||
uint32_t gpio_num = (uint32_t) arg;
|
||||
xQueueSendFromISR(s_evt_queue, &gpio_num, NULL);
|
||||
}
|
||||
|
||||
static void switch_key_init(uint32_t key)
|
||||
{
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||
io_conf.pin_bit_mask = 1 << key;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pull_up_en = 1;
|
||||
io_conf.pull_down_en = 0;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
gpio_set_intr_type(key, GPIO_INTR_NEGEDGE);
|
||||
gpio_install_isr_service(INTR_FLAG_DEFAULT);
|
||||
gpio_isr_handler_add(key, switch_isr_handler, (void *)key);
|
||||
}
|
||||
|
||||
static void switch_task_entry(void *arg)
|
||||
{
|
||||
while (1) {
|
||||
uint32_t io_num;
|
||||
if (xQueueReceive(s_evt_queue, &io_num, portMAX_DELAY) == pdTRUE) {
|
||||
uint8_t onoff = led_state[0].previous;
|
||||
ESP_LOGI(TAG, "GPIO[%d] intr, val: %d", io_num, gpio_get_level(io_num));
|
||||
board_led_operation(LED_R, !onoff);
|
||||
led_state[0].previous = !onoff;
|
||||
//TODO: publish state change message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_init(gpio_num_t gpio_num)
|
||||
{
|
||||
s_evt_queue = xQueueCreate(3, sizeof(uint32_t));
|
||||
if (!s_evt_queue) {
|
||||
return;
|
||||
}
|
||||
|
||||
BaseType_t ret = xTaskCreate(switch_task_entry, "switch", 4096, NULL, 4, NULL);
|
||||
if (ret == pdFAIL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch_key_init(gpio_num);
|
||||
return;
|
||||
|
||||
fail:
|
||||
vQueueDelete(s_evt_queue);
|
||||
}
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
board_led_init();
|
||||
switch_init(GPIO_NUM_18);
|
||||
}
|
||||
+1
-1
@@ -4,4 +4,4 @@ cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(ble_mesh_node)
|
||||
project(onoff_client)
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_mesh_node
|
||||
PROJECT_NAME := onoff_client
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
ESP BLE Mesh Client Model Demo
|
||||
========================
|
||||
|
||||
This demo shows how to use the Generic OnOff Client Model to get/set the generic on/off state. The basic procedures are as follows:
|
||||
|
||||
1. Download and run this demo.
|
||||
2. Use any app for BLE Mesh to provision this device as well as the device running the Generic OnOff Server demo.
|
||||
3. After both onoff client and server devices are provisioned, use UART1 to input the unicast address of the element within the server device.
|
||||
4. The Generic OnOff Client will start to get and set Generic OnOff states periodically.
|
||||
|
||||
>**Notes:**
|
||||
>
|
||||
>1. The NetKey index and AppKey index are fixed to 0x0000 in this demo.
|
||||
>2. If the client device is re-provisioned, but the server device is not, the first few get/set messages from the client will be treated as replay attacks. To avoid this, both devices should be re-provisioned prior to transmitting messages.
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
|
||||
set(COMPONENT_SRCS "button.c"
|
||||
"button_obj.cpp")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ". include")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,21 @@
|
||||
menu "Button"
|
||||
|
||||
choice BUTTON_TIMER_IMPLEMENT
|
||||
bool "Button Timer Mode"
|
||||
default BUTTON_USE_ESP_TIMER
|
||||
help
|
||||
Choose a implementation of timer for button instance.
|
||||
|
||||
config BUTTON_USE_RTOS_TIMER
|
||||
bool "Use FreeRTOS Timer"
|
||||
|
||||
config BUTTON_USE_ESP_TIMER
|
||||
bool "Use ESP Timer"
|
||||
endchoice
|
||||
|
||||
config BUTTON_IO_GLITCH_FILTER_TIME_MS
|
||||
int "IO glitch filter timer ms (10~100)"
|
||||
range 10 100
|
||||
default 50
|
||||
|
||||
endmenu
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
# Component: Button
|
||||
|
||||
* This component defines a button as a well encapsulated object.
|
||||
* A button device is defined by:
|
||||
* GPIO number on which the button is attached.
|
||||
* Active level which decided by peripheral hardware.
|
||||
* Trigger mode which decides whether to call serial trigger callback during pressing
|
||||
* Serial threshold seconds which decides that serial trigger callback will be called after how many seconds' pressing
|
||||
* A button device can provide:
|
||||
* One push event callback
|
||||
* One release event callback
|
||||
* One short-time tap event callback
|
||||
* One serial trigger event callback
|
||||
* Several long-time press event callback
|
||||
We can set different jitter filters for all the events.
|
||||
Once any of the long press callback is triggered, the short tap event will not be triggered.
|
||||
This components are based on GPIO provided by idf and soft timer provided by FreeRTOS.
|
||||
|
||||
* To use the button device, you need to :
|
||||
* create a button object returned by iot_button_create().
|
||||
* Then hook different event callbacks to the button object.
|
||||
* To free the object, you can call iot_button_delete to delete the button object and free the memory that used.
|
||||
|
||||
* Todo:
|
||||
* Add hardware timer mode(because sometimes soft-timer callback function is limited)
|
||||
|
||||
### NOTE:
|
||||
> All the event callback function are realized by FreeRTOS soft timer APIs, the callback must follow the rule:
|
||||
|
||||
|
||||
|
||||
```
|
||||
Button callback functions execute in the context of the timer service task.
|
||||
It is therefore essential that button callback functions never attempt to block.
|
||||
For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(), or specify a non zero block time when accessing a queue or a semaphore.
|
||||
```
|
||||
|
||||
> In addition:
|
||||
> You can adjust the following macros within FreeRTOS to adjust the stack depth/queue length/task priority of the timer service.
|
||||
|
||||
|
||||
```
|
||||
#define configUSE_TIMERS //enable soft-timer
|
||||
#define configTIMER_TASK_PRIORITY // priority of the timers service task
|
||||
#define configQueue_LENGTH // length of timer command queue
|
||||
#define configTIMER_TASK_STACK_DEPTH // stack depth of the soft-timer
|
||||
```
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "iot_button.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define USE_ESP_TIMER CONFIG_BUTTON_USE_ESP_TIMER
|
||||
#if USE_ESP_TIMER
|
||||
#define STOP_TIMER(tmr) esp_timer_stop(tmr)
|
||||
#define DELETE_TIMER(tmr) esp_timer_delete(tmr)
|
||||
#else
|
||||
#define STOP_TIMER(tmr) xTimerStop(tmr, portMAX_DELAY)
|
||||
#define DELETE_TIMER(tmr) xTimerDelete(tmr, portMAX_DELAY);
|
||||
#endif
|
||||
|
||||
#define IOT_CHECK(tag, a, ret) if(!(a)) { \
|
||||
ESP_LOGE(tag,"%s:%d (%s)", __FILE__, __LINE__, __FUNCTION__); \
|
||||
return (ret); \
|
||||
}
|
||||
#define ERR_ASSERT(tag, param) IOT_CHECK(tag, (param) == ESP_OK, ESP_FAIL)
|
||||
#define POINT_ASSERT(tag, param, ret) IOT_CHECK(tag, (param) != NULL, (ret))
|
||||
|
||||
typedef enum {
|
||||
BUTTON_STATE_IDLE = 0,
|
||||
BUTTON_STATE_PUSH,
|
||||
BUTTON_STATE_PRESSED,
|
||||
} button_status_t;
|
||||
|
||||
typedef struct button_dev button_dev_t;
|
||||
typedef struct btn_cb button_cb_t;
|
||||
|
||||
struct btn_cb{
|
||||
TickType_t interval;
|
||||
button_cb cb;
|
||||
void* arg;
|
||||
#if !USE_ESP_TIMER
|
||||
TimerHandle_t tmr;
|
||||
#else
|
||||
esp_timer_handle_t tmr;
|
||||
#endif
|
||||
button_dev_t *pbtn;
|
||||
button_cb_t *next_cb;
|
||||
};
|
||||
|
||||
struct button_dev{
|
||||
uint8_t io_num;
|
||||
uint8_t active_level;
|
||||
uint32_t serial_thres_sec;
|
||||
button_status_t state;
|
||||
button_cb_t tap_short_cb;
|
||||
button_cb_t tap_psh_cb;
|
||||
button_cb_t tap_rls_cb;
|
||||
button_cb_t press_serial_cb;
|
||||
button_cb_t* cb_head;
|
||||
};
|
||||
|
||||
#define BUTTON_GLITCH_FILTER_TIME_MS CONFIG_BUTTON_IO_GLITCH_FILTER_TIME_MS
|
||||
static const char* TAG = "button";
|
||||
|
||||
// static void button_press_cb(xTimerHandle tmr)
|
||||
static void button_press_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_cb_t* btn_cb = (button_cb_t*)(tmr);
|
||||
#endif
|
||||
|
||||
button_dev_t* btn = btn_cb->pbtn;
|
||||
// low, then restart
|
||||
if (btn->active_level == gpio_get_level(btn->io_num)) {
|
||||
btn->state = BUTTON_STATE_PRESSED;
|
||||
if (btn_cb->cb) {
|
||||
btn_cb->cb(btn_cb->arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static void button_tap_psh_cb(xTimerHandle tmr)
|
||||
static void button_tap_psh_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_cb_t* btn_cb = (button_cb_t*)(tmr);
|
||||
#endif
|
||||
|
||||
button_dev_t* btn = btn_cb->pbtn;
|
||||
STOP_TIMER(btn->tap_rls_cb.tmr);
|
||||
|
||||
int lv = gpio_get_level(btn->io_num);
|
||||
|
||||
if (btn->active_level == lv) {
|
||||
// high, then key is up
|
||||
btn->state = BUTTON_STATE_PUSH;
|
||||
if (btn->press_serial_cb.tmr) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
|
||||
xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
|
||||
#else
|
||||
esp_timer_stop(btn->press_serial_cb.tmr);
|
||||
esp_timer_start_once(btn->press_serial_cb.tmr, btn->serial_thres_sec * 1000 * 1000);
|
||||
#endif
|
||||
|
||||
}
|
||||
if (btn->tap_psh_cb.cb) {
|
||||
btn->tap_psh_cb.cb(btn->tap_psh_cb.arg);
|
||||
}
|
||||
} else {
|
||||
// 50ms, check if this is a real key up
|
||||
if (btn->tap_rls_cb.tmr) {
|
||||
STOP_TIMER(btn->tap_rls_cb.tmr);
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerReset(btn->tap_rls_cb.tmr, portMAX_DELAY);
|
||||
#else
|
||||
esp_timer_start_once(btn->tap_rls_cb.tmr, btn->tap_rls_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void button_tap_rls_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_cb_t* btn_cb = (button_cb_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_cb_t* btn_cb = (button_cb_t*)(tmr);
|
||||
#endif
|
||||
button_dev_t* btn = btn_cb->pbtn;
|
||||
STOP_TIMER(btn->tap_rls_cb.tmr);
|
||||
|
||||
if (btn->active_level == gpio_get_level(btn->io_num)) {
|
||||
|
||||
} else {
|
||||
// high, then key is up
|
||||
button_cb_t *pcb = btn->cb_head;
|
||||
while (pcb != NULL) {
|
||||
if (pcb->tmr != NULL) {
|
||||
STOP_TIMER(pcb->tmr);
|
||||
}
|
||||
pcb = pcb->next_cb;
|
||||
}
|
||||
if (btn->press_serial_cb.tmr && btn->press_serial_cb.tmr != NULL) {
|
||||
STOP_TIMER(btn->press_serial_cb.tmr);
|
||||
}
|
||||
if (btn->tap_short_cb.cb && btn->state == BUTTON_STATE_PUSH) {
|
||||
btn->tap_short_cb.cb(btn->tap_short_cb.arg);
|
||||
}
|
||||
if(btn->tap_rls_cb.cb && btn->state != BUTTON_STATE_IDLE) {
|
||||
btn->tap_rls_cb.cb(btn->tap_rls_cb.arg);
|
||||
}
|
||||
btn->state = BUTTON_STATE_IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
static void button_press_serial_cb(void* tmr)
|
||||
{
|
||||
#if !USE_ESP_TIMER
|
||||
button_dev_t* btn = (button_dev_t*) pvTimerGetTimerID(tmr);
|
||||
#else
|
||||
button_dev_t* btn = (button_dev_t*)(tmr);
|
||||
#endif
|
||||
|
||||
if (btn->press_serial_cb.cb) {
|
||||
btn->press_serial_cb.cb(btn->press_serial_cb.arg);
|
||||
}
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->press_serial_cb.interval, portMAX_DELAY);
|
||||
xTimerReset(btn->press_serial_cb.tmr, portMAX_DELAY);
|
||||
#else
|
||||
esp_timer_stop(btn->press_serial_cb.tmr);
|
||||
esp_timer_start_once(btn->press_serial_cb.tmr, btn->press_serial_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void button_gpio_isr_handler(void* arg)
|
||||
{
|
||||
button_dev_t* btn = (button_dev_t*) arg;
|
||||
portBASE_TYPE HPTaskAwoken = pdFALSE;
|
||||
int level = gpio_get_level(btn->io_num);
|
||||
if (level == btn->active_level) {
|
||||
if (btn->tap_psh_cb.tmr) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerStopFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
|
||||
xTimerResetFromISR(btn->tap_psh_cb.tmr, &HPTaskAwoken);
|
||||
#else
|
||||
esp_timer_stop(btn->tap_psh_cb.tmr);
|
||||
esp_timer_start_once(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
button_cb_t *pcb = btn->cb_head;
|
||||
while (pcb != NULL) {
|
||||
if (pcb->tmr != NULL) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerStopFromISR(pcb->tmr, &HPTaskAwoken);
|
||||
xTimerResetFromISR(pcb->tmr, &HPTaskAwoken);
|
||||
#else
|
||||
esp_timer_stop(pcb->tmr);
|
||||
esp_timer_start_once(pcb->tmr, pcb->interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
pcb = pcb->next_cb;
|
||||
}
|
||||
} else {
|
||||
// 50ms, check if this is a real key up
|
||||
if (btn->tap_rls_cb.tmr) {
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerStopFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
|
||||
xTimerResetFromISR(btn->tap_rls_cb.tmr, &HPTaskAwoken);
|
||||
#else
|
||||
esp_timer_stop(btn->tap_rls_cb.tmr);
|
||||
esp_timer_start_once(btn->tap_rls_cb.tmr, btn->tap_rls_cb.interval * portTICK_PERIOD_MS * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if(HPTaskAwoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
#if !USE_ESP_TIMER
|
||||
static void button_free_tmr(xTimerHandle* tmr)
|
||||
#else
|
||||
static void button_free_tmr(esp_timer_handle_t *tmr)
|
||||
#endif
|
||||
{
|
||||
if (tmr && *tmr) {
|
||||
STOP_TIMER(*tmr);
|
||||
DELETE_TIMER(*tmr);
|
||||
*tmr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t iot_button_delete(button_handle_t btn_handle)
|
||||
{
|
||||
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
gpio_set_intr_type(btn->io_num, GPIO_INTR_DISABLE);
|
||||
gpio_isr_handler_remove(btn->io_num);
|
||||
|
||||
button_free_tmr(&btn->tap_rls_cb.tmr);
|
||||
button_free_tmr(&btn->tap_psh_cb.tmr);
|
||||
button_free_tmr(&btn->tap_short_cb.tmr);
|
||||
button_free_tmr(&btn->press_serial_cb.tmr);
|
||||
|
||||
button_cb_t *pcb = btn->cb_head;
|
||||
while (pcb != NULL) {
|
||||
button_cb_t *cb_next = pcb->next_cb;
|
||||
button_free_tmr(&pcb->tmr);
|
||||
free(pcb);
|
||||
pcb = cb_next;
|
||||
}
|
||||
free(btn);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level)
|
||||
{
|
||||
#if USE_ESP_TIMER
|
||||
ets_printf("use esp timer !!!\n");
|
||||
esp_timer_init();
|
||||
#endif
|
||||
|
||||
IOT_CHECK(TAG, gpio_num < GPIO_NUM_MAX, NULL);
|
||||
button_dev_t* btn = (button_dev_t*) calloc(1, sizeof(button_dev_t));
|
||||
POINT_ASSERT(TAG, btn, NULL);
|
||||
btn->active_level = active_level;
|
||||
btn->io_num = gpio_num;
|
||||
btn->state = BUTTON_STATE_IDLE;
|
||||
btn->tap_rls_cb.arg = NULL;
|
||||
btn->tap_rls_cb.cb = NULL;
|
||||
btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
|
||||
btn->tap_rls_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
btn->tap_rls_cb.tmr = xTimerCreate("btn_rls_tmr", btn->tap_rls_cb.interval, pdFALSE,
|
||||
&btn->tap_rls_cb, button_tap_rls_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_rls;
|
||||
tmr_param_rls.arg = &btn->tap_rls_cb;
|
||||
tmr_param_rls.callback = button_tap_rls_cb;
|
||||
tmr_param_rls.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_rls.name = "btn_rls_tmr";
|
||||
esp_timer_create(&tmr_param_rls, &btn->tap_rls_cb.tmr);
|
||||
#endif
|
||||
|
||||
btn->tap_psh_cb.arg = NULL;
|
||||
btn->tap_psh_cb.cb = NULL;
|
||||
btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_PERIOD_MS;
|
||||
btn->tap_psh_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
btn->tap_psh_cb.tmr = xTimerCreate("btn_psh_tmr", btn->tap_psh_cb.interval, pdFALSE,
|
||||
&btn->tap_psh_cb, button_tap_psh_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_psh;
|
||||
tmr_param_psh.arg = &btn->tap_psh_cb;
|
||||
tmr_param_psh.callback = button_tap_psh_cb;
|
||||
tmr_param_psh.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_psh.name = "btn_psh_tmr";
|
||||
esp_timer_create(&tmr_param_psh, &btn->tap_psh_cb.tmr);
|
||||
#endif
|
||||
gpio_install_isr_service(0);
|
||||
gpio_config_t gpio_conf;
|
||||
gpio_conf.intr_type = GPIO_INTR_ANYEDGE;
|
||||
gpio_conf.mode = GPIO_MODE_INPUT;
|
||||
gpio_conf.pin_bit_mask = (1ULL << gpio_num);
|
||||
gpio_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
gpio_config(&gpio_conf);
|
||||
gpio_isr_handler_add(gpio_num, button_gpio_isr_handler, btn);
|
||||
return (button_handle_t) btn;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type)
|
||||
{
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
button_cb_t* btn_cb = NULL;
|
||||
if (type == BUTTON_CB_PUSH) {
|
||||
btn_cb = &btn->tap_psh_cb;
|
||||
} else if (type == BUTTON_CB_RELEASE) {
|
||||
btn_cb = &btn->tap_rls_cb;
|
||||
} else if (type == BUTTON_CB_TAP) {
|
||||
btn_cb = &btn->tap_short_cb;
|
||||
} else if (type == BUTTON_CB_SERIAL) {
|
||||
btn_cb = &btn->press_serial_cb;
|
||||
}
|
||||
btn_cb->cb = NULL;
|
||||
btn_cb->arg = NULL;
|
||||
btn_cb->pbtn = btn;
|
||||
button_free_tmr(&btn_cb->tmr);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg)
|
||||
{
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
btn->serial_thres_sec = start_after_sec;
|
||||
|
||||
if (btn->press_serial_cb.tmr == NULL) {
|
||||
#if !USE_ESP_TIMER
|
||||
btn->press_serial_cb.tmr = xTimerCreate("btn_serial_tmr", btn->serial_thres_sec*1000 / portTICK_PERIOD_MS,
|
||||
pdFALSE, btn, button_press_serial_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_ser;
|
||||
tmr_param_ser.arg = btn;
|
||||
tmr_param_ser.callback = button_press_serial_cb;
|
||||
tmr_param_ser.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_ser.name = "btn_serial_tmr";
|
||||
esp_timer_create(&tmr_param_ser, &btn->press_serial_cb.tmr);
|
||||
#endif
|
||||
}
|
||||
btn->press_serial_cb.arg = arg;
|
||||
btn->press_serial_cb.cb = cb;
|
||||
btn->press_serial_cb.interval = interval_tick;
|
||||
btn->press_serial_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->press_serial_cb.tmr, btn->serial_thres_sec*1000 / portTICK_PERIOD_MS, portMAX_DELAY);
|
||||
#endif
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg)
|
||||
{
|
||||
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
if (type == BUTTON_CB_PUSH) {
|
||||
btn->tap_psh_cb.arg = arg;
|
||||
btn->tap_psh_cb.cb = cb;
|
||||
btn->tap_psh_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
|
||||
btn->tap_psh_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->tap_psh_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
|
||||
#endif
|
||||
} else if (type == BUTTON_CB_RELEASE) {
|
||||
btn->tap_rls_cb.arg = arg;
|
||||
btn->tap_rls_cb.cb = cb;
|
||||
btn->tap_rls_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
|
||||
btn->tap_rls_cb.pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
xTimerChangePeriod(btn->tap_rls_cb.tmr, btn->tap_psh_cb.interval, portMAX_DELAY);
|
||||
#endif
|
||||
} else if (type == BUTTON_CB_TAP) {
|
||||
btn->tap_short_cb.arg = arg;
|
||||
btn->tap_short_cb.cb = cb;
|
||||
btn->tap_short_cb.interval = BUTTON_GLITCH_FILTER_TIME_MS / portTICK_RATE_MS;
|
||||
btn->tap_short_cb.pbtn = btn;
|
||||
} else if (type == BUTTON_CB_SERIAL) {
|
||||
iot_button_set_serial_cb(btn_handle, 1, 1000 / portTICK_RATE_MS, cb, arg);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg)
|
||||
{
|
||||
POINT_ASSERT(TAG, btn_handle, ESP_ERR_INVALID_ARG);
|
||||
IOT_CHECK(TAG, press_sec != 0, ESP_ERR_INVALID_ARG);
|
||||
button_dev_t* btn = (button_dev_t*) btn_handle;
|
||||
button_cb_t* cb_new = (button_cb_t*) calloc(1, sizeof(button_cb_t));
|
||||
POINT_ASSERT(TAG, cb_new, ESP_FAIL);
|
||||
cb_new->arg = arg;
|
||||
cb_new->cb = cb;
|
||||
cb_new->interval = press_sec * 1000 / portTICK_PERIOD_MS;
|
||||
cb_new->pbtn = btn;
|
||||
#if !USE_ESP_TIMER
|
||||
cb_new->tmr = xTimerCreate("btn_press_tmr", cb_new->interval, pdFALSE, cb_new, button_press_cb);
|
||||
#else
|
||||
esp_timer_create_args_t tmr_param_cus;
|
||||
tmr_param_cus.arg = cb_new;
|
||||
tmr_param_cus.callback = button_press_cb;
|
||||
tmr_param_cus.dispatch_method = ESP_TIMER_TASK;
|
||||
tmr_param_cus.name = "btn_press_custom_tmr";
|
||||
esp_timer_create(&tmr_param_cus, &cb_new->tmr);
|
||||
#endif
|
||||
cb_new->next_cb = btn->cb_head;
|
||||
btn->cb_head = cb_new;
|
||||
return ESP_OK;
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "iot_button.h"
|
||||
|
||||
CButton::CButton(gpio_num_t gpio_num, button_active_t active_level)
|
||||
{
|
||||
m_btn_handle = iot_button_create(gpio_num, active_level);
|
||||
}
|
||||
|
||||
CButton::~CButton()
|
||||
{
|
||||
iot_button_delete(m_btn_handle);
|
||||
m_btn_handle = NULL;
|
||||
}
|
||||
|
||||
esp_err_t CButton::set_evt_cb(button_cb_type_t type, button_cb cb, void* arg)
|
||||
{
|
||||
return iot_button_set_evt_cb(m_btn_handle, type, cb, arg);
|
||||
}
|
||||
|
||||
esp_err_t CButton::set_serial_cb(button_cb cb, void* arg, TickType_t interval_tick, uint32_t start_after_sec)
|
||||
{
|
||||
return iot_button_set_serial_cb(m_btn_handle, start_after_sec, interval_tick, cb, arg);
|
||||
}
|
||||
|
||||
esp_err_t CButton::add_custom_cb(uint32_t press_sec, button_cb cb, void* arg)
|
||||
{
|
||||
return iot_button_add_custom_cb(m_btn_handle, press_sec, cb, arg);
|
||||
}
|
||||
|
||||
esp_err_t CButton::rm_cb(button_cb_type_t type)
|
||||
{
|
||||
return iot_button_rm_cb(m_btn_handle, type);
|
||||
}
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#ifndef _IOT_BUTTON_H_
|
||||
#define _IOT_BUTTON_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/portmacro.h"
|
||||
typedef void (* button_cb)(void*);
|
||||
typedef void* button_handle_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_ACTIVE_HIGH = 1, /*!<button active level: high level*/
|
||||
BUTTON_ACTIVE_LOW = 0, /*!<button active level: low level*/
|
||||
} button_active_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_CB_PUSH = 0, /*!<button push callback event */
|
||||
BUTTON_CB_RELEASE, /*!<button release callback event */
|
||||
BUTTON_CB_TAP, /*!<button quick tap callback event(will not trigger if there already is a "PRESS" event) */
|
||||
BUTTON_CB_SERIAL, /*!<button serial trigger callback event */
|
||||
} button_cb_type_t;
|
||||
|
||||
/**
|
||||
* @brief Init button functions
|
||||
*
|
||||
* @param gpio_num GPIO index of the pin that the button uses
|
||||
* @param active_level button hardware active level.
|
||||
* For "BUTTON_ACTIVE_LOW" it means when the button pressed, the GPIO will read low level.
|
||||
*
|
||||
* @return A button_handle_t handle to the created button object, or NULL in case of error.
|
||||
*/
|
||||
button_handle_t iot_button_create(gpio_num_t gpio_num, button_active_t active_level);
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a serial trigger event.
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @start_after_sec define the time after which to start serial trigger action
|
||||
* @interval_tick serial trigger interval
|
||||
* @cb callback function for "TAP" action.
|
||||
* @arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_set_serial_cb(button_handle_t btn_handle, uint32_t start_after_sec, TickType_t interval_tick, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a button_cb_type_t action.
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @param type callback function type
|
||||
* @param cb callback function for "TAP" action.
|
||||
* @param arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_set_evt_cb(button_handle_t btn_handle, button_cb_type_t type, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @param press_sec the callback function would be called if you press the button for a specified period of time
|
||||
* @param cb callback function for "PRESS" action.
|
||||
* @param arg Parameter for callback function
|
||||
*
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_add_custom_cb(button_handle_t btn_handle, uint32_t press_sec, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Delete button object and free memory
|
||||
* @param btn_handle handle of the button object
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t iot_button_delete(button_handle_t btn_handle);
|
||||
|
||||
/**
|
||||
* @brief Remove callback
|
||||
*
|
||||
* @param btn_handle The handle of the button object
|
||||
* @param type callback function event type
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t iot_button_rm_cb(button_handle_t btn_handle, button_cb_type_t type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/**
|
||||
* class of button
|
||||
* simple usage:
|
||||
* CButton* btn = new CButton(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL, BUTTON_SERIAL_TRIGGER, 3);
|
||||
* btn->add_cb(BUTTON_CB_PUSH, button_tap_cb, (void*) push, 50 / portTICK_PERIOD_MS);
|
||||
* btn->add_custom_cb(5, button_press_5s_cb, NULL);
|
||||
* ......
|
||||
* delete btn;
|
||||
*/
|
||||
class CButton
|
||||
{
|
||||
private:
|
||||
button_handle_t m_btn_handle;
|
||||
|
||||
/**
|
||||
* prevent copy constructing
|
||||
*/
|
||||
CButton(const CButton&);
|
||||
CButton& operator = (const CButton&);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor of CButton
|
||||
*
|
||||
* @param gpio_num GPIO index of the pin that the button uses
|
||||
* @param active_level button hardware active level.
|
||||
* For "BUTTON_ACTIVE_LOW" it means when the button pressed, the GPIO will read low level.
|
||||
*/
|
||||
CButton(gpio_num_t gpio_num, button_active_t active_level = BUTTON_ACTIVE_LOW);
|
||||
|
||||
~CButton();
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a button_cb_type_t action.
|
||||
*
|
||||
* @param type callback function type
|
||||
* @param cb callback function for "TAP" action.
|
||||
* @param arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t set_evt_cb(button_cb_type_t type, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for a serial trigger event.
|
||||
*
|
||||
* @param btn_handle handle of the button object
|
||||
* @start_after_sec define the time after which to start serial trigger action
|
||||
* @interval_tick serial trigger interval
|
||||
* @cb callback function for "TAP" action.
|
||||
* @arg Parameter for callback function
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t set_serial_cb(button_cb cb, void* arg, TickType_t interval_tick, uint32_t start_after_sec);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param press_sec the callback function would be called if you press the button for a specified period of time
|
||||
* @param cb callback function for "PRESS" action.
|
||||
* @param arg Parameter for callback function
|
||||
*
|
||||
* @note
|
||||
* Button callback functions execute in the context of the timer service task.
|
||||
* It is therefore essential that button callback functions never attempt to block.
|
||||
* For example, a button callback function must not call vTaskDelay(), vTaskDelayUntil(),
|
||||
* or specify a non zero block time when accessing a queue or a semaphore.
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_FAIL Parameter error
|
||||
*/
|
||||
esp_err_t add_custom_cb(uint32_t press_sec, button_cb cb, void* arg);
|
||||
|
||||
/**
|
||||
* @brief Remove callback
|
||||
*
|
||||
* @param type callback function event type
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
*/
|
||||
esp_err_t rm_cb(button_cb_type_t type);
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice BLE_MESH_EXAMPLE_BOARD
|
||||
prompt "Board selection for BLE Mesh"
|
||||
default BLE_MESH_ESP_WROOM_32
|
||||
help
|
||||
Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32
|
||||
|
||||
config BLE_MESH_ESP_WROOM_32
|
||||
bool "ESP32-WROOM-32"
|
||||
|
||||
config BLE_MESH_ESP_WROVER
|
||||
bool "ESP32-WROVER"
|
||||
endchoice
|
||||
|
||||
config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0
|
||||
bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0"
|
||||
default y
|
||||
help
|
||||
It is an ad hoc solution and needs further modifications.
|
||||
|
||||
endmenu
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
#ifndef _BLE_MESH_DEMO_INIT_H_
|
||||
#define _BLE_MESH_DEMO_INIT_H_
|
||||
|
||||
#define TAG "ble_mesh_node"
|
||||
#define TAG "onoff_client"
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
|
||||
#define CID_ESP 0x02E5
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
static uint16_t node_net_idx = ESP_BLE_MESH_KEY_UNUSED;
|
||||
static uint16_t node_app_idx = ESP_BLE_MESH_KEY_UNUSED;
|
||||
static uint8_t remote_onoff = LED_OFF;
|
||||
static uint8_t msg_tid = 0x0;
|
||||
|
||||
/* The remote node address shall be input through UART1, see board.c */
|
||||
uint16_t remote_addr = ESP_BLE_MESH_ADDR_UNASSIGNED;
|
||||
|
||||
static esp_ble_mesh_client_t onoff_client;
|
||||
|
||||
static esp_ble_mesh_cfg_srv_t config_server = {
|
||||
.relay = ESP_BLE_MESH_RELAY_DISABLED,
|
||||
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
|
||||
#if defined(CONFIG_BLE_MESH_FRIEND)
|
||||
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
|
||||
#else
|
||||
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
|
||||
#endif
|
||||
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
|
||||
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
.default_ttl = 7,
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, ROLE_NODE);
|
||||
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_comp_t composition = {
|
||||
.cid = CID_ESP,
|
||||
.elements = elements,
|
||||
.element_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
static esp_ble_mesh_prov_t provision = {
|
||||
.uuid = dev_uuid,
|
||||
#if 0
|
||||
.output_size = 4,
|
||||
.output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
|
||||
.input_actions = ESP_BLE_MESH_PUSH,
|
||||
.input_size = 4,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
||||
{
|
||||
ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr);
|
||||
ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index);
|
||||
board_led_operation(LED_G, LED_OFF);
|
||||
node_net_idx = net_idx;
|
||||
}
|
||||
|
||||
static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
|
||||
esp_ble_mesh_prov_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
|
||||
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
|
||||
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
|
||||
prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
|
||||
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void example_ble_mesh_send_gen_onoff_set(void)
|
||||
{
|
||||
esp_ble_mesh_generic_client_set_state_t set = {0};
|
||||
esp_ble_mesh_client_common_param_t common = {0};
|
||||
esp_err_t err;
|
||||
|
||||
common.opcode = ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK;
|
||||
common.model = onoff_client.model;
|
||||
common.ctx.net_idx = node_net_idx;
|
||||
common.ctx.app_idx = node_app_idx;
|
||||
common.ctx.addr = 0xFFFF; /* to all nodes */
|
||||
common.ctx.send_ttl = 3;
|
||||
common.ctx.send_rel = false;
|
||||
common.msg_timeout = 0; /* 0 indicates that timeout value from menuconfig will be used */
|
||||
common.msg_role = ROLE_NODE;
|
||||
|
||||
set.onoff_set.op_en = false;
|
||||
set.onoff_set.onoff = remote_onoff;
|
||||
set.onoff_set.tid = msg_tid++;
|
||||
|
||||
err = esp_ble_mesh_generic_client_set_state(&common, &set);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
|
||||
} else {
|
||||
remote_onoff = !remote_onoff;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event,
|
||||
esp_ble_mesh_generic_client_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "%s: event is %d, error code is %d, opcode is 0x%x",
|
||||
__func__, event, param->error_code, param->params->opcode);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT");
|
||||
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) {
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, onoff %d", param->status_cb.onoff_status.present_onoff);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT");
|
||||
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, onoff %d", param->status_cb.onoff_status.present_onoff);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT");
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT");
|
||||
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
/* If failed to get the response of Generic OnOff Set, resend Generic OnOff Set */
|
||||
example_ble_mesh_send_gen_onoff_set();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
|
||||
esp_ble_mesh_cfg_server_cb_param_t *param)
|
||||
{
|
||||
if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
|
||||
switch (param->ctx.recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
|
||||
ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
|
||||
param->value.state_change.appkey_add.net_idx,
|
||||
param->value.state_change.appkey_add.app_idx);
|
||||
ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
|
||||
ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
||||
param->value.state_change.mod_app_bind.element_addr,
|
||||
param->value.state_change.mod_app_bind.app_idx,
|
||||
param->value.state_change.mod_app_bind.company_id,
|
||||
param->value.state_change.mod_app_bind.model_id);
|
||||
if (param->value.state_change.mod_app_bind.company_id == 0xFFFF &&
|
||||
param->value.state_change.mod_app_bind.model_id == ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_CLI) {
|
||||
node_app_idx = param->value.state_change.mod_app_bind.app_idx;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err = 0;
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
esp_ble_mesh_register_generic_client_callback(example_ble_mesh_generic_client_cb);
|
||||
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
||||
|
||||
err = esp_ble_mesh_init(&provision, &composition);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
||||
|
||||
ESP_LOGI(TAG, "BLE Mesh Node initialized");
|
||||
|
||||
board_led_operation(LED_G, LED_ON);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing...");
|
||||
|
||||
board_init();
|
||||
|
||||
err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
err = bluetooth_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
ble_mesh_get_dev_uuid(dev_uuid);
|
||||
|
||||
/* Initialize the Bluetooth Mesh Subsystem */
|
||||
err = ble_mesh_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/* board.c - Board-specific hooks */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "driver/uart.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "iot_button.h"
|
||||
#include "board.h"
|
||||
|
||||
#define TAG "BOARD"
|
||||
|
||||
#define BUTTON_IO_NUM 0
|
||||
#define BUTTON_ACTIVE_LEVEL 0
|
||||
|
||||
extern void example_ble_mesh_send_gen_onoff_set(void);
|
||||
|
||||
struct _led_state led_state[3] = {
|
||||
{ LED_OFF, LED_OFF, LED_R, "red" },
|
||||
{ LED_OFF, LED_OFF, LED_G, "green" },
|
||||
{ LED_OFF, LED_OFF, LED_B, "blue" },
|
||||
};
|
||||
|
||||
void board_led_operation(uint8_t pin, uint8_t onoff)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(led_state); i++) {
|
||||
if (led_state[i].pin != pin) {
|
||||
continue;
|
||||
}
|
||||
if (onoff == led_state[i].previous) {
|
||||
ESP_LOGW(TAG, "led %s is already %s",
|
||||
led_state[i].name, (onoff ? "on" : "off"));
|
||||
return;
|
||||
}
|
||||
gpio_set_level(pin, onoff);
|
||||
led_state[i].previous = onoff;
|
||||
return;
|
||||
}
|
||||
ESP_LOGE(TAG, "LED is not found!");
|
||||
}
|
||||
|
||||
static void board_led_init(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(led_state); i++) {
|
||||
gpio_pad_select_gpio(led_state[i].pin);
|
||||
gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
|
||||
gpio_set_level(led_state[i].pin, LED_OFF);
|
||||
led_state[i].previous = LED_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
static void button_tap_cb(void* arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "tap cb (%s)", (char *)arg);
|
||||
|
||||
example_ble_mesh_send_gen_onoff_set();
|
||||
}
|
||||
|
||||
static void board_button_init(void)
|
||||
{
|
||||
button_handle_t btn_handle = iot_button_create(BUTTON_IO_NUM, BUTTON_ACTIVE_LEVEL);
|
||||
if (btn_handle) {
|
||||
iot_button_set_evt_cb(btn_handle, BUTTON_CB_RELEASE, button_tap_cb, "RELEASE");
|
||||
}
|
||||
}
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
board_led_init();
|
||||
board_button_init();
|
||||
}
|
||||
+1
-4
@@ -2,6 +2,7 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -31,10 +32,6 @@ struct _led_state {
|
||||
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);
|
||||
@@ -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,47 @@
|
||||
# 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
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
# 1. Introduction
|
||||
## 1.1 Demo Function
|
||||
|
||||
1. This demo forwards the message sent by the nRF Mesh app.
|
||||
2. The user enters the address of the destination node and use it to forwarded packet.
|
||||
3. The types of the forwarded message include:
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET`,
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET`,
|
||||
* `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK`.
|
||||
4. The destination node reports its Onoff state with the `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS` message.
|
||||
|
||||
Example: The nRF Mesh app sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the node that runs the `ble_mesh_client_model` project. Then this node sends a `ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET` message to the destination node that runs the `ble_mesh_node` project. The address of the destination node is entered by the user via the serial port.
|
||||
|
||||
## 1.1.1 What You Need
|
||||
|
||||
* 1 x Device that runs the `ble_mesh_client_model` project.
|
||||
* 1 x Device that runs the `ble_mesh_node` project.
|
||||
* 1 x Phone that installs the nRF Mesh app for controlling these two devices
|
||||
|
||||
## 1.2 Node Composition
|
||||
|
||||
This demo has only one element, in which the following three Models are implemented:
|
||||
|
||||
- **Configuration Server Model** is mainly to represent a mesh network configuration, such as its AppKey, Relay State, TTL State, Subscription List State, etc.
|
||||
- **Generic OnOff Client Model** controls a Generic OnOff Server via messages defined by the Generic OnOff Model, that is, turning on and off the lights.
|
||||
- **Generic OnOff Server Model** implements the nodes' Onoff state.
|
||||
|
||||
## 1.3 Message Sequence
|
||||
|
||||
You can choose from the 4 message sequences described below:
|
||||
|
||||
1. Acknowledged Get
|
||||
2. Acknowledged Set
|
||||
3. Unacknowledged Set
|
||||
4. Acknowledged Set with Periodic Publishing
|
||||
|
||||

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

|
||||
|
||||
1. Scan the unprovisioned devices.
|
||||
2. Identity the the capability of the unprovisioned devices.
|
||||
3. Provisioning the unprovisioned devices.
|
||||
4. Check if the Mesh node has been configured successful.
|
||||
5. Configure the Models of the nodes.
|
||||
6. Click on the Generic On Off Client option.
|
||||
7. Bind the Generic On Off Client Model to the Appkey.
|
||||
8. Check if the binding is successfully.
|
||||
9. Bind the Generic On Off Server Model to the Appkey.
|
||||
10. Send controlling messages.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 433 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -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)
|
||||
set(SUPPORTED_TARGETS esp32)
|
||||
project(onoff_server)
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := onoff_server
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
@@ -0,0 +1,7 @@
|
||||
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
|
||||
"ble_mesh_demo_init.c"
|
||||
"board.c")
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,143 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sdkconfig.h>
|
||||
/* BLE */
|
||||
#ifdef CONFIG_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
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#ifndef _BLE_MESH_DEMO_INIT_H_
|
||||
#define _BLE_MESH_DEMO_INIT_H_
|
||||
|
||||
#define TAG "onoff_server"
|
||||
|
||||
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
|
||||
|
||||
esp_err_t bluetooth_init(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,332 @@
|
||||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "esp_ble_mesh_defs.h"
|
||||
#include "esp_ble_mesh_common_api.h"
|
||||
#include "esp_ble_mesh_networking_api.h"
|
||||
#include "esp_ble_mesh_provisioning_api.h"
|
||||
#include "esp_ble_mesh_config_model_api.h"
|
||||
#include "esp_ble_mesh_generic_model_api.h"
|
||||
#include "esp_ble_mesh_local_data_operation_api.h"
|
||||
|
||||
#include "board.h"
|
||||
#include "ble_mesh_demo_init.h"
|
||||
|
||||
#define CID_ESP 0x02E5
|
||||
|
||||
extern struct _led_state led_state[3];
|
||||
|
||||
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
|
||||
|
||||
static esp_ble_mesh_cfg_srv_t config_server = {
|
||||
.relay = ESP_BLE_MESH_RELAY_DISABLED,
|
||||
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
|
||||
#if defined(CONFIG_BLE_MESH_FRIEND)
|
||||
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
|
||||
#else
|
||||
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
|
||||
#endif
|
||||
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
|
||||
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
.default_ttl = 7,
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_0, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server_0 = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_1, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server_1 = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
||||
};
|
||||
|
||||
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub_2, 2 + 3, ROLE_NODE);
|
||||
static esp_ble_mesh_gen_onoff_srv_t onoff_server_2 = {
|
||||
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
|
||||
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_RSP_BY_APP,
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t root_models[] = {
|
||||
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_0, &onoff_server_0),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t extend_model_0[] = {
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_1, &onoff_server_1),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_model_t extend_model_1[] = {
|
||||
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub_2, &onoff_server_2),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_elem_t elements[] = {
|
||||
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
|
||||
ESP_BLE_MESH_ELEMENT(0, extend_model_0, ESP_BLE_MESH_MODEL_NONE),
|
||||
ESP_BLE_MESH_ELEMENT(0, extend_model_1, ESP_BLE_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static esp_ble_mesh_comp_t composition = {
|
||||
.cid = CID_ESP,
|
||||
.elements = elements,
|
||||
.element_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
static esp_ble_mesh_prov_t provision = {
|
||||
.uuid = dev_uuid,
|
||||
#if 0
|
||||
.output_size = 4,
|
||||
.output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
|
||||
.input_actions = ESP_BLE_MESH_PUSH,
|
||||
.input_size = 4,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
|
||||
{
|
||||
ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr);
|
||||
ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index);
|
||||
board_led_operation(LED_G, LED_OFF);
|
||||
}
|
||||
|
||||
static void example_change_led_state(esp_ble_mesh_model_t *model,
|
||||
esp_ble_mesh_msg_ctx_t *ctx, uint8_t onoff)
|
||||
{
|
||||
uint16_t primary_addr = esp_ble_mesh_get_primary_element_address();
|
||||
uint8_t elem_count = esp_ble_mesh_get_element_count();
|
||||
struct _led_state *led = NULL;
|
||||
uint8_t i;
|
||||
|
||||
if (ESP_BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
|
||||
for (i = 0; i < elem_count; i++) {
|
||||
if (ctx->recv_dst == (primary_addr + i)) {
|
||||
led = &led_state[i];
|
||||
board_led_operation(led->pin, onoff);
|
||||
}
|
||||
}
|
||||
} else if (ESP_BLE_MESH_ADDR_IS_GROUP(ctx->recv_dst)) {
|
||||
if (esp_ble_mesh_is_model_subscribed_to_group(model, ctx->recv_dst)) {
|
||||
led = &led_state[model->element->element_addr - primary_addr];
|
||||
board_led_operation(led->pin, onoff);
|
||||
}
|
||||
} else if (ctx->recv_dst == 0xFFFF) {
|
||||
led = &led_state[model->element->element_addr - primary_addr];
|
||||
board_led_operation(led->pin, onoff);
|
||||
}
|
||||
}
|
||||
|
||||
static void example_handle_gen_onoff_msg(esp_ble_mesh_model_t *model,
|
||||
esp_ble_mesh_msg_ctx_t *ctx,
|
||||
esp_ble_mesh_server_recv_gen_onoff_set_t *set)
|
||||
{
|
||||
esp_ble_mesh_gen_onoff_srv_t *srv = model->user_data;
|
||||
|
||||
switch (ctx->recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
|
||||
esp_ble_mesh_server_model_send_msg(model, ctx,
|
||||
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
|
||||
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK:
|
||||
if (set->op_en == false) {
|
||||
srv->state.onoff = set->onoff;
|
||||
} else {
|
||||
/* TODO: Delay and state transition */
|
||||
srv->state.onoff = set->onoff;
|
||||
}
|
||||
if (ctx->recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET) {
|
||||
esp_ble_mesh_server_model_send_msg(model, ctx,
|
||||
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS, sizeof(srv->state.onoff), &srv->state.onoff);
|
||||
}
|
||||
esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
|
||||
sizeof(srv->state.onoff), &srv->state.onoff, ROLE_NODE);
|
||||
example_change_led_state(model, ctx, srv->state.onoff);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_provisioning_cb(esp_ble_mesh_prov_cb_event_t event,
|
||||
esp_ble_mesh_prov_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
|
||||
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
|
||||
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT");
|
||||
prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
|
||||
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_RESET_EVT");
|
||||
break;
|
||||
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event,
|
||||
esp_ble_mesh_generic_server_cb_param_t *param)
|
||||
{
|
||||
ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04x, src 0x%04x, dst 0x%04x",
|
||||
event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst);
|
||||
|
||||
switch (event) {
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
|
||||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff);
|
||||
example_change_led_state(param->model, ¶m->ctx, param->value.state_change.onoff_set.onoff);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_GET_MSG_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET) {
|
||||
example_handle_gen_onoff_msg(param->model, ¶m->ctx, NULL);
|
||||
}
|
||||
break;
|
||||
case ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_RECV_SET_MSG_EVT");
|
||||
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
|
||||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
|
||||
ESP_LOGI(TAG, "onoff 0x%02x, tid 0x%02x", param->value.set.onoff.onoff, param->value.set.onoff.tid);
|
||||
if (param->value.set.onoff.op_en) {
|
||||
ESP_LOGI(TAG, "trans_time 0x%02x, delay 0x%02x",
|
||||
param->value.set.onoff.trans_time, param->value.set.onoff.delay);
|
||||
}
|
||||
example_handle_gen_onoff_msg(param->model, ¶m->ctx, ¶m->value.set.onoff);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown Generic Server event 0x%02x", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t event,
|
||||
esp_ble_mesh_cfg_server_cb_param_t *param)
|
||||
{
|
||||
if (event == ESP_BLE_MESH_CFG_SERVER_STATE_CHANGE_EVT) {
|
||||
switch (param->ctx.recv_op) {
|
||||
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD");
|
||||
ESP_LOGI(TAG, "net_idx 0x%04x, app_idx 0x%04x",
|
||||
param->value.state_change.appkey_add.net_idx,
|
||||
param->value.state_change.appkey_add.app_idx);
|
||||
ESP_LOG_BUFFER_HEX("AppKey", param->value.state_change.appkey_add.app_key, 16);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND");
|
||||
ESP_LOGI(TAG, "elem_addr 0x%04x, app_idx 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
||||
param->value.state_change.mod_app_bind.element_addr,
|
||||
param->value.state_change.mod_app_bind.app_idx,
|
||||
param->value.state_change.mod_app_bind.company_id,
|
||||
param->value.state_change.mod_app_bind.model_id);
|
||||
break;
|
||||
case ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD:
|
||||
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_MODEL_SUB_ADD");
|
||||
ESP_LOGI(TAG, "elem_addr 0x%04x, sub_addr 0x%04x, cid 0x%04x, mod_id 0x%04x",
|
||||
param->value.state_change.mod_sub_add.element_addr,
|
||||
param->value.state_change.mod_sub_add.sub_addr,
|
||||
param->value.state_change.mod_sub_add.company_id,
|
||||
param->value.state_change.mod_sub_add.model_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t ble_mesh_init(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
|
||||
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
|
||||
esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb);
|
||||
|
||||
err = esp_ble_mesh_init(&provision, &composition);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
|
||||
|
||||
ESP_LOGI(TAG, "BLE Mesh Node initialized");
|
||||
|
||||
board_led_operation(LED_G, LED_ON);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
|
||||
ESP_LOGI(TAG, "Initializing...");
|
||||
|
||||
board_init();
|
||||
|
||||
err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
err = bluetooth_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
|
||||
return;
|
||||
}
|
||||
|
||||
ble_mesh_get_dev_uuid(dev_uuid);
|
||||
|
||||
/* Initialize the Bluetooth Mesh Subsystem */
|
||||
err = ble_mesh_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/* 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 "board.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_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;
|
||||
}
|
||||
}
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
board_led_init();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* 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"
|
||||
|
||||
#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.)
|
||||
Reference in New Issue
Block a user