Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP32: Add UAT button for lit-icd-app #33043

Merged
merged 5 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading