ble_mesh: Add ESP BLE Mesh vendor models example

This commit is contained in:
lly 2020-03-02 18:17:44 +08:00 committed by bot
parent 842f7da7d4
commit 6a9c1ed48c
31 changed files with 2279 additions and 0 deletions

View file

@ -66,6 +66,22 @@ This example shows how ESP32 acts as a BLE Mesh Provisioner and provisions other
See [ble_mesh_provisioner](ble_mesh_provisioner) folder for more details.
## ble_mesh_vendor_model
This example demonstrates how ESP32 acts as a BLE Mesh Provisioner with vendor client model or as a BLE Mesh node with vendor server model.
#### vendor_client
This example shows how ESP32 acts as a BLE Mesh Provisioner with a vendor client model in the Primary Element.
See [vendor_client](ble_mesh_vendor_model/vendor_client) folder for more details.
#### vendor_server
This example shows how ESP32 acts as a BLE Mesh Node with a vendor server model in the Primary Element.
See [vendor_server](ble_mesh_vendor_model/vendor_server) folder for more details.
## ble_mesh_wifi_coexist
This example shows how ESP32 acts as a BLE Mesh Fast Provisioning Server and coexists with Wi-Fi iperf functionality.

View file

@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(SUPPORTED_TARGETS esp32)
project(vendor_client)

View file

@ -0,0 +1,10 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := vendor_client
COMPONENT_ADD_INCLUDEDIRS := components/include
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,61 @@
ESP BLE Mesh Vendor Client Example
==================================
This example demonstrates how to create a vendor client model in Provisioner, and the [vendor server example](../vendor_server) demonstrates how to create a vendor server model in an unprovisioned device.
### 1. Procedures
1. Compile the vendor client and vendor server examples and flash;
2. When Provisioner starts, it will register callbacks, initialize mesh stack, initialize the vendor client model, set matching device uuid, enable its functionality, add local application key and bind the application key with the vendor client model;
3. When the unprovisioned device starts, it will initialize mesh stack and enable its functionality;
4. When the Provisioner and unprovisioned device are ready, the Provisioner will start to provision the unprovisioned device;
5. After the device is provisioned successfully, Provisioner will configure the node, i.e. add application key, bind application key with the vendor server model of the node;
6. After the configuration is completed, users can press the "Boot" button on the development board to send a vendor client message to the node;
7. When the node receives the vendor client message, it will send a vendor server message as a response;
8. After the Provisioner receives the response, it will calculate the latency (in microseconds).
### 2. Results
The following is a sample test result, the distance between the Provisioner and the node is about 1 meter.
#### 2.1 Provisioner - Vendor Client
I (6684) Client: Send 0xc002e5
I (6834) Client: Recv 0xc102e5, tid 0x0001, time 156585us
I (7934) Client: Send 0xc002e5
I (8024) Client: Recv 0xc102e5, tid 0x0002, time 83348us
I (9044) Client: Send 0xc002e5
I (9094) Client: Recv 0xc102e5, tid 0x0003, time 51202us
I (10244) Client: Send 0xc002e5
I (10294) Client: Recv 0xc102e5, tid 0x0004, time 45290us
I (11544) Client: Send 0xc002e5
I (11564) Client: Recv 0xc102e5, tid 0x0005, time 22973us
I (12734) Client: Send 0xc002e5
I (12754) Client: Recv 0xc102e5, tid 0x0006, time 22369us
I (14114) Client: Send 0xc002e5
I (14134) Client: Recv 0xc102e5, tid 0x0007, time 22113us
I (15544) Client: Send 0xc002e5
I (15614) Client: Recv 0xc102e5, tid 0x0008, time 68969us
I (16694) Client: Send 0xc002e5
I (16714) Client: Recv 0xc102e5, tid 0x0009, time 21782us
I (17784) Client: Send 0xc002e5
I (17814) Client: Recv 0xc102e5, tid 0x000a, time 25010us
#### 2.2 Node - Vendor Server
I (6409) Server: Recv 0xc002e5, tid 0x0001
I (6429) Server: Send 0xc102e5
I (7609) Server: Recv 0xc002e5, tid 0x0002
I (7619) Server: Send 0xc102e5
I (8719) Server: Recv 0xc002e5, tid 0x0003
I (8729) Server: Send 0xc102e5
I (9899) Server: Recv 0xc002e5, tid 0x0004
I (9909) Server: Send 0xc102e5
I (11189) Server: Recv 0xc002e5, tid 0x0005
I (11199) Server: Send 0xc102e5
I (12379) Server: Recv 0xc002e5, tid 0x0006
I (12389) Server: Send 0xc102e5
I (13759) Server: Recv 0xc002e5, tid 0x0007
I (13769) Server: Send 0xc102e5
I (15189) Server: Recv 0xc002e5, tid 0x0008
I (15209) Server: Send 0xc102e5
I (16339) Server: Recv 0xc002e5, tid 0x0009
I (16349) Server: Send 0xc102e5
I (17439) Server: Recv 0xc002e5, tid 0x000a
I (17449) Server: Send 0xc102e5

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,46 @@
# 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.
These components are based on GPIO provided by ESP-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 used memory.
* Todo: Add hardware timer mode(because sometimes soft-timer callback function is limited)
### NOTE:
> All the event callback function are implemented 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,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,231 @@
// 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

