diff --git a/examples/light-switch-app/silabs/include/AppTask.h b/examples/light-switch-app/silabs/include/AppTask.h index 541e9aa37f..45079a0132 100644 --- a/examples/light-switch-app/silabs/include/AppTask.h +++ b/examples/light-switch-app/silabs/include/AppTask.h @@ -57,6 +57,29 @@ class AppTask : public BaseApplication static AppTask & GetAppTask() { return sAppTask; } + struct Timer + { + typedef void (*Callback)(Timer & timer); + + Timer(uint32_t timeoutInMs, Callback callback, void * context); + ~Timer(); + + void Start(); + void Stop(); + void Timeout(); + + Callback mCallback = nullptr; + void * mContext = nullptr; + bool mIsActive = false; + + osTimerId_t mHandler = nullptr; + + private: + static void TimerCallback(void * timerCbArg); + }; + + Timer * longPressTimer = nullptr; + /** * @brief AppTask task main loop function * @@ -65,6 +88,19 @@ class AppTask : public BaseApplication static void AppTaskMain(void * pvParameter); CHIP_ERROR StartAppTask(); + /** + * @brief Event handler when a button is pressed + * Function posts an event for button processing + * + * @param buttonHandle BTN0 or BTN1 + * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, + * SL_SIMPLE_BUTTON_RELEASED or SL_SIMPLE_BUTTON_DISABLED + */ + static void ButtonEventHandler(uint8_t button, uint8_t btnAction); + + AppEvent CreateNewEvent(AppEvent::AppEventTypes type); + + static void AppEventHandler(AppEvent * aEvent); private: static AppTask sAppTask; @@ -75,4 +111,20 @@ class AppTask : public BaseApplication * @return CHIP_ERROR */ CHIP_ERROR Init(); + + /** + * @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 OnLongPressTimeout(Timer & timer); + + /** + * @brief This function will be called when PB1 is + * long-pressed to trigger the level-control action + */ + void HandleLongPress(); }; diff --git a/examples/light-switch-app/silabs/include/LightSwitchMgr.h b/examples/light-switch-app/silabs/include/LightSwitchMgr.h index e5bf3b33db..26e7af5af1 100644 --- a/examples/light-switch-app/silabs/include/LightSwitchMgr.h +++ b/examples/light-switch-app/silabs/include/LightSwitchMgr.h @@ -52,84 +52,36 @@ class LightSwitchMgr .stepSize = 1, .transitionTime = 0, .optionsMask = 0, .optionsOverride = 0 }; - struct Timer - { - typedef void (*Callback)(Timer & timer); - - Timer(uint32_t timeoutInMs, Callback callback, void * context); - ~Timer(); - - void Start(); - void Stop(); - void Timeout(); - - Callback mCallback = nullptr; - void * mContext = nullptr; - bool mIsActive = false; - - osTimerId_t mHandler = nullptr; - - private: - static void TimerCallback(void * timerCbArg); - }; - CHIP_ERROR Init(chip::EndpointId lightSwitchEndpoint, chip::EndpointId genericSwitchEndpoint); void GenericSwitchOnInitialPress(); void GenericSwitchOnShortRelease(); + /** + * @brief 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); + void TriggerLightSwitchAction(LightSwitchAction action, bool isGroupCommand = false); void TriggerLevelControlAction(StepModeEnum stepMode, bool isGroupCommand = false); StepModeEnum getStepMode(); - - AppEvent CreateNewEvent(AppEvent::AppEventTypes type); + void changeStepMode(); static LightSwitchMgr & GetInstance() { return sSwitch; } - /** - * @brief Event handler when a button is pressed - * Function posts an event for button processing - * - * @param button BUTTON0 or BUTTON1 - * @param btnAction button action - SL_SIMPLE_BUTTON_PRESSED, - * SL_SIMPLE_BUTTON_RELEASED - */ - static void ButtonEventHandler(uint8_t button, uint8_t btnAction); - - static void AppEventHandler(AppEvent * aEvent); - private: static LightSwitchMgr sSwitch; - Timer * mLongPressTimer = nullptr; - bool mFunctionButtonPressed = false; // True when button0 is pressed, used to trigger factory reset - bool mActionButtonPressed = false; // True when button1 is pressed, used to initiate toggle or level-up/down - bool mActionButtonSuppressed = false; // True when both button0 and button1 are pressed, used to switch step direction - bool mResetWarning = false; - // Default Step direction for Level control StepModeEnum stepDirection = StepModeEnum::kUp; - - static void OnLongPressTimeout(Timer & timer); - LightSwitchMgr() = default; - - /** - * @brief This function will be called when PB0 is - * long-pressed to trigger the factory-reset - */ - void HandleLongPress(); + LightSwitchMgr() = default; static void GenericSwitchWorkerFunction(intptr_t context); chip::EndpointId mLightSwitchEndpoint = chip::kInvalidEndpointId; chip::EndpointId mGenericSwitchEndpoint = chip::kInvalidEndpointId; - - /** - * @brief 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); }; diff --git a/examples/light-switch-app/silabs/src/AppTask.cpp b/examples/light-switch-app/silabs/src/AppTask.cpp index c3a32415ab..3a3b285c80 100644 --- a/examples/light-switch-app/silabs/src/AppTask.cpp +++ b/examples/light-switch-app/silabs/src/AppTask.cpp @@ -67,11 +67,15 @@ using namespace ::chip::DeviceLayer; *********************************************************/ AppTask AppTask::sAppTask; +bool sFunctionButtonPressed = false; // True when button0 is pressed, used to trigger factory reset +bool sActionButtonPressed = false; // True when button1 is pressed, used to initiate toggle or level-up/down +bool sActionButtonSuppressed = false; // True when both button0 and button1 are pressed, used to switch step direction +bool sIsButtonEventTriggered = false; // True when button0 press event is posted to BaseApplication CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; - chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(LightSwitchMgr::ButtonEventHandler); + chip::DeviceLayer::Silabs::GetPlatform().SetButtonsCb(AppTask::ButtonEventHandler); #ifdef DISPLAY_ENABLED GetLCD().Init((uint8_t *) "Light Switch"); @@ -91,9 +95,98 @@ CHIP_ERROR AppTask::Init() appError(err); } + longPressTimer = new Timer(LONG_PRESS_TIMEOUT, OnLongPressTimeout, this); + return err; } +void AppTask::Timer::Start() +{ + // Starts or restarts the function timer + if (osTimerStart(mHandler, pdMS_TO_TICKS(LONG_PRESS_TIMEOUT)) != osOK) + { + SILABS_LOG("Timer start() failed"); + appError(CHIP_ERROR_INTERNAL); + } + + mIsActive = true; +} + +void AppTask::Timer::Timeout() +{ + mIsActive = false; + if (mCallback) + { + mCallback(*this); + } +} + +void AppTask::HandleLongPress() +{ + AppEvent event; + event.Handler = AppTask::AppEventHandler; + + if (sActionButtonPressed) + { + sActionButtonSuppressed = true; + // Long press button up : Trigger Level Control Action + event.Type = AppEvent::kEventType_TriggerLevelControlAction; + AppTask::GetAppTask().PostEvent(&event); + } +} + +void AppTask::OnLongPressTimeout(AppTask::Timer & timer) +{ + AppTask * app = static_cast(timer.mContext); + if (app) + { + app->HandleLongPress(); + } +} + +AppTask::Timer::Timer(uint32_t timeoutInMs, Callback callback, void * context) : mCallback(callback), mContext(context) +{ + mHandler = osTimerNew(TimerCallback, // timer callback handler + osTimerOnce, // no timer reload (one-shot timer) + this, // pass the app task obj context + NULL // No osTimerAttr_t to provide. + ); + + if (mHandler == NULL) + { + SILABS_LOG("Timer create failed"); + appError(CHIP_ERROR_INTERNAL); + } +} + +AppTask::Timer::~Timer() +{ + if (mHandler) + { + osTimerDelete(mHandler); + mHandler = nullptr; + } +} + +void AppTask::Timer::Stop() +{ + mIsActive = false; + if (osTimerStop(mHandler) == osError) + { + SILABS_LOG("Timer stop() failed"); + appError(CHIP_ERROR_INTERNAL); + } +} + +void AppTask::Timer::TimerCallback(void * timerCbArg) +{ + Timer * timer = reinterpret_cast(timerCbArg); + if (timer) + { + timer->Timeout(); + } +} + CHIP_ERROR AppTask::StartAppTask() { return BaseApplication::StartAppTask(AppTaskMain); @@ -126,3 +219,109 @@ void AppTask::AppTaskMain(void * pvParameter) } } } + +AppEvent AppTask::CreateNewEvent(AppEvent::AppEventTypes type) +{ + AppEvent aEvent; + aEvent.Type = type; + aEvent.Handler = AppTask::AppEventHandler; + return aEvent; +} + +void AppTask::ButtonEventHandler(uint8_t button, uint8_t btnAction) +{ + AppEvent event = {}; + if (btnAction == to_underlying(SilabsPlatform::ButtonAction::ButtonPressed)) + { + event = AppTask::GetAppTask().CreateNewEvent(button ? AppEvent::kEventType_ActionButtonPressed + : AppEvent::kEventType_FunctionButtonPressed); + } + else + { + event = AppTask::GetAppTask().CreateNewEvent(button ? AppEvent::kEventType_ActionButtonReleased + : AppEvent::kEventType_FunctionButtonReleased); + } + AppTask::GetAppTask().PostEvent(&event); +} + +void AppTask::AppEventHandler(AppEvent * aEvent) +{ + switch (aEvent->Type) + { + case AppEvent::kEventType_FunctionButtonPressed: + sFunctionButtonPressed = true; + if (sActionButtonPressed) + { + sActionButtonSuppressed = true; + LightSwitchMgr::GetInstance().changeStepMode(); + ChipLogProgress(AppServer, "Step direction changed. Current Step Direction : %s", + ((LightSwitchMgr::GetInstance().getStepMode() == StepModeEnum::kUp) ? "kUp" : "kDown")); + } + else + { + sIsButtonEventTriggered = true; + // Post button press event to BaseApplication + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Action = static_cast(SilabsPlatform::ButtonAction::ButtonPressed); + button_event.Handler = BaseApplication::ButtonHandler; + AppTask::GetAppTask().PostEvent(&button_event); + } + break; + case AppEvent::kEventType_FunctionButtonReleased: { + sFunctionButtonPressed = false; + if (sIsButtonEventTriggered) + { + sIsButtonEventTriggered = false; + // Post button release event to BaseApplication + AppEvent button_event = {}; + button_event.Type = AppEvent::kEventType_Button; + button_event.ButtonEvent.Action = static_cast(SilabsPlatform::ButtonAction::ButtonReleased); + button_event.Handler = BaseApplication::ButtonHandler; + AppTask::GetAppTask().PostEvent(&button_event); + } + break; + } + case AppEvent::kEventType_ActionButtonPressed: + sActionButtonPressed = true; + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + if (sFunctionButtonPressed) + { + sActionButtonSuppressed = true; + LightSwitchMgr::GetInstance().changeStepMode(); + ChipLogProgress(AppServer, "Step direction changed. Current Step Direction : %s", + ((LightSwitchMgr::GetInstance().getStepMode() == StepModeEnum::kUp) ? "kUp" : "kDown")); + } + else if (sAppTask.longPressTimer) + { + sAppTask.longPressTimer->Start(); + } + break; + case AppEvent::kEventType_ActionButtonReleased: + sActionButtonPressed = false; + if (sAppTask.longPressTimer) + { + sAppTask.longPressTimer->Stop(); + } + if (sActionButtonSuppressed) + { + sActionButtonSuppressed = false; + } + else + { + aEvent->Type = AppEvent::kEventType_TriggerToggle; + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + } + aEvent->Type = AppEvent::kEventType_ActionButtonReleased; + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + break; + case AppEvent::kEventType_TriggerLevelControlAction: + aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; + AppTask::GetAppTask().PostEvent(aEvent); + default: + break; + } +} diff --git a/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp b/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp index 4c0ee0cad6..85b8a1ce1e 100644 --- a/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp +++ b/examples/light-switch-app/silabs/src/LightSwitchMgr.cpp @@ -43,113 +43,6 @@ using namespace chip::DeviceLayer::Silabs; LightSwitchMgr LightSwitchMgr::sSwitch; -AppEvent LightSwitchMgr::CreateNewEvent(AppEvent::AppEventTypes type) -{ - AppEvent aEvent; - aEvent.Type = type; - aEvent.Handler = LightSwitchMgr::AppEventHandler; - LightSwitchMgr * lightSwitch = &LightSwitchMgr::GetInstance(); - aEvent.LightSwitchEvent.Context = lightSwitch; - return aEvent; -} - -void LightSwitchMgr::Timer::Start() -{ - // Starts or restarts the function timer - if (osTimerStart(mHandler, pdMS_TO_TICKS(LONG_PRESS_TIMEOUT)) != osOK) - { - SILABS_LOG("Timer start() failed"); - appError(CHIP_ERROR_INTERNAL); - } - - mIsActive = true; -} - -void LightSwitchMgr::Timer::Timeout() -{ - mIsActive = false; - if (mCallback) - { - mCallback(*this); - } -} - -void LightSwitchMgr::HandleLongPress() -{ - AppEvent event; - event.Handler = AppEventHandler; - LightSwitchMgr * lightSwitch = &LightSwitchMgr::GetInstance(); - event.LightSwitchEvent.Context = lightSwitch; - if (mFunctionButtonPressed) - { - if (!mResetWarning) - { - // Long press button down: Reset warning! - event.Type = AppEvent::kEventType_ResetWarning; - AppTask::GetAppTask().PostEvent(&event); - } - } - else if (mActionButtonPressed) - { - mActionButtonSuppressed = true; - // Long press button up : Trigger Level Control Action - event.Type = AppEvent::kEventType_TriggerLevelControlAction; - AppTask::GetAppTask().PostEvent(&event); - } -} - -void LightSwitchMgr::OnLongPressTimeout(LightSwitchMgr::Timer & timer) -{ - LightSwitchMgr * app = static_cast(timer.mContext); - if (app) - { - app->HandleLongPress(); - } -} - -LightSwitchMgr::Timer::Timer(uint32_t timeoutInMs, Callback callback, void * context) : mCallback(callback), mContext(context) -{ - mHandler = osTimerNew(TimerCallback, // timer callback handler - osTimerOnce, // no timer reload (one-shot timer) - this, // pass the app task obj context - NULL // No osTimerAttr_t to provide. - ); - - if (mHandler == NULL) - { - SILABS_LOG("Timer create failed"); - appError(CHIP_ERROR_INTERNAL); - } -} - -LightSwitchMgr::Timer::~Timer() -{ - if (mHandler) - { - osTimerDelete(mHandler); - mHandler = nullptr; - } -} - -void LightSwitchMgr::Timer::Stop() -{ - mIsActive = false; - if (osTimerStop(mHandler) == osError) - { - SILABS_LOG("Timer stop() failed"); - appError(CHIP_ERROR_INTERNAL); - } -} - -void LightSwitchMgr::Timer::TimerCallback(void * timerCbArg) -{ - Timer * timer = reinterpret_cast(timerCbArg); - if (timer) - { - timer->Timeout(); - } -} - /** * @brief Configures LightSwitchMgr * This function needs to be call before using the LightSwitchMgr @@ -165,8 +58,6 @@ CHIP_ERROR LightSwitchMgr::Init(EndpointId lightSwitchEndpoint, chip::EndpointId mLightSwitchEndpoint = lightSwitchEndpoint; mGenericSwitchEndpoint = genericSwitchEndpoint; - mLongPressTimer = new Timer(LONG_PRESS_TIMEOUT, OnLongPressTimeout, this); - // Configure Bindings CHIP_ERROR error = InitBindingHandler(); if (error != CHIP_NO_ERROR) @@ -213,6 +104,11 @@ StepModeEnum LightSwitchMgr::getStepMode() return stepDirection; } +void LightSwitchMgr::changeStepMode() +{ + stepDirection = (stepDirection == StepModeEnum::kUp) ? StepModeEnum::kDown : StepModeEnum::kUp; +} + void LightSwitchMgr::TriggerLightSwitchAction(LightSwitchAction action, bool isGroupCommand) { BindingCommandData * data = Platform::New(); @@ -295,107 +191,6 @@ void LightSwitchMgr::GenericSwitchWorkerFunction(intptr_t context) Platform::Delete(data); } -void LightSwitchMgr::ButtonEventHandler(uint8_t button, uint8_t btnAction) -{ - AppEvent event = {}; - if (btnAction == to_underlying(SilabsPlatform::ButtonAction::ButtonPressed)) - { - event = LightSwitchMgr::GetInstance().CreateNewEvent(button ? AppEvent::kEventType_ActionButtonPressed - : AppEvent::kEventType_FunctionButtonPressed); - } - else - { - event = LightSwitchMgr::GetInstance().CreateNewEvent(button ? AppEvent::kEventType_ActionButtonReleased - : AppEvent::kEventType_FunctionButtonReleased); - } - AppTask::GetAppTask().PostEvent(&event); -} - -void LightSwitchMgr::AppEventHandler(AppEvent * aEvent) -{ - LightSwitchMgr * lightSwitch = static_cast(aEvent->LightSwitchEvent.Context); - switch (aEvent->Type) - { - case AppEvent::kEventType_ResetWarning: - lightSwitch->mResetWarning = true; - AppTask::GetAppTask().StartFactoryResetSequence(); - break; - case AppEvent::kEventType_ResetCanceled: - lightSwitch->mResetWarning = false; - AppTask::GetAppTask().CancelFactoryResetSequence(); - break; - case AppEvent::kEventType_FunctionButtonPressed: - lightSwitch->mFunctionButtonPressed = true; - if (lightSwitch->mLongPressTimer) - { - lightSwitch->mLongPressTimer->Start(); - } - if (lightSwitch->mActionButtonPressed) - { - lightSwitch->mActionButtonSuppressed = true; - lightSwitch->stepDirection = - (lightSwitch->stepDirection == StepModeEnum::kUp) ? StepModeEnum::kDown : StepModeEnum::kUp; - ChipLogProgress(AppServer, "Step direction changed. Current Step Direction : %s", - ((lightSwitch->stepDirection == StepModeEnum::kUp) ? "kUp" : "kDown")); - } - break; - case AppEvent::kEventType_FunctionButtonReleased: - lightSwitch->mFunctionButtonPressed = false; - if (lightSwitch->mLongPressTimer) - { - lightSwitch->mLongPressTimer->Stop(); - } - if (lightSwitch->mResetWarning) - { - aEvent->Type = AppEvent::kEventType_ResetCanceled; - AppTask::GetAppTask().PostEvent(aEvent); - } - break; - case AppEvent::kEventType_ActionButtonPressed: - lightSwitch->mActionButtonPressed = true; - aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; - AppTask::GetAppTask().PostEvent(aEvent); - if (lightSwitch->mLongPressTimer) - { - lightSwitch->mLongPressTimer->Start(); - } - if (lightSwitch->mFunctionButtonPressed) - { - lightSwitch->mActionButtonSuppressed = true; - lightSwitch->stepDirection = - (lightSwitch->stepDirection == StepModeEnum::kUp) ? StepModeEnum::kDown : StepModeEnum::kUp; - ChipLogProgress(AppServer, "Step direction changed. Current Step Direction : %s", - ((lightSwitch->stepDirection == StepModeEnum::kUp) ? "kUp" : "kDown")); - } - break; - case AppEvent::kEventType_ActionButtonReleased: - lightSwitch->mActionButtonPressed = false; - if (lightSwitch->mLongPressTimer) - { - lightSwitch->mLongPressTimer->Stop(); - } - if (lightSwitch->mActionButtonSuppressed) - { - lightSwitch->mActionButtonSuppressed = false; - } - else - { - aEvent->Type = AppEvent::kEventType_TriggerToggle; - aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; - AppTask::GetAppTask().PostEvent(aEvent); - } - aEvent->Type = AppEvent::kEventType_ActionButtonReleased; - aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; - AppTask::GetAppTask().PostEvent(aEvent); - break; - case AppEvent::kEventType_TriggerLevelControlAction: - aEvent->Handler = LightSwitchMgr::SwitchActionEventHandler; - AppTask::GetAppTask().PostEvent(aEvent); - default: - break; - } -} - void LightSwitchMgr::SwitchActionEventHandler(AppEvent * aEvent) { switch (aEvent->Type)