Skip to content

Commit 49ae9ad

Browse files
committedApr 18, 2024·
ESP32: Add UAT button for lit-icd-app
1 parent 9966940 commit 49ae9ad

File tree

4 files changed

+232
-5
lines changed

4 files changed

+232
-5
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "IcdUatButton.h"
19+
20+
#include "driver/gpio.h"
21+
#include "esp_attr.h"
22+
#include "esp_log.h"
23+
#include "freertos/FreeRTOS.h"
24+
#include "freertos/queue.h"
25+
#include "freertos/task.h"
26+
#include "hal/gpio_types.h"
27+
#include "soc/gpio_num.h"
28+
#include <cstdint>
29+
30+
#define ESP_INTR_FLAG_DEFAULT 0
31+
32+
static const char TAG[] = "Button";
33+
QueueHandle_t UatButton::sEventQueue = nullptr;
34+
TaskHandle_t UatButton::sTaskHandle = nullptr;
35+
36+
static void IRAM_ATTR gpio_isr_handler(void * arg)
37+
{
38+
if (UatButton::sEventQueue)
39+
{
40+
UatButton * button = (UatButton *) arg;
41+
button->GpioIntrEnable(false);
42+
xQueueSendFromISR(UatButton::sEventQueue, &button, NULL);
43+
}
44+
}
45+
46+
void UatButton::RunEventLoop(void * arg)
47+
{
48+
bool eventDone = true;
49+
UatButton * button = nullptr;
50+
51+
for (;;)
52+
{
53+
if (xQueueReceive(sEventQueue, &button, portMAX_DELAY) == pdTRUE && button)
54+
{
55+
button->GpioIntrEnable(false);
56+
eventDone = false;
57+
}
58+
while (!eventDone)
59+
{
60+
// GPIO Pull up is enabled so the button is pressed when this value is false.
61+
bool value = gpio_get_level(button->mGpioNum);
62+
switch (button->mState)
63+
{
64+
case ButtonState::kIdle:
65+
button->mState = value == false ? ButtonState::kPressed : ButtonState::kIdle;
66+
break;
67+
case ButtonState::kPressed:
68+
button->mState = value == false ? ButtonState::kPressed : ButtonState::kReleased;
69+
break;
70+
case ButtonState::kReleased:
71+
button->mState = ButtonState::kIdle;
72+
if (button->mUatButtonPressCallback)
73+
{
74+
button->mUatButtonPressCallback(button);
75+
}
76+
break;
77+
default:
78+
break;
79+
}
80+
if (button->mState == ButtonState::kIdle)
81+
{
82+
button->GpioIntrEnable(true);
83+
eventDone = true;
84+
break;
85+
}
86+
vTaskDelay(10 / portTICK_PERIOD_MS);
87+
}
88+
}
89+
}
90+
91+
void UatButton::GpioIntrEnable(bool enable)
92+
{
93+
if (enable)
94+
{
95+
gpio_intr_enable(mGpioNum);
96+
}
97+
else
98+
{
99+
gpio_intr_disable(mGpioNum);
100+
}
101+
}
102+
103+
void UatButton::Init(gpio_num_t gpioNum, esp_sleep_ext1_wakeup_mode_t wakeupMode)
104+
{
105+
mGpioNum = gpioNum;
106+
mState = ButtonState::kIdle;
107+
gpio_config_t io_conf = {};
108+
io_conf.intr_type = GPIO_INTR_LOW_LEVEL;
109+
io_conf.pin_bit_mask = (1ULL << static_cast<uint8_t>(mGpioNum));
110+
io_conf.mode = GPIO_MODE_INPUT;
111+
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
112+
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
113+
// configure GPIO with the given settings
114+
gpio_config(&io_conf);
115+
if (!sEventQueue)
116+
{
117+
// create a queue to handle gpio event from isr
118+
sEventQueue = xQueueCreate(10, sizeof(UatButton *));
119+
if (!sEventQueue)
120+
{
121+
ESP_LOGE(TAG, "Failed to create GPIO EventQueue");
122+
return;
123+
}
124+
}
125+
if (!sTaskHandle)
126+
{
127+
// start gpio task
128+
xTaskCreate(RunEventLoop, "UatButton", 4096, nullptr, 10, &sTaskHandle);
129+
if (!sTaskHandle)
130+
{
131+
ESP_LOGE(TAG, "Failed to create GPIO Task");
132+
return;
133+
}
134+
}
135+
// install gpio isr service
136+
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
137+
// hook isr handler for specific gpio pin
138+
gpio_isr_handler_add(mGpioNum, gpio_isr_handler, (void *) this);
139+
ESP_LOGI(TAG, "UAT Button initialized..");
140+
// Configure RTC IO wake up
141+
esp_sleep_enable_ext1_wakeup(1ULL << static_cast<uint8_t>(mGpioNum), wakeupMode);
142+
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
143+
rtc_gpio_pulldown_dis(mGpioNum);
144+
rtc_gpio_pullup_en(mGpioNum);
145+
#else
146+
gpio_pulldown_dis(mGpioNum);
147+
gpio_pullup_en(mGpioNum);
148+
#endif
149+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
*
3+
* Copyright (c) 2024 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#pragma once
19+
20+
#include <driver/gpio.h>
21+
#include <esp_sleep.h>
22+
#include <freertos/FreeRTOS.h>
23+
#include <freertos/queue.h>
24+
#include <freertos/task.h>
25+
#include <soc/gpio_num.h>
26+
27+
class UatButton
28+
{
29+
public:
30+
using UatButtonPressCallback = void (*)(UatButton *);
31+
32+
enum class ButtonState : uint8_t
33+
{
34+
kIdle = 0,
35+
kPressed,
36+
kReleased,
37+
};
38+
39+
void Init(gpio_num_t gpioNum, esp_sleep_ext1_wakeup_mode_t wakeMode);
40+
void SetUatButtonPressCallback(UatButtonPressCallback buttonCallback) { mUatButtonPressCallback = buttonCallback; }
41+
void GpioIntrEnable(bool enable);
42+
43+
static void RunEventLoop(void * arg);
44+
static TaskHandle_t sTaskHandle;
45+
static QueueHandle_t sEventQueue;
46+
47+
private:
48+
gpio_num_t mGpioNum;
49+
ButtonState mState;
50+
UatButtonPressCallback mUatButtonPressCallback;
51+
};

‎examples/lit-icd-app/esp32/main/main.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,16 @@
2424
#include "nvs_flash.h"
2525

2626
#include <DeviceCallbacks.h>
27+
#include <IcdUatButton.h>
28+
#include <app/icd/server/ICDManager.h>
2729
#include <app/server/Server.h>
2830
#include <common/CHIPDeviceManager.h>
2931
#include <common/Esp32AppServer.h>
3032
#include <common/Esp32ThreadInit.h>
3133
#include <credentials/DeviceAttestationCredsProvider.h>
3234
#include <credentials/examples/DeviceAttestationCredsExample.h>
3335
#include <platform/ESP32/ESP32Utils.h>
36+
#include <platform/PlatformManager.h>
3437

3538
#if CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER
3639
#include <platform/ESP32/ESP32FactoryDataProvider.h>
@@ -58,6 +61,18 @@ chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
5861
#error "Currently this example only support Thread chips"
5962
#endif
6063

64+
#ifdef CONFIG_IDF_TARGET_ESP32H2
65+
// GPIO9-GPIO14 could be used to wake up ESP32-H2.
66+
// For ESP32-H2 DevKitM, the boot button is GPIO9.
67+
#define UAT_GPIO GPIO_NUM_9
68+
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
69+
// GPIO0-GPIO7 could be used to wake up ESP32-C6.
70+
// For ESP32-C6 DevKitC, the boot button is GPIO9, we cannot use it to wake up the chip.
71+
#define UAT_GPIO GPIO_NUM_7
72+
#else
73+
#error "Unsupport IDF target"
74+
#endif
75+
6176
using namespace ::chip;
6277
using namespace ::chip::DeviceManager;
6378
using namespace ::chip::Credentials;
@@ -66,6 +81,13 @@ extern const char TAG[] = "lit-icd-app";
6681

6782
static AppDeviceCallbacks EchoCallbacks;
6883

84+
static void UatButtonHandler(UatButton *button)
85+
{
86+
DeviceLayer::PlatformMgr().ScheduleWork([](intptr_t) {
87+
Server::GetInstance().GetICDManager().UpdateOperationState(app::ICDManager::OperationalState::ActiveMode);
88+
});
89+
}
90+
6991
static void InitServer(intptr_t context)
7092
{
7193
Esp32AppServer::Init(); // Init ZCL Data Model and CHIP App Server AND Initialize device attestation config
@@ -110,6 +132,9 @@ extern "C" void app_main()
110132
SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());
111133
#endif // CONFIG_ENABLE_ESP32_FACTORY_DATA_PROVIDER
112134
ESPOpenThreadInit();
135+
static UatButton sButton;
136+
sButton.Init(UAT_GPIO, ESP_EXT1_WAKEUP_ANY_LOW);
137+
sButton.SetUatButtonPressCallback(UatButtonHandler);
113138

114139
chip::DeviceLayer::PlatformMgr().ScheduleWork(InitServer, reinterpret_cast<intptr_t>(nullptr));
115140
}