@ -0,0 +1,7 @@
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
"ble_mesh_demo_init.c"
"board.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
/* BLE */
#ifdef CONFIG_BLUEDROID_ENABLED
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#endif
#ifdef CONFIG_NIMBLE_ENABLED
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#endif
#include "esp_ble_mesh_defs.h"
#include "ble_mesh_demo_init.h"
#include "esp_ble_mesh_common_api.h"
#ifdef CONFIG_BLUEDROID_ENABLED
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
{
if (dev_uuid == NULL) {
ESP_LOGE(TAG, "%s, Invalid device uuid", __func__);
return;
}
/* Copy device address to the device uuid with offset equals to 2 here.
* The first two bytes is used for matching device uuid by Provisioner.
* And using device address here is to avoid using the same device uuid
* by different unprovisioned devices.
*/
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), BD_ADDR_LEN);
}
esp_err_t bluetooth_init(void)
{
esp_err_t ret;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
return ret;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(TAG, "%s enable controller failed", __func__);
return ret;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
return ret;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
return ret;
}
return ret;
}
#endif
#ifdef CONFIG_NIMBLE_ENABLED
static SemaphoreHandle_t mesh_sem;
static uint8_t own_addr_type;
void ble_store_config_init(void);
static uint8_t addr_val[BD_ADDR_LEN] = {0};
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
{
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
}
static void mesh_on_reset(int reason)
{
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
}
static void mesh_on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Figure out address to use while advertising (no privacy for now) */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
return;
}
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
xSemaphoreGive(mesh_sem);
}
void mesh_host_task(void *param)
{
ESP_LOGI(TAG, "BLE Host Task Started");
/* This function will return only when nimble_port_stop() is executed */
nimble_port_run();
nimble_port_freertos_deinit();
}
esp_err_t bluetooth_init(void)
{
mesh_sem = xSemaphoreCreateBinary();
if (mesh_sem == NULL) {
ESP_LOGE(TAG, "Failed to create mesh semaphore");
return ESP_FAIL;
}
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
nimble_port_init();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = mesh_on_reset;
ble_hs_cfg.sync_cb = mesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* XXX Need to have template for store */
ble_store_config_init();
nimble_port_freertos_init(mesh_host_task);
xSemaphoreTake(mesh_sem, portMAX_DELAY);
return ESP_OK;
}
#endif

View file

@ -0,0 +1,18 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef _BLE_MESH_DEMO_INIT_H_
#define _BLE_MESH_DEMO_INIT_H_
#define TAG "Client"
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
esp_err_t bluetooth_init(void);
#endif

View file

