Skip to content

Commit

Permalink
ESP32: Add UAT button for lit-icd-app (project-chip#33043)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
wqx6 and restyled-commits authored Apr 22, 2024
1 parent b4650b9 commit a860932
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 5 deletions.
148 changes: 148 additions & 0 deletions examples/lit-icd-app/esp32/main/IcdUatButton.cpp
Original file line number Diff line number Diff line change
@@ -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 <cstdint>

#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<uint8_t>(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<uint8_t>(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
}
50 changes: 50 additions & 0 deletions examples/lit-icd-app/esp32/main/include/IcdUatButton.h
Original file line number Diff line number Diff line change
@@ -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 <driver/gpio.h>
#include <esp_sleep.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <freertos/task.h>

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;
};
24 changes: 24 additions & 0 deletions examples/lit-icd-app/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -24,13 +25,16 @@
#include "nvs_flash.h"

#include <DeviceCallbacks.h>
#include <IcdUatButton.h>
#include <app/icd/server/ICDManager.h>
#include <app/server/Server.h>
#include <common/CHIPDeviceManager.h>
#include <common/Esp32AppServer.h>
#include <common/Esp32ThreadInit.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include <platform/ESP32/ESP32Utils.h>
#include <platform/PlatformManager.h>

#if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER
#include <platform/ESP32/ESP32FactoryDataProvider.h>
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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<intptr_t>(nullptr));
}
12 changes: 7 additions & 5 deletions examples/platform/esp32/common/Esp32AppServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -158,17 +158,19 @@ 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)
{
ESP_LOGE(TAG, "Failed to convert the EnableKey string to octstr type value");
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();
Expand Down

0 comments on commit a860932

Please sign in to comment.