ble_mesh: update ble mesh examples

This commit is contained in:
lly 2019-10-21 22:48:05 +08:00
parent a302d210b9
commit e0e62232e0
44 changed files with 1632 additions and 1301 deletions

View File

@ -1,496 +0,0 @@
/* main.c - Application main entry point */
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_networking_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "esp_ble_mesh_generic_model_api.h"
#include "board.h"
#include "ble_mesh_demo_init.h"
#define CID_ESP 0x02E5
#define MSG_SEND_TTL 3
#define MSG_SEND_REL false
#define MSG_TIMEOUT 0 /* 0 indicates that timeout value from menuconfig will be used */
#define MSG_ROLE ROLE_NODE
extern struct _led_state led_state[3];
static uint8_t dev_uuid[16] = { 0xdd, 0xdd };
static uint16_t node_net_idx = ESP_BLE_MESH_KEY_UNUSED;
static uint16_t node_app_idx = ESP_BLE_MESH_KEY_UNUSED;
static uint8_t remote_onoff = LED_OFF;
/* The remote node address shall be input through UART1, see board.c */
uint16_t remote_addr = ESP_BLE_MESH_ADDR_UNASSIGNED;
static esp_ble_mesh_client_t onoff_client;
static esp_ble_mesh_cfg_srv_t config_server = {
.relay = ESP_BLE_MESH_RELAY_DISABLED,
.beacon = ESP_BLE_MESH_BEACON_ENABLED,
#if defined(CONFIG_BLE_MESH_FRIEND)
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
#else
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
#endif
#if defined(CONFIG_BLE_MESH_GATT_PROXY_SERVER)
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_ENABLED,
#else
.gatt_proxy = ESP_BLE_MESH_GATT_PROXY_NOT_SUPPORTED,
#endif
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
};
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_srv_pub, 2 + 1, MSG_ROLE);
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_cli_pub, 2 + 1, MSG_ROLE);
static esp_ble_mesh_model_op_t onoff_op[] = {
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET, 0),
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, 2),
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2),
/* Each model operation struct array must use this terminator
* as the end tag of the operation uint. */
ESP_BLE_MESH_MODEL_OP_END,
};
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
&onoff_srv_pub, &led_state[0]),
ESP_BLE_MESH_MODEL_GEN_ONOFF_CLI(&onoff_cli_pub, &onoff_client),
};
static esp_ble_mesh_elem_t elements[] = {
ESP_BLE_MESH_ELEMENT(0, root_models, ESP_BLE_MESH_MODEL_NONE),
};
static esp_ble_mesh_comp_t composition = {
.cid = CID_ESP,
.elements = elements,
.element_count = ARRAY_SIZE(elements),
};
/* Disable OOB security for SILabs Android app */
static esp_ble_mesh_prov_t provision = {
.uuid = dev_uuid,
#if 0
.output_size = 4,
.output_actions = ESP_BLE_MESH_DISPLAY_NUMBER,
.input_actions = ESP_BLE_MESH_PUSH,
.input_size = 4,
#else
.output_size = 0,
.output_actions = 0,
#endif
};
static int output_number(esp_ble_mesh_output_action_t action, uint32_t number)
{
board_output_number(action, number);
return 0;
}
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
{
ESP_LOGI(TAG, "net_idx: 0x%04x, addr: 0x%04x", net_idx, addr);
ESP_LOGI(TAG, "flags: 0x%02x, iv_index: 0x%08x", flags, iv_index);
board_prov_complete();
node_net_idx = net_idx;
}
static void gen_onoff_get_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t length, uint8_t *data)
{
struct _led_state *led = (struct _led_state *)model->user_data;
uint8_t send_data;
esp_err_t err;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
send_data = led->current;
/* Send Generic OnOff Status as a response to Generic OnOff Get */
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__);
return;
}
}
static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t length, uint8_t *data)
{
struct _led_state *led = (struct _led_state *)model->user_data;
uint8_t prev_onoff;
esp_err_t err;
prev_onoff = led->previous;
led->current = data[0];
remote_onoff = led->current;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
/* If Generic OnOff state is changed, and the publish address of Generic OnOff Server
* model is valid, Generic OnOff Status will be published.
*/
if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) {
ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current);
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(led->current), &led->current, ROLE_NODE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__);
return;
}
}
}
static void gen_onoff_set_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t length, uint8_t *data)
{
struct net_buf_simple *msg = model->pub->msg;
struct _led_state *led = (struct _led_state *)model->user_data;
uint8_t prev_onoff, send_data;
esp_err_t err;
prev_onoff = led->previous;
led->current = data[0];
remote_onoff = led->current;
ESP_LOGI(TAG, "%s, addr 0x%04x onoff 0x%02x", __func__, model->element->element_addr, led->current);
board_led_operation(led->pin, led->current);
send_data = led->current;
/* Send Generic OnOff Status as a response to Generic OnOff Get */
err = esp_ble_mesh_server_model_send_msg(model, ctx, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Status failed", __func__);
return;
}
/* If Generic OnOff state is changed, and the publish address of Generic OnOff Server
* model is valid, Generic OnOff Status will be published.
*/
if (prev_onoff != led->current && model->pub->publish_addr != ESP_BLE_MESH_ADDR_UNASSIGNED) {
ESP_LOGI(TAG, "Publish previous 0x%02x current 0x%02x", prev_onoff, led->current);
bt_mesh_model_msg_init(msg, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS);
err = esp_ble_mesh_model_publish(model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_STATUS,
sizeof(send_data), &send_data, ROLE_NODE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Publish Generic OnOff Status failed", __func__);
return;
}
}
}
static char *esp_ble_mesh_prov_event_to_str(esp_ble_mesh_prov_cb_event_t event)
{
switch (event) {
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
return "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT";
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
return "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT";
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
return "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT";
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
return "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT";
case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT:
return "ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT";
case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT:
return "ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT";
case ESP_BLE_MESH_NODE_PROV_INPUT_EVT:
return "ESP_BLE_MESH_NODE_PROV_INPUT_EVT";
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
return "ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT";
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
return "ESP_BLE_MESH_NODE_PROV_RESET_EVT";
default:
return "Invalid BLE Mesh provision event";
}
return NULL;
}
static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event,
esp_ble_mesh_prov_cb_param_t *param)
{
ESP_LOGI(TAG, "%s, event = %s", __func__, esp_ble_mesh_prov_event_to_str(event));
switch (event) {
case ESP_BLE_MESH_PROV_REGISTER_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, err_code %d", param->prov_register_comp.err_code);
break;
case ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_ENABLE_COMP_EVT, err_code %d", param->node_prov_enable_comp.err_code);
break;
case ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_OPEN_EVT, bearer %s",
param->node_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
break;
case ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_PROV_LINK_CLOSE_EVT, bearer %s",
param->node_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
break;
case ESP_BLE_MESH_NODE_PROV_OUTPUT_NUMBER_EVT:
output_number(param->node_prov_output_num.action, param->node_prov_output_num.number);
break;
case ESP_BLE_MESH_NODE_PROV_OUTPUT_STRING_EVT:
break;
case ESP_BLE_MESH_NODE_PROV_INPUT_EVT:
break;
case ESP_BLE_MESH_NODE_PROV_COMPLETE_EVT:
prov_complete(param->node_prov_complete.net_idx, param->node_prov_complete.addr,
param->node_prov_complete.flags, param->node_prov_complete.iv_index);
break;
case ESP_BLE_MESH_NODE_PROV_RESET_EVT:
break;
case ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_NODE_SET_UNPROV_DEV_NAME_COMP_EVT, err_code %d", param->node_set_unprov_dev_name_comp.err_code);
break;
default:
break;
}
return;
}
static esp_err_t esp_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common,
esp_ble_mesh_generic_client_set_state_t *set,
esp_ble_mesh_model_t *model, uint32_t opcode,
uint8_t onoff)
{
if (!common || !set || !model) {
return ESP_ERR_INVALID_ARG;
}
common->opcode = opcode;
common->model = model;
common->ctx.net_idx = node_net_idx;
common->ctx.app_idx = node_app_idx;
common->ctx.addr = remote_addr;
common->ctx.send_ttl = MSG_SEND_TTL;
common->ctx.send_rel = MSG_SEND_REL;
common->msg_timeout = MSG_TIMEOUT;
common->msg_role = MSG_ROLE;
set->onoff_set.op_en = false;
set->onoff_set.onoff = onoff;
set->onoff_set.tid = 0x0;
return ESP_OK;
}
static void esp_ble_mesh_model_cb(esp_ble_mesh_model_cb_event_t event,
esp_ble_mesh_model_cb_param_t *param)
{
esp_ble_mesh_client_common_param_t common = {0};
int err;
switch (event) {
case ESP_BLE_MESH_MODEL_OPERATION_EVT: {
if (!param->model_operation.model || !param->model_operation.model->op || !param->model_operation.ctx) {
ESP_LOGE(TAG, "ESP_BLE_MESH_MODEL_OPERATION_EVT parameter is NULL");
return;
}
if (node_app_idx == ESP_BLE_MESH_KEY_UNUSED) {
/* Generic OnOff Server/Client Models need to bind with the same app key */
node_app_idx = param->model_operation.ctx->app_idx;
}
switch (param->model_operation.opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
gen_onoff_get_handler(param->model_operation.model, param->model_operation.ctx,
param->model_operation.length, param->model_operation.msg);
break;
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: {
esp_ble_mesh_generic_client_set_state_t set_state = {0};
gen_onoff_set_handler(param->model_operation.model, param->model_operation.ctx,
param->model_operation.length, param->model_operation.msg);
/* This node has a Generic OnOff Client and Server Model.
* When Generic OnOff Server Model receives a Generic OnOff Set message, after
* this message is been handled, the Generic OnOff Client Model will send the
* Generic OnOff Set message to another node(contains Generic OnOff Server Model)
* identified by the remote_addr.
*/
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
return;
}
break;
}
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK: {
esp_ble_mesh_generic_client_set_state_t set_state = {0};
gen_onoff_set_unack_handler(param->model_operation.model, param->model_operation.ctx,
param->model_operation.length, param->model_operation.msg);
/* This node has a Generic OnOff Client and Server Model.
* When Generic OnOff Client Model receives a Generic OnOff Set Unack message,
* after this message is been handled, the Generic OnOff Client Model will send
* the Generic OnOff Set Unack message to another node(contains Generic OnOff
* Server Model) identified by the remote_addr.
*/
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set Unack failed", __func__);
return;
}
break;
}
default:
break;
}
break;
}
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
break;
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
break;
default:
break;
}
return;
}
static void esp_ble_mesh_generic_cb(esp_ble_mesh_generic_client_cb_event_t event,
esp_ble_mesh_generic_client_cb_param_t *param)
{
uint32_t opcode;
int err;
ESP_LOGI(TAG, "%s: event is %d, error code is %d, opcode is 0x%x",
__func__, event, param->error_code, param->params->opcode);
opcode = param->params->opcode;
switch (event) {
case ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_GET_STATE_EVT");
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET:
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: onoff %d", param->status_cb.onoff_status.present_onoff);
break;
default:
break;
}
break;
case ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_SET_STATE_EVT");
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET:
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: onoff %d", param->status_cb.onoff_status.present_onoff);
break;
default:
break;
}
break;
case ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_PUBLISH_EVT");
break;
case ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT: {
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_CLIENT_TIMEOUT_EVT");
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET: {
esp_ble_mesh_client_common_param_t common = {0};
esp_ble_mesh_generic_client_set_state_t set_state = {0};
/* If failed to get the response of Generic OnOff Set, resend Generic OnOff Set */
esp_ble_mesh_set_msg_common(&common, &set_state, onoff_client.model,
ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET, remote_onoff);
err = esp_ble_mesh_generic_client_set_state(&common, &set_state);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: Generic OnOff Set failed", __func__);
return;
}
break;
}
default:
break;
}
break;
}
default:
break;
}
return;
}
static int ble_mesh_init(void)
{
int err = 0;
esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb);
esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb);
esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_cb);
err = esp_ble_mesh_init(&provision, &composition);
if (err) {
ESP_LOGE(TAG, "Initializing mesh failed (err %d)", err);
return err;
}
esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
ESP_LOGI(TAG, "BLE Mesh Node initialized");
board_led_operation(LED_G, LED_ON);
return err;
}
void app_main(void)
{
int err;
ESP_LOGI(TAG, "Initializing...");
board_init();
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
err = bluetooth_init();
if (err) {
ESP_LOGE(TAG, "esp32_bluetooth_init failed (err %d)", err);
return;
}
ble_mesh_get_dev_uuid(dev_uuid);
/* Initialize the Bluetooth Mesh Subsystem */
err = ble_mesh_init();
if (err) {
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
}
}

