Skip to content

Commit 02b8c27

Browse files
[nrfconnect] Adapt lock-app to Door Lock cluster (#17593)
1. Listen to lock-state attribute changes rather than lock/unlock commands to support the auto-relock feature. 2. Remove obsolete code from BoltLockManager as now the auto-relock feature is handled in the common cluster code.
1 parent 560bcf2 commit 02b8c27

File tree

6 files changed

+141
-249
lines changed

6 files changed

+141
-249
lines changed

examples/lock-app/nrfconnect/main/AppTask.cpp

+48-61
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <app-common/zap-generated/attribute-type.h>
2727
#include <app-common/zap-generated/attributes/Accessors.h>
2828
#include <app-common/zap-generated/cluster-id.h>
29+
#include <app/clusters/door-lock-server/door-lock-server.h>
2930
#include <app/server/OnboardingCodesUtil.h>
3031
#include <app/server/Server.h>
3132
#include <credentials/DeviceAttestationCredsProvider.h>
@@ -120,15 +121,14 @@ CHIP_ERROR AppTask::Init()
120121

121122
sStatusLED.Init(SYSTEM_STATE_LED);
122123
sLockLED.Init(LOCK_STATE_LED);
123-
sLockLED.Set(!BoltLockMgr().IsUnlocked());
124+
sLockLED.Set(BoltLockMgr().IsLocked());
124125

125126
sUnusedLED.Init(DK_LED3);
126127
sUnusedLED_1.Init(DK_LED4);
127128

128129
UpdateStatusLED();
129130

130-
BoltLockMgr().Init();
131-
BoltLockMgr().SetCallbacks(ActionInitiated, ActionCompleted);
131+
BoltLockMgr().Init(LockStateChanged);
132132

133133
// Initialize buttons
134134
int ret = dk_buttons_init(ButtonEventHandler);
@@ -191,22 +191,14 @@ CHIP_ERROR AppTask::StartApp()
191191

192192
void AppTask::LockActionEventHandler(AppEvent * aEvent)
193193
{
194-
BoltLockManager::Action_t action = BoltLockManager::INVALID_ACTION;
195-
int32_t actor = 0;
196-
197-
if (aEvent->Type == AppEvent::kEventType_Lock)
194+
if (BoltLockMgr().IsLocked())
198195
{
199-
action = static_cast<BoltLockManager::Action_t>(aEvent->LockEvent.Action);
200-
actor = aEvent->LockEvent.Actor;
196+
BoltLockMgr().Unlock(BoltLockManager::OperationSource::kButton);
201197
}
202-
else if (aEvent->Type == AppEvent::kEventType_Button)
198+
else
203199
{
204-
action = BoltLockMgr().IsUnlocked() ? BoltLockManager::LOCK_ACTION : BoltLockManager::UNLOCK_ACTION;
205-
actor = AppEvent::kEventType_Button;
200+
BoltLockMgr().Lock(BoltLockManager::OperationSource::kButton);
206201
}
207-
208-
if (action != BoltLockManager::INVALID_ACTION && !BoltLockMgr().InitiateAction(actor, action))
209-
LOG_INF("Action is already in progress or active.");
210202
}
211203

212204
void AppTask::ButtonEventHandler(uint32_t button_state, uint32_t has_changed)
@@ -341,7 +333,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent)
341333
sUnusedLED_1.Set(false);
342334

343335
// Set lock status LED back to show state of lock.
344-
sLockLED.Set(!BoltLockMgr().IsUnlocked());
336+
sLockLED.Set(BoltLockMgr().IsLocked());
345337

346338
UpdateStatusLED();
347339
sAppTask.CancelTimer();
@@ -480,54 +472,34 @@ void AppTask::StartTimer(uint32_t aTimeoutInMs)
480472
mFunctionTimerActive = true;
481473
}
482474

