Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions applications/matter_weather_station/src/app_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,35 @@

#pragma once

#include <cstdint>

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;
};
126 changes: 73 additions & 53 deletions applications/matter_weather_station/src/app_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 */
Expand Down Expand Up @@ -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. */
Expand All @@ -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:
Expand All @@ -245,7 +252,7 @@ void AppTask::FunctionTimerHandler(AppEvent *)
}
}

void AppTask::MeasurementsTimerHandler(AppEvent *)
void AppTask::MeasurementsTimerHandler()
{
sAppTask.UpdateClusterState();
}
Expand Down Expand Up @@ -335,7 +342,7 @@ void AppTask::UpdateClusterState()
}
}

void AppTask::UpdateLedState()
void AppTask::UpdateStatusLED()
{
LedState nextState;

Expand Down Expand Up @@ -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
17 changes: 9 additions & 8 deletions applications/matter_weather_station/src/app_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#pragma once

#include "app_event.h"
#include "led_widget.h"

#include <platform/CHIPDeviceLayer.h>

Expand All @@ -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;
Expand Down
44 changes: 33 additions & 11 deletions samples/matter/common/src/led_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,30 @@
#include <dk_buttons_and_leds.h>
#include <zephyr.h>

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;
mBlinkOnTimeMS = 0;
mBlinkOffTimeMS = 0;
mGPIONum = gpioNum;
mState = false;

k_timer_init(&mLedTimer, &LEDWidget::LedStateTimerHandler, nullptr);
k_timer_user_data_set(&mLedTimer, this);

Set(false);
}

Expand All @@ -31,37 +43,47 @@ 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);
}

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<LEDWidget *>(timer->user_data));
}
Loading