@ -0,0 +1,549 @@
/* main.c - Application main entry point */
/*
* 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_bt.h"
#include "esp_ble_mesh_defs.h"
#include "esp_ble_mesh_common_api.h"
#include "esp_ble_mesh_provisioning_api.h"
#include "esp_ble_mesh_networking_api.h"
#include "esp_ble_mesh_config_model_api.h"
#include "ble_mesh_demo_init.h"
#include "board.h"
#define CID_ESP 0x02E5
#define CID_NVAL 0xFFFF
#define PROV_OWN_ADDR 0x0001
#define MSG_SEND_TTL 3
#define MSG_SEND_REL false
#define MSG_TIMEOUT 0
#define MSG_ROLE ROLE_PROVISIONER
#define COMP_DATA_PAGE_0 0x00
#define APP_KEY_IDX 0x0000
#define APP_KEY_OCTET 0x12
#define COMP_DATA_1_OCTET(msg, offset) (msg[offset])
#define COMP_DATA_2_OCTET(msg, offset) (msg[offset + 1] << 8 | msg[offset])
#define ESP_BLE_MESH_VND_MODEL_ID_CLIENT 0x0000
#define ESP_BLE_MESH_VND_MODEL_ID_SERVER 0x0001
#define ESP_BLE_MESH_VND_MODEL_OP_SEND ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP)
#define ESP_BLE_MESH_VND_MODEL_OP_STATUS ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)
static uint8_t dev_uuid[ESP_BLE_MESH_OCTET16_LEN];
static uint16_t server_address = ESP_BLE_MESH_ADDR_UNASSIGNED;
static uint16_t vnd_tid;
static int64_t start_time;
static struct esp_ble_mesh_key {
uint16_t net_idx;
uint16_t app_idx;
uint8_t app_key[ESP_BLE_MESH_OCTET16_LEN];
} prov_key;
static esp_ble_mesh_cfg_srv_t config_server = {
.beacon = ESP_BLE_MESH_BEACON_DISABLED,
#if defined(CONFIG_BLE_MESH_FRIEND)
.friend_state = ESP_BLE_MESH_FRIEND_ENABLED,
#else
.friend_state = ESP_BLE_MESH_FRIEND_NOT_SUPPORTED,
#endif
.default_ttl = 7,
/* 3 transmissions with 20ms interval */
.net_transmit = ESP_BLE_MESH_TRANSMIT(2, 20),
.relay_retransmit = ESP_BLE_MESH_TRANSMIT(2, 20),
};
static esp_ble_mesh_client_t config_client;
static const esp_ble_mesh_client_op_pair_t vnd_op_pair[] = {
{ ESP_BLE_MESH_VND_MODEL_OP_SEND, ESP_BLE_MESH_VND_MODEL_OP_STATUS },
};
static esp_ble_mesh_client_t vendor_client = {
.op_pair_size = ARRAY_SIZE(vnd_op_pair),
.op_pair = vnd_op_pair,
};
static esp_ble_mesh_model_op_t vnd_op[] = {
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_STATUS, 2),
ESP_BLE_MESH_MODEL_OP_END,
};
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
ESP_BLE_MESH_MODEL_CFG_CLI(&config_client),
};
static esp_ble_mesh_model_t vnd_models[] = {
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_CLIENT,
vnd_op, NULL, &vendor_client),
};
static esp_ble_mesh_elem_t elements[] = {
ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
};
static esp_ble_mesh_comp_t composition = {
.cid = CID_ESP,
.elements = elements,
.element_count = ARRAY_SIZE(elements),
};
static esp_ble_mesh_prov_t provision = {
.prov_uuid = dev_uuid,
.prov_unicast_addr = PROV_OWN_ADDR,
.prov_start_address = 0x0005,
};
static void example_ble_mesh_set_msg_common(esp_ble_mesh_client_common_param_t *common,
esp_ble_mesh_node_t *node,
esp_ble_mesh_model_t *model, uint32_t opcode)
{
common->opcode = opcode;
common->model = model;
common->ctx.net_idx = prov_key.net_idx;
common->ctx.app_idx = prov_key.app_idx;
common->ctx.addr = node->unicast_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;
}
static esp_err_t prov_complete(uint16_t node_index, const esp_ble_mesh_octet16_t uuid,
uint16_t primary_addr, uint8_t element_num, uint16_t net_idx)
{
esp_ble_mesh_client_common_param_t common = {0};
esp_ble_mesh_cfg_client_get_state_t get = {0};
esp_ble_mesh_node_t *node = NULL;
char name[10] = {'\0'};
esp_err_t err;
ESP_LOGI(TAG, "node_index %u, primary_addr 0x%04x, element_num %u, net_idx 0x%03x",
node_index, primary_addr, element_num, net_idx);
ESP_LOG_BUFFER_HEX("uuid", uuid, ESP_BLE_MESH_OCTET16_LEN);
server_address = primary_addr;
sprintf(name, "%s%02x", "NODE-", node_index);
err = esp_ble_mesh_provisioner_set_node_name(node_index, name);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set node name");
return ESP_FAIL;
}
node = esp_ble_mesh_provisioner_get_node_with_addr(primary_addr);
if (node == NULL) {
ESP_LOGE(TAG, "Failed to get node 0x%04x info", primary_addr);
return ESP_FAIL;
}
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET);
get.comp_data_get.page = COMP_DATA_PAGE_0;
err = esp_ble_mesh_config_client_get_state(&common, &get);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send Config Composition Data Get");
return ESP_FAIL;
}
return ESP_OK;
}
static void recv_unprov_adv_pkt(uint8_t dev_uuid[ESP_BLE_MESH_OCTET16_LEN], uint8_t addr[BD_ADDR_LEN],
esp_ble_mesh_addr_type_t addr_type, uint16_t oob_info,
uint8_t adv_type, esp_ble_mesh_prov_bearer_t bearer)
{
esp_ble_mesh_unprov_dev_add_t add_dev = {0};
esp_err_t err;
/* Due to the API esp_ble_mesh_provisioner_set_dev_uuid_match, Provisioner will only
* use this callback to report the devices, whose device UUID starts with 0xdd & 0xdd,
* to the application layer.
*/
ESP_LOG_BUFFER_HEX("Device address", addr, BD_ADDR_LEN);
ESP_LOGI(TAG, "Address type 0x%02x, adv type 0x%02x", addr_type, adv_type);
ESP_LOG_BUFFER_HEX("Device UUID", dev_uuid, ESP_BLE_MESH_OCTET16_LEN);
ESP_LOGI(TAG, "oob info 0x%04x, bearer %s", oob_info, (bearer & ESP_BLE_MESH_PROV_ADV) ? "PB-ADV" : "PB-GATT");
memcpy(add_dev.addr, addr, BD_ADDR_LEN);
add_dev.addr_type = (uint8_t)addr_type;
memcpy(add_dev.uuid, dev_uuid, ESP_BLE_MESH_OCTET16_LEN);
add_dev.oob_info = oob_info;
add_dev.bearer = (uint8_t)bearer;
/* Note: If unprovisioned device adv packets have not been received, we should not add
device with ADD_DEV_START_PROV_NOW_FLAG set. */
err = esp_ble_mesh_provisioner_add_unprov_dev(&add_dev,
ADD_DEV_RM_AFTER_PROV_FLAG | ADD_DEV_START_PROV_NOW_FLAG | ADD_DEV_FLUSHABLE_DEV_FLAG);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to start provisioning device");
}
}
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_PROVISIONER_PROV_ENABLE_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_ENABLE_COMP_EVT, err_code %d", param->provisioner_prov_enable_comp.err_code);
break;
case ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_DISABLE_COMP_EVT, err_code %d", param->provisioner_prov_disable_comp.err_code);
break;
case ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_RECV_UNPROV_ADV_PKT_EVT");
recv_unprov_adv_pkt(param->provisioner_recv_unprov_adv_pkt.dev_uuid, param->provisioner_recv_unprov_adv_pkt.addr,
param->provisioner_recv_unprov_adv_pkt.addr_type, param->provisioner_recv_unprov_adv_pkt.oob_info,
param->provisioner_recv_unprov_adv_pkt.adv_type, param->provisioner_recv_unprov_adv_pkt.bearer);
break;
case ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_OPEN_EVT, bearer %s",
param->provisioner_prov_link_open.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT");
break;
case ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_PROV_LINK_CLOSE_EVT, bearer %s, reason 0x%02x",
param->provisioner_prov_link_close.bearer == ESP_BLE_MESH_PROV_ADV ? "PB-ADV" : "PB-GATT", param->provisioner_prov_link_close.reason);
break;
case ESP_BLE_MESH_PROVISIONER_PROV_COMPLETE_EVT:
prov_complete(param->provisioner_prov_complete.node_idx, param->provisioner_prov_complete.device_uuid,
param->provisioner_prov_complete.unicast_addr, param->provisioner_prov_complete.element_num,
param->provisioner_prov_complete.netkey_idx);
break;
case ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_UNPROV_DEV_COMP_EVT, err_code %d", param->provisioner_add_unprov_dev_comp.err_code);
break;
case ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_DEV_UUID_MATCH_COMP_EVT, err_code %d", param->provisioner_set_dev_uuid_match_comp.err_code);
break;
case ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_SET_NODE_NAME_COMP_EVT, err_code %d", param->provisioner_set_node_name_comp.err_code);
if (param->provisioner_set_node_name_comp.err_code == 0) {
const char *name = esp_ble_mesh_provisioner_get_node_name(param->provisioner_set_node_name_comp.node_index);
if (name) {
ESP_LOGI(TAG, "Node %d name %s", param->provisioner_set_node_name_comp.node_index, name);
}
}
break;
case ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_ADD_LOCAL_APP_KEY_COMP_EVT, err_code %d", param->provisioner_add_app_key_comp.err_code);
if (param->provisioner_add_app_key_comp.err_code == 0) {
prov_key.app_idx = param->provisioner_add_app_key_comp.app_idx;
esp_err_t err = esp_ble_mesh_provisioner_bind_app_key_to_local_model(PROV_OWN_ADDR, prov_key.app_idx,
ESP_BLE_MESH_VND_MODEL_ID_CLIENT, CID_ESP);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to bind AppKey to vendor client");
}
}
break;
case ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_BIND_APP_KEY_TO_MODEL_COMP_EVT, err_code %d", param->provisioner_bind_app_key_to_model_comp.err_code);
break;
case ESP_BLE_MESH_PROVISIONER_STORE_NODE_COMP_DATA_COMP_EVT:
ESP_LOGI(TAG, "ESP_BLE_MESH_PROVISIONER_STORE_NODE_COMP_DATA_COMP_EVT, err_code %d", param->provisioner_store_node_comp_data_comp.err_code);
break;
default:
break;
}
}
static void example_ble_mesh_parse_node_comp_data(const uint8_t *data, uint16_t length)
{
uint16_t cid, pid, vid, crpl, feat;
uint16_t loc, model_id, company_id;
uint8_t nums, numv;
uint16_t offset;
int i;
cid = COMP_DATA_2_OCTET(data, 0);
pid = COMP_DATA_2_OCTET(data, 2);
vid = COMP_DATA_2_OCTET(data, 4);
crpl = COMP_DATA_2_OCTET(data, 6);
feat = COMP_DATA_2_OCTET(data, 8);
offset = 10;
ESP_LOGI(TAG, "********************** Composition Data Start **********************");
ESP_LOGI(TAG, "* CID 0x%04x, PID 0x%04x, VID 0x%04x, CRPL 0x%04x, Features 0x%04x *", cid, pid, vid, crpl, feat);
for (; offset < length; ) {
loc = COMP_DATA_2_OCTET(data, offset);
nums = COMP_DATA_1_OCTET(data, offset + 2);
numv = COMP_DATA_1_OCTET(data, offset + 3);
offset += 4;
ESP_LOGI(TAG, "* Loc 0x%04x, NumS 0x%02x, NumV 0x%02x *", loc, nums, numv);
for (i = 0; i < nums; i++) {
model_id = COMP_DATA_2_OCTET(data, offset);
ESP_LOGI(TAG, "* SIG Model ID 0x%04x *", model_id);
offset += 2;
}
for (i = 0; i < numv; i++) {
company_id = COMP_DATA_2_OCTET(data, offset);
model_id = COMP_DATA_2_OCTET(data, offset + 2);
ESP_LOGI(TAG, "* Vendor Model ID 0x%04x, Company ID 0x%04x *", model_id, company_id);
offset += 4;
}
}
ESP_LOGI(TAG, "*********************** Composition Data End ***********************");
}
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_cfg_client_set_state_t set = {0};
esp_ble_mesh_node_t *node = NULL;
esp_err_t err;
ESP_LOGI(TAG, "Config client, err_code %d, event %u, addr 0x%04x, opcode 0x%04x",
param->error_code, event, param->params->ctx.addr, param->params->opcode);
if (param->error_code) {
ESP_LOGE(TAG, "Send config client message failed, opcode 0x%04x", param->params->opcode);
return;
}
node = esp_ble_mesh_provisioner_get_node_with_addr(param->params->ctx.addr);
if (!node) {
ESP_LOGE(TAG, "Failed to get node 0x%04x info", param->params->ctx.addr);
return;
}
switch (event) {
case ESP_BLE_MESH_CFG_CLIENT_GET_STATE_EVT:
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET) {
ESP_LOG_BUFFER_HEX("Composition data", param->status_cb.comp_data_status.composition_data->data,
param->status_cb.comp_data_status.composition_data->len);
example_ble_mesh_parse_node_comp_data(param->status_cb.comp_data_status.composition_data->data,
param->status_cb.comp_data_status.composition_data->len);
err = esp_ble_mesh_provisioner_store_node_comp_data(param->params->ctx.addr,
param->status_cb.comp_data_status.composition_data->data,
param->status_cb.comp_data_status.composition_data->len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to store node composition data");
break;
}
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD);
set.app_key_add.net_idx = prov_key.net_idx;
set.app_key_add.app_idx = prov_key.app_idx;
memcpy(set.app_key_add.app_key, prov_key.app_key, ESP_BLE_MESH_OCTET16_LEN);
err = esp_ble_mesh_config_client_set_state(&common, &set);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send Config AppKey Add");
}
}
break;
case ESP_BLE_MESH_CFG_CLIENT_SET_STATE_EVT:
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_APP_KEY_ADD) {
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND);
set.model_app_bind.element_addr = node->unicast_addr;
set.model_app_bind.model_app_idx = prov_key.app_idx;
set.model_app_bind.model_id = ESP_BLE_MESH_VND_MODEL_ID_SERVER;
set.model_app_bind.company_id = CID_ESP;
err = esp_ble_mesh_config_client_set_state(&common, &set);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send Config Model App Bind");
}
} else if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_MODEL_APP_BIND) {
ESP_LOGW(TAG, "%s, Provision and config successfully", __func__);
}
break;
case ESP_BLE_MESH_CFG_CLIENT_PUBLISH_EVT:
if (param->params->opcode == ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_STATUS) {
ESP_LOG_BUFFER_HEX("Composition data", param->status_cb.comp_data_status.composition_data->data,
param->status_cb.comp_data_status.composition_data->len);
}
break;
case ESP_BLE_MESH_CFG_CLIENT_TIMEOUT_EVT:
switch (param->params->opcode) {
case ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET: {
esp_ble_mesh_cfg_client_get_state_t get = {0};
example_ble_mesh_set_msg_common(&common, node, config_client.model, ESP_BLE_MESH_MODEL_OP_COMPOSITION_DATA_GET);
get.comp_data_get.page = COMP_DATA_PAGE_0;
err = esp_ble_mesh_config_client_get_state(&common, &get);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send Config Composition Data Get");
}
break;
}
case 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.app_key_add.net_idx = prov_key.net_idx;
set.app_key_add.app_idx = prov_key.app_idx;
memcpy(set.app_key_add.app_key, prov_key.app_key, ESP_BLE_MESH_OCTET16_LEN);
err = esp_ble_mesh_config_client_set_state(&common, &set);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send Config AppKey Add");
}
break;
case 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.model_app_bind.element_addr = node->unicast_addr;
set.model_app_bind.model_app_idx = prov_key.app_idx;
set.model_app_bind.model_id = ESP_BLE_MESH_VND_MODEL_ID_SERVER;
set.model_app_bind.company_id = CID_ESP;
err = esp_ble_mesh_config_client_set_state(&common, &set);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send Config Model App Bind");
}
break;
default:
break;
}
break;
default:
ESP_LOGE(TAG, "Invalid config client event %u", event);
break;
}
}
void example_ble_mesh_send_vendor_message(bool resend)
{
esp_ble_mesh_msg_ctx_t ctx = {0};
uint32_t opcode;
esp_err_t err;
ctx.net_idx = prov_key.net_idx;
ctx.app_idx = prov_key.app_idx;
ctx.addr = server_address;
ctx.send_ttl = MSG_SEND_TTL;
ctx.send_rel = MSG_SEND_REL;
opcode = ESP_BLE_MESH_VND_MODEL_OP_SEND;
if (resend == false) {
vnd_tid++;
}
err = esp_ble_mesh_client_model_send_msg(vendor_client.model, &ctx, opcode,
sizeof(vnd_tid), (uint8_t *)&vnd_tid, MSG_TIMEOUT, true, MSG_ROLE);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to send vendor message 0x%06x", opcode);
}
}
static void example_ble_mesh_custom_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.opcode == ESP_BLE_MESH_VND_MODEL_OP_STATUS) {
int64_t end_time = esp_timer_get_time();
ESP_LOGI(TAG, "Recv 0x%06x, tid 0x%04x, time %lldus",
param->model_operation.opcode, vnd_tid, end_time - start_time);
}
break;
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
if (param->model_send_comp.err_code) {
ESP_LOGE(TAG, "Failed to send message 0x%06x", param->model_send_comp.opcode);
break;
}
start_time = esp_timer_get_time();
ESP_LOGI(TAG, "Send 0x%06x", param->model_send_comp.opcode);
break;
case ESP_BLE_MESH_CLIENT_MODEL_RECV_PUBLISH_MSG_EVT:
ESP_LOGI(TAG, "Receive publish message 0x%06x", param->client_recv_publish_msg.opcode);
break;
case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT:
ESP_LOGW(TAG, "Client message 0x%06x timeout", param->client_send_timeout.opcode);
example_ble_mesh_send_vendor_message(true);
break;
default:
break;
}
}
static esp_err_t ble_mesh_init(void)
{
uint8_t match[2] = { 0x32, 0x10 };
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(example_ble_mesh_provisioning_cb);
esp_ble_mesh_register_config_client_callback(example_ble_mesh_config_client_cb);
esp_ble_mesh_register_custom_model_callback(example_ble_mesh_custom_model_cb);
err = esp_ble_mesh_init(&provision, &composition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize mesh stack");
return err;
}
err = esp_ble_mesh_client_model_init(&vnd_models[0]);
if (err) {
ESP_LOGE(TAG, "Failed to initialize vendor client");
return err;
}
err = esp_ble_mesh_provisioner_set_dev_uuid_match(match, sizeof(match), 0x0, false);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to set matching device uuid");
return err;
}
err = esp_ble_mesh_provisioner_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to enable mesh provisioner");
return err;
}
err = esp_ble_mesh_provisioner_add_local_app_key(prov_key.app_key, prov_key.net_idx, prov_key.app_idx);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to add local AppKey");
return err;
}
ESP_LOGI(TAG, "ESP BLE Mesh Provisioner initialized");
return ESP_OK;
}
void app_main(void)
{
esp_err_t err;
ESP_LOGI(TAG, "Initializing...");
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
board_init();
err = bluetooth_init();
if (err != ESP_OK) {
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_OK) {
ESP_LOGE(TAG, "Bluetooth mesh init failed (err %d)", err);
}
}

