Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chef doorlock sample update #24118

Merged
merged 1 commit into from
Feb 28, 2023
Merged
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
212 changes: 210 additions & 2 deletions examples/chef/common/stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,227 @@
#ifdef EMBER_AF_PLUGIN_DOOR_LOCK_SERVER
#include <app/clusters/door-lock-server/door-lock-server.h>

class LockManager
{
public:
static constexpr uint32_t kNumEndpoints = 1;
static constexpr uint32_t kNumUsersPerEndpoint = 2;
static constexpr uint32_t kNumCredentialsPerEndpoint = 20;
achaulk-goog marked this conversation as resolved.
Show resolved Hide resolved
static constexpr uint32_t kNumCredentialsPerUser = 10;
static constexpr uint32_t kMaxNameLength = 32;
static constexpr uint32_t kMaxDataLength = 16;

struct Credential
{
bool set(DlCredentialStatus status, DlCredentialType type, chip::ByteSpan newData)
{
if (newData.size() > kMaxDataLength || type != DlCredentialType::kPIN)
return false;
memcpy(data, newData.data(), newData.size());
info = EmberAfPluginDoorLockCredentialInfo{
status,
type,
chip::ByteSpan(data, newData.size()),
};
return true;
}

EmberAfPluginDoorLockCredentialInfo info = { DlCredentialStatus::kAvailable };
uint8_t data[kMaxDataLength];
};

struct User
{
void set(chip::CharSpan newName, uint32_t userId, DlUserStatus userStatus, DlUserType type, DlCredentialRule credentialRule)
{
size_t sz = std::min(sizeof(name), newName.size());
memcpy(name, newName.data(), sz);
info = EmberAfPluginDoorLockUserInfo{
chip::CharSpan(name, sz), chip::Span<const DlCredential>(), userId, userStatus, type, credentialRule,
};
}
bool addCredential(uint8_t type, uint16_t index)
{
if (info.credentials.size() == kNumCredentialsPerUser)
return false;
auto & cr = credentialMap[info.credentials.size()];
cr.CredentialType = type;
cr.CredentialIndex = index;
info.credentials = chip::Span<const DlCredential>(credentialMap, info.credentials.size() + 1);
return true;
}

EmberAfPluginDoorLockUserInfo info = { .userStatus = DlUserStatus::kAvailable };
char name[kMaxNameLength];
DlCredential credentialMap[kNumCredentialsPerUser];
};

struct Endpoint
{
chip::EndpointId id;
User users[kNumUsersPerEndpoint];
Credential credentials[kNumCredentialsPerEndpoint];
};

static LockManager & Instance()
{
static LockManager instance;
return instance;
}

LockManager() { defaultInitialize(); }

bool getUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
{
auto ep = findEndpoint(endpointId);
if (!ep)
return false;
if (userIndex >= kNumUsersPerEndpoint)
return false;
user = ep->users[userIndex].info;
return true;
}

bool setUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
const chip::CharSpan & userName, uint32_t uniqueId, DlUserStatus userStatus, DlUserType usertype,
DlCredentialRule credentialRule, const DlCredential * credentials, size_t totalCredentials)
{
auto ep = findEndpoint(endpointId);
if (!ep)
return false;
if (userIndex >= kNumUsersPerEndpoint || totalCredentials > kNumCredentialsPerUser)
return false;
ep->users[userIndex].set(userName, uniqueId, userStatus, usertype, credentialRule);
ep->users[userIndex].info.creationSource = DlAssetSource::kMatterIM;
ep->users[userIndex].info.createdBy = creator;
ep->users[userIndex].info.modificationSource = DlAssetSource::kMatterIM;
ep->users[userIndex].info.lastModifiedBy = modifier;
for (size_t i = 0; i < totalCredentials; i++)
ep->users[userIndex].addCredential(credentials[i].CredentialType, credentials[i].CredentialIndex);
return true;
}

bool getCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType,
EmberAfPluginDoorLockCredentialInfo & credential)
{
auto ep = findEndpoint(endpointId);
if (!ep)
return false;
if (credentialIndex >= kNumCredentialsPerEndpoint)
return false;
if (credentialType != DlCredentialType::kPIN)
return false;
credential = ep->credentials[credentialIndex].info;
achaulk-goog marked this conversation as resolved.
Show resolved Hide resolved
return true;
}

bool setCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
DlCredentialStatus credentialStatus, DlCredentialType credentialType, const chip::ByteSpan & credentialData)
{
auto ep = findEndpoint(endpointId);
if (!ep)
return false;
if (credentialIndex >= kNumCredentialsPerEndpoint)
return false;
if (credentialType != DlCredentialType::kPIN)
return false;
auto & credential = ep->credentials[credentialIndex];
if (!credential.set(credentialStatus, credentialType, credentialData))
return false;
credential.info.creationSource = DlAssetSource::kMatterIM;
credential.info.createdBy = creator;
credential.info.modificationSource = DlAssetSource::kMatterIM;
credential.info.lastModifiedBy = modifier;
return true;
}

bool checkPin(chip::EndpointId endpointId, const chip::Optional<chip::ByteSpan> & pinCode,
chip::app::Clusters::DoorLock::DlOperationError & err)
{
if (!pinCode.HasValue())
{
err = DlOperationError::kInvalidCredential;
return false;
}
auto ep = findEndpoint(endpointId);
if (!ep)
return false;
for (auto & pin : ep->credentials)
{
if (pin.info.status == DlCredentialStatus::kOccupied && pin.info.credentialData.data_equal(pinCode.Value()))
{
return true;
}
}
err = DlOperationError::kInvalidCredential;
return false;
}

private:
Endpoint * findEndpoint(chip::EndpointId endpointId)
{
for (auto & e : endpoints)
{
if (e.id == endpointId)
return &e;
}
return nullptr;
}

void defaultInitialize()
{
endpoints[0].id = 1;
uint8_t pin[6] = { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 };
endpoints[0].credentials[chip::to_underlying(DlCredentialType::kPin)][0].set(DlCredentialStatus::kOccupied,
DlCredentialType::kPin, chip::ByteSpan(pin));
endpoints[0].users[0].set(chip::CharSpan("default"), 1, DlUserStatus::kOccupiedEnabled, DlUserType::kUnrestrictedUser,
DlCredentialRule::kSingle);
endpoints[0].users[0].addCredential(chip::to_underlying(DlCredentialType::kPin), 1);
}

Endpoint endpoints[kNumEndpoints];
};

bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const chip::Optional<chip::ByteSpan> & pinCode,
chip::app::Clusters::DoorLock::OperationErrorEnum & err)
{
err = OperationErrorEnum::kUnspecified;
// TBD: LockManager, check pinCode, ...
return DoorLockServer::Instance().SetLockState(endpointId, DlLockState::kLocked);
}

bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const chip::Optional<chip::ByteSpan> & pinCode,
chip::app::Clusters::DoorLock::OperationErrorEnum & err)
{
err = OperationErrorEnum::kUnspecified;
// TBD: LockManager, check pinCode, ...
return DoorLockServer::Instance().SetLockState(endpointId, DlLockState::kUnlocked);
}

bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
{
return LockManager::Instance().getUser(endpointId, userIndex - 1, user);
}

bool emberAfPluginDoorLockSetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator,
chip::FabricIndex modifier, const chip::CharSpan & userName, uint32_t uniqueId,
DlUserStatus userStatus, DlUserType usertype, DlCredentialRule credentialRule,
const DlCredential * credentials, size_t totalCredentials)
{
return LockManager::Instance().setUser(endpointId, userIndex - 1, creator, modifier, userName, uniqueId, userStatus, usertype,
credentialRule, credentials, totalCredentials);
}

bool emberAfPluginDoorLockGetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType,
EmberAfPluginDoorLockCredentialInfo & credential)
{
return LockManager::Instance().getCredential(endpointId, credentialIndex - 1, credentialType, credential);
}

bool emberAfPluginDoorLockSetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator,
chip::FabricIndex modifier, DlCredentialStatus credentialStatus,
DlCredentialType credentialType, const chip::ByteSpan & credentialData)
{
return LockManager::Instance().setCredential(endpointId, credentialIndex - 1, creator, modifier, credentialStatus,
credentialType, credentialData);
}

#endif /* EMBER_AF_PLUGIN_DOOR_LOCK_SERVER */
85 changes: 84 additions & 1 deletion examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,11 @@ server cluster DoorLock = 257 {
kHolidaySchedules = 0x800;
}

struct CredentialStruct {
CredentialTypeEnum credentialType = 0;
int16u credentialIndex = 1;
}

critical event DoorLockAlarm = 0 {
AlarmCodeEnum alarmCode = 0;
}
Expand Down Expand Up @@ -1468,9 +1473,11 @@ server cluster DoorLock = 257 {
readonly attribute nullable DlLockState lockState = 0;
readonly attribute DlLockType lockType = 1;
readonly attribute boolean actuatorEnabled = 2;
readonly attribute int16u numberOfTotalUsersSupported = 17;
readonly attribute int16u numberOfPINUsersSupported = 18;
readonly attribute int8u maxPINCodeLength = 23;
readonly attribute int8u minPINCodeLength = 24;
readonly attribute int8u numberOfCredentialsSupportedPerUser = 28;
attribute access(write: manage) int32u autoRelockTime = 35;
attribute access(write: manage) OperatingModeEnum operatingMode = 37;
readonly attribute DlSupportedOperatingModes supportedOperatingModes = 38;
Expand All @@ -1493,8 +1500,82 @@ server cluster DoorLock = 257 {
optional OCTET_STRING PINCode = 0;
}

request struct UnlockWithTimeoutRequest {
INT16U timeout = 0;
optional OCTET_STRING PINCode = 1;
}

request struct SetUserRequest {
DataOperationTypeEnum operationType = 0;
INT16U userIndex = 1;
nullable CHAR_STRING userName = 2;
nullable INT32U userUniqueID = 3;
nullable UserStatusEnum userStatus = 4;
nullable UserTypeEnum userType = 5;
nullable CredentialRuleEnum credentialRule = 6;
}

request struct GetUserRequest {
INT16U userIndex = 0;
}

request struct ClearUserRequest {
INT16U userIndex = 0;
}

request struct SetCredentialRequest {
DataOperationTypeEnum operationType = 0;
CredentialStruct credential = 1;
LONG_OCTET_STRING credentialData = 2;
nullable INT16U userIndex = 3;
nullable UserStatusEnum userStatus = 4;
nullable UserTypeEnum userType = 5;
}

request struct GetCredentialStatusRequest {
CredentialStruct credential = 0;
}

request struct ClearCredentialRequest {
nullable CredentialStruct credential = 0;
}

response struct GetUserResponse = 28 {
INT16U userIndex = 0;
nullable CHAR_STRING userName = 1;
nullable INT32U userUniqueID = 2;
nullable UserStatusEnum userStatus = 3;
nullable UserTypeEnum userType = 4;
nullable CredentialRuleEnum credentialRule = 5;
nullable CredentialStruct credentials[] = 6;
nullable fabric_idx creatorFabricIndex = 7;
nullable fabric_idx lastModifiedFabricIndex = 8;
nullable INT16U nextUserIndex = 9;
}

response struct SetCredentialResponse = 35 {
DlStatus status = 0;
nullable INT16U userIndex = 1;
nullable INT16U nextCredentialIndex = 2;
}

response struct GetCredentialStatusResponse = 37 {
boolean credentialExists = 0;
nullable INT16U userIndex = 1;
nullable fabric_idx creatorFabricIndex = 2;
nullable fabric_idx lastModifiedFabricIndex = 3;
nullable INT16U nextCredentialIndex = 4;
}

timed command LockDoor(LockDoorRequest): DefaultSuccess = 0;
timed command UnlockDoor(UnlockDoorRequest): DefaultSuccess = 1;
timed command UnlockWithTimeout(UnlockWithTimeoutRequest): DefaultSuccess = 3;
timed command access(invoke: administer) SetUser(SetUserRequest): DefaultSuccess = 26;
command access(invoke: administer) GetUser(GetUserRequest): GetUserResponse = 27;
timed command access(invoke: administer) ClearUser(ClearUserRequest): DefaultSuccess = 29;
timed command access(invoke: administer) SetCredential(SetCredentialRequest): SetCredentialResponse = 34;
command access(invoke: administer) GetCredentialStatus(GetCredentialStatusRequest): GetCredentialStatusResponse = 36;
timed command access(invoke: administer) ClearCredential(ClearCredentialRequest): DefaultSuccess = 38;
}

endpoint 0 {
Expand Down Expand Up @@ -1711,9 +1792,11 @@ endpoint 1 {
ram attribute lockState default = 1;
ram attribute lockType;
ram attribute actuatorEnabled;
ram attribute numberOfTotalUsersSupported default = 2;
ram attribute numberOfPINUsersSupported default = 2;
ram attribute maxPINCodeLength default = 10;
ram attribute minPINCodeLength default = 5;
ram attribute numberOfCredentialsSupportedPerUser default = 5;
ram attribute autoRelockTime;
ram attribute operatingMode;
ram attribute supportedOperatingModes default = 0xFFF6;
Expand All @@ -1724,7 +1807,7 @@ endpoint 1 {
callback attribute generatedCommandList;
callback attribute acceptedCommandList;
callback attribute attributeList;
ram attribute featureMap default = 0x0081;
ram attribute featureMap default = 0x0181;
ram attribute clusterRevision default = 6;
}
}
Expand Down
Loading