483-
void AppTask::ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor)
475+
void AppTask::LockStateChanged(BoltLockManager::State state, BoltLockManager::OperationSource source)
484476
{
485-
// If the action has been initiated by the lock, update the bolt lock trait
486-
// and start flashing the LEDs rapidly to indicate action initiation.
487-
if (aAction == BoltLockManager::LOCK_ACTION)
488-
{
489-
LOG_INF("Lock Action has been initiated");
490-
}
491-
else if (aAction == BoltLockManager::UNLOCK_ACTION)
477+
switch (state)
492478
{
493-
LOG_INF("Unlock Action has been initiated");
494-
}
495-
496-
sLockLED.Blink(50, 50);
497-
}
498-
499-
void AppTask::ActionCompleted(BoltLockManager::Action_t aAction, int32_t aActor)
500-
{
501-
// if the action has been completed by the lock, update the bolt lock trait.
502-
// Turn on the lock LED if in a LOCKED state OR
503-
// Turn off the lock LED if in an UNLOCKED state.
504-
if (aAction == BoltLockManager::LOCK_ACTION)
505-
{
506-
LOG_INF("Lock Action has been completed");
479+
case BoltLockManager::State::kLockingInitiated:
480+
LOG_INF("Lock action initiated");
481+
sLockLED.Blink(50, 50);
482+
break;
483+
case BoltLockManager::State::kLockingCompleted:
484+
LOG_INF("Lock action completed");
507485
sLockLED.Set(true);
508-
}
509-
else if (aAction == BoltLockManager::UNLOCK_ACTION)
510-
{
511-
LOG_INF("Unlock Action has been completed");
486+
break;
487+
case BoltLockManager::State::kUnlockingInitiated:
488+
LOG_INF("Unlock action initiated");
489+
sLockLED.Blink(50, 50);
490+
break;
491+
case BoltLockManager::State::kUnlockingCompleted:
492+
LOG_INF("Unlock action completed");
512493
sLockLED.Set(false);
494+
break;
513495
}
514496

515-
if (aActor == AppEvent::kEventType_Button)
497+
if (source != BoltLockManager::OperationSource::kRemote)
516498
{
517-
sAppTask.UpdateClusterState();
499+
sAppTask.UpdateClusterState(state, source);
518500
}
519501
}
520502

521-
void AppTask::PostLockActionRequest(int32_t aActor, BoltLockManager::Action_t aAction)
522-
{
523-
AppEvent event;
524-
event.Type = AppEvent::kEventType_Lock;
525-
event.LockEvent.Actor = aActor;
526-
event.LockEvent.Action = aAction;
527-
event.Handler = LockActionEventHandler;
528-
PostEvent(&event);
529-
}
530-
531503
void AppTask::PostEvent(AppEvent * aEvent)
532504
{
533505
if (k_msgq_put(&sAppEventQueue, aEvent, K_NO_WAIT))
@@ -548,14 +520,29 @@ void AppTask::DispatchEvent(AppEvent * aEvent)
548520
}
549521
}
550522

551-
void AppTask::UpdateClusterState()
523+
void AppTask::UpdateClusterState(BoltLockManager::State state, BoltLockManager::OperationSource source)
552524
{
553-
EmberAfStatus status;
554-
LOG_INF("Updating door lock state");
555-
status = Clusters::DoorLock::Attributes::LockState::Set(
556-
kLockEndpointId, BoltLockMgr().IsUnlocked() ? DlLockState::kUnlocked : DlLockState::kLocked);
557-
if (status != EMBER_ZCL_STATUS_SUCCESS)
525+
DlLockState lockState;
526+
527+
switch (state)
558528
{
559-
LOG_ERR("Updating door lock state %x", status);
529+
case BoltLockManager::State::kLockingCompleted:
530+
lockState = DlLockState::kLocked;
531+
break;
532+
case BoltLockManager::State::kUnlockingCompleted:
533+
lockState = DlLockState::kUnlocked;
534+
break;
535+
default:
536+
lockState = DlLockState::kNotFullyLocked;
537+
break;
560538
}
539+
540+
SystemLayer().ScheduleLambda([lockState, source] {
541+
LOG_INF("Updating LockState attribute");
542+
543+
if (!DoorLockServer::Instance().SetLockState(kLockEndpointId, lockState, source))
544+
{
545+
LOG_ERR("Failed to update LockState attribute");
546+
}
547+
});
561548
}

examples/lock-app/nrfconnect/main/BoltLockManager.cpp

+37-134
Original file line numberDiff line numberDiff line change
@@ -20,170 +20,73 @@
2020
#include "BoltLockManager.h"
2121