View File

@ -1,115 +0,0 @@
/* board.c - Board-specific hooks */
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "board.h"
#define TAG "BOARD"
#define MESH_UART_NUM UART_NUM_1
#define MESH_UART (&UART1)
#define UART_BUF_SIZE 128
#define UART1_TX_PIN GPIO_NUM_16
#define UART1_RX_PIN GPIO_NUM_17
extern uint16_t remote_addr;
struct _led_state led_state[3] = {
{ LED_OFF, LED_OFF, LED_R, "red" },
{ LED_OFF, LED_OFF, LED_G, "green" },
{ LED_OFF, LED_OFF, LED_B, "blue" },
};
void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number)
{
ESP_LOGI(TAG, "Board output number %d", number);
}
void board_prov_complete(void)
{
board_led_operation(LED_G, LED_OFF);
}
void board_led_operation(uint8_t pin, uint8_t onoff)
{
for (int i = 0; i < ARRAY_SIZE(led_state); i++) {
if (led_state[i].pin != pin) {
continue;
}
if (onoff == led_state[i].previous) {
ESP_LOGW(TAG, "led %s is already %s",
led_state[i].name, (onoff ? "on" : "off"));
return;
}
gpio_set_level(pin, onoff);
led_state[i].previous = onoff;
return;
}
ESP_LOGE(TAG, "LED is not found!");
}
static void board_uart_task(void *p)
{
uint8_t *data = calloc(1, UART_BUF_SIZE);
uint32_t input;
while (1) {
int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS);
if (len > 0) {
input = strtoul((const char *)data, NULL, 16);
remote_addr = input & 0xFFFF;
ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr);
memset(data, 0, UART_BUF_SIZE);
}
}
vTaskDelete(NULL);
}
static void board_led_init(void)
{
for (int i = 0; i < ARRAY_SIZE(led_state); i++) {
gpio_pad_select_gpio(led_state[i].pin);
gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT);
gpio_set_level(led_state[i].pin, LED_OFF);
led_state[i].previous = LED_OFF;
}
}
static void board_uart_init(void)
{
uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(MESH_UART_NUM, &uart_config);
uart_set_pin(MESH_UART_NUM, UART1_TX_PIN, UART1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_driver_install(MESH_UART_NUM, UART_BUF_SIZE * 2, 0, 0, NULL, 0);
}
void board_init(void)
{
board_led_init();
board_uart_init();
xTaskCreate(board_uart_task, "board_uart_task", 2048, NULL, 5, NULL);
}

View File

@ -574,7 +574,7 @@ static esp_err_t ble_mesh_init(void)
void app_main(void)
{
int err;
esp_err_t err;
ESP_LOGI(TAG, "Initializing...");

View File

@ -24,6 +24,7 @@
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "esp_ble_mesh_generic_model_api.h"
#include "esp_ble_mesh_local_data_operation_api.h"
#include "board.h"
#include "esp_fast_prov_operation.h"
@ -95,15 +96,12 @@ example_fast_prov_server_t fast_prov_server = {
.state = STATE_IDLE,
};
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),
ESP_BLE_MESH_MODEL_OP_END,
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 3, ROLE_FAST_PROV);
static esp_ble_mesh_gen_onoff_srv_t onoff_server = {
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
};
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 1, ROLE_FAST_PROV);
static esp_ble_mesh_model_op_t fast_prov_srv_op[] = {
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3),
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16),
@ -124,8 +122,7 @@ static esp_ble_mesh_model_op_t fast_prov_cli_op[] = {
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
ESP_BLE_MESH_MODEL_CFG_CLI(&config_client),
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
&onoff_pub, &led_state[1]),
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub, &onoff_server),
};
static esp_ble_mesh_model_t vnd_models[] = {
@ -158,29 +155,11 @@ static esp_ble_mesh_prov_t prov = {
.iv_index = 0x00,
};
static void gen_onoff_get_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t len, uint8_t *data)
static void example_change_led_state(uint8_t onoff)
{
struct _led_state *led = NULL;
uint8_t send_data;
esp_err_t err;
struct _led_state *led = &led_state[1];
led = (struct _led_state *)model->user_data;
if (!led) {
ESP_LOGE(TAG, "%s: Failed to get generic onoff server model user_data", __func__);
return;
}
send_data = led->current;
/* Sends Generic OnOff Status as a reponse 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: Failed to send Generic OnOff Status message", __func__);
return;
}
board_led_operation(led->pin, onoff);
/* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will
* start the timer used to disable fast provisioning functionality.
@ -190,37 +169,6 @@ static void gen_onoff_get_handler(esp_ble_mesh_model_t *model,
}
}
static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t len, uint8_t *data)
{
struct _led_state *led = NULL;
led = (struct _led_state *)model->user_data;
if (!led) {
ESP_LOGE(TAG, "%s: Failed to get generic onoff server model user_data", __func__);
return;
}
led->current = data[0];
gpio_set_level(led->pin, led->current);
/* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will
* start the timer used to disable fast provisioning functionality.
*/
if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) {
k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT);
}
}
static void gen_onoff_set_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t len, uint8_t *data)
{
gen_onoff_set_unack_handler(model, ctx, len, data);
gen_onoff_get_handler(model, ctx, len, data);
}
static void node_prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
{
ESP_LOGI(TAG, "net_idx: 0x%04x, unicast_addr: 0x%04x", net_idx, addr);
@ -484,14 +432,6 @@ static void example_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event
}
opcode = param->model_operation.opcode;
switch (opcode) {
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;
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET:
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD:
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR:
@ -724,6 +664,27 @@ static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t
}
}
static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event,
esp_ble_mesh_generic_server_cb_param_t *param)
{
ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04x, src 0x%04x, dst 0x%04x",
event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst);
switch (event) {
case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT");
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff);
example_change_led_state(param->value.state_change.onoff_set.onoff);
}
break;
default:
ESP_LOGW(TAG, "Unknown Generic Server event 0x%02x", event);
break;
}
}
static esp_err_t ble_mesh_init(void)
{
esp_err_t err;
@ -732,6 +693,7 @@ static esp_err_t ble_mesh_init(void)
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb);
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb);
err = esp_ble_mesh_init(&prov, &comp);
if (err != ESP_OK) {

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ble_mesh_node)
project(onoff_client)

