From 4430546c995257f79c0174098f432dd105f5cd53 Mon Sep 17 00:00:00 2001 From: Jean-Francois Penven <67962328+jepenven-silabs@users.noreply.github.com> Date: Wed, 3 Aug 2022 17:51:23 -0400 Subject: [PATCH] Complete AppTask update (#21605) --- examples/chef/efr32/BUILD.gn | 1 + examples/chef/efr32/include/AppTask.h | 115 +++-- examples/chef/efr32/src/AppTask.cpp | 368 +--------------- examples/chef/efr32/src/LightingManager.cpp | 2 +- examples/chef/efr32/src/main.cpp | 4 +- examples/thermostat/efr32/BUILD.gn | 1 + examples/thermostat/efr32/include/AppTask.h | 114 +---- examples/thermostat/efr32/src/AppTask.cpp | 453 +------------------- examples/thermostat/efr32/src/main.cpp | 4 +- 9 files changed, 116 insertions(+), 946 deletions(-) diff --git a/examples/chef/efr32/BUILD.gn b/examples/chef/efr32/BUILD.gn index 8016d069fb4b34..3437758d955625 100644 --- a/examples/chef/efr32/BUILD.gn +++ b/examples/chef/efr32/BUILD.gn @@ -179,6 +179,7 @@ efr32_executable("chef_app") { defines = [] sources = [ + "${examples_plat_dir}/BaseApplication.cpp", "${examples_plat_dir}/LEDWidget.cpp", "${examples_plat_dir}/efr32_utils.cpp", "${examples_plat_dir}/heap_4_silabs.c", diff --git a/examples/chef/efr32/include/AppTask.h b/examples/chef/efr32/include/AppTask.h index be75aff4df2de9..a8e186083c23f6 100644 --- a/examples/chef/efr32/include/AppTask.h +++ b/examples/chef/efr32/include/AppTask.h @@ -19,18 +19,27 @@ #pragma once +/********************************************************** + * Includes + *********************************************************/ + #include #include #include "AppEvent.h" -#include "LightingManager.h" -#include "sl_simple_button_instances.h" - +#include "BaseApplication.h" #include "FreeRTOS.h" +#include "sl_simple_button_instances.h" #include "timers.h" // provides FreeRTOS timer support +#include #include +#include #include +/********************************************************** + * Defines + *********************************************************/ + // Application-defined error codes in the CHIP_ERROR space. #define APP_ERROR_EVENT_QUEUE_FAILED CHIP_APPLICATION_ERROR(0x01) #define APP_ERROR_CREATE_TASK_FAILED CHIP_APPLICATION_ERROR(0x02) @@ -39,57 +48,75 @@ #define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) #define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) -class AppTask +/********************************************************** + * AppTask Declaration + *********************************************************/ + +class AppTask : public BaseApplication { public: - CHIP_ERROR StartAppTask(); + AppTask() = default; + + static AppTask & GetAppTask() { return sAppTask; } + + /** + * @brief AppTask task main loop function + * + * @param pvParameter FreeRTOS task parameter + */ static void AppTaskMain(void * pvParameter); - void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction); - void PostEvent(const AppEvent * event); + CHIP_ERROR StartAppTask(); - void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction); + /** + * @brief Event handler when a button is pressed + * Function posts an event for button processing + * + * @param buttonHandle APP_LIGHT_SWITCH or APP_FUNCTION_BUTTON + * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, + * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED + */ + void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) override; + + /** + * @brief Callback called by the identify-server when an identify command is received + * + * @param identify identify structure the command applies on + */ + static void OnIdentifyStart(Identify * identify); + + /** + * @brief Callback called by the identify-server when an identify command is stopped or finished + * + * @param identify identify structure the command applies on + */ + static void OnIdentifyStop(Identify * identify); private: - friend AppTask & GetAppTask(void); + static AppTask sAppTask; + /** + * @brief AppTask initialisation function + * + * @return CHIP_ERROR + */ CHIP_ERROR Init(); - static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor); - static void ActionCompleted(LightingManager::Action_t aAction); - - void CancelTimer(void); - - void DispatchEvent(AppEvent * event); - - static void FunctionTimerEventHandler(AppEvent * aEvent); - static void FunctionHandler(AppEvent * aEvent); + /** + * @brief PB0 Button event processing function + * Press and hold will trigger a factory reset timer start + * Press and release will restart BLEAdvertising if not commisionned + * + * @param aEvent button event being processed + */ + static void ButtonHandler(AppEvent * aEvent); + + /** + * @brief PB1 Button event processing function + * Function triggers a switch action sent to the CHIP task + * + * @param aEvent button event being processed + */ static void SwitchActionEventHandler(AppEvent * aEvent); - static void TimerEventHandler(TimerHandle_t xTimer); - - static void UpdateClusterState(void); - - void StartTimer(uint32_t aTimeoutMs); - - enum Function_t - { - kFunction_NoneSelected = 0, - kFunction_SoftwareUpdate = 0, - kFunction_StartBleAdv = 1, - kFunction_FactoryReset = 2, - - kFunction_Invalid - } Function; - - Function_t mFunction; - bool mFunctionTimerActive; - bool mSyncClusterToButtonAction; - - static AppTask sAppTask; }; - -inline AppTask & GetAppTask(void) -{ - return AppTask::sAppTask; -} diff --git a/examples/chef/efr32/src/AppTask.cpp b/examples/chef/efr32/src/AppTask.cpp index b6450ba696d126..0ba9b8aa4e08e0 100644 --- a/examples/chef/efr32/src/AppTask.cpp +++ b/examples/chef/efr32/src/AppTask.cpp @@ -51,23 +51,6 @@ #include #include -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#endif -#ifdef SL_WIFI -#include "wfx_host_events.h" -#include -#include -#endif /* SL_WIFI */ - -#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 -#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 -#define APP_TASK_STACK_SIZE (4096) -#define APP_TASK_PRIORITY 2 -#define APP_EVENT_QUEUE_SIZE 10 -#define EXAMPLE_VENDOR_ID 0xcafe #define SYSTEM_STATE_LED &sl_led_led0 #define APP_FUNCTION_BUTTON &sl_button_btn0 @@ -76,38 +59,11 @@ using namespace chip; using namespace ::chip::DeviceLayer; namespace { -TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. - -TaskHandle_t sAppTaskHandle; -QueueHandle_t sAppEventQueue; - -LEDWidget sStatusLED; - -#ifdef SL_WIFI -bool sIsWiFiProvisioned = false; -bool sIsWiFiEnabled = false; -bool sIsWiFiAttached = false; - -app::Clusters::NetworkCommissioning::Instance - sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); -#endif /* SL_WIFI */ - -#if CHIP_ENABLE_OPENTHREAD -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -#endif /* CHIP_ENABLE_OPENTHREAD */ -bool sHaveBLEConnections = false; #ifdef EMBER_AF_PLUGIN_IDENTIFY_SERVER EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; #endif // EMBER_AF_PLUGIN_IDENTIFY_SERVER -uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; -StaticQueue_t sAppEventQueueStruct; - -StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; -StaticTask_t appTaskStruct; - namespace { #ifdef EMBER_AF_PLUGIN_IDENTIFY_SERVER void OnTriggerIdentifyEffectCompleted(chip::System::Layer * systemLayer, void * appState) @@ -168,93 +124,29 @@ using namespace ::chip::DeviceLayer; AppTask AppTask::sAppTask; -CHIP_ERROR AppTask::StartAppTask() -{ - sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); - if (sAppEventQueue == NULL) - { - EFR32_LOG("Failed to allocate app event queue"); - appError(APP_ERROR_EVENT_QUEUE_FAILED); - } - - // Start App task. - sAppTaskHandle = xTaskCreateStatic(AppTaskMain, APP_TASK_NAME, ArraySize(appStack), NULL, 1, appStack, &appTaskStruct); - return (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; -} - CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; -#ifdef SL_WIFI - /* - * Wait for the WiFi to be initialized - */ - EFR32_LOG("APP: Wait WiFi Init"); - while (!wfx_hw_ready()) - { - vTaskDelay(10); - } - EFR32_LOG("APP: Done WiFi Init"); - /* We will init server when we get IP */ - - sWiFiNetworkCommissioningInstance.Init(); -#endif - - // Create FreeRTOS sw timer for Function Selection. - sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel - 1, // == default timer period (mS) - false, // no timer reload (==one-shot) - (void *) this, // init timer id = app task obj context - TimerEventHandler // timer callback handler - ); - if (sFunctionTimer == NULL) - { - EFR32_LOG("funct timer create failed"); - appError(APP_ERROR_CREATE_TIMER_FAILED); - } - - EFR32_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); - err = LightMgr().Init(); + err = BaseApplication::Init(&gIdentify); if (err != CHIP_NO_ERROR) { - EFR32_LOG("LightMgr().Init() failed"); + EFR32_LOG("BaseApplication::Init() failed"); appError(err); } - LightMgr().SetCallbacks(ActionInitiated, ActionCompleted); - - // Initialize LEDs - LEDWidget::InitGpio(); - sStatusLED.Init(SYSTEM_STATE_LED); - UpdateClusterState(); - - ConfigurationMgr().LogDeviceConfig(); - -// Print setup info on LCD if available -#ifdef DISPLAY_ENABLED - // Create buffer for QR code that can fit max size and null terminator. - char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; - chip::MutableCharSpan QRCode(qrCodeBuffer); - - if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) - { - LCDWriteQRCode((uint8_t *) QRCode.data()); - } - else - { - EFR32_LOG("Getting QR code failed!"); - } -#else - PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); -#endif - return err; } +CHIP_ERROR AppTask::StartAppTask() +{ + return BaseApplication::StartAppTask(AppTaskMain); +} + void AppTask::AppTaskMain(void * pvParameter) { AppEvent event; + QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); CHIP_ERROR err = sAppTask.Init(); if (err != CHIP_NO_ERROR) @@ -273,73 +165,6 @@ void AppTask::AppTaskMain(void * pvParameter) sAppTask.DispatchEvent(&event); eventReceived = xQueueReceive(sAppEventQueue, &event, 0); } - - // Collect connectivity and configuration state from the CHIP stack. Because - // the CHIP event loop is being run in a separate task, the stack must be - // locked while these values are queried. However we use a non-blocking - // lock request (TryLockCHIPStack()) to avoid blocking other UI activities - // when the CHIP task is busy (e.g. with a long crypto operation). - if (PlatformMgr().TryLockChipStack()) - { -#ifdef SL_WIFI - sIsWiFiProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); - sIsWiFiEnabled = ConnectivityMgr().IsWiFiStationEnabled(); - sIsWiFiAttached = ConnectivityMgr().IsWiFiStationConnected(); -#endif /* SL_WIFI */ -#if CHIP_ENABLE_OPENTHREAD - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); -#endif /* CHIP_ENABLE_OPENTHREAD */ - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - // Update the status LED if factory reset has not been initiated. - // - // If system has "full connectivity", keep the LED On constantly. - // - // If thread and service provisioned, but not attached to the thread network - // yet OR no connectivity to the service OR subscriptions are not fully - // established THEN blink the LED Off for a short period of time. - // - // If the system has ble connection(s) uptill the stage above, THEN blink - // the LEDs at an even rate of 100ms. - // - // Otherwise, blink the LED ON for a very short time. - if (sAppTask.mFunction != kFunction_FactoryReset) - { - if (gIdentify.mActive) - { - sStatusLED.Blink(250, 250); - } - if (sIdentifyEffect != EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT) - { - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK) - { - sStatusLED.Blink(50, 50); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE) - { - sStatusLED.Blink(1000, 1000); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY) - { - sStatusLED.Blink(300, 700); - } - } -#if CHIP_ENABLE_OPENTHREAD - if (sIsThreadProvisioned && sIsThreadEnabled) -#else - if (sIsWiFiProvisioned && sIsWiFiEnabled && !sIsWiFiAttached) -#endif - { - sStatusLED.Blink(950, 50); - } - else if (sHaveBLEConnections) { sStatusLED.Blink(100, 100); } - else { sStatusLED.Blink(50, 950); } - } - - sStatusLED.Animate(); } } @@ -356,182 +181,7 @@ void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAc if (buttonHandle == APP_FUNCTION_BUTTON) { - button_event.Handler = FunctionHandler; + button_event.Handler = BaseApplication::ButtonHandler; sAppTask.PostEvent(&button_event); } } - -void AppTask::TimerEventHandler(TimerHandle_t xTimer) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = (void *) xTimer; - event.Handler = FunctionTimerEventHandler; - sAppTask.PostEvent(&event); -} - -void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) -{ - if (aEvent->Type != AppEvent::kEventType_Timer) - { - return; - } - - // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, - // initiate factory reset - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - EFR32_LOG("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to - // cancel, if required. - sAppTask.StartTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - sAppTask.mFunction = kFunction_FactoryReset; - - // Turn off all LEDs before starting blink to make sure blink is - // co-ordinated. - sStatusLED.Set(false); - sStatusLED.Blink(500); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Actually trigger Factory Reset - sAppTask.mFunction = kFunction_NoneSelected; - chip::Server::GetInstance().ScheduleFactoryReset(); - } -} - -void AppTask::FunctionHandler(AppEvent * aEvent) -{ - // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< - // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the - // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + - // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after - // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. - // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs - // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT - if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED) - { - if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_NoneSelected) - { - sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); - sAppTask.mFunction = kFunction_StartBleAdv; - } - } - else - { - // If the button was released before factory reset got initiated, start BLE advertissement in fast mode - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - sAppTask.CancelTimer(); - sAppTask.mFunction = kFunction_NoneSelected; - -#ifdef SL_WIFI - if (!ConnectivityMgr().IsWiFiStationProvisioned()) -#else - if (!ConnectivityMgr().IsThreadProvisioned()) -#endif /* !SL_WIFI */ - { - // Enable BLE advertisements - ConnectivityMgr().SetBLEAdvertisingEnabled(true); - ConnectivityMgr().SetBLEAdvertisingMode(ConnectivityMgr().kFastAdvertising); - } - else { EFR32_LOG("Network is already provisioned, Ble advertissement not enabled"); } - } - } -} - -void AppTask::CancelTimer() -{ - if (xTimerStop(sFunctionTimer, 0) == pdFAIL) - { - EFR32_LOG("app timer stop() failed"); - appError(APP_ERROR_STOP_TIMER_FAILED); - } - - mFunctionTimerActive = false; -} - -void AppTask::StartTimer(uint32_t aTimeoutInMs) -{ - if (xTimerIsTimerActive(sFunctionTimer)) - { - EFR32_LOG("app timer already started!"); - CancelTimer(); - } - - // timer is not active, change its period to required value (== restart). - // FreeRTOS- Block for a maximum of 100 ticks if the change period command - // cannot immediately be sent to the timer command queue. - if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) - { - EFR32_LOG("app timer start() failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } - - mFunctionTimerActive = true; -} - -void AppTask::ActionInitiated(LightingManager::Action_t aAction, int32_t aActor) -{ - if (aActor == AppEvent::kEventType_Button) - { - sAppTask.mSyncClusterToButtonAction = true; - } -} - -void AppTask::ActionCompleted(LightingManager::Action_t aAction) -{ - if (sAppTask.mSyncClusterToButtonAction) - { - UpdateClusterState(); - sAppTask.mSyncClusterToButtonAction = false; - } -} - -void AppTask::PostEvent(const AppEvent * aEvent) -{ - if (sAppEventQueue != NULL) - { - BaseType_t status; - if (xPortIsInsideInterrupt()) - { - BaseType_t higherPrioTaskWoken = pdFALSE; - status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); - -#ifdef portYIELD_FROM_ISR - portYIELD_FROM_ISR(higherPrioTaskWoken); -#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - portEND_SWITCHING_ISR(higherPrioTaskWoken); -#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR -#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" -#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - } - else - { - status = xQueueSend(sAppEventQueue, aEvent, 1); - } - - if (!status) - EFR32_LOG("Failed to post event to app task event queue"); - } - else - { - EFR32_LOG("Event Queue is NULL should never happen"); - } -} - -void AppTask::DispatchEvent(AppEvent * aEvent) -{ - if (aEvent->Handler) - { - aEvent->Handler(aEvent); - } - else - { - EFR32_LOG("Event received with no handler. Dropping event."); - } -} - -void AppTask::UpdateClusterState(void) {} diff --git a/examples/chef/efr32/src/LightingManager.cpp b/examples/chef/efr32/src/LightingManager.cpp index 7b206fd1ab6f37..59ee2744cf6d5e 100644 --- a/examples/chef/efr32/src/LightingManager.cpp +++ b/examples/chef/efr32/src/LightingManager.cpp @@ -167,7 +167,7 @@ void LightingManager::TimerEventHandler(TimerHandle_t xTimer) { event.Handler = ActuatorMovementTimerEventHandler; } - GetAppTask().PostEvent(&event); + AppTask::GetAppTask().PostEvent(&event); } void LightingManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) diff --git a/examples/chef/efr32/src/main.cpp b/examples/chef/efr32/src/main.cpp index 1e658f4369c92d..81cc220fc6a346 100644 --- a/examples/chef/efr32/src/main.cpp +++ b/examples/chef/efr32/src/main.cpp @@ -66,7 +66,7 @@ int main(void) chip::DeviceLayer::PlatformMgr().UnlockChipStack(); EFR32_LOG("Starting App Task"); - if (GetAppTask().StartAppTask() != CHIP_NO_ERROR) + if (AppTask::GetAppTask().StartAppTask() != CHIP_NO_ERROR) appError(CHIP_ERROR_INTERNAL); EFR32_LOG("Starting FreeRTOS scheduler"); @@ -80,5 +80,5 @@ int main(void) void sl_button_on_change(const sl_button_t * handle) { - GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); + AppTask::GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); } diff --git a/examples/thermostat/efr32/BUILD.gn b/examples/thermostat/efr32/BUILD.gn index 435bf123f75764..4683fbba0842bc 100644 --- a/examples/thermostat/efr32/BUILD.gn +++ b/examples/thermostat/efr32/BUILD.gn @@ -169,6 +169,7 @@ efr32_executable("thermostat_app") { defines = [] sources = [ + "${examples_plat_dir}/BaseApplication.cpp", "${examples_plat_dir}/LEDWidget.cpp", "${examples_plat_dir}/efr32_utils.cpp", "${examples_plat_dir}/heap_4_silabs.c", diff --git a/examples/thermostat/efr32/include/AppTask.h b/examples/thermostat/efr32/include/AppTask.h index 357d2d97c4584a..800dda99ad37ac 100644 --- a/examples/thermostat/efr32/include/AppTask.h +++ b/examples/thermostat/efr32/include/AppTask.h @@ -27,6 +27,7 @@ #include #include "AppEvent.h" +#include "BaseApplication.h" #include "FreeRTOS.h" #include "sl_simple_button_instances.h" #include "timers.h" // provides FreeRTOS timer support @@ -51,21 +52,13 @@ * AppTask Declaration *********************************************************/ -class AppTask +class AppTask : public BaseApplication { public: - /********************************************************** - * Public Function Declaration - *********************************************************/ + AppTask() = default; - /** - * @brief Create AppTask task and Event Queue - * If an error occurs during creation, application will hang after printing out error code - * - * @return CHIP_ERROR CHIP_NO_ERROR if no errors - */ - CHIP_ERROR StartAppTask(); + static AppTask & GetAppTask() { return sAppTask; } /** * @brief AppTask task main loop function @@ -74,12 +67,7 @@ class AppTask */ static void AppTaskMain(void * pvParameter); - /** - * @brief PostEvent function that add event to AppTask queue for processing - * - * @param event AppEvent to post - */ - void PostEvent(const AppEvent * event); + CHIP_ERROR StartAppTask(); /** * @brief Event handler when a button is pressed @@ -89,7 +77,7 @@ class AppTask * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED */ - void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction); + void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) override; /** * @brief Callback called by the identify-server when an identify command is received @@ -105,23 +93,8 @@ class AppTask */ static void OnIdentifyStop(Identify * identify); - /** - * @brief Function called to start the LED light timer - */ - void StartLightTimer(void); - - /** - * @brief Function to stop LED light timer - * Turns off Status LED before stopping timer - */ - void CancelLightTimer(void); - private: - /********************************************************** - * Private Function Declaration - *********************************************************/ - - friend AppTask & GetAppTask(void); + static AppTask sAppTask; /** * @brief AppTask initialisation function @@ -130,41 +103,6 @@ class AppTask */ CHIP_ERROR Init(); - /** - * @brief Function called to start the function timer - * - * @param aTimeoutMs timer duration in ms - */ - void StartFunctionTimer(uint32_t aTimeoutMs); - - /** - * @brief Function to stop function timer - */ - void CancelFunctionTimer(void); - - /** - * @brief Function call event callback function for processing - * - * @param event triggered event to be processed - */ - void DispatchEvent(AppEvent * event); - - /** - * @brief Function Timer finished callback function - * Post an FunctionEventHandler event - * - * @param xTimer timer that finished - */ - static void FunctionTimerEventHandler(TimerHandle_t xTimer); - - /** - * @brief Timer Event processing function - * Trigger factory if Press and Hold duration is respected - * - * @param aEvent post event being processed - */ - static void FunctionEventHandler(AppEvent * aEvent); - /** * @brief PB0 Button event processing function * Press and hold will trigger a factory reset timer start @@ -181,42 +119,4 @@ class AppTask * @param aEvent button event being processed */ static void ThermostatActionEventHandler(AppEvent * aEvent); - - /** - * @brief Light Timer finished callback function - * Calls LED processing function - * - * @param xTimer timer that finished - */ - static void LightTimerEventHandler(TimerHandle_t xTimer); - - /** - * @brief Updates device LEDs - */ - static void LightEventHandler(); - - /********************************************************** - * Private Attributes declaration - *********************************************************/ - - enum Function_t - { - kFunction_NoneSelected = 0, - kFunction_SoftwareUpdate = 0, - kFunction_StartBleAdv = 1, - kFunction_FactoryReset = 2, - - kFunction_Invalid - } Function; - - Function_t mFunction; - bool mFunctionTimerActive; - bool mSyncClusterToButtonAction; - - static AppTask sAppTask; }; - -inline AppTask & GetAppTask(void) -{ - return AppTask::sAppTask; -} diff --git a/examples/thermostat/efr32/src/AppTask.cpp b/examples/thermostat/efr32/src/AppTask.cpp index e972594d078d2d..a74f81e4ee4192 100644 --- a/examples/thermostat/efr32/src/AppTask.cpp +++ b/examples/thermostat/efr32/src/AppTask.cpp @@ -47,73 +47,23 @@ #include #include -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#endif // CHIP_ENABLE_OPENTHREAD - -#ifdef SL_WIFI -#include "wfx_host_events.h" -#include -#include -#endif // SL_WIFI - /********************************************************** * Defines and Constants *********************************************************/ -#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 -#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 -#define APP_TASK_STACK_SIZE (4096) -#define APP_TASK_PRIORITY 2 -#define APP_EVENT_QUEUE_SIZE 10 -#define EXAMPLE_VENDOR_ID 0xcafe - -#define SYSTEM_STATE_LED &sl_led_led0 - #define APP_FUNCTION_BUTTON &sl_button_btn0 #define APP_THERMOSTAT &sl_button_btn1 using namespace chip; using namespace ::chip::DeviceLayer; -namespace { - /********************************************************** * Variable declarations *********************************************************/ - -TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. -TimerHandle_t sLightTimer; - -TaskHandle_t sAppTaskHandle; -QueueHandle_t sAppEventQueue; - -LEDWidget sStatusLED; - -#ifdef SL_WIFI -app::Clusters::NetworkCommissioning::Instance - sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); -#endif /* SL_WIFI */ - -#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) - -bool sIsProvisioned = false; -bool sIsEnabled = false; -bool sIsAttached = false; -bool sHaveBLEConnections = false; - -#endif // CHIP_DEVICE_CONFIG_ENABLE_SED - +namespace { EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; -uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; -StaticQueue_t sAppEventQueueStruct; - -StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; -StaticTask_t appTaskStruct; - +} /********************************************************** * Identify Callbacks *********************************************************/ @@ -125,10 +75,9 @@ void OnTriggerIdentifyEffectCompleted(chip::System::Layer * systemLayer, void * sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; #if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - GetAppTask().CancelLightTimer(); + AppTask::GetAppTask().StopStatusLEDTimer(); #endif } -} // namespace void OnTriggerIdentifyEffect(Identify * identify) { @@ -143,7 +92,7 @@ void OnTriggerIdentifyEffect(Identify * identify) } #if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - GetAppTask().StartLightTimer(); + AppTask::GetAppTask().StartStatusLEDTimer(); #endif switch (sIdentifyEffect) @@ -169,8 +118,10 @@ void OnTriggerIdentifyEffect(Identify * identify) } Identify gIdentify = { - chip::EndpointId{ 1 }, GetAppTask().OnIdentifyStart, - GetAppTask().OnIdentifyStop, EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, + chip::EndpointId{ 1 }, + AppTask::GetAppTask().OnIdentifyStart, + AppTask::GetAppTask().OnIdentifyStop, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, OnTriggerIdentifyEffect, }; @@ -185,101 +136,29 @@ using namespace ::chip::DeviceLayer; AppTask AppTask::sAppTask; -CHIP_ERROR AppTask::StartAppTask() -{ - sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); - if (sAppEventQueue == NULL) - { - EFR32_LOG("Failed to allocate app event queue"); - appError(APP_ERROR_EVENT_QUEUE_FAILED); - } - - // Start App task. - sAppTaskHandle = xTaskCreateStatic(AppTaskMain, APP_TASK_NAME, ArraySize(appStack), NULL, 1, appStack, &appTaskStruct); - if (sAppTaskHandle == nullptr) - { - EFR32_LOG("Failed to create app task"); - appError(APP_ERROR_CREATE_TASK_FAILED); - } - return CHIP_NO_ERROR; -} - CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; -#ifdef SL_WIFI - /* - * Wait for the WiFi to be initialized - */ - EFR32_LOG("APP: Wait WiFi Init"); - while (!wfx_hw_ready()) - { - vTaskDelay(10); - } - EFR32_LOG("APP: Done WiFi Init"); - /* We will init server when we get IP */ - - sWiFiNetworkCommissioningInstance.Init(); -#endif - - // Create FreeRTOS sw timer for Function Selection. - sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel - 1, // == default timer period (mS) - false, // no timer reload (==one-shot) - (void *) this, // init timer id = app task obj context - FunctionTimerEventHandler // timer callback handler - ); - if (sFunctionTimer == NULL) - { - EFR32_LOG("funct timer create failed"); - appError(APP_ERROR_CREATE_TIMER_FAILED); - } - - // Create FreeRTOS sw timer for LED Management. - sLightTimer = xTimerCreate("LightTmr", // Text Name - 10, // Default timer period (mS) - true, // reload timer - (void *) this, // Timer Id - LightTimerEventHandler // Timer callback handler - ); - if (sLightTimer == NULL) - { - EFR32_LOG("Light Timer create failed"); - appError(APP_ERROR_CREATE_TIMER_FAILED); - } - - EFR32_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); - - LEDWidget::InitGpio(); - sStatusLED.Init(SYSTEM_STATE_LED); - - ConfigurationMgr().LogDeviceConfig(); - -// Print setup info on LCD if available -#ifdef QR_CODE_ENABLED - // Create buffer for QR code that can fit max size and null terminator. - char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; - chip::MutableCharSpan QRCode(qrCodeBuffer); - - if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) - { - LCDWriteQRCode((uint8_t *) QRCode.data()); - } - else + err = BaseApplication::Init(&gIdentify); + if (err != CHIP_NO_ERROR) { - EFR32_LOG("Getting QR code failed!"); + EFR32_LOG("BaseApplication::Init() failed"); + appError(err); } -#else - PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); -#endif // QR_CODE_ENABLED return err; } +CHIP_ERROR AppTask::StartAppTask() +{ + return BaseApplication::StartAppTask(AppTaskMain); +} + void AppTask::AppTaskMain(void * pvParameter) { AppEvent event; + QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); CHIP_ERROR err = sAppTask.Init(); if (err != CHIP_NO_ERROR) @@ -289,7 +168,7 @@ void AppTask::AppTaskMain(void * pvParameter) } #if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) - sAppTask.StartLightTimer(); + sAppTask.StartStatusLEDTimer(); #endif EFR32_LOG("App Task started"); @@ -309,7 +188,7 @@ void AppTask::OnIdentifyStart(Identify * identify) ChipLogProgress(Zcl, "onIdentifyStart"); #if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - sAppTask.StartLightTimer(); + sAppTask.StartStatusLEDTimer(); #endif // CHIP_DEVICE_CONFIG_ENABLE_SED } @@ -318,7 +197,7 @@ void AppTask::OnIdentifyStop(Identify * identify) ChipLogProgress(Zcl, "onIdentifyStop"); #if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - sAppTask.CancelLightTimer(); + sAppTask.StopStatusLEDTimer(); #endif // CHIP_DEVICE_CONFIG_ENABLE_SED } @@ -349,295 +228,7 @@ void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAc } else if (buttonHandle == APP_FUNCTION_BUTTON) { - button_event.Handler = ButtonHandler; + button_event.Handler = BaseApplication::ButtonHandler; sAppTask.PostEvent(&button_event); } } - -void AppTask::FunctionTimerEventHandler(TimerHandle_t xTimer) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = (void *) xTimer; - event.Handler = FunctionEventHandler; - sAppTask.PostEvent(&event); -} - -void AppTask::LightTimerEventHandler(TimerHandle_t xTimer) -{ - sAppTask.LightEventHandler(); -} - -void AppTask::FunctionEventHandler(AppEvent * aEvent) -{ - if (aEvent->Type != AppEvent::kEventType_Timer) - { - return; - } - - // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, - // initiate factory reset - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - EFR32_LOG("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to - // cancel, if required. - sAppTask.StartFunctionTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - -#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - sAppTask.StartLightTimer(); -#endif // CHIP_DEVICE_CONFIG_ENABLE_SED - - sAppTask.mFunction = kFunction_FactoryReset; - - // Turn off all LEDs before starting blink to make sure blink is - // co-ordinated. - sStatusLED.Set(false); - sStatusLED.Blink(500); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Actually trigger Factory Reset - sAppTask.mFunction = kFunction_NoneSelected; - -#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - sAppTask.CancelLightTimer(); -#endif // CHIP_DEVICE_CONFIG_ENABLE_SED - - chip::Server::GetInstance().ScheduleFactoryReset(); - } -} - -void AppTask::LightEventHandler() -{ - // Collect connectivity and configuration state from the CHIP stack. Because - // the CHIP event loop is being run in a separate task, the stack must be - // locked while these values are queried. However we use a non-blocking - // lock request (TryLockCHIPStack()) to avoid blocking other UI activities - // when the CHIP task is busy (e.g. with a long crypto operation). -#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) - if (PlatformMgr().TryLockChipStack()) - { -#ifdef SL_WIFI - sIsProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); - sIsEnabled = ConnectivityMgr().IsWiFiStationEnabled(); - sIsAttached = ConnectivityMgr().IsWiFiStationConnected(); -#endif /* SL_WIFI */ -#if CHIP_ENABLE_OPENTHREAD - sIsProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsEnabled = ConnectivityMgr().IsThreadEnabled(); - sIsAttached = ConnectivityMgr().IsThreadAttached(); -#endif /* CHIP_ENABLE_OPENTHREAD */ - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } -#endif // CHIP_DEVICE_CONFIG_ENABLE_SED - - // Update the status LED if factory reset has not been initiated. - // - // If system has "full connectivity", keep the LED On constantly. - // - // If thread and service provisioned, but not attached to the thread network - // yet OR no connectivity to the service OR subscriptions are not fully - // established THEN blink the LED Off for a short period of time. - // - // If the system has ble connection(s) uptill the stage above, THEN blink - // the LEDs at an even rate of 100ms. - // - // Otherwise, blink the LED ON for a very short time. - if (sAppTask.mFunction != kFunction_FactoryReset) - { - if (gIdentify.mActive) - { - sStatusLED.Blink(250, 250); - } - else if (sIdentifyEffect != EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT) - { - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK) - { - sStatusLED.Blink(50, 50); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE) - { - sStatusLED.Blink(1000, 1000); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY) - { - sStatusLED.Blink(300, 700); - } - } -#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) - else if (sIsProvisioned && sIsEnabled) - { - if (sIsAttached) - { - sStatusLED.Set(true); - } - else - { - sStatusLED.Blink(950, 50); - } - } - else if (sHaveBLEConnections) - { - sStatusLED.Blink(100, 100); - } - else - { - sStatusLED.Blink(50, 950); - } -#endif // CHIP_DEVICE_CONFIG_ENABLE_SED - } - - sStatusLED.Animate(); -} - -void AppTask::ButtonHandler(AppEvent * aEvent) -{ - // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< - // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the - // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + - // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after - // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. - // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs - // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT - if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED) - { - if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_NoneSelected) - { - sAppTask.StartFunctionTimer(FACTORY_RESET_TRIGGER_TIMEOUT); - sAppTask.mFunction = kFunction_StartBleAdv; - } - } - else - { - // If the button was released before factory reset got initiated, start BLE advertissement in fast mode - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - sAppTask.CancelFunctionTimer(); - sAppTask.mFunction = kFunction_NoneSelected; - -#ifdef SL_WIFI - if (!ConnectivityMgr().IsWiFiStationProvisioned()) -#else - if (!ConnectivityMgr().IsThreadProvisioned()) -#endif /* !SL_WIFI */ - { - // Enable BLE advertisements - ConnectivityMgr().SetBLEAdvertisingEnabled(true); - ConnectivityMgr().SetBLEAdvertisingMode(ConnectivityMgr().kFastAdvertising); - } - else { EFR32_LOG("Network is already provisioned, Ble advertissement not enabled"); } - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - sAppTask.CancelFunctionTimer(); - -#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 - sAppTask.CancelLightTimer(); -#endif - - // Change the function to none selected since factory reset has been - // canceled. - sAppTask.mFunction = kFunction_NoneSelected; - EFR32_LOG("Factory Reset has been Canceled"); - } - } -} - -void AppTask::CancelFunctionTimer() -{ - if (xTimerStop(sFunctionTimer, 0) == pdFAIL) - { - EFR32_LOG("app timer stop() failed"); - appError(APP_ERROR_STOP_TIMER_FAILED); - } - - mFunctionTimerActive = false; -} - -void AppTask::CancelLightTimer() -{ - sStatusLED.Set(false); - if (xTimerStop(sLightTimer, 100) != pdPASS) - { - EFR32_LOG("Light Time start failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } -} - -void AppTask::StartFunctionTimer(uint32_t aTimeoutInMs) -{ - if (xTimerIsTimerActive(sFunctionTimer)) - { - EFR32_LOG("app timer already started!"); - CancelFunctionTimer(); - } - - // timer is not active, change its period to required value (== restart). - // FreeRTOS- Block for a maximum of 100 ticks if the change period command - // cannot immediately be sent to the timer command queue. - if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) - { - EFR32_LOG("app timer start() failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } - - mFunctionTimerActive = true; -} - -void AppTask::StartLightTimer() -{ - if (pdPASS != xTimerStart(sLightTimer, 0)) - { - EFR32_LOG("Light Time start failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } -} - -void AppTask::PostEvent(const AppEvent * aEvent) -{ - if (sAppEventQueue != NULL) - { - BaseType_t status; - if (xPortIsInsideInterrupt()) - { - BaseType_t higherPrioTaskWoken = pdFALSE; - status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); - -#ifdef portYIELD_FROM_ISR - portYIELD_FROM_ISR(higherPrioTaskWoken); -#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - portEND_SWITCHING_ISR(higherPrioTaskWoken); -#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR -#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" -#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - } - else - { - status = xQueueSend(sAppEventQueue, aEvent, 1); - } - - if (!status) - { - EFR32_LOG("Failed to post event to app task event queue"); - } - } - else - { - EFR32_LOG("Event Queue is NULL should never happen"); - } -} - -void AppTask::DispatchEvent(AppEvent * aEvent) -{ - if (aEvent->Handler) - { - aEvent->Handler(aEvent); - } - else - { - EFR32_LOG("Event received with no handler. Dropping event."); - } -} diff --git a/examples/thermostat/efr32/src/main.cpp b/examples/thermostat/efr32/src/main.cpp index e06d3c4a520416..d2f19619adf86f 100644 --- a/examples/thermostat/efr32/src/main.cpp +++ b/examples/thermostat/efr32/src/main.cpp @@ -66,7 +66,7 @@ int main(void) chip::DeviceLayer::PlatformMgr().UnlockChipStack(); EFR32_LOG("Starting App Task"); - if (GetAppTask().StartAppTask() != CHIP_NO_ERROR) + if (AppTask::GetAppTask().StartAppTask() != CHIP_NO_ERROR) appError(CHIP_ERROR_INTERNAL); EFR32_LOG("Starting FreeRTOS scheduler"); @@ -80,5 +80,5 @@ int main(void) void sl_button_on_change(const sl_button_t * handle) { - GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); + AppTask::GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); }