2222
#include "AppConfig.h"
23+
#include "AppEvent.h"
2324
#include "AppTask.h"
2425

25-
#include <logging/log.h>
26-
#include <zephyr.h>
27-
28-
LOG_MODULE_DECLARE(app, CONFIG_MATTER_LOG_LEVEL);
29-
30-
static k_timer sLockTimer;
31-
3226
BoltLockManager BoltLockManager::sLock;
3327

34-
void BoltLockManager::Init()
28+
void BoltLockManager::Init(StateChangeCallback callback)
3529
{
36-
k_timer_init(&sLockTimer, &BoltLockManager::TimerEventHandler, nullptr);
37-
k_timer_user_data_set(&sLockTimer, this);
30+
mStateChangeCallback = callback;
3831

39-
mState = kState_LockingCompleted;
40-
mAutoLockTimerArmed = false;
41-
mAutoRelock = false;
42-
mAutoLockDuration = 0;
43-
}
44-
45-
void BoltLockManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB)
46-
{
47-
mActionInitiated_CB = aActionInitiated_CB;
48-
mActionCompleted_CB = aActionCompleted_CB;
32+
k_timer_init(&mActuatorTimer, &BoltLockManager::ActuatorTimerEventHandler, nullptr);
33+
k_timer_user_data_set(&mActuatorTimer, this);
4934
}
5035

51-
bool BoltLockManager::IsActionInProgress()
36+
void BoltLockManager::Lock(OperationSource source)
5237
{
53-
return (mState == kState_LockingInitiated || mState == kState_UnlockingInitiated) ? true : false;
54-
}
38+
VerifyOrReturn(mState != State::kLockingCompleted);
39+
SetState(State::kLockingInitiated, source);
5540

56-
bool BoltLockManager::IsUnlocked()
57-
{
58-
return (mState == kState_UnlockingCompleted) ? true : false;
41+
mActuatorOperationSource = source;
42+
k_timer_start(&mActuatorTimer, K_MSEC(kActuatorMovementTimeMs), K_NO_WAIT);
5943
}
6044

61-
void BoltLockManager::EnableAutoRelock(bool aOn)
45+
void BoltLockManager::Unlock(OperationSource source)
6246
{
63-
mAutoRelock = aOn;
64-
}
47+
VerifyOrReturn(mState != State::kUnlockingCompleted);
48+
SetState(State::kUnlockingInitiated, source);
6549

66-
void BoltLockManager::SetAutoLockDuration(uint32_t aDurationInSecs)
67-
{
68-
mAutoLockDuration = aDurationInSecs;
50+
mActuatorOperationSource = source;
51+
k_timer_start(&mActuatorTimer, K_MSEC(kActuatorMovementTimeMs), K_NO_WAIT);
6952
}
7053

71-
bool BoltLockManager::InitiateAction(int32_t aActor, Action_t aAction)
54+
void BoltLockManager::ActuatorTimerEventHandler(k_timer * timer)
7255
{
73-
bool action_initiated = false;
74-
State_t new_state;
75-
76-
// Initiate Lock/Unlock Action only when the previous one is complete.
77-
if (mState == kState_LockingCompleted && aAction == UNLOCK_ACTION)
78-
{
79-
action_initiated = true;
80-
mCurrentActor = aActor;
81-
new_state = kState_UnlockingInitiated;
82-
}
83-
else if (mState == kState_UnlockingCompleted && aAction == LOCK_ACTION)
84-
{
85-
action_initiated = true;
86-
mCurrentActor = aActor;
87-
new_state = kState_LockingInitiated;
88-
}
89-
90-
if (action_initiated)
91-
{
92-
if (mAutoLockTimerArmed && new_state == kState_LockingInitiated)
93-
{
94-
// If auto lock timer has been armed and someone initiates locking,
95-
// cancel the timer and continue as normal.
96-
mAutoLockTimerArmed = false;
97-
98-
CancelTimer();
99-
}
100-
101-
StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS);
102-
103-
// Since the timer started successfully, update the state and trigger callback
104-
mState = new_state;
105-
106-
if (mActionInitiated_CB)
107-
{
108-
mActionInitiated_CB(aAction, aActor);
109-
}
110-
}
111-
112-
return action_initiated;
113-
}
56+
// The timer event handler is called in the context of the system clock ISR.
57+
// Post an event to the application task queue to process the event in the
58+
// context of the application thread.
11459

