feat(zigbee): upgrade zigbee example to v2.0

This commit is contained in:
xieqinan@espressif.com
2026-09-09 11:34:28 +08:00
parent a8a5106421
commit 256403fe73
53 changed files with 1880 additions and 1251 deletions
@@ -0,0 +1,4 @@
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
REQUIRES esp_timer
)
@@ -0,0 +1,12 @@
menu "Zigbee Example Configuration"
config ZB_EXAMPLE_PRIMARY_CHANNEL
int "Zigbee primary channel"
range 11 26
default 13
config ZB_EXAMPLE_SECONDARY_CHANNEL_MASK
hex "Zigbee secondary channel mask"
default 0x07FFF800
endmenu
@@ -0,0 +1,47 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* Alarm driver
*
* 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.
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The argument type for the alarm callback.
*
*/
typedef uintptr_t alarm_timer_arg_t;
/**
* @brief The callback for the timer.
*
*/
typedef void (*alarm_timer_callback_t)(alarm_timer_arg_t arg);
/**
* @brief Schedule an alarm to fire at a given time.
*
* @param cb The callback to execute when the alarm fires.
* @param arg The argument to pass to the callback.
* @param time_ms The time to fire the timer in milliseconds.
*
* @return ESP_OK on success, error code otherwise.
*/
esp_err_t alarm_timer_schedule(alarm_timer_callback_t cb, alarm_timer_arg_t arg, uint32_t time_ms);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,51 @@
# This config file optimizes the mbedTLS code size by disabling
# unused features by ESP-Zigbee-SDK.
#
# mbedTLS
#
# Enable required
CONFIG_MBEDTLS_AES_C=y
CONFIG_MBEDTLS_CCM_C=y
# Disable unused
CONFIG_MBEDTLS_GCM_C=n
CONFIG_MBEDTLS_CMAC_C=n
CONFIG_MBEDTLS_SHA1_C=n
CONFIG_MBEDTLS_SHA3_C=n
CONFIG_MBEDTLS_SHA512_C=n
CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=n
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=n
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=n
## v5.0
CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=n
CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=n
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=n
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=n
## v6.0
CONFIG_MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH=y
CONFIG_MBEDTLS_CTR_DRBG_C=y
CONFIG_MBEDTLS_HMAC_DRBG_C=n
CONFIG_MBEDTLS_X509_RSASSA_PSS_SUPPORT=n
CONFIG_MBEDTLS_CIPHER_MODE_CBC=n
CONFIG_MBEDTLS_CIPHER_MODE_CFB=n
CONFIG_MBEDTLS_CIPHER_MODE_CTR=n
CONFIG_MBEDTLS_CIPHER_MODE_OFB=n
CONFIG_MBEDTLS_CIPHER_MODE_XTS=n
# PSA_WANT_ALG_RSA_PSS needs CONFIG_MBEDTLS_RSA_C=y on ESP-IDF master
CONFIG_MBEDTLS_RSA_C=y
CONFIG_MBEDTLS_MD5_C=n
CONFIG_MBEDTLS_SHA384_C=n
# end of mbedTLS
@@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* Alarm Timer
*
* 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.
*/
#include <stdlib.h>
#include "esp_timer.h"
#include "alarm_timer.h"
typedef struct alarm_timer_s {
esp_timer_handle_t timer;
alarm_timer_callback_t cb;
alarm_timer_arg_t arg;
} alarm_timer_t;
static void alarm_timer_cb(void *arg)
{
alarm_timer_t *alarm = (alarm_timer_t *)arg;
esp_timer_delete(alarm->timer);
alarm->cb(alarm->arg);
free(alarm);
}
esp_err_t alarm_timer_schedule(alarm_timer_callback_t cb, alarm_timer_arg_t arg, uint32_t time_ms)
{
if (cb == NULL) {
return ESP_ERR_INVALID_ARG;
}
alarm_timer_t *alarm = malloc(sizeof(alarm_timer_t));
if (alarm == NULL) {
return ESP_ERR_NO_MEM;
}
alarm->cb = cb;
alarm->arg = arg;
alarm->timer = NULL;
esp_timer_create_args_t timer_args = {
.callback = alarm_timer_cb,
.arg = alarm,
};
esp_err_t err = esp_timer_create(&timer_args, &alarm->timer);
if (err != ESP_OK) {
free(alarm);
return err;
}
uint64_t time_us = (uint64_t)time_ms * 1000;
err = esp_timer_start_once(alarm->timer, time_us);
if (err != ESP_OK) {
esp_timer_delete(alarm->timer);
free(alarm);
return err;
}
return ESP_OK;
}
@@ -1,3 +0,0 @@
idf_component_register(SRCS "zcl_utility.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES espressif__esp-zigbee-lib)
@@ -1,50 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* ZCL utility functions for Zigbee examples
*
* 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.
*/
#pragma once
#include "esp_err.h"
#include "esp_zigbee_core.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! Maximum length of ManufacturerName string field */
#define ESP_ZB_ZCL_CLUSTER_ID_BASIC_MANUFACTURER_NAME_MAX_LEN 32
/*! Maximum length of ModelIdentifier string field */
#define ESP_ZB_ZCL_CLUSTER_ID_BASIC_MODEL_IDENTIFIER_MAX_LEN 32
/** optional basic manufacturer information */
typedef struct zcl_basic_manufacturer_info_s {
char *manufacturer_name;
char *model_identifier;
} zcl_basic_manufacturer_info_t;
/**
* @brief Adds manufacturer information to the ZCL basic cluster of endpoint
*
* @param ep_list The pointer to the endpoint list with @p endpoint_id
* @param endpoint_id The endpoint identifier indicating where the ZCL basic cluster resides
* @param info The pointer to the basic manufacturer information, @see zcl_basic_manufacturer_info_t
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
*/
esp_err_t esp_zcl_utility_add_ep_basic_manufacturer_info(esp_zb_ep_list_t *ep_list, uint8_t endpoint_id, zcl_basic_manufacturer_info_t *info);
#ifdef __cplusplus
} // extern "C"
#endif
@@ -1,40 +0,0 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* ZCL utility functions for Zigbee examples
*
* 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.
*/
#include <stdint.h>
#include <string.h>
#include "esp_check.h"
#include "esp_zigbee_core.h"
#include "zcl_utility.h"
static const char *TAG = "ZCL_UTILITY";
esp_err_t esp_zcl_utility_add_ep_basic_manufacturer_info(esp_zb_ep_list_t *ep_list, uint8_t endpoint_id, zcl_basic_manufacturer_info_t *info)
{
esp_err_t ret = ESP_OK;
esp_zb_cluster_list_t *cluster_list = NULL;
esp_zb_attribute_list_t *basic_cluster = NULL;
cluster_list = esp_zb_ep_list_get_ep(ep_list, endpoint_id);
ESP_RETURN_ON_FALSE(cluster_list, ESP_ERR_INVALID_ARG, TAG, "Failed to find endpoint id: %d in list: %p", endpoint_id, ep_list);
basic_cluster = esp_zb_cluster_list_get_cluster(cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
ESP_RETURN_ON_FALSE(basic_cluster, ESP_ERR_INVALID_ARG, TAG, "Failed to find basic cluster in endpoint: %d", endpoint_id);
ESP_RETURN_ON_FALSE((info && info->manufacturer_name), ESP_ERR_INVALID_ARG, TAG, "Invalid manufacturer name");
ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, info->manufacturer_name));
ESP_RETURN_ON_FALSE((info && info->model_identifier), ESP_ERR_INVALID_ARG, TAG, "Invalid model identifier");
ESP_ERROR_CHECK(esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, info->model_identifier));
return ret;
}
@@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
REQUIRES led_strip)
@@ -0,0 +1,13 @@
menu "ESP Zigbee DevKit LED Configuration"
config GPIO_LED_ON_DEVKIT
int "LED GPIO on devkit"
default 8 if IDF_TARGET_ESP32H2
default 8 if IDF_TARGET_ESP32C6
default 27 if IDF_TARGET_ESP32C5
default 8
help
The GPIO connected to the LED on the devkits
endmenu
@@ -0,0 +1,3 @@
## IDF Component Manager Manifest File
dependencies:
espressif/led_strip: "~3.0.0"
@@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* Zigbee light driver example
*
* 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.
*/
#pragma once
#include <stdbool.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
/* light intensity level */
#define LIGHT_DEFAULT_ON 1
#define LIGHT_DEFAULT_OFF 0
/* LED strip configuration */
#define CONFIG_EXAMPLE_STRIP_LED_GPIO CONFIG_GPIO_LED_ON_DEVKIT
#define CONFIG_EXAMPLE_STRIP_LED_NUMBER 1
/** Convert Hue,Saturation,V to RGB
* RGB - [0..0xffff]
* hue - [0..0xff]
* Sat - [0..0xff]
* V always = (ZB_UINT16_MAX-1)
*/
#define HSV_to_RGB(h, s, v, r, g, b) \
{ \
uint8_t i; \
uint8_t sector = UINT8_MAX / 6; \
float f, p, q, t; \
if (s == 0) { /* achromatic (grey)*/ \
r = g = b = (v); \
} else { \
i = h / sector; /* sector 0 to 5 */ \
f = h % sector; /* factorial part of h*/ \
p = (float)(v * (1.0 - (float)s / UINT8_MAX)); \
q = (float)(v * (1.0 - (float)s / UINT8_MAX * f / (float)sector)); \
t = (float)(v * (1.0 - (float)s / UINT8_MAX * (1 - f / (float)sector))); \
switch (i) { \
case 0: \
r = (v); \
g = t; \
b = p; \
break; \
case 1: \
r = q; \
g = (v); \
b = p; \
break; \
case 2: \
r = p; \
g = (v); \
b = t; \
break; \
case 3: \
r = p; \
g = q; \
b = (v); \
break; \
case 4: \
r = t; \
g = p; \
b = (v); \
break; \
case 5: \
default: \
r = (v); \
g = p; \
b = q; \
break; \
} \
} \
}
#define XYZ_to_RGB(X, Y, Z, r, g, b) \
{ \
r = (float)(3.240479 * (X)-1.537150 * (Y)-0.498535 * (Z)); \
g = (float)(-0.969256 * (X) + 1.875992 * (Y) + 0.041556 * (Z)); \
b = (float)(0.055648 * (X)-0.204043 * (Y) + 1.057311 * (Z)); \
if (r > 1) { \
r = 1; \
} \
if (g > 1) { \
g = 1; \
} \
if (b > 1) { \
b = 1; \
} \
}
/**
* @brief Set light power (on/off).
*
* @param power The light power value to be set
*/
void light_driver_set_power(bool power);
/**
* @brief color light driver init, be invoked where you want to use color light
*
* @param power power on/off
*/
void light_driver_init(bool power);
/**
* @brief Set light level
*
* @param level The light level value to be set
*/
void light_driver_set_level(uint8_t level);
/**
* @brief Set light color from RGB
*
* @param red The red color value to be set
* @param green The green color value to be set
* @param blue The blue color value to be set
*/
void light_driver_set_color_RGB(uint8_t red, uint8_t green, uint8_t blue);
/**
* @brief Set light color from color xy
*
* @param color_current_x The color x value to be set
* @param color_current_y The color y value to be set
*/
void light_driver_set_color_xy(uint16_t color_current_x, uint16_t color_current_y);
/**
* @brief Set light color from hue saturation
*
* @param hue The hue value to be set
* @param sat The saturation value to be set
*/
void light_driver_set_color_hue_sat(uint8_t hue, uint8_t sat);
#ifdef __cplusplus
} // extern "C"
#endif
@@ -0,0 +1,87 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* Zigbee light driver example
*
* 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.
*/
#include "led_strip.h"
#include "light_driver.h"
static led_strip_handle_t s_led_strip;
static uint8_t s_red = 255, s_green = 255, s_blue = 255, s_level = 255;
void light_driver_set_color_xy(uint16_t color_current_x, uint16_t color_current_y)
{
float red_f = 0, green_f = 0, blue_f = 0, color_x, color_y;
color_x = (float)color_current_x / 65535;
color_y = (float)color_current_y / 65535;
/* assume color_Y is full light level value 1 (0-1.0) */
float color_X = color_x / color_y;
float color_Z = (1 - color_x - color_y) / color_y;
/* change from xy to linear RGB NOT sRGB */
XYZ_to_RGB(color_X, 1, color_Z, red_f, green_f, blue_f);
float ratio = (float)s_level / 255;
s_red = (uint8_t)(red_f * (float)255);
s_green = (uint8_t)(green_f * (float)255);
s_blue = (uint8_t)(blue_f * (float)255);
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * ratio, s_green * ratio, s_blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_color_hue_sat(uint8_t hue, uint8_t sat)
{
float red_f, green_f, blue_f;
HSV_to_RGB(hue, sat, UINT8_MAX, red_f, green_f, blue_f);
float ratio = (float)s_level / 255;
s_red = (uint8_t)red_f;
s_green = (uint8_t)green_f;
s_blue = (uint8_t)blue_f;
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * ratio, s_green * ratio, s_blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_color_RGB(uint8_t red, uint8_t green, uint8_t blue)
{
float ratio = (float)s_level / 255;
s_red = red;
s_green = green;
s_blue = blue;
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, red * ratio, green * ratio, blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_power(bool power)
{
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * power, s_green * power, s_blue * power));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_set_level(uint8_t level)
{
s_level = level;
float ratio = (float)s_level / 255;
ESP_ERROR_CHECK(led_strip_set_pixel(s_led_strip, 0, s_red * ratio, s_green * ratio, s_blue * ratio));
ESP_ERROR_CHECK(led_strip_refresh(s_led_strip));
}
void light_driver_init(bool power)
{
led_strip_config_t led_strip_conf = {
.max_leds = CONFIG_EXAMPLE_STRIP_LED_NUMBER,
.strip_gpio_num = CONFIG_EXAMPLE_STRIP_LED_GPIO,
};
led_strip_rmt_config_t rmt_conf = {
.resolution_hz = 10 * 1000 * 1000, // 10MHz
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&led_strip_conf, &rmt_conf, &s_led_strip));
light_driver_set_power(power);
}
@@ -0,0 +1,13 @@
include($ENV{IDF_PATH}/tools/cmake/version.cmake)
set(public_requires "freertos")
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.3")
list(APPEND public_requires "esp_driver_gpio")
else()
list(APPEND public_requires "driver")
endif()
idf_component_register(SRC_DIRS "src"
INCLUDE_DIRS "include"
REQUIRES ${public_requires})
@@ -0,0 +1,27 @@
menu "ESP Zigbee DevKit GPIO Configuration"
config GPIO_BOOT_ON_DEVKIT
int "BOOT GPIO on devkit"
default 9 if IDF_TARGET_ESP32H2
default 9 if IDF_TARGET_ESP32C6
default 28 if IDF_TARGET_ESP32C5
default 9
help
The GPIO connected to the BOOT button on the devkits
config GPIO_EXT1_WAKEUP_SOURCE
int "External wakeup GPIO"
default 9 if IDF_TARGET_ESP32H2
default 7 if IDF_TARGET_ESP32C6
default 7 if IDF_TARGET_ESP32S31
default 6 if IDF_TARGET_ESP32C5
range 7 14 if IDF_TARGET_ESP32H2
range 0 7 if IDF_TARGET_ESP32C6
range 0 7 if IDF_TARGET_ESP32S31
range 0 6 if IDF_TARGET_ESP32C5
default 9
help
The GPIO can be used as external wake up source for sleep device
endmenu
@@ -0,0 +1,79 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* Zigbee switch driver
*
* This driver reads a physical GPIO switch/button (e.g. BOOT button on devkit),
* uses GPIO interrupt and a queue to report press/release events to the application
* via a callback. Typical use: Zigbee HA On/Off Switch sending commands on button press.
*
* 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.
*/
#pragma once
#include <stdbool.h>
#include "driver/gpio.h"
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Opaque handle for the switch driver instance.
*/
typedef void* switch_driver_handle_t;
/**
* @brief Invalid handle value.
*/
#define SWITCH_INV_HANDLE NULL
/**
* @brief Callback invoked from GPIO ISR (low-level) when the switch level changes.
*
* Runs in interrupt context: keep it minimal (e.g. set a flag or post to a queue).
* Do not block or call blocking / non-ISR-safe APIs.
*
* @param user_ctx User context passed at init
*/
typedef void (*switch_event_cb_t)(switch_driver_handle_t handle);
/**
* @brief Switch driver configuration.
*/
typedef struct {
gpio_num_t gpio_num; /*!< GPIO number used as switch input (e.g. BOOT button) */
switch_event_cb_t event_cb; /*!< Callback on level change (invoked from ISR); may be NULL if only polling */
} switch_driver_config_t;
/**
* @brief Initialize the switch driver.
*
* Configures the GPIO in switch_driver_init() as input with pull-up enabled,
* installs the GPIO ISR, and hooks the callback. The callback is triggered in low-level
* (GPIO ISR) context on level change.
*
* @param config Driver configuration (gpio_num required; event_cb optional)
* @return Handle
*/
switch_driver_handle_t switch_driver_init(const switch_driver_config_t *config);
/**
* @brief Deinitialize the switch driver.
*
* Removes ISR handler and resets GPIO.
*
* @param handle Handle from switch_driver_init; may be NULL
*/
void switch_driver_deinit(switch_driver_handle_t handle);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,116 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: LicenseRef-Included
*
* Zigbee switch driver
*
* 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.
*/
#include <stdlib.h>
#include <string.h>
#include "switch_driver.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "esp_attr.h"
#include "esp_log.h"
static QueueHandle_t gpio_event_queue = NULL;
static void switch_driver_gpio_intr_enabled(gpio_num_t gpio_num, bool enabled)
{
if (enabled) {
gpio_intr_enable(gpio_num);
} else {
gpio_intr_disable(gpio_num);
}
}
static void IRAM_ATTR gpio_isr_handler(void *arg)
{
switch_driver_config_t *config = (switch_driver_config_t *)arg;
switch_driver_gpio_intr_enabled(config->gpio_num, false);
xQueueSendFromISR(gpio_event_queue, &config, NULL);
}
static void switch_driver_button_detected(void *arg)
{
(void)arg;
switch_driver_config_t *config = NULL;
while (1) {
if (xQueueReceive(gpio_event_queue, &config, portMAX_DELAY) == pdTRUE) {
if (config) {
if (config->event_cb) {
config->event_cb(config);
}
}
}
vTaskDelay(pdMS_TO_TICKS(200));
switch_driver_gpio_intr_enabled(config->gpio_num, true);
}
}
switch_driver_handle_t switch_driver_init(const switch_driver_config_t *config)
{
if (config == NULL || config->gpio_num < 0) {
return NULL;
}
switch_driver_config_t *handle = (switch_driver_config_t *)malloc(sizeof(switch_driver_config_t));
if (handle == NULL) {
return NULL;
}
memcpy(handle, (void *)config, sizeof(switch_driver_config_t));
/* Configure GPIO in init: input, pull-up, and negative-edge interrupt */
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << config->gpio_num),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_LOW_LEVEL,
};
esp_err_t ret = gpio_config(&io_conf);
if (ret != ESP_OK) {
free(handle);
return NULL;
}
gpio_event_queue = xQueueCreate(10, sizeof(switch_driver_config_t *));
if (gpio_event_queue == 0) {
gpio_reset_pin(config->gpio_num);
free(handle);
return NULL;
}
xTaskCreate(switch_driver_button_detected, "button_detected", 4096, NULL, 10, NULL);
ret = gpio_install_isr_service(0);
if (ret != ESP_OK) {
gpio_reset_pin(config->gpio_num);
free(handle);
return NULL;
}
ret = gpio_isr_handler_add(config->gpio_num, gpio_isr_handler, (void *)handle);
if (ret != ESP_OK) {
gpio_reset_pin(config->gpio_num);
free(handle);
return NULL;
}
return handle;
}
void switch_driver_deinit(switch_driver_handle_t handle)
{
if (handle == NULL) {
return;
}
switch_driver_config_t *config = (switch_driver_config_t *)handle;
gpio_isr_handler_remove(config->gpio_num);
gpio_reset_pin(config->gpio_num);
free(config);
}