diff --git a/examples/multiple_on_off_plugin_units/CMakeLists.txt b/examples/multiple_on_off_plugin_units/CMakeLists.txt index 33aaf49d3..aaa0d5c51 100644 --- a/examples/multiple_on_off_plugin_units/CMakeLists.txt +++ b/examples/multiple_on_off_plugin_units/CMakeLists.txt @@ -19,6 +19,7 @@ include(${ESP_MATTER_PATH}/examples/common/cmake_common/components_include.cmake set(EXTRA_COMPONENT_DIRS "${MATTER_SDK_PATH}/config/esp32/components" "${ESP_MATTER_PATH}/components" + "${ESP_MATTER_PATH}/examples/common" ${extra_components_dirs_append}) project(multiple_on_off_plugin_units) diff --git a/examples/multiple_on_off_plugin_units/README.md b/examples/multiple_on_off_plugin_units/README.md index 4f3fac2c7..306c2f8df 100644 --- a/examples/multiple_on_off_plugin_units/README.md +++ b/examples/multiple_on_off_plugin_units/README.md @@ -11,10 +11,33 @@ To update the existing CONFIG_GPIO_PLUG values, follow these steps: 1. Run the following command to access the configuration menu: `idf.py menuconfig` 1. Navigate to the "Plugin manager" menu. -1. Update the GPIO pin number values (**Use only available GPIO pins as per the target chip**). +1. Update the GPIO pin number used for the factory reset button and plug output (**Use only available GPIO pins as per the target chip**). +You can update the number of plugin units from same menu. -You can update maximum configurable plugin units from same menu. +The following table defines the default GPIO pin numbers for each supported target device. + +| IO Function | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 | +|----------------------|-------|----------|----------|----------|----------|----------| +| Factory Reset Button | 0 | 9 | 9 | 9 | 9 | 0 | +| Plug 1 | 2 | 2 | 2 | 2 | 2 | 2 | +| Plug 2 | 4 | 4 | 4 | 4 | 4 | 4 | +| Plug 3 | 5 | 5 | 5 | 5 | 5 | 5 | +| Plug 4 | 12 | 6 | 6 | 12 | 12 | 12 | +| Plug 5 | 13 | 7 | 7 | 13 | 13 | 13 | +| Plug 6 | 14 | 8 | 8 | 15 | 14 | 14 | +| Plug 7 | 15 | 10 | 10 | 18 | 22 | 15 | +| Plug 8 | 16 | 18 | 18 | 19 | 25 | 16 | +| Plug 9 | 17 | 0 | 19 | 20 | 26 | 17 | +| Plug 10 | 18 | 1 | 0 | 21 | 27 | 18 | +| Plug 11 | 19 | 3 | 1 | 22 | 0 | 19 | +| Plug 12 | 21 | | 3 | 23 | 1 | 20 | +| Plug 13 | 22 | | | 0 | 3 | 21 | +| Plug 14 | 23 | | | 1 | 8 | 35 | +| Plug 15 | 25 | | | 3 | 10 | 36 | +| Plug 16 | 26 | | | 6 | 11 | 37 | + +**Note**: ESP32-C2 and ESP32-C3 do not have enough IO to use all 16 plugs See the [docs](https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html) for more information about building and flashing the firmware. diff --git a/examples/multiple_on_off_plugin_units/main/Kconfig.projbuild b/examples/multiple_on_off_plugin_units/main/Kconfig.projbuild index 35d2614a2..2c077c906 100644 --- a/examples/multiple_on_off_plugin_units/main/Kconfig.projbuild +++ b/examples/multiple_on_off_plugin_units/main/Kconfig.projbuild @@ -1,25 +1,174 @@ menu "Plugin manager" - config MAX_CONFIGURABLE_PLUGS - int "Maximum virtual configurable plugs" - default 5 + config USER_BUTTON + bool "Use custom GPIO for factory reset button" + default n + + config USER_BUTTON_GPIO + int "GPIO pin number for factory reset button" + default 0 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3 + default 9 + depends on USER_BUTTON + + config USER_BUTTON_LEVEL + int "GPIO level when factory reset button is active" + default 0 + range 0 1 + depends on USER_BUTTON + + config NUM_VIRTUAL_PLUGS + int "Number of virtual plugs" + default 3 + range 1 11 if IDF_TARGET_ESP32C2 + range 1 12 if IDF_TARGET_ESP32C3 range 1 16 config GPIO_PLUG_1 int "GPIO pin number for plug 1" - default 3 if IDF_TARGET_ESP32S3 - default 2 if !IDF_TARGET_ESP32S3 + default 2 + depends on (NUM_VIRTUAL_PLUGS >= 1) help Set GPIO pin value for target chip to create plugin unit config GPIO_PLUG_2 int "GPIO pin number for plug 2" default 4 + depends on (NUM_VIRTUAL_PLUGS >= 2) help Set GPIO pin value for target chip to create plugin unit config GPIO_PLUG_3 int "GPIO pin number for plug 3" default 5 + depends on (NUM_VIRTUAL_PLUGS >= 3) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_4 + int "GPIO pin number for plug 4" + default 6 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 + default 12 + depends on (NUM_VIRTUAL_PLUGS >= 4) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_5 + int "GPIO pin number for plug 5" + default 7 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 + default 13 + depends on (NUM_VIRTUAL_PLUGS >= 5) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_6 + int "GPIO pin number for plug 6" + default 8 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 + default 15 if IDF_TARGET_ESP32C6 + default 14 + depends on (NUM_VIRTUAL_PLUGS >= 6) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_7 + int "GPIO pin number for plug 7" + default 10 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 + default 18 if IDF_TARGET_ESP32C6 + default 22 if IDF_TARGET_ESP32H2 + default 15 + depends on (NUM_VIRTUAL_PLUGS >= 7) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_8 + int "GPIO pin number for plug 8" + default 18 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 + default 19 if IDF_TARGET_ESP32C6 + default 25 if IDF_TARGET_ESP32H2 + default 16 + depends on (NUM_VIRTUAL_PLUGS >= 8) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_9 + int "GPIO pin number for plug 9" + default 0 if IDF_TARGET_ESP32C2 + default 19 if IDF_TARGET_ESP32C3 + default 20 if IDF_TARGET_ESP32C6 + default 26 if IDF_TARGET_ESP32H2 + default 17 + depends on (NUM_VIRTUAL_PLUGS >= 9) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_10 + int "GPIO pin number for plug 10" + default 1 if IDF_TARGET_ESP32C2 + default 0 if IDF_TARGET_ESP32C3 + default 21 if IDF_TARGET_ESP32C6 + default 27 if IDF_TARGET_ESP32H2 + default 18 + depends on (NUM_VIRTUAL_PLUGS >= 10) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_11 + int "GPIO pin number for plug 11" + default 3 if IDF_TARGET_ESP32C2 + default 1 if IDF_TARGET_ESP32C3 + default 22 if IDF_TARGET_ESP32C6 + default 0 if IDF_TARGET_ESP32H2 + default 19 + depends on (NUM_VIRTUAL_PLUGS >= 11) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_12 + int "GPIO pin number for plug 12" + default 3 if IDF_TARGET_ESP32C3 + default 23 if IDF_TARGET_ESP32C6 + default 1 if IDF_TARGET_ESP32H2 + default 20 if IDF_TARGET_ESP32S3 + default 21 + depends on (NUM_VIRTUAL_PLUGS >= 12) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_13 + int "GPIO pin number for plug 13" + default 0 if IDF_TARGET_ESP32C6 + default 3 if IDF_TARGET_ESP32H2 + default 21 if IDF_TARGET_ESP32S3 + default 22 + depends on (NUM_VIRTUAL_PLUGS >= 13) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_14 + int "GPIO pin number for plug 14" + default 1 if IDF_TARGET_ESP32C6 + default 8 if IDF_TARGET_ESP32H2 + default 35 if IDF_TARGET_ESP32S3 + default 23 + depends on (NUM_VIRTUAL_PLUGS >= 14) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_15 + int "GPIO pin number for plug 15" + default 3 if IDF_TARGET_ESP32C6 + default 10 if IDF_TARGET_ESP32H2 + default 36 if IDF_TARGET_ESP32S3 + default 25 + depends on (NUM_VIRTUAL_PLUGS >= 15) + help + Set GPIO pin value for target chip to create plugin unit + + config GPIO_PLUG_16 + int "GPIO pin number for plug 16" + default 6 if IDF_TARGET_ESP32C6 + default 11 if IDF_TARGET_ESP32H2 + default 37 if IDF_TARGET_ESP32S3 + default 26 + depends on (NUM_VIRTUAL_PLUGS >= 16) help Set GPIO pin value for target chip to create plugin unit endmenu \ No newline at end of file diff --git a/examples/multiple_on_off_plugin_units/main/app_driver.cpp b/examples/multiple_on_off_plugin_units/main/app_driver.cpp index a78d47d1b..8e049c2b0 100644 --- a/examples/multiple_on_off_plugin_units/main/app_driver.cpp +++ b/examples/multiple_on_off_plugin_units/main/app_driver.cpp @@ -6,10 +6,15 @@ CONDITIONS OF ANY KIND, either express or implied. */ +#include #include +#include #include #include +#include "bsp/esp_bsp_devkit.h" #include "driver/gpio.h" +#include "soc/gpio_num.h" +#include "support/CodeUtils.h" #include @@ -57,9 +62,9 @@ esp_err_t app_driver_plugin_unit_init(const gpio_plug* plug) gpio_num_t get_gpio(uint16_t endpoint_id) { gpio_num_t gpio_pin = GPIO_NUM_NC; - for (int i = 0; i < s_configure_plugs; i++) { - if (s_plugin_unit_list[i].endpoint_id == endpoint_id) { - gpio_pin = s_plugin_unit_list[i].plug; + for (int i = 0; i < configure_plugs; i++) { + if (plugin_unit_list[i].endpoint_id == endpoint_id) { + gpio_pin = plugin_unit_list[i].plug; } } return gpio_pin; @@ -85,4 +90,54 @@ esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_ return err; } +app_driver_handle_t app_driver_button_init(gpio_num_t * reset_gpio) +{ + VerifyOrReturnValue((reset_gpio), (app_driver_handle_t)NULL, ESP_LOGE(TAG, "reset_gpio cannot be NULL")); +#ifdef CONFIG_USER_BUTTON + *reset_gpio = (gpio_num_t)CONFIG_USER_BUTTON_GPIO; +#elif CONFIG_BSP_BUTTONS_NUM >= 1 + *reset_gpio = (gpio_num_t)BSP_BUTTON_1_IO; +#else + *reset_gpio = gpio_num_t::GPIO_NUM_NC; + return (app_driver_handle_t)NULL; +#endif + ESP_LOGI(TAG, "Initializing reset button with gpio pin %d ...", (int)*reset_gpio); + + // Make sure button's IO pin isn't assigned to a plug's IO pin + for (int i = 0; i < configure_plugs; i++) { + if (plugin_unit_list[i].plug == *reset_gpio) { + ESP_LOGE(TAG, "Button's gpio pin %d is already configured for plug %d", *reset_gpio, i); + *reset_gpio = gpio_num_t::GPIO_NUM_NC; + return (app_driver_handle_t)NULL; + } + } + + /* Initialize button */ + app_driver_handle_t reset_handle = NULL; +#ifdef CONFIG_USER_BUTTON + button_config_t config = { + .type = BUTTON_TYPE_GPIO, + .gpio_button_config = { + .gpio_num = CONFIG_USER_BUTTON_GPIO, + .active_level = CONFIG_USER_BUTTON_LEVEL, + } + }; + reset_handle = (app_driver_handle_t)iot_button_create(&config); +#else + button_handle_t bsp_buttons[BSP_BUTTON_NUM]; + int btn_cnt = 0;// will contain # of buttons that were created by BSP + bsp_iot_button_create(bsp_buttons, &btn_cnt, BSP_BUTTON_NUM); + if (btn_cnt >= 1) { + // return handle to dev board's 1st built-in button + reset_handle = (app_driver_handle_t)bsp_buttons[0]; + } else { + ESP_LOGE(TAG, "bsp_iot_button_create() didn't return a usable button count: %d", btn_cnt); + } +#endif + + if (!reset_handle) { + *reset_gpio = gpio_num_t::GPIO_NUM_NC; + } + return reset_handle; +} diff --git a/examples/multiple_on_off_plugin_units/main/app_main.cpp b/examples/multiple_on_off_plugin_units/main/app_main.cpp index 2037d9c6e..cbbb85e7e 100644 --- a/examples/multiple_on_off_plugin_units/main/app_main.cpp +++ b/examples/multiple_on_off_plugin_units/main/app_main.cpp @@ -14,9 +14,11 @@ #include #include #include "driver/gpio.h" +#include "soc/gpio_num.h" #include #include +#include #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #include #endif @@ -24,6 +26,11 @@ #include #include +#define CREATE_PLUG(node, plug_id) \ + struct gpio_plug plug##plug_id; \ + plug##plug_id.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_##plug_id; \ + create_plug(&plug##plug_id, node); + static const char *TAG = "app_main"; using namespace esp_matter; @@ -32,8 +39,9 @@ using namespace esp_matter::endpoint; using namespace chip::app::Clusters; constexpr auto k_timeout_seconds = 300; -uint16_t s_configure_plugs = 0; -plugin_endpoint s_plugin_unit_list[CONFIG_MAX_CONFIGURABLE_PLUGS]; +uint16_t configure_plugs = 0; +plugin_endpoint plugin_unit_list[CONFIG_NUM_VIRTUAL_PLUGS]; +static gpio_num_t reset_gpio = gpio_num_t::GPIO_NUM_NC; #if CONFIG_ENABLE_ENCRYPTED_OTA extern const char decryption_key_start[] asm("_binary_esp_image_encryption_key_pem_start"); @@ -155,11 +163,17 @@ static esp_err_t create_plug(gpio_plug* plug, node_t* node) return ESP_ERR_INVALID_ARG; } + // Check if plug's IO pin is already used by reset button + if ((reset_gpio != gpio_num_t::GPIO_NUM_NC) && (reset_gpio == plug->GPIO_PIN_VALUE)) { + ESP_LOGE(TAG, "Reset button already configured for gpio pin : %d", plug->GPIO_PIN_VALUE); + return ESP_ERR_INVALID_STATE; + } + // Check for plug if already configured. - for (int i = 0; i < s_configure_plugs; i++) { - if (s_plugin_unit_list[i].plug == plug->GPIO_PIN_VALUE) { + for (int i = 0; i < configure_plugs; i++) { + if (plugin_unit_list[i].plug == plug->GPIO_PIN_VALUE) { ESP_LOGE(TAG, "Plug already configured for gpio pin : %d", plug->GPIO_PIN_VALUE); - return ESP_OK; + return ESP_ERR_INVALID_STATE; } } @@ -180,10 +194,10 @@ static esp_err_t create_plug(gpio_plug* plug, node_t* node) } // Check for maximum plugs that can be configured. - if (s_configure_plugs < CONFIG_MAX_CONFIGURABLE_PLUGS) { - s_plugin_unit_list[s_configure_plugs].plug = plug->GPIO_PIN_VALUE; - s_plugin_unit_list[s_configure_plugs].endpoint_id = endpoint::get_id(endpoint); - s_configure_plugs++; + if (configure_plugs < CONFIG_NUM_VIRTUAL_PLUGS) { + plugin_unit_list[configure_plugs].plug = plug->GPIO_PIN_VALUE; + plugin_unit_list[configure_plugs].endpoint_id = endpoint::get_id(endpoint); + configure_plugs++; } else { ESP_LOGE(TAG, "Maximum plugs configuration limit exceeded!!!"); return ESP_FAIL; @@ -208,17 +222,75 @@ extern "C" void app_main() node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb); ABORT_APP_ON_FAILURE(node != nullptr, ESP_LOGE(TAG, "Failed to create Matter node")); - struct gpio_plug plug1; - plug1.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_1; - create_plug(&plug1, node); +#ifdef CONFIG_GPIO_PLUG_1 + CREATE_PLUG(node, 1) +#endif - struct gpio_plug plug2; - plug2.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_2; - create_plug(&plug2, node); +#ifdef CONFIG_GPIO_PLUG_2 + CREATE_PLUG(node, 2) +#endif - struct gpio_plug plug3; - plug3.GPIO_PIN_VALUE = (gpio_num_t) CONFIG_GPIO_PLUG_3; - create_plug(&plug3, node); +#ifdef CONFIG_GPIO_PLUG_3 + CREATE_PLUG(node, 3) +#endif + +#ifdef CONFIG_GPIO_PLUG_4 + CREATE_PLUG(node, 4) +#endif + +#ifdef CONFIG_GPIO_PLUG_5 + CREATE_PLUG(node, 5) +#endif + +#ifdef CONFIG_GPIO_PLUG_6 + CREATE_PLUG(node, 6) +#endif + +#ifdef CONFIG_GPIO_PLUG_7 + CREATE_PLUG(node, 7) +#endif + +#ifdef CONFIG_GPIO_PLUG_8 + CREATE_PLUG(node, 8) +#endif + +#ifdef CONFIG_GPIO_PLUG_9 + CREATE_PLUG(node, 9) +#endif + +#ifdef CONFIG_GPIO_PLUG_10 + CREATE_PLUG(node, 10) +#endif + +#ifdef CONFIG_GPIO_PLUG_11 + CREATE_PLUG(node, 11) +#endif + +#ifdef CONFIG_GPIO_PLUG_12 + CREATE_PLUG(node, 12) +#endif + +#ifdef CONFIG_GPIO_PLUG_13 + CREATE_PLUG(node, 13) +#endif + +#ifdef CONFIG_GPIO_PLUG_14 + CREATE_PLUG(node, 14) +#endif + +#ifdef CONFIG_GPIO_PLUG_15 + CREATE_PLUG(node, 15) +#endif + +#ifdef CONFIG_GPIO_PLUG_16 + CREATE_PLUG(node, 16) +#endif + + // Initialize factory reset button + app_driver_handle_t button_handle = app_driver_button_init(&reset_gpio); + if (button_handle) { + app_reset_button_register(button_handle); + } #if CHIP_DEVICE_CONFIG_ENABLE_THREAD /* Set OpenThread platform config */ diff --git a/examples/multiple_on_off_plugin_units/main/app_priv.h b/examples/multiple_on_off_plugin_units/main/app_priv.h index 3af07c203..691d9b693 100644 --- a/examples/multiple_on_off_plugin_units/main/app_priv.h +++ b/examples/multiple_on_off_plugin_units/main/app_priv.h @@ -10,6 +10,7 @@ #include #include +#include "soc/gpio_num.h" #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #include "esp_openthread_types.h" @@ -28,8 +29,8 @@ struct plugin_endpoint { gpio_num_t get_gpio(uint16_t endpoint_id); -extern plugin_endpoint s_plugin_unit_list[CONFIG_MAX_CONFIGURABLE_PLUGS]; -extern uint16_t s_configure_plugs; +extern plugin_endpoint plugin_unit_list[CONFIG_NUM_VIRTUAL_PLUGS]; +extern uint16_t configure_plugs; typedef void *app_driver_handle_t; @@ -60,6 +61,17 @@ esp_err_t app_driver_plugin_unit_init(const gpio_plug* plug); esp_err_t app_driver_attribute_update(app_driver_handle_t driver_handle, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t *val); +/** Initialize the button driver + * + * This initializes the button driver associated with the selected board. + * + * @param[out] reset_gpio GPIO pin # assigned to the reset button + * + * @return Handle on success. + * @return NULL in case of failure. + */ +app_driver_handle_t app_driver_button_init(gpio_num_t * reset_gpio); + #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \ { \ diff --git a/examples/multiple_on_off_plugin_units/main/idf_component.yml b/examples/multiple_on_off_plugin_units/main/idf_component.yml index c489c846c..58b8ca55d 100644 --- a/examples/multiple_on_off_plugin_units/main/idf_component.yml +++ b/examples/multiple_on_off_plugin_units/main/idf_component.yml @@ -3,4 +3,6 @@ dependencies: version: 0.* rules: # will add "optional_component" only when all if clauses are True - if: "idf_version >=5.0" - - if: "target in [esp32c2]" \ No newline at end of file + - if: "target in [esp32c2]" + esp_bsp_devkit: + version: "1.0.0" \ No newline at end of file