115-
void BoltLockManager::StartTimer(uint32_t aTimeoutMs)
116-
{
117-
k_timer_start(&sLockTimer, K_MSEC(aTimeoutMs), K_NO_WAIT);
118-
}
119-
120-
void BoltLockManager::CancelTimer(void)
121-
{
122-
k_timer_stop(&sLockTimer);
123-
}
124-
125-
void BoltLockManager::TimerEventHandler(k_timer * timer)
126-
{
127-
BoltLockManager * lock = static_cast<BoltLockManager *>(k_timer_user_data_get(timer));
128-
129-
// The timer event handler will be called in the context of the timer task
130-
// once sLockTimer expires. Post an event to apptask queue with the actual handler
131-
// so that the event can be handled in the context of the apptask.
13260
AppEvent event;
13361
event.Type = AppEvent::kEventType_Timer;
134-
event.TimerEvent.Context = lock;
135-
event.Handler = lock->mAutoLockTimerArmed ? AutoReLockTimerEventHandler : ActuatorMovementTimerEventHandler;
62+
event.TimerEvent.Context = static_cast<BoltLockManager *>(k_timer_user_data_get(timer));
63+
event.Handler = BoltLockManager::ActuatorAppEventHandler;
13664
GetAppTask().PostEvent(&event);
13765
}
13866

139-
void BoltLockManager::AutoReLockTimerEventHandler(AppEvent * aEvent)
67+
void BoltLockManager::ActuatorAppEventHandler(AppEvent * aEvent)
14068
{
14169
BoltLockManager * lock = static_cast<BoltLockManager *>(aEvent->TimerEvent.Context);
142-
int32_t actor = 0;
143-
144-
// Make sure auto lock timer is still armed.
145-
if (!lock->mAutoLockTimerArmed)
146-
return;
14770

148-
lock->mAutoLockTimerArmed = false;
149-
150-
LOG_INF("Auto Re-Lock has been triggered!");
151-
152-
lock->InitiateAction(actor, LOCK_ACTION);
71+
switch (lock->mState)
72+
{
73+
case State::kLockingInitiated:
74+
lock->SetState(State::kLockingCompleted, lock->mActuatorOperationSource);
75+
break;
76+
case State::kUnlockingInitiated:
77+
lock->SetState(State::kUnlockingCompleted, lock->mActuatorOperationSource);
78+
break;
79+
default:
80+
break;
81+
}
15382
}
15483

155-
void BoltLockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent)
84+
void BoltLockManager::SetState(State state, OperationSource source)
15685
{
157-
Action_t actionCompleted = INVALID_ACTION;
158-
159-
BoltLockManager * lock = static_cast<BoltLockManager *>(aEvent->TimerEvent.Context);
86+
mState = state;
16087

161-
if (lock->mState == kState_LockingInitiated)
88+
if (mStateChangeCallback != nullptr)
16289
{
163-
lock->mState = kState_LockingCompleted;
164-
actionCompleted = LOCK_ACTION;
165-
}
166-
else if (lock->mState == kState_UnlockingInitiated)
167-
{
168-
lock->mState = kState_UnlockingCompleted;
169-
actionCompleted = UNLOCK_ACTION;
170-
}
171-
172-
if (actionCompleted != INVALID_ACTION)
173-
{
174-
if (lock->mActionCompleted_CB)
175-
{
176-
lock->mActionCompleted_CB(actionCompleted, lock->mCurrentActor);
177-
}
178-
179-
if (lock->mAutoRelock && actionCompleted == UNLOCK_ACTION)
180-
{
181-
// Start the timer for auto relock
182-
lock->StartTimer(lock->mAutoLockDuration * 1000);
183-
184-
lock->mAutoLockTimerArmed = true;
185-
186-
LOG_INF("Auto Re-lock enabled. Will be triggered in %u seconds", lock->mAutoLockDuration);
187-
}
90+
mStateChangeCallback(state, source);
18891
}
18992
}

0 commit comments

Comments
 (0)