diff --git a/examples/bluetooth/esp_ble_mesh/README.md b/examples/bluetooth/esp_ble_mesh/README.md index aa69e954a..cd3b14281 100644 --- a/examples/bluetooth/esp_ble_mesh/README.md +++ b/examples/bluetooth/esp_ble_mesh/README.md @@ -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. diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt index 5f9bd92c1..1dcfafdf9 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/CMakeLists.txt @@ -2,7 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_mesh_fast_prov_client) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile index 9aff276e2..d6537805f 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_client/Makefile @@ -7,6 +7,6 @@ PROJECT_NAME := ble_mesh_fast_prov_client COMPONENT_ADD_INCLUDEDIRS := components/include -EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_vendor_models/fast_prov_vendor_model/components include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt index 56ef44654..c09547f94 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/CMakeLists.txt @@ -2,7 +2,7 @@ # in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components) +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/bluetooth/esp_ble_mesh/common_vendor_models/fast_prov_vendor_model/components) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(ble_mesh_fast_prov_server) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile index 31160373f..07484a570 100644 --- a/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_fast_provision/ble_mesh_fast_prov_server/Makefile @@ -7,6 +7,6 @@ PROJECT_NAME := ble_mesh_fast_prov_server COMPONENT_ADD_INCLUDEDIRS := components/include -EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_models/fast_prov_vendor_model/components +EXTRA_COMPONENT_DIRS := $(IDF_PATH)/examples/bluetooth/esp_ble_mesh/common_vendor_models/fast_prov_vendor_model/components include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/CMakeLists.txt new file mode 100644 index 000000000..9ed701d40 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/CMakeLists.txt @@ -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) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/Makefile new file mode 100644 index 000000000..4d1ae41b9 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/Makefile @@ -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 diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/README.md new file mode 100644 index 000000000..5a6ac057d --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/README.md @@ -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 \ No newline at end of file diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/CMakeLists.txt new file mode 100644 index 000000000..6c385ee21 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/CMakeLists.txt @@ -0,0 +1,7 @@ + +set(COMPONENT_SRCS "button.c" + "button_obj.cpp") + +set(COMPONENT_ADD_INCLUDEDIRS ". include") + +register_component() diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/Kconfig b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/Kconfig new file mode 100644 index 000000000..308410a69 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/Kconfig @@ -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 \ No newline at end of file diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/README.md new file mode 100644 index 000000000..0c55e2d29 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/README.md @@ -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 +``` \ No newline at end of file diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/button.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/button.c new file mode 100644 index 000000000..ac391a5c3 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/button.c @@ -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 +#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; +} diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/button_obj.cpp b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/button_obj.cpp new file mode 100644 index 000000000..bf49238e5 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/button_obj.cpp @@ -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); +} diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/component.mk new file mode 100644 index 000000000..a98f634ea --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/include/iot_button.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/include/iot_button.h new file mode 100644 index 000000000..0a8564d68 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_vendor_model/vendor_client/components/button/include/iot_button.h @@ -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, /*!