diff --git a/applications/matter_weather_station/src/app_event.h b/applications/matter_weather_station/src/app_event.h index d826d70b6db..f02ad25d170 100644 --- a/applications/matter_weather_station/src/app_event.h +++ b/applications/matter_weather_station/src/app_event.h @@ -6,18 +6,35 @@ #pragma once +#include + struct AppEvent { - enum class Type { - kButtonPush, - kButtonRelease, - kTimer, + enum FunctionEventType : uint8_t { + FunctionPress, + FunctionRelease, + FunctionTimer, + MeasurementsTimer, + }; + + enum UpdateLedStateEventType : uint8_t { UpdateLedState = MeasurementsTimer + 1 }; + + enum OtherEventType : uint8_t { #ifdef CONFIG_MCUMGR_SMP_BT - kStartSMPAdvertising + StartSMPAdvertising = UpdateLedState + 1 #endif }; - using Handler = void (*)(AppEvent *); + AppEvent() = default; + + explicit AppEvent(FunctionEventType type) : Type(type) {} + + AppEvent(UpdateLedStateEventType type, LEDWidget *ledWidget) : Type(type), UpdateLedStateEvent{ ledWidget } {} + + explicit AppEvent(OtherEventType type) : Type(type) {} + + uint8_t Type; - Type mType; - Handler mHandler; + struct { + LEDWidget *LedWidget; + } UpdateLedStateEvent; }; diff --git a/applications/matter_weather_station/src/app_task.cpp b/applications/matter_weather_station/src/app_task.cpp index 6e2992b4f9e..3bc1967250e 100644 --- a/applications/matter_weather_station/src/app_task.cpp +++ b/applications/matter_weather_station/src/app_task.cpp @@ -75,10 +75,14 @@ int AppTask::Init() { /* Initialize RGB LED */ LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); + sRedLED.Init(DK_LED1); sGreenLED.Init(DK_LED2); sBlueLED.Init(DK_LED3); + UpdateStatusLED(); + /* Initialize buttons */ int ret = dk_buttons_init(ButtonStateHandler); if (ret) { @@ -99,11 +103,10 @@ int AppTask::Init() /* Initialize timers */ k_timer_init( - &sFunctionTimer, [](k_timer *) { sAppTask.PostEvent(AppEvent::Type::kTimer, FunctionTimerHandler); }, - nullptr); + &sFunctionTimer, [](k_timer *) { sAppTask.PostEvent(AppEvent{ AppEvent::FunctionTimer }); }, nullptr); k_timer_init( - &sMeasurementsTimer, - [](k_timer *) { sAppTask.PostEvent(AppEvent::Type::kTimer, MeasurementsTimerHandler); }, nullptr); + &sMeasurementsTimer, [](k_timer *) { sAppTask.PostEvent(AppEvent{ AppEvent::MeasurementsTimer }); }, + nullptr); k_timer_start(&sMeasurementsTimer, K_MSEC(kMeasurementsIntervalMs), K_MSEC(kMeasurementsIntervalMs)); /* Init ZCL Data Model and start server */ @@ -152,61 +155,65 @@ int AppTask::StartApp() AppEvent event = {}; while (true) { - ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10)); + ret = k_msgq_get(&sAppEventQueue, &event, K_FOREVER); while (!ret) { - DispatchEvent(&event); + DispatchEvent(event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - if (PlatformMgr().TryLockChipStack()) { - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); - sIsBleAdvertisingEnabled = ConnectivityMgr().IsBLEAdvertisingEnabled(); - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - UpdateLedState(); } } -void AppTask::PostEvent(const AppEvent *event) +void AppTask::PostEvent(const AppEvent &event) { - if (k_msgq_put(&sAppEventQueue, event, K_NO_WAIT)) { + if (k_msgq_put(&sAppEventQueue, &event, K_NO_WAIT)) { LOG_ERR("Failed to post event to app task event queue"); } } -void AppTask::PostEvent(AppEvent::Type type, AppEvent::Handler handler) -{ - AppEvent event; - event.mType = type; - event.mHandler = handler; - PostEvent(&event); -} - #ifdef CONFIG_MCUMGR_SMP_BT void AppTask::RequestSMPAdvertisingStart(void) { - sAppTask.PostEvent(AppEvent::Type::kStartSMPAdvertising, - [](AppEvent *) { GetDFUOverSMP().StartBLEAdvertising(); }); + sAppTask.PostEvent(AppEvent{ AppEvent::StartSMPAdvertising }); } #endif -void AppTask::DispatchEvent(AppEvent *event) +void AppTask::DispatchEvent(AppEvent &event) { - assert(event->mHandler); - event->mHandler(event); + switch (event.Type) { + case AppEvent::FunctionPress: + ButtonPushHandler(); + break; + case AppEvent::FunctionRelease: + ButtonReleaseHandler(); + break; + case AppEvent::FunctionTimer: + FunctionTimerHandler(); + break; + case AppEvent::MeasurementsTimer: + MeasurementsTimerHandler(); + break; + case AppEvent::UpdateLedState: + event.UpdateLedStateEvent.LedWidget->UpdateState(); + break; +#ifdef CONFIG_MCUMGR_SMP_BT + case AppEvent::StartSMPAdvertising: + GetDFUOverSMP().StartBLEAdvertising(); + break; +#endif + default: + LOG_INF("Unknown event received"); + break; + } } -void AppTask::ButtonPushHandler(AppEvent *) +void AppTask::ButtonPushHandler() { sFunctionTimerMode = FunctionTimerMode::kFactoryResetTrigger; k_timer_start(&sFunctionTimer, K_MSEC(kFactoryResetTriggerTimeoutMs), K_NO_WAIT); } -void AppTask::ButtonReleaseHandler(AppEvent *) +void AppTask::ButtonReleaseHandler() { /* If the button was released within the first kFactoryResetTriggerTimeoutMs, open the BLE pairing * window. */ @@ -222,13 +229,13 @@ void AppTask::ButtonStateHandler(uint32_t buttonState, uint32_t hasChanged) { if (hasChanged & DK_BTN1_MSK) { if (buttonState & DK_BTN1_MSK) - sAppTask.PostEvent(AppEvent::Type::kButtonPush, ButtonPushHandler); + sAppTask.PostEvent(AppEvent{ AppEvent::FunctionPress }); else - sAppTask.PostEvent(AppEvent::Type::kButtonRelease, ButtonReleaseHandler); + sAppTask.PostEvent(AppEvent{ AppEvent::FunctionRelease }); } } -void AppTask::FunctionTimerHandler(AppEvent *) +void AppTask::FunctionTimerHandler() { switch (sFunctionTimerMode) { case FunctionTimerMode::kFactoryResetTrigger: @@ -245,7 +252,7 @@ void AppTask::FunctionTimerHandler(AppEvent *) } } -void AppTask::MeasurementsTimerHandler(AppEvent *) +void AppTask::MeasurementsTimerHandler() { sAppTask.UpdateClusterState(); } @@ -335,7 +342,7 @@ void AppTask::UpdateClusterState() } } -void AppTask::UpdateLedState() +void AppTask::UpdateStatusLED() { LedState nextState; @@ -374,26 +381,39 @@ void AppTask::UpdateLedState() default: break; } +} - sGreenLED.Animate(); - sBlueLED.Animate(); - sRedLED.Animate(); +void AppTask::LEDStateUpdateHandler(LEDWidget &ledWidget) +{ + sAppTask.PostEvent(AppEvent{ AppEvent::UpdateLedState, &ledWidget }); } -#ifdef CONFIG_CHIP_NFC_COMMISSIONING void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) { - if (event->Type != DeviceEventType::kCHIPoBLEAdvertisingChange) - return; - - if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) { - if (NFCMgr().IsTagEmulationStarted()) { - LOG_INF("NFC Tag emulation is already started"); - } else { - ShareQRCodeOverNFC(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + switch (event->Type) { + case DeviceEventType::kCHIPoBLEAdvertisingChange: +#ifdef CONFIG_CHIP_NFC_COMMISSIONING + if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) { + if (NFCMgr().IsTagEmulationStarted()) { + LOG_INF("NFC Tag emulation is already started"); + } else { + ShareQRCodeOverNFC( + chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + } + } else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) { + NFCMgr().StopTagEmulation(); } - } else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) { - NFCMgr().StopTagEmulation(); +#endif + sIsBleAdvertisingEnabled = ConnectivityMgr().IsBLEAdvertisingEnabled(); + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + UpdateStatusLED(); + break; + default: + break; } } -#endif diff --git a/applications/matter_weather_station/src/app_task.h b/applications/matter_weather_station/src/app_task.h index c7a42e3c72b..f1e4365a75c 100644 --- a/applications/matter_weather_station/src/app_task.h +++ b/applications/matter_weather_station/src/app_task.h @@ -7,6 +7,7 @@ #pragma once #include "app_event.h" +#include "led_widget.h" #include @@ -20,26 +21,26 @@ class AppTask { public: int StartApp(); - void PostEvent(const AppEvent *aEvent); - void PostEvent(AppEvent::Type type, AppEvent::Handler handler); + void PostEvent(const AppEvent &aEvent); void UpdateClusterState(); - void UpdateLedState(); private: friend AppTask &GetAppTask(); int Init(); void OpenPairingWindow(); - void DispatchEvent(AppEvent *event); + void DispatchEvent(AppEvent &event); #ifdef CONFIG_MCUMGR_SMP_BT static void RequestSMPAdvertisingStart(void); #endif static void ButtonStateHandler(uint32_t buttonState, uint32_t hasChanged); - static void ButtonPushHandler(AppEvent *event); - static void ButtonReleaseHandler(AppEvent *event); - static void FunctionTimerHandler(AppEvent *event); - static void MeasurementsTimerHandler(AppEvent *event); + static void ButtonPushHandler(); + static void ButtonReleaseHandler(); + static void FunctionTimerHandler(); + static void MeasurementsTimerHandler(); + static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget &ledWidget); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *event, intptr_t arg); static AppTask sAppTask; diff --git a/samples/matter/common/src/led_widget.cpp b/samples/matter/common/src/led_widget.cpp index a8bf592dd73..3bb7ac6c69f 100644 --- a/samples/matter/common/src/led_widget.cpp +++ b/samples/matter/common/src/led_widget.cpp @@ -9,11 +9,19 @@ #include #include +static LEDWidget::LEDWidgetStateUpdateHandler sStateUpdateCallback; + void LEDWidget::InitGpio() { dk_leds_init(); } +void LEDWidget::SetStateUpdateCallback(LEDWidgetStateUpdateHandler stateUpdateCb) +{ + if (stateUpdateCb) + sStateUpdateCallback = stateUpdateCb; +} + void LEDWidget::Init(uint32_t gpioNum) { mLastChangeTimeMS = 0; @@ -21,6 +29,10 @@ void LEDWidget::Init(uint32_t gpioNum) mBlinkOffTimeMS = 0; mGPIONum = gpioNum; mState = false; + + k_timer_init(&mLedTimer, &LEDWidget::LedStateTimerHandler, nullptr); + k_timer_user_data_set(&mLedTimer, this); + Set(false); } @@ -31,12 +43,14 @@ void LEDWidget::Invert() void LEDWidget::Set(bool state) { + k_timer_stop(&mLedTimer); mLastChangeTimeMS = mBlinkOnTimeMS = mBlinkOffTimeMS = 0; DoSet(state); } void LEDWidget::Blink(uint32_t changeRateMS) { + k_timer_stop(&mLedTimer); Blink(changeRateMS, changeRateMS); } @@ -44,24 +58,32 @@ void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) { mBlinkOnTimeMS = onTimeMS; mBlinkOffTimeMS = offTimeMS; - Animate(); -} -void LEDWidget::Animate() -{ if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) { - int64_t nowMS = k_uptime_get(); - int64_t stateDurMS = mState ? mBlinkOnTimeMS : mBlinkOffTimeMS; - - if (nowMS > mLastChangeTimeMS + stateDurMS) { - DoSet(!mState); - mLastChangeTimeMS = nowMS; - } + DoSet(!mState); + ScheduleStateChange(); } } +void LEDWidget::ScheduleStateChange() +{ + k_timer_start(&mLedTimer, K_MSEC(mState ? mBlinkOnTimeMS : mBlinkOffTimeMS), K_NO_WAIT); +} + void LEDWidget::DoSet(bool state) { mState = state; dk_set_led(mGPIONum, state); } + +void LEDWidget::UpdateState() +{ + DoSet(!mState); + ScheduleStateChange(); +} + +void LEDWidget::LedStateTimerHandler(k_timer *timer) +{ + if (sStateUpdateCallback) + sStateUpdateCallback(*reinterpret_cast(timer->user_data)); +} diff --git a/samples/matter/common/src/led_widget.h b/samples/matter/common/src/led_widget.h index f288d5355a4..973c45e9869 100644 --- a/samples/matter/common/src/led_widget.h +++ b/samples/matter/common/src/led_widget.h @@ -8,15 +8,20 @@ #include +#include + class LEDWidget { public: + typedef void (*LEDWidgetStateUpdateHandler)(LEDWidget &ledWidget); + static void InitGpio(); + static void SetStateUpdateCallback(LEDWidgetStateUpdateHandler stateUpdateCb); void Init(uint32_t gpioNum); void Set(bool state); void Invert(); void Blink(uint32_t changeRateMS); void Blink(uint32_t onTimeMS, uint32_t offTimeMS); - void Animate(); + void UpdateState(); private: int64_t mLastChangeTimeMS; @@ -24,6 +29,10 @@ class LEDWidget { uint32_t mBlinkOffTimeMS; uint32_t mGPIONum; bool mState; + k_timer mLedTimer; + + static void LedStateTimerHandler(k_timer *timer); void DoSet(bool state); + void ScheduleStateChange(); }; diff --git a/samples/matter/light_bulb/src/app_event.h b/samples/matter/light_bulb/src/app_event.h index 1fbc613e27a..f53074c08e4 100644 --- a/samples/matter/light_bulb/src/app_event.h +++ b/samples/matter/light_bulb/src/app_event.h @@ -8,13 +8,17 @@ #include +#include "led_widget.h" + struct AppEvent { enum LightEventType : uint8_t { On, Off, Toggle, Level }; enum FunctionEventType : uint8_t { FunctionPress = Level + 1, FunctionRelease, FunctionTimer }; + enum UpdateLedStateEventType : uint8_t { UpdateLedState = FunctionTimer + 1 }; + enum OtherEventType : uint8_t { - StartThread = FunctionTimer + 1, + StartThread = UpdateLedState + 1, StartBleAdvertising, PublishLightBulbService, #ifdef CONFIG_MCUMGR_SMP_BT @@ -31,6 +35,8 @@ struct AppEvent { AppEvent(FunctionEventType type) : Type(type) {} + AppEvent(UpdateLedStateEventType type, LEDWidget *ledWidget) : Type(type), UpdateLedStateEvent{ ledWidget } {} + AppEvent(OtherEventType type) : Type(type) {} uint8_t Type; @@ -42,5 +48,8 @@ struct AppEvent { /* was the event triggered by CHIP Data Model layer */ bool ChipInitiated; } LightEvent; + struct { + LEDWidget *LedWidget; + } UpdateLedStateEvent; }; }; diff --git a/samples/matter/light_bulb/src/app_task.cpp b/samples/matter/light_bulb/src/app_task.cpp index 635d0e0fe84..582f5ff68b5 100644 --- a/samples/matter/light_bulb/src/app_task.cpp +++ b/samples/matter/light_bulb/src/app_task.cpp @@ -61,6 +61,7 @@ int AppTask::Init() { /* Initialize LEDs */ LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(DK_LED1); sLightLED.Init(DK_LED2); @@ -68,6 +69,8 @@ int AppTask::Init() sUnusedLED.Init(DK_LED3); sUnusedLED_1.Init(DK_LED4); + UpdateStatusLED(); + /* Initialize buttons */ int ret = dk_buttons_init(ButtonEventHandler); if (ret) { @@ -120,45 +123,12 @@ int AppTask::StartApp() AppEvent event = {}; while (true) { - ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10)); + ret = k_msgq_get(&sAppEventQueue, &event, K_FOREVER); while (!ret) { DispatchEvent(event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - /* 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()) { - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - /* Update the status LED. - * - * If thread and service provisioned, keep the LED On constantly. - * - * If the system has ble connection(s) uptill the stage above, THEN blink the LED at an even - * rate of 100ms. - * - * Otherwise, blink the LED On for a very short time. */ - if (sIsThreadProvisioned && sIsThreadEnabled) { - sStatusLED.Set(true); - } else if (sHaveBLEConnections) { - sStatusLED.Blink(100, 100); - } else { - sStatusLED.Blink(50, 950); - } - - sStatusLED.Animate(); - sUnusedLED.Animate(); - sUnusedLED_1.Animate(); } } @@ -211,7 +181,7 @@ void AppTask::DispatchEvent(const AppEvent &aEvent) break; case AppEvent::Toggle: LightingMgr().InitiateAction(LightingMgr().IsTurnedOn() ? LightingManager::Action::Off : - LightingManager::Action::On, + LightingManager::Action::On, aEvent.LightEvent.Value, aEvent.LightEvent.ChipInitiated); break; case AppEvent::Level: @@ -233,6 +203,9 @@ void AppTask::DispatchEvent(const AppEvent &aEvent) case AppEvent::StartBleAdvertising: StartBLEAdvertisingHandler(); break; + case AppEvent::UpdateLedState: + aEvent.UpdateLedStateEvent.LedWidget->UpdateState(); + break; #ifdef CONFIG_MCUMGR_SMP_BT case AppEvent::StartSMPAdvertising: GetDFUOverSMP().StartBLEAdvertising(); @@ -295,6 +268,8 @@ void AppTask::FunctionReleaseHandler() sUnusedLED_1.Set(false); sUnusedLED.Set(false); + UpdateStatusLED(); + sAppTask.CancelFunctionTimer(); sAppTask.mFunction = TimerFunction::NoneSelected; LOG_INF("Factory Reset has been Canceled"); @@ -359,23 +334,58 @@ void AppTask::StartBLEAdvertisingHandler() } } -#ifdef CONFIG_CHIP_NFC_COMMISSIONING -void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) +void AppTask::LEDStateUpdateHandler(LEDWidget &ledWidget) { - if (event->Type != DeviceEventType::kCHIPoBLEAdvertisingChange) - return; + sAppTask.PostEvent(AppEvent{ AppEvent::UpdateLedState, &ledWidget }); +} - if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) { - if (NFCMgr().IsTagEmulationStarted()) { - LOG_INF("NFC Tag emulation is already started"); - } else { - ShareQRCodeOverNFC(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); - } - } else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) { - NFCMgr().StopTagEmulation(); +void AppTask::UpdateStatusLED() +{ + /* Update the status LED. + * + * If thread and service provisioned, keep the LED On constantly. + * + * If the system has ble connection(s) uptill the stage above, THEN blink the LED at an even + * rate of 100ms. + * + * Otherwise, blink the LED On for a very short time. */ + if (sIsThreadProvisioned && sIsThreadEnabled) { + sStatusLED.Set(true); + } else if (sHaveBLEConnections) { + sStatusLED.Blink(100, 100); + } else { + sStatusLED.Blink(50, 950); } } + +void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) +{ + switch (event->Type) { + case DeviceEventType::kCHIPoBLEAdvertisingChange: +#ifdef CONFIG_CHIP_NFC_COMMISSIONING + if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) { + if (NFCMgr().IsTagEmulationStarted()) { + LOG_INF("NFC Tag emulation is already started"); + } else { + ShareQRCodeOverNFC( + chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + } + } else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) { + NFCMgr().StopTagEmulation(); + } #endif + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + UpdateStatusLED(); + break; + default: + break; + } +} void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) { diff --git a/samples/matter/light_bulb/src/app_task.h b/samples/matter/light_bulb/src/app_task.h index b2716e8dd09..1dddd93c850 100644 --- a/samples/matter/light_bulb/src/app_task.h +++ b/samples/matter/light_bulb/src/app_task.h @@ -7,6 +7,7 @@ #pragma once #include "app_event.h" +#include "led_widget.h" #include "lighting_manager.h" #include @@ -41,8 +42,10 @@ class AppTask { static void ActionInitiated(LightingManager::Action aAction); static void ActionCompleted(LightingManager::Action aAction); + static void UpdateStatusLED(); static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); static void TimerEventHandler(k_timer *timer); + static void LEDStateUpdateHandler(LEDWidget &ledWidget); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *event, intptr_t arg); #ifdef CONFIG_MCUMGR_SMP_BT static void RequestSMPAdvertisingStart(void); diff --git a/samples/matter/lock/src/app_event.h b/samples/matter/lock/src/app_event.h index 87e2d81d2ce..488ebfe1559 100644 --- a/samples/matter/lock/src/app_event.h +++ b/samples/matter/lock/src/app_event.h @@ -8,13 +8,17 @@ #include +#include "led_widget.h" + struct AppEvent { enum LockEventType : uint8_t { Lock, Unlock, Toggle, CompleteLockAction }; enum FunctionEventType : uint8_t { FunctionPress = CompleteLockAction + 1, FunctionRelease, FunctionTimer }; + enum UpdateLedStateEventType : uint8_t { UpdateLedState = FunctionTimer + 1 }; + enum OtherEventType : uint8_t { - StartThread = FunctionTimer + 1, + StartThread = UpdateLedState + 1, StartBleAdvertising, #ifdef CONFIG_MCUMGR_SMP_BT StartSMPAdvertising @@ -24,6 +28,7 @@ struct AppEvent { AppEvent() = default; AppEvent(LockEventType type, bool chipInitiated) : Type(type), LockEvent{ chipInitiated } {} explicit AppEvent(FunctionEventType type) : Type(type) {} + AppEvent(UpdateLedStateEventType type, LEDWidget *ledWidget) : Type(type), UpdateLedStateEvent{ ledWidget } {} explicit AppEvent(OtherEventType type) : Type(type) {} uint8_t Type; @@ -32,5 +37,8 @@ struct AppEvent { struct { /* was the event triggered by CHIP Data Model layer */ bool ChipInitiated; } LockEvent; + struct { + LEDWidget *LedWidget; + } UpdateLedStateEvent; }; }; diff --git a/samples/matter/lock/src/app_task.cpp b/samples/matter/lock/src/app_task.cpp index 8adf25f7cb4..e4191a27df2 100644 --- a/samples/matter/lock/src/app_task.cpp +++ b/samples/matter/lock/src/app_task.cpp @@ -57,6 +57,7 @@ int AppTask::Init() { /* Initialize LEDs */ LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(DK_LED1); sLockLED.Init(DK_LED2); @@ -64,6 +65,8 @@ int AppTask::Init() sUnusedLED.Init(DK_LED3); sUnusedLED_1.Init(DK_LED4); + UpdateStatusLED(); + /* Initialize buttons */ int ret = dk_buttons_init(ButtonEventHandler); if (ret) { @@ -110,46 +113,12 @@ int AppTask::StartApp() AppEvent event = {}; while (true) { - ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10)); + ret = k_msgq_get(&sAppEventQueue, &event, K_FOREVER); while (!ret) { DispatchEvent(event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - /* 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()) { - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - /* Update the status LED. - * - * If thread and service provisioned, keep the LED On constantly. - * - * If the system has ble connection(s) uptill the stage above, THEN blink the LED at an even - * rate of 100ms. - * - * Otherwise, blink the LED On for a very short time. */ - if (sIsThreadProvisioned && sIsThreadEnabled) { - sStatusLED.Set(true); - } else if (sHaveBLEConnections) { - sStatusLED.Blink(100, 100); - } else { - sStatusLED.Blink(50, 950); - } - - sStatusLED.Animate(); - sLockLED.Animate(); - sUnusedLED.Animate(); - sUnusedLED_1.Animate(); } } @@ -191,7 +160,7 @@ void AppTask::DispatchEvent(const AppEvent &event) break; case AppEvent::Toggle: LockActionHandler(BoltLockMgr().IsUnlocked() ? BoltLockManager::Action::Lock : - BoltLockManager::Action::Unlock, + BoltLockManager::Action::Unlock, event.LockEvent.ChipInitiated); break; case AppEvent::CompleteLockAction: @@ -212,6 +181,9 @@ void AppTask::DispatchEvent(const AppEvent &event) case AppEvent::StartBleAdvertising: StartBLEAdvertisingHandler(); break; + case AppEvent::UpdateLedState: + event.UpdateLedStateEvent.LedWidget->UpdateState(); + break; #ifdef CONFIG_MCUMGR_SMP_BT case AppEvent::StartSMPAdvertising: GetDFUOverSMP().StartBLEAdvertising(); @@ -271,6 +243,8 @@ void AppTask::FunctionReleaseHandler() /* Set lock status LED back to show state of lock. */ sLockLED.Set(!BoltLockMgr().IsUnlocked()); + UpdateStatusLED(); + sAppTask.CancelFunctionTimer(); sAppTask.mFunction = TimerFunction::NoneSelected; LOG_INF("Factory Reset has been Canceled"); @@ -335,23 +309,58 @@ void AppTask::StartBLEAdvertisingHandler() } } -#ifdef CONFIG_CHIP_NFC_COMMISSIONING -void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) +void AppTask::LEDStateUpdateHandler(LEDWidget &ledWidget) { - if (event->Type != DeviceEventType::kCHIPoBLEAdvertisingChange) - return; + sAppTask.PostEvent(AppEvent{ AppEvent::UpdateLedState, &ledWidget }); +} - if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) { - if (NFCMgr().IsTagEmulationStarted()) { - LOG_INF("NFC Tag emulation is already started"); - } else { - ShareQRCodeOverNFC(chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); - } - } else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) { - NFCMgr().StopTagEmulation(); +void AppTask::UpdateStatusLED() +{ + /* Update the status LED. + * + * If thread and service provisioned, keep the LED On constantly. + * + * If the system has ble connection(s) uptill the stage above, THEN blink the LED at an even + * rate of 100ms. + * + * Otherwise, blink the LED On for a very short time. */ + if (sIsThreadProvisioned && sIsThreadEnabled) { + sStatusLED.Set(true); + } else if (sHaveBLEConnections) { + sStatusLED.Blink(100, 100); + } else { + sStatusLED.Blink(50, 950); } } + +void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) +{ + switch (event->Type) { + case DeviceEventType::kCHIPoBLEAdvertisingChange: +#ifdef CONFIG_CHIP_NFC_COMMISSIONING + if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Started) { + if (NFCMgr().IsTagEmulationStarted()) { + LOG_INF("NFC Tag emulation is already started"); + } else { + ShareQRCodeOverNFC( + chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)); + } + } else if (event->CHIPoBLEAdvertisingChange.Result == kActivity_Stopped) { + NFCMgr().StopTagEmulation(); + } #endif + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + UpdateStatusLED(); + break; + default: + break; + } +} void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) { diff --git a/samples/matter/lock/src/app_task.h b/samples/matter/lock/src/app_task.h index 3794fdf057e..8fcf015c081 100644 --- a/samples/matter/lock/src/app_task.h +++ b/samples/matter/lock/src/app_task.h @@ -8,6 +8,7 @@ #include "app_event.h" #include "bolt_lock_manager.h" +#include "led_widget.h" #include @@ -39,8 +40,10 @@ class AppTask { void StartThreadHandler(); void StartBLEAdvertisingHandler(); + static void UpdateStatusLED(); static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); static void TimerEventHandler(k_timer *timer); + static void LEDStateUpdateHandler(LEDWidget &ledWidget); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *event, intptr_t arg); #ifdef CONFIG_MCUMGR_SMP_BT static void RequestSMPAdvertisingStart(void); diff --git a/samples/matter/template/src/app_event.h b/samples/matter/template/src/app_event.h index f58dda52bab..940563e9a9c 100644 --- a/samples/matter/template/src/app_event.h +++ b/samples/matter/template/src/app_event.h @@ -11,8 +11,15 @@ struct AppEvent { enum EventType : uint8_t { FunctionPress, FunctionRelease, FunctionTimer }; + enum UpdateLedStateEventType : uint8_t { UpdateLedState = FunctionTimer + 1 }; + AppEvent() = default; explicit AppEvent(EventType type) : Type(type) {} + AppEvent(UpdateLedStateEventType type, LEDWidget *ledWidget) : Type(type), UpdateLedStateEvent{ ledWidget } {} uint8_t Type; + + struct { + LEDWidget *LedWidget; + } UpdateLedStateEvent; }; diff --git a/samples/matter/template/src/app_task.cpp b/samples/matter/template/src/app_task.cpp index f7bfbe74156..c894f936b59 100644 --- a/samples/matter/template/src/app_task.cpp +++ b/samples/matter/template/src/app_task.cpp @@ -47,12 +47,15 @@ int AppTask::Init() { /* Initialize LEDs */ LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); sStatusLED.Init(DK_LED1); sUnusedLED.Init(DK_LED2); sUnusedLED_1.Init(DK_LED3); sUnusedLED_2.Init(DK_LED4); + UpdateStatusLED(); + /* Initialize buttons */ int ret = dk_buttons_init(ButtonEventHandler); if (ret) { @@ -87,46 +90,12 @@ int AppTask::StartApp() AppEvent event = {}; while (true) { - ret = k_msgq_get(&sAppEventQueue, &event, K_MSEC(10)); + ret = k_msgq_get(&sAppEventQueue, &event, K_FOREVER); while (!ret) { DispatchEvent(event); ret = k_msgq_get(&sAppEventQueue, &event, K_NO_WAIT); } - - /* 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()) { - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - /* Update the status LED. - * - * If thread and service provisioned, keep the LED On constantly. - * - * If the system has ble connection(s) uptill the stage above, THEN blink the LED at an even - * rate of 100ms. - * - * Otherwise, blink the LED On for a very short time. */ - if (sIsThreadProvisioned && sIsThreadEnabled) { - sStatusLED.Set(true); - } else if (sHaveBLEConnections) { - sStatusLED.Blink(100, 100); - } else { - sStatusLED.Blink(50, 950); - } - - sStatusLED.Animate(); - sUnusedLED.Animate(); - sUnusedLED_1.Animate(); - sUnusedLED_2.Animate(); } } @@ -149,6 +118,9 @@ void AppTask::DispatchEvent(const AppEvent &event) case AppEvent::FunctionTimer: FunctionTimerEventHandler(); break; + case AppEvent::UpdateLedState: + event.UpdateLedStateEvent.LedWidget->UpdateState(); + break; default: LOG_INF("Unknown event received"); break; @@ -168,6 +140,8 @@ void AppTask::FunctionReleaseHandler() sUnusedLED_1.Set(false); sUnusedLED.Set(false); + UpdateStatusLED(); + sAppTask.CancelFunctionTimer(); sAppTask.mFunction = TimerFunction::NoneSelected; LOG_INF("Factory Reset has been Canceled"); @@ -189,6 +163,47 @@ void AppTask::FunctionTimerEventHandler() } } +void AppTask::LEDStateUpdateHandler(LEDWidget &ledWidget) +{ + sAppTask.PostEvent(AppEvent{ AppEvent::UpdateLedState, &ledWidget }); +} + +void AppTask::UpdateStatusLED() +{ + /* Update the status LED. + * + * If thread and service provisioned, keep the LED On constantly. + * + * If the system has ble connection(s) uptill the stage above, THEN blink the LED at an even + * rate of 100ms. + * + * Otherwise, blink the LED On for a very short time. */ + if (sIsThreadProvisioned && sIsThreadEnabled) { + sStatusLED.Set(true); + } else if (sHaveBLEConnections) { + sStatusLED.Blink(100, 100); + } else { + sStatusLED.Blink(50, 950); + } +} + +void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) +{ + switch (event->Type) { + case DeviceEventType::kCHIPoBLEAdvertisingChange: + sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; + UpdateStatusLED(); + break; + case DeviceEventType::kThreadStateChange: + sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); + sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); + UpdateStatusLED(); + break; + default: + break; + } +} + void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) { if (DK_BTN1_MSK & buttonState & hasChanged) { diff --git a/samples/matter/template/src/app_task.h b/samples/matter/template/src/app_task.h index cc9e6799117..26cad6c921a 100644 --- a/samples/matter/template/src/app_task.h +++ b/samples/matter/template/src/app_task.h @@ -7,6 +7,7 @@ #pragma once #include "app_event.h" +#include "led_widget.h" #include @@ -29,6 +30,9 @@ class AppTask { void FunctionReleaseHandler(); void FunctionTimerEventHandler(); + static void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget &ledWidget); + static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *event, intptr_t arg); static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); static void TimerEventHandler(k_timer *timer);