View file

@ -0,0 +1,38 @@
/* 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 "esp_log.h"
#include "driver/uart.h"
#include "iot_button.h"
#define TAG "BOARD"
#define BUTTON_IO_NUM 0
#define BUTTON_ACTIVE_LEVEL 0
extern void example_ble_mesh_send_vendor_message(bool resend);
static void button_tap_cb(void* arg)
{
example_ble_mesh_send_vendor_message(false);
}
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_button_init();
}

View file

@ -0,0 +1,14 @@
/* board.h - Board-specific hooks */
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BOARD_H_
#define _BOARD_H_
void board_init(void);
#endif /* _BOARD_H_ */

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

@ -0,0 +1,30 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CONTROLLER_MODE_BTDM=n
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTU_TASK_STACK_SIZE=4512
# Override some defaults of ESP BLE Mesh
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_PROVISIONER=y
CONFIG_BLE_MESH_PB_GATT=y
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
CONFIG_BLE_MESH_CFG_CLI=y
#
# Serial flasher config
#
CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=921600
#
# ESP32-specific
#
CONFIG_ESP_CONSOLE_UART_BAUDRATE=921600

View file

@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(SUPPORTED_TARGETS esp32)
project(vendor_server)

View file

@ -0,0 +1,10 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := vendor_server
COMPONENT_ADD_INCLUDEDIRS := components/include
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,4 @@
ESP BLE Mesh Vendor Server Example
==================================
For description of this example please refer to [ESP BLE Mesh Vendor Client Example](../vendor_client/README.md)

