diff --git a/samples/matter/common/src/board.cpp b/samples/matter/common/src/board.cpp new file mode 100644 index 000000000000..b0bf5bf4a009 --- /dev/null +++ b/samples/matter/common/src/board.cpp @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "board.h" +#include "task_executor.h" + +#ifdef CONFIG_MCUMGR_TRANSPORT_BT +#include "dfu_over_smp.h" +#endif + +#include +#include + +#include + +LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); + +Board Board::sInstance; + +bool Board::Init(ButtonHandler buttonCallback) +{ + mButtonCallback = buttonCallback; + + /* Initialize LEDs */ + LEDWidget::InitGpio(); + LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); + mStatusLED.Init(SYSTEM_STATE_LED); + mApplicationLED.Init(APPLICATION_STATE_LED); +#if NUMBER_OF_LEDS == 4 + mUserLED1.Init(USER_LED_1); + mUserLED2.Init(USER_LED_2); +#endif + + /* Initialize buttons */ + int ret = dk_buttons_init(ButtonEventHandler); + if (ret) { + LOG_ERR("dk_buttons_init() failed"); + return false; + } + + /* Initialize function timer */ + k_timer_init(&mFunctionTimer, &FunctionTimerTimeoutCallback, nullptr); + k_timer_user_data_set(&mFunctionTimer, this); + + UpdateStatusLED(); + + return true; +} + +void Board::UpdateDeviceState(DeviceState state) +{ + mState = state; + UpdateStatusLED(); +} + +void Board::ResetAllLeds() +{ + sInstance.mStatusLED.Set(false); + sInstance.mApplicationLED.Set(false); +#if NUMBER_OF_LEDS == 4 + sInstance.mUserLED1.Set(false); + sInstance.mUserLED2.Set(false); +#endif +} + +void Board::LEDStateUpdateHandler(LEDWidget &ledWidget) +{ + SystemEvent ledEvent(SystemEventType::UpdateLedState); + TaskExecutor::PostTask([ledEvent] { UpdateLedStateEventHandler(ledEvent); }); +} + +void Board::UpdateLedStateEventHandler(const SystemEvent &event) +{ + if (event.mType == SystemEventType::UpdateLedState) { + event.UpdateLedStateEvent.LedWidget->UpdateState(); + } +} + +void Board::UpdateStatusLED() +{ + /* Update the status LED. + * + * If IPv6 network 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 for a very short time. */ + switch (mState) { + case DeviceState::kDeviceDisconnected: + mStatusLED.Blink(LedConsts::StatusLed::Disconnected::kOn_ms, + LedConsts::StatusLed::Disconnected::kOff_ms); + + break; + case DeviceState::kDeviceConnectedBLE: + mStatusLED.Blink(LedConsts::StatusLed::BleConnected::kOn_ms, + LedConsts::StatusLed::BleConnected::kOff_ms); + break; + case DeviceState::kDeviceProvisioned: + mStatusLED.Set(true); + break; + } +} + +LEDWidget &Board::GetLED(DeviceLeds led) +{ + switch (led) { +#if NUMBER_OF_LEDS == 4 + case DeviceLeds::kUserLED1: + return mUserLED1; + case DeviceLeds::kUserLED2: + return mUserLED2; +#endif + case DeviceLeds::kAppLED: + default: + return mApplicationLED; + } +} + +void Board::CancelTimer() +{ + k_timer_stop(&mFunctionTimer); + mFunctionTimerActive = false; +} + +void Board::StartTimer(uint32_t timeoutInMs) +{ + k_timer_start(&mFunctionTimer, K_MSEC(timeoutInMs), K_NO_WAIT); + mFunctionTimerActive = true; +} + +void Board::FunctionTimerTimeoutCallback(k_timer *timer) +{ + SystemEvent timerEvent(SystemEventType::Timer); + timerEvent.TimerEvent.Timer = timer; + TaskExecutor::PostTask([timerEvent] { FunctionTimerEventHandler(timerEvent); }); +} + +void Board::FunctionTimerEventHandler(const SystemEvent &event) +{ + /* If we reached here, the button was held past kFactoryResetTriggerTimeout, initiate factory reset */ + if (sInstance.mFunction == SystemEventType::SoftwareUpdate) { + LOG_INF("Factory reset has been triggered. Release button within %ums to cancel.", + FactoryResetConsts::kFactoryResetTriggerTimeout); + + /* Start timer for kFactoryResetCancelWindowTimeout to allow user to cancel, if required. */ + sInstance.StartTimer(FactoryResetConsts::kFactoryResetCancelWindowTimeout); + sInstance.mFunction = SystemEventType::FactoryReset; + + /* Turn off all LEDs before starting blink to make sure blink is coordinated. */ + sInstance.ResetAllLeds(); + + sInstance.mStatusLED.Blink(LedConsts::kBlinkRate_ms); + sInstance.mApplicationLED.Blink(LedConsts::kBlinkRate_ms); +#if NUMBER_OF_LEDS == 4 + sInstance.mUserLED1.Blink(LedConsts::kBlinkRate_ms); + sInstance.mUserLED2.Blink(LedConsts::kBlinkRate_ms); +#endif + } else if (sInstance.mFunction == SystemEventType::FactoryReset) { + /* Actually trigger Factory Reset */ + sInstance.mFunction = SystemEventType::None; + chip::Server::GetInstance().ScheduleFactoryReset(); + + } else if (sInstance.mFunction == SystemEventType::AdvertisingStart) { + /* The button was held past kAdvertisingTriggerTimeout, start BLE advertisement + if we have 2 buttons UI*/ +#if NUMBER_OF_BUTTONS == 2 + StartBLEAdvertisement(); + sInstance.mFunction = SystemEventType::None; +#endif + } +} + +void Board::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) +{ + SystemEvent buttonEvent(SystemEventType::Button); + bool isAppButtonEvent = false; + ButtonActions action; + DeviceButtons source; + + if (BLUETOOTH_ADV_BUTTON_MASK & hasChanged) { + buttonEvent.ButtonEvent.PinNo = BLUETOOTH_ADV_BUTTON; + buttonEvent.ButtonEvent.Action = static_cast((BLUETOOTH_ADV_BUTTON_MASK & buttonState) ? + SystemEventType::ButtonPushed : + SystemEventType::ButtonReleased); + TaskExecutor::PostTask([buttonEvent] { StartBLEAdvertisementHandler(buttonEvent); }); + } + + if (FUNCTION_BUTTON_MASK & hasChanged) { + buttonEvent.ButtonEvent.PinNo = FUNCTION_BUTTON; + buttonEvent.ButtonEvent.Action = + static_cast((FUNCTION_BUTTON_MASK & buttonState) ? SystemEventType::ButtonPushed : + SystemEventType::ButtonReleased); + TaskExecutor::PostTask([buttonEvent] { FunctionHandler(buttonEvent); }); + } + +#if NUMBER_OF_BUTTONS == 4 + if (APPLICATION_BUTTON_MASK & hasChanged) { + source = DeviceButtons::kAppButton; + action = (APPLICATION_BUTTON_MASK & buttonState) ? ButtonActions::kButtonPressed : + ButtonActions::kButtonReleased; + isAppButtonEvent = true; + } + + if (USER_BUTTON_1_MASK & hasChanged) { + source = DeviceButtons::kUserButton1; + action = (USER_BUTTON_1_MASK & buttonState) ? ButtonActions::kButtonPressed : + ButtonActions::kButtonReleased; + isAppButtonEvent = true; + } + if (USER_BUTTON_2_MASK & hasChanged) { + source = DeviceButtons::kUserButton2; + action = (USER_BUTTON_2_MASK & buttonState) ? ButtonActions::kButtonPressed : + ButtonActions::kButtonReleased; + isAppButtonEvent = true; + } +#endif + + if (isAppButtonEvent && sInstance.mButtonCallback) { + sInstance.mButtonCallback(source, action); + } +} + +void Board::FunctionHandler(const SystemEvent &event) +{ + if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) { + return; + } + + if (event.ButtonEvent.Action == static_cast(SystemEventType::ButtonPushed)) { + if (!sInstance.mFunctionTimerActive && sInstance.mFunction == SystemEventType::None) { + sInstance.mFunction = SystemEventType::SoftwareUpdate; + sInstance.StartTimer(FactoryResetConsts::kFactoryResetTriggerTimeout); + } + } else { + /* If the button was released before factory reset got initiated, trigger a software update. */ + if (sInstance.mFunctionTimerActive && sInstance.mFunction == SystemEventType::SoftwareUpdate) { + sInstance.CancelTimer(); + sInstance.mFunction = SystemEventType::None; + +#ifdef CONFIG_MCUMGR_TRANSPORT_BT + GetDFUOverSMP().StartServer(); +#else + LOG_INF("Software update is disabled"); +#endif + } else if (sInstance.mFunctionTimerActive && sInstance.mFunction == SystemEventType::FactoryReset) { + sInstance.ResetAllLeds(); + sInstance.CancelTimer(); + sInstance.UpdateStatusLED(); + sInstance.mFunction = SystemEventType::None; + LOG_INF("Factory reset has been canceled"); + } + } +} + +void Board::StartBLEAdvertisementHandler(const SystemEvent &event) +{ +#if NUMBER_OF_BUTTONS == 4 + if (event.ButtonEvent.Action == static_cast(SystemEventType::ButtonPushed)) { + StartBLEAdvertisement(); + } + +#elif NUMBER_OF_BUTTONS == 2 + if (event.ButtonEvent.Action == static_cast(SystemEventType::ButtonPushed)) { + sInstance.StartTimer(AdvertisingConsts::kAdvertisingTriggerTimeout); + sInstance.mFunction = SystemEventType::AdvertisingStart; + } else { + if (sInstance.mFunction == SystemEventType::AdvertisingStart && sInstance.mFunctionTimerActive) { + sInstance.CancelTimer(); + sInstance.mFunction = SystemEventType::None; + + if (sInstance.mButtonCallback) { + sInstance.mButtonCallback(DeviceButtons::kAppButton, ButtonActions::kButtonPressed); + } + } + } +#endif +} + +void Board::StartBLEAdvertisement() +{ + if (chip::Server::GetInstance().GetFabricTable().FabricCount() != 0) { + LOG_INF("Matter service BLE advertising not started - device is already commissioned"); + return; + } + + if (chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled()) { + LOG_INF("BLE advertising is already enabled"); + return; + } + + if (chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != + CHIP_NO_ERROR) { + LOG_ERR("OpenBasicCommissioningWindow() failed"); + } +} diff --git a/samples/matter/common/src/board.h b/samples/matter/common/src/board.h new file mode 100644 index 000000000000..3e3607d1b701 --- /dev/null +++ b/samples/matter/common/src/board.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include "board_config.h" +#include "board_consts.h" +#include "led_util.h" +#include "led_widget.h" +#include "system_event.h" + +enum class DeviceState : uint8_t { kDeviceDisconnected, kDeviceConnectedBLE, kDeviceProvisioned }; +enum class DeviceLeds : uint8_t { kAppLED, kUserLED1, kUserLED2 }; +enum class DeviceButtons : uint8_t { kAppButton, kUserButton1, kUserButton2 }; +enum class ButtonActions : uint8_t { kButtonPressed, kButtonReleased }; + +using ButtonHandler = void (*)(DeviceButtons source, ButtonActions action); + +class Board { + using LedState = bool; + +public: + bool Init(ButtonHandler buttonCallback = nullptr); + + /* LEDs */ + LEDWidget &GetLED(DeviceLeds led); + void UpdateDeviceState(DeviceState state); + +private: + Board() {} + friend Board &GetBoard(); + static Board sInstance; + + /* LEDs */ + void UpdateStatusLED(); + static void LEDStateUpdateHandler(LEDWidget &ledWidget); + static void UpdateLedStateEventHandler(const SystemEvent& event); + void ResetAllLeds(); + + LEDWidget mStatusLED; + LEDWidget mApplicationLED; + k_timer mFunctionTimer; + DeviceState mState = DeviceState::kDeviceDisconnected; +#if NUMBER_OF_LEDS == 4 + LEDWidget mUserLED1; + LEDWidget mUserLED2; +#endif + + /* Function Timer */ + void CancelTimer(); + void StartTimer(uint32_t timeoutInMs); + static void FunctionTimerTimeoutCallback(k_timer *timer); + static void FunctionTimerEventHandler(const SystemEvent& event); + + bool mFunctionTimerActive = false; + SystemEventType mFunction; + + /* Buttons */ + static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); + static void FunctionHandler(const SystemEvent& event); + static void StartBLEAdvertisementHandler(const SystemEvent& event); + static void StartBLEAdvertisement(); + + ButtonHandler mButtonCallback = nullptr; + +}; + +inline Board &GetBoard() +{ + return Board::sInstance; +} diff --git a/samples/matter/common/src/board_config.h b/samples/matter/common/src/board_config.h new file mode 100644 index 000000000000..501bca2f159e --- /dev/null +++ b/samples/matter/common/src/board_config.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include +#include + +/* Override application configuration */ +#include "app_config.h" + +#define LEDS_NODE_ID DT_PATH(leds) +#define BUTTONS_NODE_ID DT_PATH(buttons) +#define INCREMENT_BY_ONE(button_or_led) +1 +#define NUMBER_OF_LEDS (0 DT_FOREACH_CHILD(LEDS_NODE_ID, INCREMENT_BY_ONE)) +#define NUMBER_OF_BUTTONS (0 DT_FOREACH_CHILD(BUTTONS_NODE_ID, INCREMENT_BY_ONE)) + +/* User configurable BUTTONS */ +#ifndef FUNCTION_BUTTON +#define FUNCTION_BUTTON DK_BTN1 +#endif +#ifndef APPLICATION_BUTTON +#define APPLICATION_BUTTON DK_BTN2 +#endif +/* User buttons 1 & 2 are available only on DKs that have 4 buttons located on the board */ +#if NUMBER_OF_BUTTONS == 4 +#ifndef USER_BUTTON_1 +#define USER_BUTTON_1 DK_BTN3 +#endif +#ifndef USER_BUTTON_2 +#define USER_BUTTON_2 DK_BTN4 +#endif +#endif + +/* User configurable LEDS */ +#ifndef SYSTEM_STATE_LED +#define SYSTEM_STATE_LED DK_LED1 +#endif +#ifndef APPLICATION_STATE_LED +#define APPLICATION_STATE_LED DK_LED2 +#endif +/* User leds 1 & 2 are available only on DKs that have 4 buttons located on the board */ +#if NUMBER_OF_LEDS == 4 +#ifndef USER_LED_1 +#define USER_LED_1 DK_LED3 +#endif +#ifndef USER_LED_2 +#define USER_LED_2 DK_LED4 +#endif +#endif + +/* Non-configurable Consts */ +#define FUNCTION_BUTTON_MASK BIT(FUNCTION_BUTTON) +#define APPLICATION_BUTTON_MASK BIT(APPLICATION_BUTTON) +#if NUMBER_OF_LEDS == 4 +#define USER_BUTTON_1_MASK BIT(USER_BUTTON_1) +#define USER_BUTTON_2_MASK BIT(USER_BUTTON_2) +#endif + +#if NUMBER_OF_BUTTONS == 4 +#define BLUETOOTH_ADV_BUTTON USER_BUTTON_2 +#else +#define BLUETOOTH_ADV_BUTTON APPLICATION_BUTTON +#endif +#define BLUETOOTH_ADV_BUTTON_MASK BIT(BLUETOOTH_ADV_BUTTON) diff --git a/samples/matter/common/src/board_consts.h b/samples/matter/common/src/board_consts.h new file mode 100644 index 000000000000..26928179c433 --- /dev/null +++ b/samples/matter/common/src/board_consts.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include + +namespace FactoryResetConsts +{ +constexpr uint32_t kFactoryResetTriggerTimeout = 3000; +constexpr uint32_t kFactoryResetCancelWindowTimeout = 3000; +} /* namespace FactoryResetConsts */ + +namespace AdvertisingConsts +{ +#if NUMBER_OF_BUTTONS == 2 +constexpr uint32_t kAdvertisingTriggerTimeout = 3000; +#endif +} // namespace AdvertisingConsts + +namespace LedConsts +{ +constexpr uint32_t kBlinkRate_ms{ 500 }; +constexpr uint32_t kIdentifyBlinkRate_ms{ 500 }; +namespace StatusLed +{ + namespace BleConnected + { + constexpr uint32_t kOn_ms{ 100 }; + constexpr uint32_t kOff_ms{ kOn_ms }; + } /* namespace BleConnected */ + namespace Disconnected + { + constexpr uint32_t kOn_ms{ 50 }; + constexpr uint32_t kOff_ms{ 950 }; + } /* namespace Disconnected */ + +} /* namespace StatusLed */ +} /* namespace LedConsts */ diff --git a/samples/matter/common/src/board_util.h b/samples/matter/common/src/board_util.h deleted file mode 100644 index 8ffa072602c0..000000000000 --- a/samples/matter/common/src/board_util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#pragma once - -#include - -#define LEDS_NODE_ID DT_PATH(leds) -#define BUTTONS_NODE_ID DT_PATH(buttons) -#define INCREMENT_BY_ONE(button_or_led) +1 -#define NUMBER_OF_LEDS (0 DT_FOREACH_CHILD(LEDS_NODE_ID, INCREMENT_BY_ONE)) -#define NUMBER_OF_BUTTONS (0 DT_FOREACH_CHILD(BUTTONS_NODE_ID, INCREMENT_BY_ONE)) diff --git a/samples/matter/common/src/event_types.h b/samples/matter/common/src/event_types.h deleted file mode 100644 index cab481bbe78b..000000000000 --- a/samples/matter/common/src/event_types.h +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright (c) 2022 Nordic Semiconductor ASA - * - * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause - */ - -#pragma once - -struct AppEvent; /* needs to be implemented in the application code */ -using EventHandler = void (*)(const AppEvent &); diff --git a/samples/matter/common/src/led_widget.h b/samples/matter/common/src/led_widget.h index a4f82a7e94dc..ae85e71acf76 100644 --- a/samples/matter/common/src/led_widget.h +++ b/samples/matter/common/src/led_widget.h @@ -22,6 +22,7 @@ class LEDWidget { void Blink(uint32_t changeRateMS); void Blink(uint32_t onTimeMS, uint32_t offTimeMS); void UpdateState(); + bool GetState() { return mState; } private: uint32_t mBlinkOnTimeMS; diff --git a/samples/matter/common/src/system_event.h b/samples/matter/common/src/system_event.h new file mode 100644 index 000000000000..3ea57c0551a0 --- /dev/null +++ b/samples/matter/common/src/system_event.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include + +#include "led_widget.h" + +enum class SystemEventType : uint8_t { + None = 0, + Button, + ButtonPushed, + ButtonReleased, + Timer, + UpdateLedState, + SoftwareUpdate, + FactoryReset, + AdvertisingStart +}; + +struct SystemEvent { + SystemEvent(SystemEventType type) { mType = type; } + SystemEvent() = default; + + union { + struct { + uint8_t PinNo; + uint8_t Action; + } ButtonEvent; + struct { + k_timer *Timer; + } TimerEvent; + struct { + LEDWidget *LedWidget; + } UpdateLedStateEvent; + }; + + SystemEventType mType; +}; diff --git a/samples/matter/common/src/task_executor.cpp b/samples/matter/common/src/task_executor.cpp new file mode 100644 index 000000000000..029e89ff26d8 --- /dev/null +++ b/samples/matter/common/src/task_executor.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "task_executor.h" +#include "app_event.h" +#include "system_event.h" + +#include + +#include + +LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); + +constexpr size_t kEventQueueSize = 10; + +K_MSGQ_DEFINE(sEventQueue, sizeof(TaskExecutor::Task), kEventQueueSize, alignof(TaskExecutor::Task)); + +void TaskExecutor::PostTask(const Task& task) +{ + if (k_msgq_put(&sEventQueue, &task, K_NO_WAIT) != 0) { + LOG_ERR("Failed to post event to app task event queue"); + } +} + +void TaskExecutor::DispatchNextTask() +{ + Task task; + k_msgq_get(&sEventQueue, &task, K_FOREVER); + task(); +} diff --git a/samples/matter/common/src/task_executor.h b/samples/matter/common/src/task_executor.h new file mode 100644 index 000000000000..f5e2a3084949 --- /dev/null +++ b/samples/matter/common/src/task_executor.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#pragma once + +#include +#include +#include +#include + +enum class EventSource : uint8_t { Undefined, Application, System }; + +namespace TaskExecutor +{ +using Task = std::function; + +void PostTask(const Task& task); +void DispatchNextTask(); +} diff --git a/samples/matter/lock/CMakeLists.txt b/samples/matter/lock/CMakeLists.txt index 4641f7e711af..4d5d64954eb5 100644 --- a/samples/matter/lock/CMakeLists.txt +++ b/samples/matter/lock/CMakeLists.txt @@ -47,6 +47,8 @@ target_sources(app PRIVATE src/zap-generated/callback-stub.cpp src/zap-generated/IMClusterCommandHandler.cpp ${COMMON_ROOT}/src/led_widget.cpp + ${COMMON_ROOT}/src/task_executor.cpp + ${COMMON_ROOT}/src/board.cpp ) if(CONFIG_CHIP_OTA_REQUESTOR OR CONFIG_MCUMGR_TRANSPORT_BT) diff --git a/samples/matter/lock/src/app_config.h b/samples/matter/lock/src/app_config.h index 6cbae7b86f74..f124955121ce 100644 --- a/samples/matter/lock/src/app_config.h +++ b/samples/matter/lock/src/app_config.h @@ -6,28 +6,5 @@ #pragma once -#include "board_util.h" - /* ---- Lock Example App Config ---- */ -#define FUNCTION_BUTTON DK_BTN1 -#define FUNCTION_BUTTON_MASK DK_BTN1_MSK - -#if NUMBER_OF_BUTTONS == 2 -#define BLE_ADVERTISEMENT_START_AND_LOCK_BUTTON DK_BTN2 -#define BLE_ADVERTISEMENT_START_AND_LOCK_BUTTON_MASK DK_BTN2_MSK -#else -#define LOCK_BUTTON DK_BTN2 -#define LOCK_BUTTON_MASK DK_BTN2_MSK -#define THREAD_WIFI_SWITCH_BUTTON DK_BTN3 -#define THREAD_WIFI_SWITCH_BUTTON_MASK DK_BTN3_MSK -#define BLE_ADVERTISEMENT_START_BUTTON DK_BTN4 -#define BLE_ADVERTISEMENT_START_BUTTON_MASK DK_BTN4_MSK -#endif - -#define SYSTEM_STATE_LED DK_LED1 -#define LOCK_STATE_LED DK_LED2 -#if NUMBER_OF_LEDS == 4 -#define FACTORY_RESET_SIGNAL_LED DK_LED3 -#define FACTORY_RESET_SIGNAL_LED1 DK_LED4 -#endif diff --git a/samples/matter/lock/src/app_event.h b/samples/matter/lock/src/app_event.h index 864731027d24..65d43c64a144 100644 --- a/samples/matter/lock/src/app_event.h +++ b/samples/matter/lock/src/app_event.h @@ -6,44 +6,20 @@ #pragma once -#include - -#include "event_types.h" - -class LEDWidget; - -enum class AppEventType : uint8_t { - None = 0, - Button, - ButtonPushed, - ButtonReleased, - Timer, - UpdateLedState, - IdentifyStart, - IdentifyStop, - NUSCommand, -}; - -enum class FunctionEvent : uint8_t { NoneSelected = 0, SoftwareUpdate = 0, FactoryReset, AdvertisingStart }; +enum class AppEventType : uint8_t { None = 0, NUSCommand, LockEvent, ThreadWiFiSwitch }; struct AppEvent { + AppEvent(AppEventType type) { mType = type; } + AppEvent() = default; + union { - struct { - uint8_t PinNo; - uint8_t Action; - } ButtonEvent; struct { void *Context; - } TimerEvent; - struct { - uint8_t Action; - int32_t Actor; } LockEvent; struct { - LEDWidget *LedWidget; - } UpdateLedStateEvent; + uint8_t ButtonAction; + } ThreadWiFiSwitchEvent; }; - AppEventType Type{ AppEventType::None }; - EventHandler Handler; + AppEventType mType; }; diff --git a/samples/matter/lock/src/app_task.cpp b/samples/matter/lock/src/app_task.cpp index 5f1b50ba88ab..2567b933dd22 100644 --- a/samples/matter/lock/src/app_task.cpp +++ b/samples/matter/lock/src/app_task.cpp @@ -5,11 +5,11 @@ */ #include "app_task.h" +#include "app_event.h" +#include "task_executor.h" -#include "app_config.h" #include "bolt_lock_manager.h" #include "fabric_table_delegate.h" -#include "led_util.h" #ifdef CONFIG_THREAD_WIFI_SWITCHING #include "software_images_swapper.h" @@ -27,7 +27,6 @@ using chip::Shell::shell_command_t; #include -#include "board_util.h" #include #include #include @@ -48,7 +47,6 @@ using chip::Shell::shell_command_t; #include "ota_util.h" #endif -#include #include #include @@ -67,13 +65,7 @@ using namespace ::chip::DeviceLayer; namespace { -constexpr uint32_t kFactoryResetTriggerTimeout = 3000; -constexpr uint32_t kFactoryResetCancelWindowTimeout = 3000; -constexpr size_t kAppEventQueueSize = 10; constexpr EndpointId kLockEndpointId = 1; -#if NUMBER_OF_BUTTONS == 2 -constexpr uint32_t kAdvertisingTriggerTimeout = 3000; -#endif #ifdef CONFIG_CHIP_NUS constexpr uint16_t kAdvertisingIntervalMin = 400; @@ -81,47 +73,18 @@ constexpr uint16_t kAdvertisingIntervalMax = 500; constexpr uint8_t kLockNUSPriority = 2; #endif -K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); -k_timer sFunctionTimer; - #ifdef CONFIG_THREAD_WIFI_SWITCHING k_timer sSwitchImagesTimer; constexpr uint32_t kSwitchImagesTimeout = 10000; #endif -Identify sIdentify = { kLockEndpointId, AppTask::IdentifyStartHandler, AppTask::IdentifyStopHandler, - Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator }; - -LEDWidget sStatusLED; -LEDWidget sLockLED; -#if NUMBER_OF_LEDS == 4 -FactoryResetLEDsWrapper<2> sFactoryResetLEDs{ { FACTORY_RESET_SIGNAL_LED, FACTORY_RESET_SIGNAL_LED1 } }; -#endif - bool sIsNetworkProvisioned = false; bool sIsNetworkEnabled = false; bool sHaveBLEConnections = false; } /* namespace */ -namespace LedConsts -{ -constexpr uint32_t kBlinkRate_ms{ 500 }; -constexpr uint32_t kIdentifyBlinkRate_ms{ 500 }; -namespace StatusLed -{ - namespace Unprovisioned - { - constexpr uint32_t kOn_ms{ 100 }; - constexpr uint32_t kOff_ms{ kOn_ms }; - } /* namespace Unprovisioned */ - namespace Provisioned - { - constexpr uint32_t kOn_ms{ 50 }; - constexpr uint32_t kOff_ms{ 950 }; - } /* namespace Provisioned */ - -} /* namespace StatusLed */ -} /* namespace LedConsts */ +Identify sIdentify = { kLockEndpointId, AppTask::IdentifyStartHandler, AppTask::IdentifyStopHandler, + Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator }; #ifdef CONFIG_CHIP_WIFI app::Clusters::NetworkCommissioning::Instance @@ -168,27 +131,11 @@ CHIP_ERROR AppTask::Init() return CHIP_ERROR_INTERNAL; #endif /* CONFIG_NET_L2_OPENTHREAD */ - /* Initialize LEDs */ - LEDWidget::InitGpio(); - LEDWidget::SetStateUpdateCallback(LEDStateUpdateHandler); - - sStatusLED.Init(SYSTEM_STATE_LED); - sLockLED.Init(LOCK_STATE_LED); - sLockLED.Set(BoltLockMgr().IsLocked()); - - UpdateStatusLED(); - - /* Initialize buttons */ - int ret = dk_buttons_init(ButtonEventHandler); - if (ret) { - LOG_ERR("dk_buttons_init() failed"); - return chip::System::MapErrorZephyr(ret); + if (!GetBoard().Init(ButtonEventHandler)) { + LOG_ERR("User interface initialization failed."); + return CHIP_ERROR_INCORRECT_STATE; } - /* Initialize function timer */ - k_timer_init(&sFunctionTimer, &AppTask::FunctionTimerTimeoutCallback, nullptr); - k_timer_user_data_set(&sFunctionTimer, this); - #ifdef CONFIG_THREAD_WIFI_SWITCHING k_timer_init(&sSwitchImagesTimer, &AppTask::SwitchImagesTimerTimeoutCallback, nullptr); #endif @@ -200,7 +147,7 @@ CHIP_ERROR AppTask::Init() } GetNUSService().RegisterCommand("Lock", sizeof("Lock"), NUSLockCallback, nullptr); GetNUSService().RegisterCommand("Unlock", sizeof("Unlock"), NUSUnlockCallback, nullptr); - if(!GetNUSService().StartServer()){ + if (!GetNUSService().StartServer()) { LOG_ERR("GetNUSService().StartServer() failed"); } #endif @@ -262,11 +209,8 @@ CHIP_ERROR AppTask::StartApp() { ReturnErrorOnFailure(Init()); - AppEvent event = {}; - while (true) { - k_msgq_get(&sAppEventQueue, &event, K_FOREVER); - DispatchEvent(event); + TaskExecutor::DispatchNextTask(); } return CHIP_NO_ERROR; @@ -274,43 +218,30 @@ CHIP_ERROR AppTask::StartApp() void AppTask::IdentifyStartHandler(Identify *) { - AppEvent event; - event.Type = AppEventType::IdentifyStart; - event.Handler = [](const AppEvent &) { sLockLED.Blink(LedConsts::kIdentifyBlinkRate_ms); }; - PostEvent(event); + TaskExecutor::PostTask([] { GetBoard().GetLED(DeviceLeds::kAppLED).Blink(LedConsts::kIdentifyBlinkRate_ms); }); } void AppTask::IdentifyStopHandler(Identify *) { - AppEvent event; - event.Type = AppEventType::IdentifyStop; - event.Handler = [](const AppEvent &) { sLockLED.Set(BoltLockMgr().IsLocked()); }; - PostEvent(event); + TaskExecutor::PostTask([] { GetBoard().GetLED(DeviceLeds::kAppLED).Set(BoltLockMgr().IsLocked()); }); } -#if NUMBER_OF_BUTTONS == 2 -void AppTask::StartBLEAdvertisementAndLockActionEventHandler(const AppEvent &event) +void AppTask::ButtonEventHandler(DeviceButtons source, ButtonActions action) { - if (event.ButtonEvent.Action == static_cast(AppEventType::ButtonPushed)) { - Instance().StartTimer(kAdvertisingTriggerTimeout); - Instance().mFunction = FunctionEvent::AdvertisingStart; - } else { - if (Instance().mFunction == FunctionEvent::AdvertisingStart && Instance().mFunctionTimerActive) { - Instance().CancelTimer(); - Instance().mFunction = FunctionEvent::NoneSelected; - - AppEvent button_event; - button_event.Type = AppEventType::Button; - button_event.ButtonEvent.PinNo = BLE_ADVERTISEMENT_START_AND_LOCK_BUTTON; - button_event.ButtonEvent.Action = static_cast(AppEventType::ButtonReleased); - button_event.Handler = LockActionEventHandler; - PostEvent(button_event); - } + if (DeviceButtons::kAppButton == source && ButtonActions::kButtonPressed == action) { + TaskExecutor::PostTask([] { LockActionEventHandler(); }); + } + +#ifdef CONFIG_THREAD_WIFI_SWITCHING + if (DeviceButtons::kUserButton1 == source) { + AppEvent event(AppEventType::ThreadWiFiSwitch); + event.ThreadWiFiSwitchEvent.ButtonAction = static_cast(action); + TaskExecutor::PostTask([event] { SwitchImagesTriggerHandler(event); }); } -} #endif +} -void AppTask::LockActionEventHandler(const AppEvent &event) +void AppTask::LockActionEventHandler() { if (BoltLockMgr().IsLocked()) { BoltLockMgr().Unlock(BoltLockManager::OperationSource::kButton); @@ -326,7 +257,7 @@ void AppTask::SwitchImagesDone() chip::Server::GetInstance().ScheduleFactoryReset(); } -void AppTask::SwitchImagesEventHandler(const AppEvent &) +void AppTask::SwitchImagesEventHandler() { LOG_INF("Switching application from " CONFIG_APPLICATION_LABEL " to " CONFIG_APPLICATION_OTHER_LABEL); @@ -344,25 +275,13 @@ void AppTask::SwitchImagesEventHandler(const AppEvent &) void AppTask::SwitchImagesTimerTimeoutCallback(k_timer *timer) { - if (!timer) { - return; - } - Instance().mSwitchImagesTimerActive = false; - - AppEvent event; - event.Type = AppEventType::Timer; - event.Handler = SwitchImagesEventHandler; - PostEvent(event); + TaskExecutor::PostTask([] { SwitchImagesEventHandler() };); } void AppTask::SwitchImagesTriggerHandler(const AppEvent &event) { - if (event.ButtonEvent.PinNo != THREAD_WIFI_SWITCH_BUTTON) { - return; - } - - if (event.ButtonEvent.Action == static_cast(AppEventType::ButtonPushed) && + if (event.ThreadWiFiSwitchEvent.ButtonAction == static_cast(ButtonActions::kButtonPressed) && !Instance().mSwitchImagesTimerActive) { k_timer_start(&sSwitchImagesTimer, K_MSEC(kSwitchImagesTimeout), K_NO_WAIT); Instance().mSwitchImagesTimerActive = true; @@ -378,203 +297,6 @@ void AppTask::SwitchImagesTriggerHandler(const AppEvent &event) } #endif -void AppTask::ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged) -{ - AppEvent button_event; - button_event.Type = AppEventType::Button; - -#if NUMBER_OF_BUTTONS == 2 - if (BLE_ADVERTISEMENT_START_AND_LOCK_BUTTON_MASK & hasChanged) { - button_event.ButtonEvent.PinNo = BLE_ADVERTISEMENT_START_AND_LOCK_BUTTON; - button_event.ButtonEvent.Action = static_cast( - (BLE_ADVERTISEMENT_START_AND_LOCK_BUTTON_MASK & buttonState) ? AppEventType::ButtonPushed : - AppEventType::ButtonReleased); - button_event.Handler = StartBLEAdvertisementAndLockActionEventHandler; - PostEvent(button_event); - } -#else - if (LOCK_BUTTON_MASK & buttonState & hasChanged) { - button_event.ButtonEvent.PinNo = LOCK_BUTTON; - button_event.ButtonEvent.Action = static_cast(AppEventType::ButtonPushed); - button_event.Handler = LockActionEventHandler; - PostEvent(button_event); - } - -#ifdef CONFIG_THREAD_WIFI_SWITCHING - if (THREAD_WIFI_SWITCH_BUTTON_MASK & hasChanged) { - button_event.ButtonEvent.PinNo = THREAD_WIFI_SWITCH_BUTTON; - button_event.ButtonEvent.Action = static_cast((THREAD_WIFI_SWITCH_BUTTON_MASK & buttonState) ? - AppEventType::ButtonPushed : - AppEventType::ButtonReleased); - button_event.Handler = SwitchImagesTriggerHandler; - PostEvent(button_event); - } -#endif - - if (BLE_ADVERTISEMENT_START_BUTTON_MASK & buttonState & hasChanged) { - button_event.ButtonEvent.PinNo = BLE_ADVERTISEMENT_START_BUTTON; - button_event.ButtonEvent.Action = static_cast(AppEventType::ButtonPushed); - button_event.Handler = StartBLEAdvertisementHandler; - PostEvent(button_event); - } -#endif - - if (FUNCTION_BUTTON_MASK & hasChanged) { - button_event.ButtonEvent.PinNo = FUNCTION_BUTTON; - button_event.ButtonEvent.Action = - static_cast((FUNCTION_BUTTON_MASK & buttonState) ? AppEventType::ButtonPushed : - AppEventType::ButtonReleased); - button_event.Handler = FunctionHandler; - PostEvent(button_event); - } -} - -void AppTask::FunctionTimerTimeoutCallback(k_timer *timer) -{ - if (!timer) { - return; - } - - Instance().mFunctionTimerActive = false; - AppEvent event; - event.Type = AppEventType::Timer; - event.TimerEvent.Context = k_timer_user_data_get(timer); - event.Handler = FunctionTimerEventHandler; - PostEvent(event); -} - -void AppTask::FunctionTimerEventHandler(const AppEvent &event) -{ - if (event.Type != AppEventType::Timer) { - return; - } - - /* If we reached here, the button was held past kFactoryResetTriggerTimeout, initiate factory reset */ - if (Instance().mFunction == FunctionEvent::SoftwareUpdate) { - LOG_INF("Factory Reset Triggered. Release button within %ums to cancel.", kFactoryResetTriggerTimeout); - - /* Start timer for kFactoryResetCancelWindowTimeout to allow user to cancel, if required. */ - Instance().StartTimer(kFactoryResetCancelWindowTimeout); - Instance().mFunction = FunctionEvent::FactoryReset; - - /* Turn off all LEDs before starting blink to make sure blink is coordinated. */ - sStatusLED.Set(false); -#if NUMBER_OF_LEDS == 4 - sFactoryResetLEDs.Set(false); -#endif - - sStatusLED.Blink(LedConsts::kBlinkRate_ms); -#if NUMBER_OF_LEDS == 4 - sFactoryResetLEDs.Blink(LedConsts::kBlinkRate_ms); -#endif - } else if (Instance().mFunction == FunctionEvent::FactoryReset) { - /* Actually trigger Factory Reset */ - Instance().mFunction = FunctionEvent::NoneSelected; - chip::Server::GetInstance().ScheduleFactoryReset(); - - } else if (Instance().mFunction == FunctionEvent::AdvertisingStart) { - /* The button was held past kAdvertisingTriggerTimeout, start BLE advertisement - if we have 2 buttons UI*/ -#if NUMBER_OF_BUTTONS == 2 - StartBLEAdvertisementHandler(event); - Instance().mFunction = FunctionEvent::NoneSelected; -#endif - } -} - -void AppTask::FunctionHandler(const AppEvent &event) -{ - if (event.ButtonEvent.PinNo != FUNCTION_BUTTON) - return; - - /* To trigger software update: press the FUNCTION_BUTTON button briefly (< kFactoryResetTriggerTimeout) - * To initiate factory reset: press the FUNCTION_BUTTON for kFactoryResetTriggerTimeout + - * kFactoryResetCancelWindowTimeout All LEDs start blinking after kFactoryResetTriggerTimeout to signal factory - * reset has been initiated. To cancel factory reset: release the FUNCTION_BUTTON once all LEDs start blinking - * within the kFactoryResetCancelWindowTimeout. - */ - if (event.ButtonEvent.Action == static_cast(AppEventType::ButtonPushed)) { - if (!Instance().mFunctionTimerActive && Instance().mFunction == FunctionEvent::NoneSelected) { - Instance().StartTimer(kFactoryResetTriggerTimeout); - - Instance().mFunction = FunctionEvent::SoftwareUpdate; - } - } else { - /* If the button was released before factory reset got initiated, trigger a software update. */ - if (Instance().mFunctionTimerActive && Instance().mFunction == FunctionEvent::SoftwareUpdate) { - Instance().CancelTimer(); - Instance().mFunction = FunctionEvent::NoneSelected; - -#ifdef CONFIG_MCUMGR_TRANSPORT_BT - GetDFUOverSMP().StartServer(); -#else - LOG_INF("Software update is disabled"); -#endif - } else if (Instance().mFunctionTimerActive && Instance().mFunction == FunctionEvent::FactoryReset) { -#if NUMBER_OF_LEDS == 4 - sFactoryResetLEDs.Set(false); -#endif - UpdateStatusLED(); - Instance().CancelTimer(); - Instance().mFunction = FunctionEvent::NoneSelected; - LOG_INF("Factory Reset has been Canceled"); - } - } -} - -void AppTask::StartBLEAdvertisementHandler(const AppEvent &) -{ - if (Server::GetInstance().GetFabricTable().FabricCount() != 0) { - LOG_INF("Matter service BLE advertising not started - device is already commissioned"); - return; - } - - if (ConnectivityMgr().IsBLEAdvertisingEnabled()) { - LOG_INF("BLE advertising is already enabled"); - return; - } - - if (Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow() != CHIP_NO_ERROR) { - LOG_ERR("OpenBasicCommissioningWindow() failed"); - } -} - -void AppTask::UpdateLedStateEventHandler(const AppEvent &event) -{ - if (event.Type == AppEventType::UpdateLedState) { - event.UpdateLedStateEvent.LedWidget->UpdateState(); - } -} - -void AppTask::LEDStateUpdateHandler(LEDWidget &ledWidget) -{ - AppEvent event; - event.Type = AppEventType::UpdateLedState; - event.Handler = UpdateLedStateEventHandler; - event.UpdateLedStateEvent.LedWidget = &ledWidget; - PostEvent(event); -} - -void AppTask::UpdateStatusLED() -{ - /* Update the status LED. - * - * If IPv6 network 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 for a very short time. */ - if (sIsNetworkProvisioned && sIsNetworkEnabled) { - sStatusLED.Set(true); - } else if (sHaveBLEConnections) { - sStatusLED.Blink(LedConsts::StatusLed::Unprovisioned::kOn_ms, - LedConsts::StatusLed::Unprovisioned::kOff_ms); - } else { - sStatusLED.Blink(LedConsts::StatusLed::Provisioned::kOn_ms, LedConsts::StatusLed::Provisioned::kOff_ms); - } -} - void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) { switch (event->Type) { @@ -592,7 +314,9 @@ void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) } #endif sHaveBLEConnections = ConnectivityMgr().NumBLEConnections() != 0; - UpdateStatusLED(); + if (sHaveBLEConnections) { + GetBoard().UpdateDeviceState(DeviceState::kDeviceConnectedBLE); + } break; #if defined(CONFIG_NET_L2_OPENTHREAD) case DeviceEventType::kDnssdInitialized: @@ -613,45 +337,37 @@ void AppTask::ChipEventHandler(const ChipDeviceEvent *event, intptr_t /* arg */) } #endif /* CONFIG_CHIP_OTA_REQUESTOR */ #endif - UpdateStatusLED(); + if (sIsNetworkEnabled && sIsNetworkProvisioned) { + GetBoard().UpdateDeviceState(DeviceState::kDeviceProvisioned); + } else { + GetBoard().UpdateDeviceState(DeviceState::kDeviceDisconnected); + } break; default: break; } } -void AppTask::CancelTimer() -{ - k_timer_stop(&sFunctionTimer); - mFunctionTimerActive = false; -} - -void AppTask::StartTimer(uint32_t timeoutInMs) -{ - k_timer_start(&sFunctionTimer, K_MSEC(timeoutInMs), K_NO_WAIT); - mFunctionTimerActive = true; -} - void AppTask::LockStateChanged(BoltLockManager::State state, BoltLockManager::OperationSource source) { switch (state) { case BoltLockManager::State::kLockingInitiated: LOG_INF("Lock action initiated"); - sLockLED.Blink(50, 50); + GetBoard().GetLED(DeviceLeds::kAppLED).Blink(50, 50); #ifdef CONFIG_CHIP_NUS GetNUSService().SendData("locking", sizeof("locking")); #endif break; case BoltLockManager::State::kLockingCompleted: LOG_INF("Lock action completed"); - sLockLED.Set(true); + GetBoard().GetLED(DeviceLeds::kAppLED).Set(true); #ifdef CONFIG_CHIP_NUS GetNUSService().SendData("locked", sizeof("locked")); #endif break; case BoltLockManager::State::kUnlockingInitiated: LOG_INF("Unlock action initiated"); - sLockLED.Blink(50, 50); + GetBoard().GetLED(DeviceLeds::kAppLED).Blink(50, 50); #ifdef CONFIG_CHIP_NUS GetNUSService().SendData("unlocking", sizeof("unlocking")); #endif @@ -661,7 +377,7 @@ void AppTask::LockStateChanged(BoltLockManager::State state, BoltLockManager::Op #ifdef CONFIG_CHIP_NUS GetNUSService().SendData("unlocked", sizeof("unlocked")); #endif - sLockLED.Set(false); + GetBoard().GetLED(DeviceLeds::kAppLED).Set(false); break; } @@ -669,22 +385,6 @@ void AppTask::LockStateChanged(BoltLockManager::State state, BoltLockManager::Op Instance().UpdateClusterState(state, source); } -void AppTask::PostEvent(const AppEvent &event) -{ - if (k_msgq_put(&sAppEventQueue, &event, K_NO_WAIT) != 0) { - LOG_INF("Failed to post event to app task event queue"); - } -} - -void AppTask::DispatchEvent(const AppEvent &event) -{ - if (event.Handler) { - event.Handler(event); - } else { - LOG_INF("Event received with no handler. Dropping event."); - } -} - void AppTask::UpdateClusterState(BoltLockManager::State state, BoltLockManager::OperationSource source) { DlLockState newLockState; @@ -722,7 +422,7 @@ void AppTask::UpdateClusterState(BoltLockManager::State state, BoltLockManager:: void AppTask::RegisterSwitchCliCommand() { static const shell_command_t sSwitchCommand = { [](int, char **) { - AppTask::Instance().SwitchImagesEventHandler(AppEvent{}); + AppTask::Instance().SwitchImagesEventHandler(); return CHIP_NO_ERROR; }, "switch_images", @@ -739,10 +439,8 @@ void AppTask::NUSLockCallback(void *context) BoltLockMgr().mState == BoltLockManager::State::kLockingInitiated) { LOG_INF("Device is already locked"); } else { - AppEvent nus_event; - nus_event.Type = AppEventType::NUSCommand; - nus_event.Handler = LockActionEventHandler; - PostEvent(nus_event); + AppEvent nusEvent(AppEventType::NUSCommand); + TaskExecutor::PostTask([nusEvent] { LockActionEventHandler(nusEvent) };); } } @@ -753,10 +451,8 @@ void AppTask::NUSUnlockCallback(void *context) BoltLockMgr().mState == BoltLockManager::State::kUnlockingInitiated) { LOG_INF("Device is already unlocked"); } else { - AppEvent nus_event; - nus_event.Type = AppEventType::NUSCommand; - nus_event.Handler = LockActionEventHandler; - PostEvent(nus_event); + AppEvent nusEvent(AppEventType::NUSCommand); + TaskExecutor::PostTask([nusEvent] { LockActionEventHandler(nusEvent) };); } } #endif diff --git a/samples/matter/lock/src/app_task.h b/samples/matter/lock/src/app_task.h index f077751ae831..93b476883d5d 100644 --- a/samples/matter/lock/src/app_task.h +++ b/samples/matter/lock/src/app_task.h @@ -6,7 +6,7 @@ #pragma once -#include "app_event.h" +#include "board.h" #include "bolt_lock_manager.h" #include "led_widget.h" @@ -27,7 +27,6 @@ struct Identify; class AppTask { public: - static AppTask &Instance() { static AppTask sAppTask; @@ -37,38 +36,22 @@ class AppTask { CHIP_ERROR StartApp(); void UpdateClusterState(BoltLockManager::State state, BoltLockManager::OperationSource source); - - static void PostEvent(const AppEvent &event); static void IdentifyStartHandler(Identify *); static void IdentifyStopHandler(Identify *); private: CHIP_ERROR Init(); - void CancelTimer(); - void StartTimer(uint32_t timeoutInMs); - - static void DispatchEvent(const AppEvent &event); - static void FunctionTimerEventHandler(const AppEvent &event); - static void FunctionHandler(const AppEvent &event); - static void StartBLEAdvertisementAndLockActionEventHandler(const AppEvent &event); - static void LockActionEventHandler(const AppEvent &event); - static void StartBLEAdvertisementHandler(const AppEvent &event); - static void UpdateLedStateEventHandler(const AppEvent &event); - + static void LockActionEventHandler(); + static void ButtonEventHandler(DeviceButtons source, ButtonActions action); static void ChipEventHandler(const chip::DeviceLayer::ChipDeviceEvent *event, intptr_t arg); - static void ButtonEventHandler(uint32_t buttonState, uint32_t hasChanged); - static void LEDStateUpdateHandler(LEDWidget &ledWidget); - static void FunctionTimerTimeoutCallback(k_timer *timer); - static void UpdateStatusLED(); - static void LockStateChanged(BoltLockManager::State state, BoltLockManager::OperationSource source); #ifdef CONFIG_THREAD_WIFI_SWITCHING static void SwitchImagesDone(); static void SwitchImagesTriggerHandler(const AppEvent &event); static void SwitchImagesTimerTimeoutCallback(k_timer *timer); - static void SwitchImagesEventHandler(const AppEvent &event); + static void SwitchImagesEventHandler(); bool mSwitchImagesTimerActive = false; #endif @@ -82,7 +65,6 @@ class AppTask { static void RegisterSwitchCliCommand(); #endif - FunctionEvent mFunction = FunctionEvent::NoneSelected; bool mFunctionTimerActive = false; #if CONFIG_CHIP_FACTORY_DATA diff --git a/samples/matter/lock/src/bolt_lock_manager.cpp b/samples/matter/lock/src/bolt_lock_manager.cpp index 3a2034c67832..9db035332892 100644 --- a/samples/matter/lock/src/bolt_lock_manager.cpp +++ b/samples/matter/lock/src/bolt_lock_manager.cpp @@ -5,8 +5,8 @@ */ #include "bolt_lock_manager.h" +#include "task_executor.h" -#include "app_event.h" #include "app_task.h" using namespace chip; @@ -19,6 +19,9 @@ void BoltLockManager::Init(StateChangeCallback callback) k_timer_init(&mActuatorTimer, &BoltLockManager::ActuatorTimerEventHandler, nullptr); k_timer_user_data_set(&mActuatorTimer, this); + + /* Set the default state */ + GetBoard().GetLED(DeviceLeds::kAppLED).Set(IsLocked()); } bool BoltLockManager::GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo &user) const @@ -157,20 +160,14 @@ void BoltLockManager::ActuatorTimerEventHandler(k_timer *timer) * context of the application thread. */ - AppEvent event; - event.Type = AppEventType::Timer; - event.TimerEvent.Context = static_cast(k_timer_user_data_get(timer)); - event.Handler = BoltLockManager::ActuatorAppEventHandler; - AppTask::Instance().PostEvent(event); + AppEvent event(AppEventType::LockEvent); + event.LockEvent.Context = static_cast(k_timer_user_data_get(timer)); + TaskExecutor::PostTask([event] { ActuatorAppEventHandler(event); }); } void BoltLockManager::ActuatorAppEventHandler(const AppEvent &event) { - BoltLockManager *lock = static_cast(event.TimerEvent.Context); - - if (!lock) { - return; - } + BoltLockManager *lock = reinterpret_cast(event.LockEvent.Context); switch (lock->mState) { case State::kLockingInitiated: diff --git a/samples/matter/lock/src/bolt_lock_manager.h b/samples/matter/lock/src/bolt_lock_manager.h index 95fa45a80d3b..ebec07a68256 100644 --- a/samples/matter/lock/src/bolt_lock_manager.h +++ b/samples/matter/lock/src/bolt_lock_manager.h @@ -9,6 +9,8 @@ #include #include +#include "app_event.h" + #include #include @@ -68,7 +70,7 @@ class BoltLockManager { void SetState(State state, OperationSource source); static void ActuatorTimerEventHandler(k_timer *timer); - static void ActuatorAppEventHandler(const AppEvent &aEvent); + static void ActuatorAppEventHandler(const AppEvent &event); friend BoltLockManager &BoltLockMgr(); State mState = State::kLockingCompleted;