diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/CMakeLists.txt new file mode 100644 index 000000000..e8789f74e --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/CMakeLists.txt @@ -0,0 +1,6 @@ +# 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) +project(sensor_client) diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/Makefile b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/Makefile new file mode 100644 index 000000000..cb51153ee --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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 := sensor_client + +COMPONENT_ADD_INCLUDEDIRS := components/include + +include $(IDF_PATH)/make/project.mk diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/README.md new file mode 100644 index 000000000..7e7a5b5cf --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/README.md @@ -0,0 +1,89 @@ +| Supported Targets | ESP32 | +| ----------------- | ----- | + +ESP BLE Mesh Sensor Client Example +================================== + +This example demonstrates how to create a sensor client model in Provisioner, and the [sensor server example](../sensor_server) demonstrates how to create a sensor server model and a sensor setup server model in an unprovisioned device. + +### 1. Introduction + +Sensor Server model is model which is used to expose a series of sensor states. When Sensor Server model is present on an element, the Sensor Setup Server model shall also be present as an extension of the Sensor Server model. +Sensor Client model is used to consume the state values exposed by the Sensor Server/Setup Server models via Sensor messages. + +Sensor state is a composite state which contains the following parts: +* Sensor Descriptor state +* Sensor Setting state +* Sensor Cadence state +* Sensor Data state +* Sensor Series Column state + +#### Sensor Descriptor state + +Sensor Descriptor state represents the attributes describing the sensor data. This state does not change throughout the lifetime of an element. + +#### Sensor Setting state + +Sensor Setting state controls parameters of a sensor. For example, an occupancy sensor may have a “sensitivity” setting that controls the sensitivity of the sensor. Sensitivity may be adjusted to prevent small animals from triggering the sensor. + +#### Sensor Cadence state + +Sensor Cadence state controls the cadence of sensor reports. It allows a sensor to be configured to send measured values using Sensor Status messages at a different cadence for a range of measured values. It also allows a sensor to be configured to send measured values when the value changes up or down by more than a configured delta value. + +#### Sensor Data state + +Sensor Data state is a sequence of one or more pairs of Sensor Property ID and Raw Value fields, with each Raw Value field size and representation defined by the characteristics referenced by the Sensor Property ID. + +#### Sensor Series Column state + +Values measured by sensors may be organized as arrays (and represented as series of columns, such as histograms). It contains Sensor Raw Value X, Sensor Column Width and Sensor Raw Value Y. + +> Note: For the supported sensor types, please refer to the [Mesh Device Properties Spec](https://www.bluetooth.com/specifications/mesh-specifications/mesh-properties/). + +### 2. Example Description + +#### Sensor Client example +In the [Sensor Client example](./), the mesh device is a Provisioner with a sensor client model. Once the device which runs the sensor server example is provisioned and configured successfully by the Provisioner, users can press the button to send sensor messages to get the corresponding state (i.e. sensor descriptor, sensor data, etc.) values. + +#### Sensor Server example + +In the [Sensor Server example](../sensor_server), the mesh device is an unprovisioned device with a sensor server model and a sensor setup server model. + +The sensor server model supports two instances of Sensor states, the first one (Sensor Property ID 0x0056) represents the "Present Indoor Ambient Temperature", and the other (Sensor Property ID 0x005B) represents the "Present Outdoor Ambient Temperature". The characteristic of the two properties is "Temperature 8", which is used to represent a measure of temperature with a unit of 0.5 degree Celsius. The minimum value of the characteristic is -64.0, and the maximum value is 63.5. + +Currently only the Sensor Descriptor state, Sensor Data state are supported by the Sensor states. The Sensor Property ID, Sensor Descriptor state, format and length of the corresponding Sensor Data state are all pre-initialized. + +### 3. Procedures +* Device A runs the sensor client example, and device B runs the sensor server example; +* Working as a Provisioner, once the unprovisioned device beacon from device B is received by device A, device A will provision and configure device B into a node; +* After the provisioning and configuration procedure is completed successfully, users can press the "Boot" button on device A to get the sensor state values of device B; +* Based on the press count, different sensor messages will be sent to device B. Sensor Descriptor Get will be sent when the button is pressed for the first time, at the second time Sensor Cadence Get will be sent, and the following messages are: Sensor Settings Get, Sensor Get and Sensor Series Get; +* If continuing to press the button, the same sensor messages with the above sequence will be sent to device B. + +### 4. Relationship + +This section is about the relationship between sensor models and messages, which gives a list of messages that can be sent or published by a specific sensor model. + +* Sensor Client model + * Sensor Descriptor Get + * Sensor Cadence Get + * Sensor Cadence Set + * Sensor Cadence Set Unacknowledged + * Sensor Settings Get + * Sensor Setting Get + * Sensor Setting Set + * Sensor Setting Set Unacknowledged + * Sensor Get + * Sensor Column Get + * Sensor Series Get + +* Sensor Server model + * Sensor Descriptor Status + * Sensor Status + * Sensor Column Status + * Sensor Series Status + +* Sensor Setup Server model + * Sensor Cadence Status + * Sensor Settings Status + * Sensor Setting Status diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/CMakeLists.txt b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/CMakeLists.txt new file mode 100644 index 000000000..13d6b0843 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/CMakeLists.txt @@ -0,0 +1,3 @@ + +idf_component_register(SRCS "button.c" "button_obj.cpp" + INCLUDE_DIRS "." "include") diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/Kconfig b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/Kconfig new file mode 100644 index 000000000..308410a69 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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_sensor_model/sensor_client/components/button/README.md b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/README.md new file mode 100644 index 000000000..0c55e2d29 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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_sensor_model/sensor_client/components/button/button.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/button.c new file mode 100644 index 000000000..ac391a5c3 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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_sensor_model/sensor_client/components/button/button_obj.cpp b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/button_obj.cpp new file mode 100644 index 000000000..bf49238e5 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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_sensor_model/sensor_client/components/button/component.mk b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/component.mk new file mode 100644 index 000000000..a98f634ea --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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_sensor_model/sensor_client/components/button/include/iot_button.h b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_client/components/button/include/iot_button.h new file mode 100644 index 000000000..0a8564d68 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_sensor_model/sensor_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, /*!