Skip to content

Commit

Permalink
Add ability to set event UserIndex and Credential in SDK and add to L…
Browse files Browse the repository at this point in the history
…inux Lock app. (project-chip#25133)

* Resolve event notifications from lock when setting the lock state.

* Fix Linux build issue.

---------

Co-authored-by: Boris Zbarsky <[email protected]>
  • Loading branch information
2 people authored and David Lechner committed Mar 22, 2023
1 parent 57a0fec commit 318377f
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 42 deletions.
7 changes: 4 additions & 3 deletions examples/lock-app/linux/include/LockEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ class LockEndpoint

inline chip::EndpointId GetEndpointId() const { return mEndpointId; }

bool Lock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err);
bool Unlock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err);
bool Lock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
bool Unlock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);

bool GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const;
bool SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier, const chip::CharSpan & userName,
Expand Down Expand Up @@ -97,7 +97,8 @@ class LockEndpoint
OperatingModeEnum operatingMode);

private:
bool setLockState(DlLockState lockState, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err);
bool setLockState(DlLockState lockState, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource = OperationSourceEnum::kUnspecified);
const char * lockStateToString(DlLockState lockState) const;

bool weekDayScheduleInAction(uint16_t userIndex) const;
Expand Down
6 changes: 4 additions & 2 deletions examples/lock-app/linux/include/LockManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ class LockManager

bool SendLockAlarm(chip::EndpointId endpointId, AlarmCodeEnum alarmCode);

bool Lock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err);
bool Unlock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err);
bool Lock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource);
bool Unlock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource);

bool GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user);
bool SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
Expand Down
19 changes: 12 additions & 7 deletions examples/lock-app/linux/src/LockEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@
#include <cstring>

using chip::to_underlying;
using chip::app::DataModel::MakeNullable;

bool LockEndpoint::Lock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
bool LockEndpoint::Lock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
{
return setLockState(DlLockState::kLocked, pin, err);
return setLockState(DlLockState::kLocked, pin, err, opSource);
}

bool LockEndpoint::Unlock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
bool LockEndpoint::Unlock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
{
return setLockState(DlLockState::kUnlocked, pin, err);
return setLockState(DlLockState::kUnlocked, pin, err, opSource);
}

bool LockEndpoint::GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const
Expand Down Expand Up @@ -376,7 +377,8 @@ DlStatus LockEndpoint::SetSchedule(uint8_t holidayIndex, DlScheduleStatus status
return DlStatus::kSuccess;
}

bool LockEndpoint::setLockState(DlLockState lockState, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
bool LockEndpoint::setLockState(DlLockState lockState, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource)
{
// Assume pin is required until told otherwise
bool requirePin = true;
Expand Down Expand Up @@ -457,8 +459,11 @@ bool LockEndpoint::setLockState(DlLockState lockState, const Optional<chip::Byte
"Lock App: specified PIN code was found in the database, setting door lock state to \"%s\" [endpointId=%d,userIndex=%u]",
lockStateToString(lockState), mEndpointId, userIndex);

mLockState = lockState;
DoorLockServer::Instance().SetLockState(mEndpointId, mLockState);
mLockState = lockState;
LockOpCredentials userCredential[] = { { CredentialTypeEnum::kPin, uint16_t(credentialIndex) } };
auto userCredentials = MakeNullable<List<const LockOpCredentials>>(userCredential);
DoorLockServer::Instance().SetLockState(mEndpointId, mLockState, opSource, MakeNullable(static_cast<uint16_t>(userIndex + 1)),
userCredentials);

return true;
}
Expand Down
10 changes: 6 additions & 4 deletions examples/lock-app/linux/src/LockManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,26 +134,28 @@ bool LockManager::SendLockAlarm(chip::EndpointId endpointId, AlarmCodeEnum alarm
return lockEndpoint->SendLockAlarm(alarmCode);
}

bool LockManager::Lock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
bool LockManager::Lock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource)
{
auto lockEndpoint = getEndpoint(endpointId);
if (nullptr == lockEndpoint)
{
ChipLogError(Zcl, "Unable to lock the door - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
return false;
}
return lockEndpoint->Lock(pin, err);
return lockEndpoint->Lock(pin, err, opSource);
}

bool LockManager::Unlock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err)
bool LockManager::Unlock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource)
{
auto lockEndpoint = getEndpoint(endpointId);
if (nullptr == lockEndpoint)
{
ChipLogError(Zcl, "Unable to unlock the door - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
return false;
}
return lockEndpoint->Unlock(pin, err);
return lockEndpoint->Unlock(pin, err, opSource);
}

bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
Expand Down
4 changes: 2 additions & 2 deletions examples/lock-app/linux/src/ZCLDoorLockCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ using namespace chip::app::Clusters::DoorLock;
bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const Optional<ByteSpan> & pinCode,
OperationErrorEnum & err)
{
return LockManager::Instance().Lock(endpointId, pinCode, err);
return LockManager::Instance().Lock(endpointId, pinCode, err, OperationSourceEnum::kRemote);
}

bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Optional<ByteSpan> & pinCode,
OperationErrorEnum & err)
{
return LockManager::Instance().Unlock(endpointId, pinCode, err);
return LockManager::Instance().Unlock(endpointId, pinCode, err, OperationSourceEnum::kRemote);
}

bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
Expand Down
30 changes: 8 additions & 22 deletions src/app/clusters/door-lock-server/door-lock-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLo
return SetAttribute(endpointId, Attributes::LockState::Id, Attributes::LockState::Set, newLockState);
}

bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLockState, OperationSourceEnum opSource)
bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLockState, OperationSourceEnum opSource,
const Nullable<uint16_t> & userIndex, const Nullable<List<const LockOpCredentials>> & credentials)
{
bool success = SetLockState(endpointId, newLockState);

Expand All @@ -122,8 +123,8 @@ bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLo
// Send LockOperation event
auto opType = (DlLockState::kLocked == newLockState) ? LockOperationTypeEnum::kLock : LockOperationTypeEnum::kUnlock;

SendLockOperationEvent(endpointId, opType, opSource, OperationErrorEnum::kUnspecified, Nullable<uint16_t>(),
Nullable<chip::FabricIndex>(), Nullable<chip::NodeId>(), nullptr, 0, success);
SendLockOperationEvent(endpointId, opType, opSource, OperationErrorEnum::kUnspecified, userIndex, Nullable<chip::FabricIndex>(),
Nullable<chip::NodeId>(), credentials, success);

// Schedule auto-relocking
if (success && LockOperationTypeEnum::kUnlock == opType)
Expand Down Expand Up @@ -3356,46 +3357,31 @@ bool DoorLockServer::HandleRemoteLockOperation(chip::app::CommandHandler * comma

// Send LockOperation/LockOperationError event. The credential index in
// foundCred will be filled in if we actually have a value to fill in.
Nullable<List<const LockOpCredentials>> credentials{};
LockOpCredentials foundCred[] = { { CredentialTypeEnum::kPin, UINT16_MAX } };
LockOpCredentials * credList = nullptr;
size_t credListSize = 0;

// appclusters.pdf 5.3.5.3, 5.3.5.4:
// The list of credentials used in performing the lock operation. This SHALL be null if no credentials were involved.
if (pinCode.HasValue() && pinCredIdx.HasValue())
{
foundCred[0].credentialIndex = pinCredIdx.Value();
credList = foundCred;
credListSize = 1;
credentials.SetNonNull(foundCred);
}

SendLockOperationEvent(endpoint, opType, OperationSourceEnum::kRemote, reason, pinUserIdx,
Nullable<chip::FabricIndex>(getFabricIndex(commandObj)), Nullable<chip::NodeId>(getNodeId(commandObj)),
credList, credListSize, success);
credentials, success);
return success;
}

void DoorLockServer::SendLockOperationEvent(chip::EndpointId endpointId, LockOperationTypeEnum opType, OperationSourceEnum opSource,
OperationErrorEnum opErr, const Nullable<uint16_t> & userId,
const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
LockOpCredentials * credList, size_t credListSize, bool opSuccess)
const Nullable<List<const LockOpCredentials>> & credentials, bool opSuccess)
{
Nullable<List<const Structs::CredentialStruct::Type>> credentials{};

// appclusters.pdf 5.3.5.3, 5.3.5.4:
// The list of credentials used in performing the lock operation. This SHALL be null if no credentials were involved.
if (nullptr == credList || 0 == credListSize)
{
credentials.SetNull();
}
else
{
credentials.SetNonNull(List<const Structs::CredentialStruct::Type>(credList, credListSize));
}

// TODO: if [USR] feature is not supported then credentials should be omitted (Optional.HasValue()==false)?
// Spec just says that it should be NULL if no PIN were provided.

if (opSuccess)
{
Events::LockOperation::Type event{ opType, opSource, userId, fabricIdx, nodeId, MakeOptional(credentials) };
Expand Down
7 changes: 5 additions & 2 deletions src/app/clusters/door-lock-server/door-lock-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ using chip::app::Clusters::DoorLock::UserStatusEnum;
using chip::app::Clusters::DoorLock::UserTypeEnum;
using chip::app::DataModel::List;
using chip::app::DataModel::Nullable;
using chip::app::DataModel::NullNullable;

using CredentialStruct = chip::app::Clusters::DoorLock::Structs::CredentialStruct::Type;
using LockOpCredentials = CredentialStruct;
Expand Down Expand Up @@ -95,7 +96,9 @@ class DoorLockServer
*
* @return true on success, false on failure.
*/
bool SetLockState(chip::EndpointId endpointId, DlLockState newLockState, OperationSourceEnum opSource);
bool SetLockState(chip::EndpointId endpointId, DlLockState newLockState, OperationSourceEnum opSource,
const Nullable<uint16_t> & userIndex = NullNullable,
const Nullable<List<const LockOpCredentials>> & credentials = NullNullable);

/**
* Updates the LockState attribute with new value.
Expand Down Expand Up @@ -408,7 +411,7 @@ class DoorLockServer
void SendLockOperationEvent(chip::EndpointId endpointId, LockOperationTypeEnum opType, OperationSourceEnum opSource,
OperationErrorEnum opErr, const Nullable<uint16_t> & userId,
const Nullable<chip::FabricIndex> & fabricIdx, const Nullable<chip::NodeId> & nodeId,
LockOpCredentials * credList, size_t credListSize, bool opSuccess = true);
const Nullable<List<const LockOpCredentials>> & credentials = NullNullable, bool opSuccess = true);

/**
* @brief Schedule auto relocking with a given timeout
Expand Down

0 comments on commit 318377f

Please sign in to comment.