diff --git a/examples/lock-app/efr32/include/LockManager.h b/examples/lock-app/efr32/include/LockManager.h index e8c2d8d0f9f117..a97d7f4bb3b8bf 100644 --- a/examples/lock-app/efr32/include/LockManager.h +++ b/examples/lock-app/efr32/include/LockManager.h @@ -31,7 +31,13 @@ using namespace ::chip; +// Currently up to 10 users are support on the EFR32 platform +#define DOOR_LOCK_MAX_USERS 10 #define DOOR_LOCK_MAX_CREDENTIAL_SIZE 8 +#define MININUM_USER_INDEX 1 +#define MINIMUM_CREDENTIAL_INDEX 1 +#define MAX_CREDENTIAL_PER_USER 10 +#define MAX_CREDENTIALS 50 static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE = 20; @@ -55,7 +61,7 @@ class LockManager } State; CHIP_ERROR Init(chip::app::DataModel::Nullable state, - uint8_t maxNumberOfCredentialsPerUser); + uint8_t maxNumberOfCredentialsPerUser, uint16_t numberOfSupportedUsers); bool NextState(); bool IsActionInProgress(); bool InitiateAction(int32_t aActor, Action_t aAction); @@ -67,10 +73,10 @@ class LockManager bool Lock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err); bool Unlock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err); - bool GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const; - bool SetUser(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); + bool GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const; + 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); bool GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType, EmberAfPluginDoorLockCredentialInfo & credential) const; @@ -99,13 +105,15 @@ class LockManager static void AutoLockTimerEventHandler(AppEvent * aEvent); static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); - EmberAfPluginDoorLockUserInfo mLockUser; - EmberAfPluginDoorLockCredentialInfo mLockCredentials; + EmberAfPluginDoorLockUserInfo mLockUsers[DOOR_LOCK_MAX_USERS]; + EmberAfPluginDoorLockCredentialInfo mLockCredentials[MAX_CREDENTIALS]; - char mUserName[DOOR_LOCK_MAX_USER_NAME_SIZE]; - uint8_t mCredentialData[DOOR_LOCK_MAX_CREDENTIAL_SIZE]; - chip::Platform::ScopedMemoryBuffer mCredentials; uint8_t mMaxCredentialsPerUser; + uint16_t mMaxUsers; + + char mUserNames[ArraySize(mLockUsers)][DOOR_LOCK_MAX_USER_NAME_SIZE]; + uint8_t mCredentialData[MAX_CREDENTIALS][DOOR_LOCK_MAX_CREDENTIAL_SIZE]; + chip::Platform::ScopedMemoryBuffer mCredentials[MAX_CREDENTIAL_PER_USER]; static LockManager sLock; }; diff --git a/examples/lock-app/efr32/src/AppTask.cpp b/examples/lock-app/efr32/src/AppTask.cpp index 78fe30c3e82453..d3cc7e9a6f17d6 100644 --- a/examples/lock-app/efr32/src/AppTask.cpp +++ b/examples/lock-app/efr32/src/AppTask.cpp @@ -245,9 +245,18 @@ CHIP_ERROR AppTask::Init() endpointId); maxCredentialsPerUser = 5; } + + uint16_t numberOfSupportedUsers = 0; + if (!DoorLockServer::Instance().GetNumberOfUserSupported(endpointId, numberOfSupportedUsers)) + { + ChipLogError(Zcl, + "Unable to get number of supported users when initializing lock endpoint, defaulting to 10 [endpointId=%d]", + endpointId); + numberOfSupportedUsers = 10; + } chip::DeviceLayer::PlatformMgr().UnlockChipStack(); - err = LockMgr().Init(state, maxCredentialsPerUser); + err = LockMgr().Init(state, maxCredentialsPerUser, numberOfSupportedUsers); if (err != CHIP_NO_ERROR) { EFR32_LOG("LockMgr().Init() failed"); diff --git a/examples/lock-app/efr32/src/LockManager.cpp b/examples/lock-app/efr32/src/LockManager.cpp index c74107594ef041..6398ff3f6f5483 100644 --- a/examples/lock-app/efr32/src/LockManager.cpp +++ b/examples/lock-app/efr32/src/LockManager.cpp @@ -22,6 +22,7 @@ #include "AppConfig.h" #include "AppTask.h" #include +#include #include #include @@ -32,16 +33,28 @@ TimerHandle_t sLockTimer; using namespace ::chip::DeviceLayer::Internal; CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state, - uint8_t maxNumberOfCredentialsPerUser) + uint8_t maxNumberOfCredentialsPerUser, uint16_t numberOfSupportedUsers) { - // Allocate buffer for credentials - if (!mCredentials.Alloc(maxNumberOfCredentialsPerUser)) + for (uint8_t i = 0; i < ArraySize(mLockUsers); i++) { - EFR32_LOG("Failed to allocate array for lock credentials"); - return APP_ERROR_ALLOCATION_FAILED; + // Allocate buffer for credentials + if (!mCredentials[i].Alloc(maxNumberOfCredentialsPerUser)) + { + EFR32_LOG("Failed to allocate array for lock credentials"); + return APP_ERROR_ALLOCATION_FAILED; + } } + mMaxCredentialsPerUser = maxNumberOfCredentialsPerUser; + mMaxUsers = numberOfSupportedUsers; + if (mMaxUsers > DOOR_LOCK_MAX_USERS) + { + EFR32_LOG("Max number of users is greater than %d, the maximum amount of users currently supported on this platform", + DOOR_LOCK_MAX_USERS); + return APP_ERROR_ALLOCATION_FAILED; + } + // Create FreeRTOS sw timer for lock timer. sLockTimer = xTimerCreate("lockTmr", // Just a text name, not used by the RTOS kernel 1, // == default timer period (mS) @@ -67,17 +80,20 @@ CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable(&mLockUser), - sizeof(EmberAfPluginDoorLockUserInfo), outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), + sizeof(EmberAfPluginDoorLockUserInfo) * ArraySize(mLockUsers), outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), - sizeof(EmberAfPluginDoorLockCredentialInfo), outLen); + sizeof(EmberAfPluginDoorLockCredentialInfo) * ArraySize(mLockCredentials), outLen); - EFR32Config::ReadConfigValueStr(EFR32Config::kConfigKey_LockUserName, mUserName, DOOR_LOCK_USER_NAME_BUFFER_SIZE, outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_LockUserName, reinterpret_cast(mUserNames), + sizeof(mUserNames), outLen); - EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_CredentialData, mCredentialData, sizeof(mCredentialData), outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_CredentialData, reinterpret_cast(mCredentialData), + sizeof(mCredentialData), outLen); - EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials.Get()), - sizeof(DlCredential), outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials[0].Get()), + sizeof(DlCredential) * mMaxUsers * mMaxCredentialsPerUser, outLen); return true; } @@ -212,21 +228,24 @@ bool LockManager::Unlock(chip::EndpointId endpointId, const Optional(userInDb.credentials.data(), userInDb.credentials.size()); + user.credentials = chip::Span(mCredentials[adjustedUserIndex].Get(), userInDb.credentials.size()); user.userUniqueId = userInDb.userUniqueId; user.userType = userInDb.userType; user.credentialRule = userInDb.credentialRule; @@ -241,14 +260,14 @@ bool LockManager::GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & us "Found occupied user " "[endpoint=%d,name=\"%.*s\",credentialsCount=%u,uniqueId=%lx,type=%u,credentialRule=%u," "createdBy=%d,lastModifiedBy=%d]", - mEndpointId, static_cast(user.userName.size()), user.userName.data(), user.credentials.size(), + endpointId, static_cast(user.userName.size()), user.userName.data(), user.credentials.size(), user.userUniqueId, to_underlying(user.userType), to_underlying(user.credentialRule), user.createdBy, user.lastModifiedBy); return true; } -bool LockManager::SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier, +bool LockManager::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) { @@ -256,27 +275,29 @@ bool LockManager::SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::F "Door Lock App: LockManager::SetUser " "[endpoint=%d,userIndex=%d,creator=%d,modifier=%d,userName=%s,uniqueId=%ld " "userStatus=%u,userType=%u,credentialRule=%u,credentials=%p,totalCredentials=%u]", - mEndpointId, userIndex, creator, modifier, userName.data(), uniqueId, to_underlying(userStatus), + endpointId, userIndex, creator, modifier, userName.data(), uniqueId, to_underlying(userStatus), to_underlying(usertype), to_underlying(credentialRule), credentials, totalCredentials); - auto & userInStorage = mLockUser; + uint16_t adjustedUserIndex = userIndex - 1; + + // door-lock-server checks for valid user index + auto & userInStorage = mLockUsers[adjustedUserIndex]; if (userName.size() > DOOR_LOCK_MAX_USER_NAME_SIZE) { - ChipLogError(Zcl, "Cannot set user - user name is too long [endpoint=%d,index=%d]", mEndpointId, userIndex); + ChipLogError(Zcl, "Cannot set user - user name is too long [endpoint=%d,index=%d]", endpointId, adjustedUserIndex); return false; } if (totalCredentials > mMaxCredentialsPerUser) { ChipLogError(Zcl, "Cannot set user - total number of credentials is too big [endpoint=%d,index=%d,totalCredentials=%u]", - mEndpointId, userIndex, totalCredentials); + endpointId, adjustedUserIndex, totalCredentials); return false; } - chip::Platform::CopyString(mUserName, userName); - mUserName[userName.size()] = 0; - userInStorage.userName = chip::CharSpan(mUserName, userName.size()); + chip::Platform::CopyString(mUserNames[adjustedUserIndex], userName); + userInStorage.userName = chip::CharSpan(mUserNames[adjustedUserIndex], userName.size()); userInStorage.userUniqueId = uniqueId; userInStorage.userStatus = userStatus; userInStorage.userType = usertype; @@ -286,23 +307,25 @@ bool LockManager::SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::F for (size_t i = 0; i < totalCredentials; ++i) { - mCredentials[i] = credentials[i]; - mCredentials[i].CredentialType = 1; - mCredentials[i].CredentialIndex = i + 1; + mCredentials[adjustedUserIndex][i] = credentials[i]; + mCredentials[adjustedUserIndex][i].CredentialType = 1; + mCredentials[adjustedUserIndex][i].CredentialIndex = i + 1; } - userInStorage.credentials = chip::Span(mCredentials.Get(), totalCredentials); + userInStorage.credentials = chip::Span(mCredentials[adjustedUserIndex].Get(), totalCredentials); // Save user information in NVM flash - EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_LockUser, reinterpret_cast(&userInStorage), - sizeof(EmberAfPluginDoorLockUserInfo)); + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), + sizeof(EmberAfPluginDoorLockUserInfo) * mMaxUsers); - EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials.Get()), - sizeof(DlCredential)); + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_UserCredentials, + reinterpret_cast(mCredentials[adjustedUserIndex].Get()), + sizeof(DlCredential) * totalCredentials); - EFR32Config::WriteConfigValueStr(EFR32Config::kConfigKey_LockUserName, mUserName, sizeof(userName.size())); + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_LockUserName, reinterpret_cast(mUserNames), + sizeof(mUserNames)); - ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", mEndpointId, userIndex); + ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", endpointId, adjustedUserIndex); return true; } @@ -310,11 +333,18 @@ bool LockManager::SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::F bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType, EmberAfPluginDoorLockCredentialInfo & credential) const { - ChipLogProgress(Zcl, "Lock App: LockManager::GetCredential [credentialType=%u]", to_underlying(credentialType)); - const auto & credentialInStorage = mLockCredentials; + uint16_t adjustedCredentialIndex = credentialIndex - 1; + + ChipLogProgress(Zcl, "Lock App: LockManager::GetCredential [credentialType=%u], credentialIndex=%d", + to_underlying(credentialType), adjustedCredentialIndex); + + // door-lock-server checks for valid credential index + const auto & credentialInStorage = mLockCredentials[adjustedCredentialIndex]; credential.status = credentialInStorage.status; + ChipLogDetail(Zcl, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, adjustedCredentialIndex); + if (DlCredentialStatus::kAvailable == credential.status) { ChipLogDetail(Zcl, "Found unoccupied credential "); @@ -344,7 +374,11 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential "[credentialStatus=%u,credentialType=%u,credentialDataSize=%u,creator=%d,modifier=%d]", to_underlying(credentialStatus), to_underlying(credentialType), credentialData.size(), creator, modifier); - auto & credentialInStorage = mLockCredentials; + uint16_t adjustedCredentialIndex = credentialIndex - 1; + + // door-lock-server checks for valid credential index + auto & credentialInStorage = mLockCredentials[adjustedCredentialIndex]; + if (credentialData.size() > DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE) { ChipLogError(Zcl, @@ -358,17 +392,15 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential credentialInStorage.createdBy = creator; credentialInStorage.lastModifiedBy = modifier; - memcpy(mCredentialData, credentialData.data(), credentialData.size()); - mCredentialData[credentialData.size()] = 0; - - credentialInStorage.credentialData = chip::ByteSpan{ mCredentialData, credentialData.size() }; + memcpy(mCredentialData[adjustedCredentialIndex], credentialData.data(), credentialData.size()); + credentialInStorage.credentialData = chip::ByteSpan{ mCredentialData[adjustedCredentialIndex], credentialData.size() }; - // Save user information in NVM flash - EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_Credential, reinterpret_cast(&credentialInStorage), - sizeof(EmberAfPluginDoorLockCredentialInfo)); + // Save credential information in NVM flash + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo) * mMaxCredentialsPerUser); EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_CredentialData, reinterpret_cast(&mCredentialData), - credentialData.size()); + sizeof(mCredentialData)); ChipLogProgress(Zcl, "Successfully set the credential [credentialType=%u]", to_underlying(credentialType)); @@ -397,31 +429,52 @@ bool LockManager::setLockState(chip::EndpointId endpointId, DlLockState lockStat if (mState == kState_UnlockCompleted) curState = DlLockState::kUnlocked; - if (curState == lockState) + if ((curState == lockState) && (curState == DlLockState::kLocked)) { ChipLogDetail(Zcl, "Door Lock App: door is already locked, ignoring command to set lock state to \"%s\" [endpointId=%d]", - lockStateToString(lockState), mEndpointId); - return false; + lockStateToString(lockState), endpointId); + return true; + } + else if ((curState == lockState) && (curState == DlLockState::kUnlocked)) + { + ChipLogDetail(Zcl, + "Door Lock App: door is already unlocked, ignoring command to set unlock state to \"%s\" [endpointId=%d]", + lockStateToString(lockState), endpointId); + return true; } + // Check the RequirePINforRemoteOperation attribute + bool requirePin = false; + // chip::app::Clusters::DoorLock::Attributes::RequirePINforRemoteOperation::Get(endpointId, &requirePin); + + // If a pin code is not given if (!pin.HasValue()) { - ChipLogDetail(Zcl, "Door Lock App: PIN code is not specified, setting door lock state to \"%s\" [endpointId=%d]", - lockStateToString(lockState), mEndpointId); + ChipLogDetail(Zcl, "Door Lock App: PIN code is not specified, but it is required [endpointId=%d]", mEndpointId); curState = lockState; - return true; + // If a pin code is not required + if (!requirePin) + { + ChipLogDetail(Zcl, "Door Lock App: setting door lock state to \"%s\" [endpointId=%d]", lockStateToString(lockState), + endpointId); + curState = lockState; + return true; + } + + return false; } // Check the PIN code - for (uint8_t i; i < 10; i++) + for (uint8_t i = 0; i < mMaxCredentialsPerUser; i++) { - if (mLockCredentials.credentialType != DlCredentialType::kPin || mLockCredentials.status == DlCredentialStatus::kAvailable) + if (mLockCredentials[i].credentialType != DlCredentialType::kPin || + mLockCredentials[i].status == DlCredentialStatus::kAvailable) { continue; } - if (mLockCredentials.credentialData.data_equal(pin.Value())) + if (mLockCredentials[i].credentialData.data_equal(pin.Value())) { ChipLogDetail(Zcl, "Lock App: specified PIN code was found in the database, setting lock state to \"%s\" [endpointId=%d]", diff --git a/examples/lock-app/efr32/src/ZclCallbacks.cpp b/examples/lock-app/efr32/src/ZclCallbacks.cpp index c271f2dc65fd5a..8fb775956a4c30 100644 --- a/examples/lock-app/efr32/src/ZclCallbacks.cpp +++ b/examples/lock-app/efr32/src/ZclCallbacks.cpp @@ -100,7 +100,7 @@ bool emberAfPluginDoorLockSetCredential(chip::EndpointId endpointId, uint16_t cr bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) { - return LockMgr().GetUser(userIndex, user); + return LockMgr().GetUser(endpointId, userIndex, user); } bool emberAfPluginDoorLockSetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, @@ -109,8 +109,8 @@ bool emberAfPluginDoorLockSetUser(chip::EndpointId endpointId, uint16_t userInde const DlCredential * credentials, size_t totalCredentials) { - return LockMgr().SetUser(userIndex, creator, modifier, userName, uniqueId, userStatus, usertype, credentialRule, credentials, - totalCredentials); + return LockMgr().SetUser(endpointId, userIndex, creator, modifier, userName, uniqueId, userStatus, usertype, credentialRule, + credentials, totalCredentials); } // TODO: These functions will be supported by door-lock-server in the future. These are set to return failure until implemented. diff --git a/src/platform/EFR32/EFR32Config.h b/src/platform/EFR32/EFR32Config.h index 17ea6cdda6ccc8..1095bb074a2bd1 100644 --- a/src/platform/EFR32/EFR32Config.h +++ b/src/platform/EFR32/EFR32Config.h @@ -122,6 +122,7 @@ class EFR32Config static constexpr Key kConfigKey_LockUserName = EFR32ConfigKey(kMatterConfig_KeyBase, 0x12); static constexpr Key kConfigKey_CredentialData = EFR32ConfigKey(kMatterConfig_KeyBase, 0x13); static constexpr Key kConfigKey_UserCredentials = EFR32ConfigKey(kMatterConfig_KeyBase, 0x14); + static constexpr Key kConfigKey_GroupKeyMax = EFR32ConfigKey(kMatterConfig_KeyBase, 0x1E); // Allows 16 Group Keys to be created. static constexpr Key kConfigKey_UniqueId = EFR32ConfigKey(kMatterFactory_KeyBase, 0x1F);