View file

@ -0,0 +1,7 @@
set(COMPONENT_SRCS "ble_mesh_demo_main.c"
"ble_mesh_demo_init.c"
"board.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View file

@ -0,0 +1,22 @@
menu "Example Configuration"
choice BLE_MESH_EXAMPLE_BOARD
prompt "Board selection for BLE Mesh"
default BLE_MESH_ESP_WROOM_32
help
Select this option to choose the board for BLE Mesh. The default is ESP32-WROOM-32
config BLE_MESH_ESP_WROOM_32
bool "ESP32-WROOM-32"
config BLE_MESH_ESP_WROVER
bool "ESP32-WROVER"
endchoice
config BLE_MESH_PATCH_FOR_SLAB_APP_1_1_0
bool "Fix bug of Silicon Lab Android App v1.1.0 when reconnection will cause sequence number to recount from 0"
default y
help
It is an ad hoc solution and needs further modifications
endmenu

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
/* BLE */
#ifdef CONFIG_BLUEDROID_ENABLED
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#endif
#ifdef CONFIG_NIMBLE_ENABLED
#include "esp_nimble_hci.h"
#include "nimble/nimble_port.h"
#include "nimble/nimble_port_freertos.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "console/console.h"
#endif
#include "esp_ble_mesh_defs.h"
#include "ble_mesh_demo_init.h"
#include "esp_ble_mesh_common_api.h"
#ifdef CONFIG_BLUEDROID_ENABLED
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
{
if (dev_uuid == NULL) {
ESP_LOGE(TAG, "%s, Invalid device uuid", __func__);
return;
}
/* Copy device address to the device uuid with offset equals to 2 here.
* The first two bytes is used for matching device uuid by Provisioner.
* And using device address here is to avoid using the same device uuid
* by different unprovisioned devices.
*/
memcpy(dev_uuid + 2, esp_bt_dev_get_address(), BD_ADDR_LEN);
}
esp_err_t bluetooth_init(void)
{
esp_err_t ret;
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
ESP_LOGE(TAG, "%s initialize controller failed", __func__);
return ret;
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
ESP_LOGE(TAG, "%s enable controller failed", __func__);
return ret;
}
ret = esp_bluedroid_init();
if (ret) {
ESP_LOGE(TAG, "%s init bluetooth failed", __func__);
return ret;
}
ret = esp_bluedroid_enable();
if (ret) {
ESP_LOGE(TAG, "%s enable bluetooth failed", __func__);
return ret;
}
return ret;
}
#endif
#ifdef CONFIG_NIMBLE_ENABLED
static SemaphoreHandle_t mesh_sem;
static uint8_t own_addr_type;
void ble_store_config_init(void);
static uint8_t addr_val[BD_ADDR_LEN] = {0};
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid)
{
memcpy(dev_uuid + 2, addr_val, BD_ADDR_LEN);
}
static void mesh_on_reset(int reason)
{
ESP_LOGI(TAG, "Resetting state; reason=%d", reason);
}
static void mesh_on_sync(void)
{
int rc;
rc = ble_hs_util_ensure_addr(0);
assert(rc == 0);
/* Figure out address to use while advertising (no privacy for now) */
rc = ble_hs_id_infer_auto(0, &own_addr_type);
if (rc != 0) {
ESP_LOGI(TAG, "error determining address type; rc=%d", rc);
return;
}
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
xSemaphoreGive(mesh_sem);
}
void mesh_host_task(void *param)
{
ESP_LOGI(TAG, "BLE Host Task Started");
/* This function will return only when nimble_port_stop() is executed */
nimble_port_run();
nimble_port_freertos_deinit();
}
esp_err_t bluetooth_init(void)
{
mesh_sem = xSemaphoreCreateBinary();
if (mesh_sem == NULL) {
ESP_LOGE(TAG, "Failed to create mesh semaphore");
return ESP_FAIL;
}
ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
nimble_port_init();
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = mesh_on_reset;
ble_hs_cfg.sync_cb = mesh_on_sync;
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
/* XXX Need to have template for store */
ble_store_config_init();
nimble_port_freertos_init(mesh_host_task);
xSemaphoreTake(mesh_sem, portMAX_DELAY);
return ESP_OK;
}
#endif

