From a86093237f24cbead2e46aa13202e39df61d6e28 Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:14:10 +0800 Subject: [PATCH] ESP32: Add UAT button for lit-icd-app (#33043) * ESP32: Add UAT button for lit-icd-app * Restyled by clang-format * Add some review changes * Restyled by clang-format * fix compile error --------- Co-authored-by: Restyled.io --- .../lit-icd-app/esp32/main/IcdUatButton.cpp | 148 ++++++++++++++++++ .../esp32/main/include/IcdUatButton.h | 50 ++++++ examples/lit-icd-app/esp32/main/main.cpp | 24 +++ .../platform/esp32/common/Esp32AppServer.cpp | 12 +- 4 files changed, 229 insertions(+), 5 deletions(-) create mode 100644 examples/lit-icd-app/esp32/main/IcdUatButton.cpp create mode 100644 examples/lit-icd-app/esp32/main/include/IcdUatButton.h diff --git a/examples/lit-icd-app/esp32/main/IcdUatButton.cpp b/examples/lit-icd-app/esp32/main/IcdUatButton.cpp new file mode 100644 index 00000000000000..b45b17c634b877 --- /dev/null +++ b/examples/lit-icd-app/esp32/main/IcdUatButton.cpp @@ -0,0 +1,148 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 "IcdUatButton.h" + +#include "driver/gpio.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" +#include "hal/gpio_types.h" +#include + +#define ESP_INTR_FLAG_DEFAULT 0 + +static const char TAG[] = "Button"; +QueueHandle_t UatButton::sEventQueue = nullptr; +TaskHandle_t UatButton::sTaskHandle = nullptr; + +static void IRAM_ATTR gpio_isr_handler(void * arg) +{ + if (UatButton::sEventQueue) + { + UatButton * button = (UatButton *) arg; + button->GpioIntrEnable(false); + xQueueSendFromISR(UatButton::sEventQueue, &button, NULL); + } +} + +void UatButton::RunEventLoop(void * arg) +{ + bool eventDone = true; + UatButton * button = nullptr; + + for (;;) + { + if (xQueueReceive(sEventQueue, &button, portMAX_DELAY) == pdTRUE && button) + { + button->GpioIntrEnable(false); + eventDone = false; + } + while (!eventDone) + { + // GPIO Pull up is enabled so the button is pressed when this value is false. + bool value = gpio_get_level(button->mGpioNum); + switch (button->mState) + { + case ButtonState::kIdle: + button->mState = value == false ? ButtonState::kPressed : ButtonState::kIdle; + break; + case ButtonState::kPressed: + button->mState = value == false ? ButtonState::kPressed : ButtonState::kReleased; + break; + case ButtonState::kReleased: + button->mState = ButtonState::kIdle; + if (button->mUatButtonPressCallback) + { + button->mUatButtonPressCallback(button); + } + break; + default: + break; + } + if (button->mState == ButtonState::kIdle) + { + button->GpioIntrEnable(true); + eventDone = true; + break; + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } + } +} + +void UatButton::GpioIntrEnable(bool enable) +{ + if (enable) + { + gpio_intr_enable(mGpioNum); + } + else + { + gpio_intr_disable(mGpioNum); + } +} + +void UatButton::Init(gpio_num_t gpioNum, esp_sleep_ext1_wakeup_mode_t wakeupMode) +{ + mGpioNum = gpioNum; + mState = ButtonState::kIdle; + gpio_config_t io_conf = {}; + io_conf.intr_type = GPIO_INTR_LOW_LEVEL; + io_conf.pin_bit_mask = (1ULL << static_cast(mGpioNum)); + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + // configure GPIO with the given settings + gpio_config(&io_conf); + if (!sEventQueue) + { + // create a queue to handle gpio event from isr + sEventQueue = xQueueCreate(10, sizeof(UatButton *)); + if (!sEventQueue) + { + ESP_LOGE(TAG, "Failed to create GPIO EventQueue"); + return; + } + } + if (!sTaskHandle) + { + // start gpio task + xTaskCreate(RunEventLoop, "UatButton", 4096, nullptr, 10, &sTaskHandle); + if (!sTaskHandle) + { + ESP_LOGE(TAG, "Failed to create GPIO Task"); + return; + } + } + // install gpio isr service + gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); + // hook isr handler for specific gpio pin + gpio_isr_handler_add(mGpioNum, gpio_isr_handler, (void *) this); + ESP_LOGI(TAG, "UAT Button initialized.."); + // Configure RTC IO wake up + esp_sleep_enable_ext1_wakeup(1ULL << static_cast(mGpioNum), wakeupMode); +#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED + rtc_gpio_pulldown_dis(mGpioNum); + rtc_gpio_pullup_en(mGpioNum); +#else + gpio_pulldown_dis(mGpioNum); + gpio_pullup_en(mGpioNum); +#endif +} diff --git a/examples/lit-icd-app/esp32/main/include/IcdUatButton.h b/examples/lit-icd-app/esp32/main/include/IcdUatButton.h new file mode 100644 index 00000000000000..2104d1a7c4079d --- /dev/null +++ b/examples/lit-icd-app/esp32/main/include/IcdUatButton.h @@ -0,0 +1,50 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +class UatButton +{ +public: + using UatButtonPressCallback = void (*)(UatButton *); + + enum class ButtonState : uint8_t + { + kIdle = 0, + kPressed, + kReleased, + }; + + void Init(gpio_num_t gpioNum, esp_sleep_ext1_wakeup_mode_t wakeMode); + void SetUatButtonPressCallback(UatButtonPressCallback buttonCallback) { mUatButtonPressCallback = buttonCallback; } + void GpioIntrEnable(bool enable); + + static void RunEventLoop(void * arg); + static TaskHandle_t sTaskHandle; + static QueueHandle_t sEventQueue; + +private: + gpio_num_t mGpioNum; + ButtonState mState; + UatButtonPressCallback mUatButtonPressCallback; +}; diff --git a/examples/lit-icd-app/esp32/main/main.cpp b/examples/lit-icd-app/esp32/main/main.cpp index 340ae124d816c3..4bb736b219eabd 100644 --- a/examples/lit-icd-app/esp32/main/main.cpp +++ b/examples/lit-icd-app/esp32/main/main.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include "app/icd/server/ICDNotifier.h" #include "esp_log.h" #include "esp_netif.h" #include "esp_system.h" @@ -24,6 +25,8 @@ #include "nvs_flash.h" #include +#include +#include #include #include #include @@ -31,6 +34,7 @@ #include #include #include +#include #if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER #include @@ -58,6 +62,18 @@ chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; #error "Currently this example only support Thread chips" #endif +#ifdef CONFIG_IDF_TARGET_ESP32H2 +// GPIO9-GPIO14 could be used to wake up ESP32-H2. +// For ESP32-H2 DevKitM, the boot button is GPIO9. +#define UAT_GPIO GPIO_NUM_9 +#elif defined(CONFIG_IDF_TARGET_ESP32C6) +// GPIO0-GPIO7 could be used to wake up ESP32-C6. +// For ESP32-C6 DevKitC, the boot button is GPIO9, we cannot use it to wake up the chip. +#define UAT_GPIO GPIO_NUM_7 +#else +#error "Unsupport IDF target" +#endif + using namespace ::chip; using namespace ::chip::DeviceManager; using namespace ::chip::Credentials; @@ -66,6 +82,11 @@ extern const char TAG[] = "lit-icd-app"; static AppDeviceCallbacks EchoCallbacks; +static void UatButtonHandler(UatButton * button) +{ + DeviceLayer::PlatformMgr().ScheduleWork([](intptr_t) { app::ICDNotifier::GetInstance().NotifyNetworkActivityNotification(); }); +} + static void InitServer(intptr_t context) { Esp32AppServer::Init(); // Init ZCL Data Model and CHIP App Server AND Initialize device attestation config @@ -110,6 +131,9 @@ extern "C" void app_main() SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); #endif // CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER ESPOpenThreadInit(); + static UatButton sButton; + sButton.Init(UAT_GPIO, ESP_EXT1_WAKEUP_ANY_LOW); + sButton.SetUatButtonPressCallback(UatButtonHandler); chip::DeviceLayer::PlatformMgr().ScheduleWork(InitServer, reinterpret_cast(nullptr)); } diff --git a/examples/platform/esp32/common/Esp32AppServer.cpp b/examples/platform/esp32/common/Esp32AppServer.cpp index 53957784b8c5f5..873115c25ab1af 100644 --- a/examples/platform/esp32/common/Esp32AppServer.cpp +++ b/examples/platform/esp32/common/Esp32AppServer.cpp @@ -61,14 +61,14 @@ static app::Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::ESPEthernetDriver::GetInstance())); #endif -#if CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR +#if CONFIG_TEST_EVENT_TRIGGER_ENABLED static uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; #endif } // namespace -#if CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR +#if CONFIG_TEST_EVENT_TRIGGER_ENABLED static int hex_digit_to_int(char hex) { if ('A' <= hex && hex <= 'F') @@ -107,7 +107,7 @@ static size_t hex_string_to_binary(const char * hex_string, uint8_t * buf, size_ return buf_size; } -#endif // CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR +#endif // CONFIG_TEST_EVENT_TRIGGER_ENABLED void Esp32AppServer::DeInitBLEIfCommissioned(void) { @@ -158,7 +158,7 @@ void Esp32AppServer::Init(AppDelegate * sAppDelegate) { // Init ZCL Data Model and CHIP App Server static chip::CommonCaseDeviceServerInitParams initParams; -#if CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR +#if CONFIG_TEST_EVENT_TRIGGER_ENABLED if (hex_string_to_binary(CONFIG_TEST_EVENT_TRIGGER_ENABLE_KEY, sTestEventTriggerEnableKey, sizeof(sTestEventTriggerEnableKey)) == 0) { @@ -166,9 +166,11 @@ void Esp32AppServer::Init(AppDelegate * sAppDelegate) memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey)); } static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate{}; - static OTATestEventTriggerHandler sOtaTestEventTriggerHandler{}; VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(sTestEventTriggerEnableKey)) == CHIP_NO_ERROR); +#if CONFIG_ENABLE_OTA_REQUESTOR + static OTATestEventTriggerHandler sOtaTestEventTriggerHandler{}; VerifyOrDie(sTestEventTriggerDelegate.AddHandler(&sOtaTestEventTriggerHandler) == CHIP_NO_ERROR); +#endif initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; #endif // CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR (void) initParams.InitializeStaticResourcesBeforeServerInit();