View File

@ -3,7 +3,7 @@
# project subdirectory.
#
PROJECT_NAME := ble_mesh_node
PROJECT_NAME := onoff_client
COMPONENT_ADD_INCLUDEDIRS := components/include

View File

@ -0,0 +1,7 @@
set(COMPONENT_SRCS "button.c"
"button_obj.cpp")
set(COMPONENT_ADD_INCLUDEDIRS ". include")
register_component()

View File

@ -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

View File

@ -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
```

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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);

View File

@ -3,4 +3,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(ble_mesh_client_model)
project(onoff_server)

View File

@ -3,7 +3,7 @@
# project subdirectory.
#
PROJECT_NAME := ble_mesh_client_model
PROJECT_NAME := onoff_server
COMPONENT_ADD_INCLUDEDIRS := components/include

View File

@ -9,7 +9,7 @@
#ifndef _BLE_MESH_DEMO_INIT_H_
#define _BLE_MESH_DEMO_INIT_H_
#define TAG "ble_mesh_client"
#define TAG "onoff_server"
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);

View File

@ -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, &param->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, &param->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, &param->ctx, &param->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);
}
}

View File

@ -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();
}

View File

@ -2,6 +2,7 @@
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -9,7 +10,6 @@
#define _BOARD_H_
#include "driver/gpio.h"
#include "esp_ble_mesh_defs.h"
#if defined(CONFIG_BLE_MESH_ESP_WROOM_32)
#define LED_R GPIO_NUM_25
@ -31,10 +31,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);

View File

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -113,8 +113,8 @@ static esp_ble_mesh_prov_t provision = {
.iv_index = 0x00,
};
static esp_err_t esp_ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t unicast,
uint8_t elem_num, uint8_t onoff_state)
static esp_err_t example_ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t unicast,
uint8_t elem_num, uint8_t onoff_state)
{
int i;
@ -146,7 +146,7 @@ static esp_err_t esp_ble_mesh_store_node_info(const uint8_t uuid[16], uint16_t u
return ESP_FAIL;
}
static esp_ble_mesh_node_info_t *esp_ble_mesh_get_node_info(uint16_t unicast)
static esp_ble_mesh_node_info_t *example_ble_mesh_get_node_info(uint16_t unicast)
{
int i;
@ -164,9 +164,9 @@ static esp_ble_mesh_node_info_t *esp_ble_mesh_get_node_info(uint16_t unicast)
return NULL;
}
static esp_err_t esp_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common,
esp_ble_mesh_node_info_t *node,
esp_ble_mesh_model_t *model, uint32_t opcode)
static esp_err_t example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common,
esp_ble_mesh_node_info_t *node,
esp_ble_mesh_model_t *model, uint32_t opcode)
{
if (!common || !node || !model) {
return ESP_ERR_INVALID_ARG;
@ -205,19 +205,19 @@ static esp_err_t prov_complete(int node_idx, const esp_ble_mesh_octet16_t uuid,
return ESP_FAIL;
}
err = esp_ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF);
err = example_ble_mesh_store_node_info(uuid, unicast, elem_num, LED_OFF);
if (err) {
ESP_LOGE(TAG, "%s: Store node info failed", __func__);
return ESP_FAIL;
}
node = esp_ble_mesh_get_node_info(unicast);
node = example_ble_mesh_get_node_info(unicast);
if (!node) {
ESP_LOGE(TAG, "%s: Get node info failed", __func__);
return ESP_FAIL;
}
esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET);
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET);
get_state.comp_data_get.page = COMP_DATA_PAGE_0;
err = esp_ble_mesh_config_client_get_state(&common, &get_state);
if (err) {
@ -271,8 +271,8 @@ static void recv_unprov_adv_pkt(uint8_t dev_uuid[16], uint8_t addr[BD_ADDR_LEN],
return;
}
static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event,
esp_ble_mesh_prov_cb_param_t *param)
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_PROVISIONER_PROV_ENABLE_COMP_EVT:
@ -341,23 +341,8 @@ static void esp_ble_mesh_prov_cb(esp_ble_mesh_prov_cb_event_t event,
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:
break;
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
break;
case ESP_BLE_MESH_MODEL_PUBLISH_COMP_EVT:
break;
default:
break;
}
}
static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event,
esp_ble_mesh_cfg_client_cb_param_t *param)
static void example_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t event,
esp_ble_mesh_cfg_client_cb_param_t *param)
{
esp_ble_mesh_client_common_param_t common = {0};
esp_ble_mesh_node_info_t *node = NULL;
@ -376,7 +361,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
return;
}
node = esp_ble_mesh_get_node_info(addr);
node = example_ble_mesh_get_node_info(addr);
if (!node) {
ESP_LOGE(TAG, "%s: Get node info failed", __func__);
return;
@ -389,7 +374,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
ESP_LOGI(TAG, "composition data %s", bt_hex(param->status_cb.comp_data_status.composition_data->data,
param->status_cb.comp_data_status.composition_data->len));
esp_ble_mesh_cfg_client_set_state_t set_state = {0};
esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD);
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD);
set_state.app_key_add.net_idx = prov_key.net_idx;
set_state.app_key_add.app_idx = prov_key.app_idx;
memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16);
@ -408,7 +393,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: {
esp_ble_mesh_cfg_client_set_state_t set_state = {0};
esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND);
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND);
set_state.model_app_bind.element_addr = node->unicast;
set_state.model_app_bind.model_app_idx = prov_key.app_idx;
set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV;
@ -422,7 +407,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
}
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: {
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);
example_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__);
@ -450,7 +435,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: {
esp_ble_mesh_cfg_client_get_state_t get_state = {0};
esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET);
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET);
get_state.comp_data_get.page = COMP_DATA_PAGE_0;
err = esp_ble_mesh_config_client_get_state(&common, &get_state);
if (err) {
@ -461,7 +446,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
}
case ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD: {
esp_ble_mesh_cfg_client_set_state_t set_state = {0};
esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD);
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD);
set_state.app_key_add.net_idx = prov_key.net_idx;
set_state.app_key_add.app_idx = prov_key.app_idx;
memcpy(set_state.app_key_add.app_key, prov_key.app_key, 16);
@ -474,7 +459,7 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
}
case ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND: {
esp_ble_mesh_cfg_client_set_state_t set_state = {0};
esp_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND);
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND);
set_state.model_app_bind.element_addr = node->unicast;
set_state.model_app_bind.model_app_idx = prov_key.app_idx;
set_state.model_app_bind.model_id = ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV;
@ -496,8 +481,8 @@ static void esp_ble_mesh_config_client_cb(esp_ble_mesh_cfg_client_cb_event_t eve
}
}
static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_t event,
esp_ble_mesh_generic_client_cb_param_t *param)
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_ble_mesh_client_common_param_t common = {0};
esp_ble_mesh_node_info_t *node = NULL;
@ -516,7 +501,7 @@ static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_
return;
}
node = esp_ble_mesh_get_node_info(addr);
node = example_ble_mesh_get_node_info(addr);
if (!node) {
ESP_LOGE(TAG, "%s: Get node info failed", __func__);
return;
@ -530,7 +515,7 @@ static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_
node->onoff = param->status_cb.onoff_status.present_onoff;
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff);
/* After Generic OnOff Status for Generic OnOff Get is received, Generic OnOff Set will be sent */
esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET);
example_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET);
set_state.onoff_set.op_en = false;
set_state.onoff_set.onoff = !node->onoff;
set_state.onoff_set.tid = 0;
@ -562,7 +547,7 @@ static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_
switch (opcode) {
case ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET: {
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);
example_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__);
@ -574,7 +559,7 @@ static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_
esp_ble_mesh_generic_client_set_state_t set_state = {0};
node->onoff = param->status_cb.onoff_status.present_onoff;
ESP_LOGI(TAG, "ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_GET onoff: 0x%02x", node->onoff);
esp_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET);
example_ble_mesh_set_msg_common(&common, node, onoff_client.model, ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET);
set_state.onoff_set.op_en = false;
set_state.onoff_set.onoff = !node->onoff;
set_state.onoff_set.tid = 0;
@ -595,19 +580,18 @@ static void esp_ble_mesh_generic_client_cb(esp_ble_mesh_generic_client_cb_event_
}
}
static int ble_mesh_init(void)
static esp_err_t ble_mesh_init(void)
{
uint8_t match[2] = {0xdd, 0xdd};
int err = 0;
esp_err_t err;
prov_key.net_idx = ESP_BLE_MESH_KEY_PRIMARY;
prov_key.app_idx = APP_KEY_IDX;
memset(prov_key.app_key, APP_KEY_OCTET, sizeof(prov_key.app_key));
esp_ble_mesh_register_prov_callback(esp_ble_mesh_prov_cb);
esp_ble_mesh_register_custom_model_callback(esp_ble_mesh_model_cb);
esp_ble_mesh_register_config_client_callback(esp_ble_mesh_config_client_cb);
esp_ble_mesh_register_generic_client_callback(esp_ble_mesh_generic_client_cb);
esp_ble_mesh_register_prov_callback(example_ble_mesh_provisioning_cb);
esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb);
esp_ble_mesh_register_generic_client_callback(example_ble_mesh_generic_client_cb);
err = esp_ble_mesh_init(&provision, &composition);
@ -629,7 +613,7 @@ static int ble_mesh_init(void)
void app_main(void)
{
int err;
esp_err_t err;
ESP_LOGI(TAG, "Initializing...");

View File

@ -36,6 +36,7 @@
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "esp_ble_mesh_generic_model_api.h"
#include "esp_ble_mesh_local_data_operation_api.h"
#include "board.h"
#include "esp_fast_prov_operation.h"
@ -107,15 +108,12 @@ example_fast_prov_server_t fast_prov_server = {
.state = STATE_IDLE,
};
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),
ESP_BLE_MESH_MODEL_OP_END,
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 3, ROLE_FAST_PROV);
static esp_ble_mesh_gen_onoff_srv_t onoff_server = {
.rsp_ctrl.get_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
.rsp_ctrl.set_auto_rsp = ESP_BLE_MESH_SERVER_AUTO_RSP,
};
ESP_BLE_MESH_MODEL_PUB_DEFINE(onoff_pub, 2 + 1, ROLE_FAST_PROV);
static esp_ble_mesh_model_op_t fast_prov_srv_op[] = {
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET, 3),
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD, 16),
@ -136,8 +134,7 @@ static esp_ble_mesh_model_op_t fast_prov_cli_op[] = {
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
ESP_BLE_MESH_MODEL_CFG_CLI(&config_client),
ESP_BLE_MESH_SIG_MODEL(ESP_BLE_MESH_MODEL_ID_GEN_ONOFF_SRV, onoff_op,
&onoff_pub, &led_state[1]),
ESP_BLE_MESH_MODEL_GEN_ONOFF_SRV(&onoff_pub, &onoff_server),
};
static esp_ble_mesh_model_t vnd_models[] = {
@ -170,29 +167,11 @@ static esp_ble_mesh_prov_t prov = {
.iv_index = 0x00,
};
static void gen_onoff_get_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t len, uint8_t *data)
static void example_change_led_state(uint8_t onoff)
{
struct _led_state *led = NULL;
uint8_t send_data;
esp_err_t err;
struct _led_state *led = &led_state[1];
led = (struct _led_state *)model->user_data;
if (!led) {
ESP_LOGE(TAG, "%s: Failed to get generic onoff server model user_data", __func__);
return;
}
send_data = led->current;
/* Sends Generic OnOff Status as a reponse 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: Failed to send Generic OnOff Status message", __func__);
return;
}
board_led_operation(led->pin, onoff);
/* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will
* start the timer used to disable fast provisioning functionality.
@ -202,37 +181,6 @@ static void gen_onoff_get_handler(esp_ble_mesh_model_t *model,
}
}
static void gen_onoff_set_unack_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t len, uint8_t *data)
{
struct _led_state *led = NULL;
led = (struct _led_state *)model->user_data;
if (!led) {
ESP_LOGE(TAG, "%s: Failed to get generic onoff server model user_data", __func__);
return;
}
led->current = data[0];
gpio_set_level(led->pin, led->current);
/* When the node receives the first Generic OnOff Get/Set/Set Unack message, it will
* start the timer used to disable fast provisioning functionality.
*/
if (!bt_mesh_atomic_test_and_set_bit(fast_prov_server.srv_flags, DISABLE_FAST_PROV_START)) {
k_delayed_work_submit(&fast_prov_server.disable_fast_prov_timer, DISABLE_FAST_PROV_TIMEOUT);
}
}
static void gen_onoff_set_handler(esp_ble_mesh_model_t *model,
esp_ble_mesh_msg_ctx_t *ctx,
uint16_t len, uint8_t *data)
{
gen_onoff_set_unack_handler(model, ctx, len, data);
gen_onoff_get_handler(model, ctx, len, data);
}
static void node_prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
{
ESP_LOGI(TAG, "net_idx: 0x%04x, unicast_addr: 0x%04x", net_idx, addr);
@ -496,14 +444,6 @@ static void example_ble_mesh_custom_model_cb(esp_ble_mesh_model_cb_event_t event
}
opcode = param->model_operation.opcode;
switch (opcode) {
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;
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_INFO_SET:
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NET_KEY_ADD:
case ESP_BLE_MESH_VND_MODEL_OP_FAST_PROV_NODE_ADDR:
@ -736,6 +676,27 @@ static void example_ble_mesh_config_server_cb(esp_ble_mesh_cfg_server_cb_event_t
}
}
static void example_ble_mesh_generic_server_cb(esp_ble_mesh_generic_server_cb_event_t event,
esp_ble_mesh_generic_server_cb_param_t *param)
{
ESP_LOGI(TAG, "event 0x%02x, opcode 0x%04x, src 0x%04x, dst 0x%04x",
event, param->ctx.recv_op, param->ctx.addr, param->ctx.recv_dst);
switch (event) {
case ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_GENERIC_SERVER_STATE_CHANGE_EVT");
if (param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET ||
param->ctx.recv_op == ESP_BLE_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK) {
ESP_LOGI(TAG, "onoff 0x%02x", param->value.state_change.onoff_set.onoff);
example_change_led_state(param->value.state_change.onoff_set.onoff);
}
break;
default:
ESP_LOGW(TAG, "Unknown Generic Server event 0x%02x", event);
break;
}
}
static esp_err_t ble_mesh_init(void)
{
esp_err_t err;
@ -744,6 +705,7 @@ static esp_err_t ble_mesh_init(void)
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb);
esp_ble_mesh_register_config_server_callback(example_ble_mesh_config_server_cb);
esp_ble_mesh_register_generic_server_callback(example_ble_mesh_generic_server_cb);
err = esp_ble_mesh_init(&prov, &comp);
if (err != ESP_OK) {