View file

@ -0,0 +1,18 @@
/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#ifndef _BLE_MESH_DEMO_INIT_H_
#define _BLE_MESH_DEMO_INIT_H_
#define TAG "Server"
void ble_mesh_get_dev_uuid(uint8_t *dev_uuid);
esp_err_t bluetooth_init(void);
#endif

View file

@ -0,0 +1,235 @@
/* 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_bt.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_local_data_operation_api.h"
#include "board.h"
#include "ble_mesh_demo_init.h"
#define CID_ESP 0x02E5
#define CID_NVAL 0xFFFF
#define ESP_BLE_MESH_VND_MODEL_ID_CLIENT 0x0000
#define ESP_BLE_MESH_VND_MODEL_ID_SERVER 0x0001
#define ESP_BLE_MESH_VND_MODEL_OP_SEND ESP_BLE_MESH_MODEL_OP_3(0x00, CID_ESP)
#define ESP_BLE_MESH_VND_MODEL_OP_STATUS ESP_BLE_MESH_MODEL_OP_3(0x01, CID_ESP)
static uint8_t dev_uuid[ESP_BLE_MESH_OCTET16_LEN] = { 0x32, 0x10 };
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),
};
static esp_ble_mesh_model_t root_models[] = {
ESP_BLE_MESH_MODEL_CFG_SRV(&config_server),
};
static esp_ble_mesh_model_op_t vnd_op[] = {
ESP_BLE_MESH_MODEL_OP(ESP_BLE_MESH_VND_MODEL_OP_SEND, 2),
ESP_BLE_MESH_MODEL_OP_END,
};
static esp_ble_mesh_model_t vnd_models[] = {
ESP_BLE_MESH_VENDOR_MODEL(CID_ESP, ESP_BLE_MESH_VND_MODEL_ID_SERVER,
vnd_op, NULL, NULL),
};
static esp_ble_mesh_elem_t elements[] = {
ESP_BLE_MESH_ELEMENT(0, root_models, vnd_models),
};
static esp_ble_mesh_comp_t composition = {
.cid = CID_ESP,
.elements = elements,
.element_count = ARRAY_SIZE(elements),
};
static esp_ble_mesh_prov_t provision = {
.uuid = dev_uuid,
};
static void prov_complete(uint16_t net_idx, uint16_t addr, uint8_t flags, uint32_t iv_index)
{
ESP_LOGI(TAG, "net_idx 0x%03x, 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_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_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;
default:
break;
}
}
}
static void example_ble_mesh_custom_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.opcode == ESP_BLE_MESH_VND_MODEL_OP_SEND) {
uint16_t tid = *(uint16_t *)param->model_operation.msg;
ESP_LOGI(TAG, "Recv 0x%06x, tid 0x%04x", param->model_operation.opcode, tid);
esp_err_t err = esp_ble_mesh_server_model_send_msg(&vnd_models[0],
param->model_operation.ctx, ESP_BLE_MESH_VND_MODEL_OP_STATUS,
sizeof(tid), (uint8_t *)&tid);
if (err) {
ESP_LOGE(TAG, "Faild to send message 0x%06x", ESP_BLE_MESH_VND_MODEL_OP_STATUS);
}
}
break;
case ESP_BLE_MESH_MODEL_SEND_COMP_EVT:
if (param->model_send_comp.err_code) {
ESP_LOGE(TAG, "Failed to send message 0x%06x", param->model_send_comp.opcode);
break;
}
ESP_LOGI(TAG, "Send 0x%06x", param->model_send_comp.opcode);
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_custom_model_callback(example_ble_mesh_custom_model_cb);
err = esp_ble_mesh_init(&provision, &composition);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize mesh stack");
return err;
}
err = esp_ble_mesh_node_prov_enable(ESP_BLE_MESH_PROV_ADV | ESP_BLE_MESH_PROV_GATT);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to enable mesh node");
return err;
}
board_led_operation(LED_G, LED_ON);
ESP_LOGI(TAG, "BLE Mesh Node initialized");
return ESP_OK;
}
void app_main(void)
{
esp_err_t err;
ESP_LOGI(TAG, "Initializing...");
err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
ESP_ERROR_CHECK(err);
board_init();
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,55 @@
/* 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

@ -0,0 +1,38 @@
/* board.h - Board-specific hooks */
/*
* Copyright (c) 2017 Intel Corporation
* Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BOARD_H_
#define _BOARD_H_
#include "driver/gpio.h"
#if defined(CONFIG_BLE_MESH_ESP_WROOM_32)
#define LED_R GPIO_NUM_25
#define LED_G GPIO_NUM_26
#define LED_B GPIO_NUM_27
#elif defined(CONFIG_BLE_MESH_ESP_WROVER)
#define LED_R GPIO_NUM_0
#define LED_G GPIO_NUM_2
#define LED_B GPIO_NUM_4
#endif
#define LED_ON 1
#define LED_OFF 0
struct _led_state {
uint8_t current;
uint8_t previous;
uint8_t pin;
char *name;
};
void board_led_operation(uint8_t pin, uint8_t onoff);
void board_init(void);
#endif

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

@ -0,0 +1,29 @@
# Override some defaults so BT stack is enabled
# by default in this example
CONFIG_BT_ENABLED=y
CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY=y
CONFIG_BTDM_CONTROLLER_MODE_BR_EDR_ONLY=n
CONFIG_BTDM_CONTROLLER_MODE_BTDM=n
CONFIG_BTDM_CONTROLLER_MODEM_SLEEP=n
CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR=y
CONFIG_BLE_MESH_SCAN_DUPLICATE_EN=y
CONFIG_GATTS_SEND_SERVICE_CHANGE_MANUAL=y
CONFIG_BTU_TASK_STACK_SIZE=4512
# Override some defaults of ESP BLE Mesh
CONFIG_BLE_MESH=y
CONFIG_BLE_MESH_NODE=y
CONFIG_BLE_MESH_PB_GATT=y
CONFIG_BLE_MESH_TX_SEG_MSG_COUNT=10
CONFIG_BLE_MESH_RX_SEG_MSG_COUNT=10
#
# Serial flasher config
#
CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B=y
CONFIG_ESPTOOLPY_MONITOR_BAUD=921600
#
# ESP32-specific
#
CONFIG_ESP_CONSOLE_UART_BAUDRATE=921600