Added unlatch state on unlock supporting Ubolt and tdded ransition locked->unlatched->unlocked (#32023)
diff --git a/examples/lock-app/silabs/include/AppConfig.h b/examples/lock-app/silabs/include/AppConfig.h
index 2045ce3..2a98805 100644
--- a/examples/lock-app/silabs/include/AppConfig.h
+++ b/examples/lock-app/silabs/include/AppConfig.h
@@ -31,6 +31,10 @@
// state to another.
#define ACTUATOR_MOVEMENT_PERIOS_MS 10
+// Time the device will be left in the unlatched state before sending it back to the unlocked state.
+// Left at 100 ms for testing purposes.
+#define UNLATCH_TIME_MS 100
+
#define ON_DEMO_BITMAP \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, \
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, \
diff --git a/examples/lock-app/silabs/include/AppTask.h b/examples/lock-app/silabs/include/AppTask.h
index b0040ac..fb911e3 100644
--- a/examples/lock-app/silabs/include/AppTask.h
+++ b/examples/lock-app/silabs/include/AppTask.h
@@ -120,6 +120,13 @@
static void UpdateClusterState(intptr_t context);
/**
+ * @brief Update Cluster State After Unlatch
+ *
+ * @param context current context
+ */
+ static void UpdateClusterStateAfterUnlatch(intptr_t context);
+
+ /**
* @brief Handle lock update event
*
* @param aEvent event received
diff --git a/examples/lock-app/silabs/include/LockManager.h b/examples/lock-app/silabs/include/LockManager.h
index fb73d1d..7345782 100644
--- a/examples/lock-app/silabs/include/LockManager.h
+++ b/examples/lock-app/silabs/include/LockManager.h
@@ -119,6 +119,7 @@
{
LOCK_ACTION = 0,
UNLOCK_ACTION,
+ UNLATCH_ACTION,
INVALID_ACTION
} Action;
@@ -128,7 +129,9 @@
kState_LockInitiated = 0,
kState_LockCompleted,
kState_UnlockInitiated,
+ kState_UnlatchInitiated,
kState_UnlockCompleted,
+ kState_UnlatchCompleted,
} State;
CHIP_ERROR Init(chip::app::DataModel::Nullable<chip::app::Clusters::DoorLock::DlLockState> state,
@@ -191,7 +194,30 @@
bool ReadConfigValues();
+ void UnlockAfterUnlatch();
+
private:
+ struct UnlatchContext
+ {
+ chip::EndpointId mEndpointId;
+ Nullable<chip::FabricIndex> mFabricIdx;
+ Nullable<chip::NodeId> mNodeId;
+ Optional<chip::ByteSpan> mPin;
+ OperationErrorEnum mErr;
+
+ void Update(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
+ const Nullable<chip::NodeId> & nodeId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
+ {
+ mEndpointId = endpointId;
+ mFabricIdx = fabricIdx;
+ mNodeId = nodeId;
+ mPin = pin;
+ mErr = err;
+ }
+ };
+ UnlatchContext mUnlatchContext;
+ chip::EndpointId mCurrentEndpointId;
+
friend LockManager & LockMgr();
State_t mState;
diff --git a/examples/lock-app/silabs/openthread.gni b/examples/lock-app/silabs/openthread.gni
index 3423049..970d3a0 100644
--- a/examples/lock-app/silabs/openthread.gni
+++ b/examples/lock-app/silabs/openthread.gni
@@ -28,7 +28,7 @@
sl_enable_test_event_trigger = true
# ICD Default configurations
-chip_enable_icd_server = true
+chip_enable_icd_server = false
chip_subscription_timeout_resumption = false
sl_use_subscription_syncing = true
diff --git a/examples/lock-app/silabs/src/AppTask.cpp b/examples/lock-app/silabs/src/AppTask.cpp
index 6937dbb..4e4d05a 100644
--- a/examples/lock-app/silabs/src/AppTask.cpp
+++ b/examples/lock-app/silabs/src/AppTask.cpp
@@ -70,6 +70,45 @@
namespace {
LEDWidget sLockLED;
+TimerHandle_t sUnlatchTimer;
+
+void UpdateClusterStateAfterUnlatch(intptr_t context)
+{
+ LockMgr().UnlockAfterUnlatch();
+}
+
+void UnlatchTimerCallback(TimerHandle_t xTimer)
+{
+ chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterStateAfterUnlatch, reinterpret_cast<intptr_t>(nullptr));
+}
+
+void CancelUnlatchTimer(void)
+{
+ if (xTimerStop(sUnlatchTimer, pdMS_TO_TICKS(0)) == pdFAIL)
+ {
+ SILABS_LOG("sUnlatchTimer stop() failed");
+ appError(APP_ERROR_STOP_TIMER_FAILED);
+ }
+}
+
+void StartUnlatchTimer(uint32_t timeoutMs)
+{
+ if (xTimerIsTimerActive(sUnlatchTimer))
+ {
+ SILABS_LOG("app timer already started!");
+ CancelUnlatchTimer();
+ }
+
+ // timer is not active, change its period to required value (== restart).
+ // FreeRTOS- Block for a maximum of 100 ms if the change period command
+ // cannot immediately be sent to the timer command queue.
+ if (xTimerStart(sUnlatchTimer, pdMS_TO_TICKS(timeoutMs)) != pdPASS)
+ {
+ SILABS_LOG("sUnlatchTimer timer start() failed");
+ appError(APP_ERROR_START_TIMER_FAILED);
+ }
+}
+
} // namespace
using namespace chip::TLV;
@@ -180,6 +219,8 @@
sLockLED.Init(LOCK_STATE_LED);
sLockLED.Set(state.Value() == DlLockState::kUnlocked);
+ sUnlatchTimer = xTimerCreate("UnlatchTimer", pdMS_TO_TICKS(UNLATCH_TIME_MS), pdFALSE, (void *) 0, UnlatchTimerCallback);
+
// Update the LCD with the Stored value. Show QR Code if not provisioned
#ifdef DISPLAY_ENABLED
GetLCD().WriteDemoUI(state.Value() != DlLockState::kUnlocked);
@@ -309,6 +350,10 @@
sAppTask.GetLCD().WriteDemoUI(locked);
#endif // DISPLAY_ENABLED
}
+ else if (aAction == LockManager::UNLATCH_ACTION)
+ {
+ SILABS_LOG("Unlatch Action has been initiated");
+ }
if (aActor == AppEvent::kEventType_Button)
{
@@ -325,6 +370,11 @@
{
SILABS_LOG("Lock Action has been completed")
}
+ else if (aAction == LockManager::UNLATCH_ACTION)
+ {
+ SILABS_LOG("Unlatch Action has been completed")
+ StartUnlatchTimer(UNLATCH_TIME_MS);
+ }
else if (aAction == LockManager::UNLOCK_ACTION)
{
SILABS_LOG("Unlock Action has been completed")
diff --git a/examples/lock-app/silabs/src/LockManager.cpp b/examples/lock-app/silabs/src/LockManager.cpp
index 3c376a2..04527e5 100644
--- a/examples/lock-app/silabs/src/LockManager.cpp
+++ b/examples/lock-app/silabs/src/LockManager.cpp
@@ -186,22 +186,24 @@
State_t new_state;
// Initiate Turn Lock/Unlock Action only when the previous one is complete.
- if (mState == kState_LockCompleted && aAction == UNLOCK_ACTION)
+ if ((mState == kState_LockCompleted || mState == kState_UnlatchCompleted) && (aAction == UNLOCK_ACTION))
{
action_initiated = true;
-
- new_state = kState_UnlockInitiated;
+ new_state = kState_UnlockInitiated;
+ }
+ else if ((mState == kState_LockCompleted || mState == kState_UnlockCompleted) && (aAction == UNLATCH_ACTION))
+ {
+ action_initiated = true;
+ new_state = kState_UnlatchInitiated;
}
else if (mState == kState_UnlockCompleted && aAction == LOCK_ACTION)
{
action_initiated = true;
-
- new_state = kState_LockInitiated;
+ new_state = kState_LockInitiated;
}
if (action_initiated)
{
-
StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS);
// Since the timer started successfully, update the state and trigger callback
@@ -249,6 +251,23 @@
event.Handler = ActuatorMovementTimerEventHandler;
AppTask::GetAppTask().PostEvent(&event);
}
+void LockManager::UnlockAfterUnlatch()
+{
+ // write the new lock value
+ bool succes = false;
+ if (mUnlatchContext.mEndpointId != kInvalidEndpointId)
+ {
+ succes = setLockState(mUnlatchContext.mEndpointId, mUnlatchContext.mFabricIdx, mUnlatchContext.mNodeId,
+ DlLockState::kUnlocked, mUnlatchContext.mPin, mUnlatchContext.mErr);
+ }
+
+ if (!succes)
+ {
+ SILABS_LOG("Failed to update the lock state after Unlatch");
+ }
+
+ InitiateAction(AppEvent::kEventType_Lock, LockManager::UNLOCK_ACTION);
+}
void LockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent)
{
@@ -261,6 +280,11 @@
lock->mState = kState_LockCompleted;
actionCompleted = LOCK_ACTION;
}
+ else if (lock->mState == kState_UnlatchInitiated)
+ {
+ lock->mState = kState_UnlatchCompleted;
+ actionCompleted = UNLATCH_ACTION;
+ }
else if (lock->mState == kState_UnlockInitiated)
{
lock->mState = kState_UnlockCompleted;
@@ -285,6 +309,29 @@
bool LockManager::Unlock(chip::EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
const Nullable<chip::NodeId> & nodeId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
{
+ if (DoorLockServer::Instance().SupportsUnbolt(endpointId))
+ {
+ // TODO: Our current implementation does not support multiple endpoint. This needs to be fixed in the future.
+ if (endpointId != mUnlatchContext.mEndpointId)
+ {
+ // If we get a request to unlock on a different endpoint while the current endpoint is in the middle of an action,
+ // we return false for now. This needs to be fixed in the future.
+ if (mState != kState_UnlockCompleted && mState != kState_LockCompleted)
+ {
+ ChipLogError(Zcl, "Cannot unlock while unlatch on another endpoint is in progress on anotther endpoint");
+ return false;
+ }
+ else
+ {
+ mUnlatchContext.Update(endpointId, fabricIdx, nodeId, pin, err);
+ return setLockState(endpointId, fabricIdx, nodeId, DlLockState::kUnlatched, pin, err);
+ }
+ }
+ else
+ {
+ return setLockState(endpointId, fabricIdx, nodeId, DlLockState::kUnlatched, pin, err);
+ }
+ }
return setLockState(endpointId, fabricIdx, nodeId, DlLockState::kUnlocked, pin, err);
}
diff --git a/examples/lock-app/silabs/src/ZclCallbacks.cpp b/examples/lock-app/silabs/src/ZclCallbacks.cpp
index 2aa0e9d..f7e333f 100644
--- a/examples/lock-app/silabs/src/ZclCallbacks.cpp
+++ b/examples/lock-app/silabs/src/ZclCallbacks.cpp
@@ -89,7 +89,14 @@
bool status = LockMgr().Unlock(endpointId, fabricIdx, nodeId, pinCode, err);
if (status == true)
{
- LockMgr().InitiateAction(AppEvent::kEventType_Lock, LockManager::UNLOCK_ACTION);
+ if (DoorLockServer::Instance().SupportsUnbolt(endpointId))
+ {
+ LockMgr().InitiateAction(AppEvent::kEventType_Lock, LockManager::UNLATCH_ACTION);
+ }
+ else
+ {
+ LockMgr().InitiateAction(AppEvent::kEventType_Lock, LockManager::UNLOCK_ACTION);
+ }
}
return status;