‎examples/platform/esp32/common/Esp32AppServer.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,14 @@ static app::Clusters::NetworkCommissioning::Instance
6161
sEthernetNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::ESPEthernetDriver::GetInstance()));
6262
#endif
6363

64-
#if CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR
64+
#if CONFIG_TEST_EVENT_TRIGGER_ENABLED
6565
static uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
6666
0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
6767
0xcc, 0xdd, 0xee, 0xff };
6868
#endif
6969
} // namespace
7070

71-
#if CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR
71+
#if CONFIG_TEST_EVENT_TRIGGER_ENABLED
7272
static int hex_digit_to_int(char hex)
7373
{
7474
if ('A' <= hex && hex <= 'F')
@@ -107,7 +107,7 @@ static size_t hex_string_to_binary(const char * hex_string, uint8_t * buf, size_
107107

108108
return buf_size;
109109
}
110-
#endif // CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR
110+
#endif // CONFIG_TEST_EVENT_TRIGGER_ENABLED
111111

112112
void Esp32AppServer::DeInitBLEIfCommissioned(void)
113113
{
@@ -158,17 +158,19 @@ void Esp32AppServer::Init(AppDelegate * sAppDelegate)
158158
{
159159
// Init ZCL Data Model and CHIP App Server
160160
static chip::CommonCaseDeviceServerInitParams initParams;
161-
#if CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR
161+
#if CONFIG_TEST_EVENT_TRIGGER_ENABLED
162162
if (hex_string_to_binary(CONFIG_TEST_EVENT_TRIGGER_ENABLE_KEY, sTestEventTriggerEnableKey,
163163
sizeof(sTestEventTriggerEnableKey)) == 0)
164164
{
165165
ESP_LOGE(TAG, "Failed to convert the EnableKey string to octstr type value");
166166
memset(sTestEventTriggerEnableKey, 0, sizeof(sTestEventTriggerEnableKey));
167167
}
168168
static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate{};
169-
static OTATestEventTriggerHandler sOtaTestEventTriggerHandler{};
170169
VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(sTestEventTriggerEnableKey)) == CHIP_NO_ERROR);
170+
#if CONFIG_ENABLE_OTA_REQUESTOR
171+
static OTATestEventTriggerHandler sOtaTestEventTriggerHandler{};
171172
VerifyOrDie(sTestEventTriggerDelegate.AddHandler(&sOtaTestEventTriggerHandler) == CHIP_NO_ERROR);
173+
#endif
172174
initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate;
173175
#endif // CONFIG_TEST_EVENT_TRIGGER_ENABLED && CONFIG_ENABLE_OTA_REQUESTOR
174176
(void) initParams.InitializeStaticResourcesBeforeServerInit();

0 commit comments

Comments
 (0)