From b7677b1e29d31806d1a9c3c0f51e483f448641e7 Mon Sep 17 00:00:00 2001 From: Michael Rupp <95718139+mykrupp@users.noreply.github.com> Date: Thu, 30 Jun 2022 14:36:10 -0400 Subject: [PATCH] [EFR32] Lock-app working schedules with nvm storage, nvm credentials fix, add comments (#20044) * working schedules with nvm storage, nvm credentials fix, add comments * restyle * return true if programmingPin is given to GetCredential * add index-checking helper functions, add param builder, replace preprocessor directive with constants, general clean up * code review comments, initial config params to 0, fix indexing check * Restyled by clang-format Co-authored-by: Restyled.io --- examples/lock-app/efr32/include/LockManager.h | 118 +++++- examples/lock-app/efr32/src/AppTask.cpp | 54 ++- examples/lock-app/efr32/src/LockManager.cpp | 338 ++++++++++++++---- examples/lock-app/efr32/src/ZclCallbacks.cpp | 28 +- src/platform/EFR32/EFR32Config.h | 3 + 5 files changed, 441 insertions(+), 100 deletions(-) diff --git a/examples/lock-app/efr32/include/LockManager.h b/examples/lock-app/efr32/include/LockManager.h index a97d7f4bb3b8bf..01332f9c42b838 100644 --- a/examples/lock-app/efr32/include/LockManager.h +++ b/examples/lock-app/efr32/include/LockManager.h @@ -29,17 +29,73 @@ #include -using namespace ::chip; +namespace EFR32DoorLock { +namespace ResourceRanges { +// Used to size arrays +static constexpr uint16_t kMaxUsers = 10; +static constexpr uint8_t kMaxCredentialsPerUser = 10; +static constexpr uint8_t kMaxWeekdaySchedulesPerUser = 10; +static constexpr uint8_t kMaxYeardaySchedulesPerUser = 10; +static constexpr uint8_t kMaxHolidaySchedules = 10; +static constexpr uint8_t kMaxCredentialSize = 8; + +// Indices received for user/credential/schedules are 1-indexed +static constexpr uint8_t kStartIndexValue = 1; -// 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 uint8_t kMaxCredentials = kMaxUsers * kMaxCredentialsPerUser; +} // namespace ResourceRanges -static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE = 20; +namespace LockInitParams { + +struct LockParam +{ + // Read from zap attributes + uint16_t numberOfUsers = 0; + uint8_t numberOfCredentialsPerUser = 0; + uint8_t numberOfWeekdaySchedulesPerUser = 0; + uint8_t numberOfYeardaySchedulesPerUser = 0; + uint8_t numberOfHolidaySchedules = 0; +}; + +class ParamBuilder +{ +public: + ParamBuilder & SetNumberOfUsers(uint16_t numberOfUsers) + { + lockParam_.numberOfUsers = numberOfUsers; + return *this; + } + ParamBuilder & SetNumberOfCredentialsPerUser(uint8_t numberOfCredentialsPerUser) + { + lockParam_.numberOfCredentialsPerUser = numberOfCredentialsPerUser; + return *this; + } + ParamBuilder & SetNumberOfWeekdaySchedulesPerUser(uint8_t numberOfWeekdaySchedulesPerUser) + { + lockParam_.numberOfWeekdaySchedulesPerUser = numberOfWeekdaySchedulesPerUser; + return *this; + } + ParamBuilder & SetNumberOfYeardaySchedulesPerUser(uint8_t numberOfYeardaySchedulesPerUser) + { + lockParam_.numberOfYeardaySchedulesPerUser = numberOfYeardaySchedulesPerUser; + return *this; + } + ParamBuilder & SetNumberOfHolidaySchedules(uint8_t numberOfHolidaySchedules) + { + lockParam_.numberOfHolidaySchedules = numberOfHolidaySchedules; + return *this; + } + LockParam GetLockParam() { return lockParam_; } + +private: + LockParam lockParam_; +}; + +} // namespace LockInitParams +} // namespace EFR32DoorLock + +using namespace ::chip; +using namespace EFR32DoorLock::ResourceRanges; class LockManager { @@ -61,7 +117,7 @@ class LockManager } State; CHIP_ERROR Init(chip::app::DataModel::Nullable state, - uint8_t maxNumberOfCredentialsPerUser, uint16_t numberOfSupportedUsers); + EFR32DoorLock::LockInitParams::LockParam lockParam); bool NextState(); bool IsActionInProgress(); bool InitiateAction(int32_t aActor, Action_t aAction); @@ -73,17 +129,40 @@ class LockManager bool Lock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err); bool Unlock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err); - bool GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const; + bool GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user); 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; + EmberAfPluginDoorLockCredentialInfo & credential); bool SetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, chip::FabricIndex creator, chip::FabricIndex modifier, DlCredentialStatus credentialStatus, DlCredentialType credentialType, const chip::ByteSpan & credentialData); + DlStatus GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + EmberAfPluginDoorLockWeekDaySchedule & schedule); + + DlStatus SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, DlScheduleStatus status, + DlDaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute); + + DlStatus GetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + EmberAfPluginDoorLockYearDaySchedule & schedule); + + DlStatus SetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status, + uint32_t localStartTime, uint32_t localEndTime); + + DlStatus GetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule & schedule); + + DlStatus SetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime, + uint32_t localEndTime, DlOperatingMode operatingMode); + + bool IsValidUserIndex(uint16_t userIndex); + bool IsValidCredentialIndex(uint16_t credentialIndex, DlCredentialType type); + bool IsValidWeekdayScheduleIndex(uint8_t scheduleIndex); + bool IsValidYeardayScheduleIndex(uint8_t scheduleIndex); + bool IsValidHolidayScheduleIndex(uint8_t scheduleIndex); + bool setLockState(chip::EndpointId endpointId, DlLockState lockState, const Optional & pin, DlOperationError & err); const char * lockStateToString(DlLockState lockState) const; @@ -105,17 +184,18 @@ class LockManager static void AutoLockTimerEventHandler(AppEvent * aEvent); static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); - EmberAfPluginDoorLockUserInfo mLockUsers[DOOR_LOCK_MAX_USERS]; - EmberAfPluginDoorLockCredentialInfo mLockCredentials[MAX_CREDENTIALS]; - - uint8_t mMaxCredentialsPerUser; - uint16_t mMaxUsers; + EmberAfPluginDoorLockUserInfo mLockUsers[kMaxUsers]; + EmberAfPluginDoorLockCredentialInfo mLockCredentials[kMaxCredentials]; + EmberAfPluginDoorLockWeekDaySchedule mWeekdaySchedule[kMaxUsers][kMaxWeekdaySchedulesPerUser]; + EmberAfPluginDoorLockYearDaySchedule mYeardaySchedule[kMaxUsers][kMaxYeardaySchedulesPerUser]; + EmberAfPluginDoorLockHolidaySchedule mHolidaySchedule[kMaxHolidaySchedules]; 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]; + uint8_t mCredentialData[kMaxCredentials][kMaxCredentialSize]; + DlCredential mCredentials[kMaxUsers][kMaxCredentialsPerUser]; static LockManager sLock; + EFR32DoorLock::LockInitParams::LockParam LockParams; }; inline LockManager & LockMgr() diff --git a/examples/lock-app/efr32/src/AppTask.cpp b/examples/lock-app/efr32/src/AppTask.cpp index d3cc7e9a6f17d6..ddb8a463c6054a 100644 --- a/examples/lock-app/efr32/src/AppTask.cpp +++ b/examples/lock-app/efr32/src/AppTask.cpp @@ -83,6 +83,7 @@ using chip::app::Clusters::DoorLock::DlOperationSource; using namespace chip; using namespace ::chip::DeviceLayer; using namespace ::chip::DeviceLayer::Internal; +using namespace EFR32DoorLock::LockInitParams; namespace { TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. @@ -236,27 +237,66 @@ CHIP_ERROR AppTask::Init() chip::DeviceLayer::PlatformMgr().LockChipStack(); chip::app::Clusters::DoorLock::Attributes::LockState::Get(endpointId, state); - uint8_t maxCredentialsPerUser = 0; - if (!DoorLockServer::Instance().GetNumberOfCredentialsSupportedPerUser(endpointId, maxCredentialsPerUser)) + uint8_t numberOfCredentialsPerUser = 0; + if (!DoorLockServer::Instance().GetNumberOfCredentialsSupportedPerUser(endpointId, numberOfCredentialsPerUser)) { ChipLogError(Zcl, "Unable to get number of credentials supported per user when initializing lock endpoint, defaulting to 5 " "[endpointId=%d]", endpointId); - maxCredentialsPerUser = 5; + numberOfCredentialsPerUser = 5; } - uint16_t numberOfSupportedUsers = 0; - if (!DoorLockServer::Instance().GetNumberOfUserSupported(endpointId, numberOfSupportedUsers)) + uint16_t numberOfUsers = 0; + if (!DoorLockServer::Instance().GetNumberOfUserSupported(endpointId, numberOfUsers)) { ChipLogError(Zcl, "Unable to get number of supported users when initializing lock endpoint, defaulting to 10 [endpointId=%d]", endpointId); - numberOfSupportedUsers = 10; + numberOfUsers = 10; } + + uint8_t numberOfWeekdaySchedulesPerUser = 0; + if (!DoorLockServer::Instance().GetNumberOfWeekDaySchedulesPerUserSupported(endpointId, numberOfWeekdaySchedulesPerUser)) + { + ChipLogError( + Zcl, + "Unable to get number of supported weekday schedules when initializing lock endpoint, defaulting to 10 [endpointId=%d]", + endpointId); + numberOfWeekdaySchedulesPerUser = 10; + } + + uint8_t numberOfYeardaySchedulesPerUser = 0; + if (!DoorLockServer::Instance().GetNumberOfYearDaySchedulesPerUserSupported(endpointId, numberOfYeardaySchedulesPerUser)) + { + ChipLogError( + Zcl, + "Unable to get number of supported yearday schedules when initializing lock endpoint, defaulting to 10 [endpointId=%d]", + endpointId); + numberOfYeardaySchedulesPerUser = 10; + } + + uint8_t numberOfHolidaySchedules = 0; + if (!DoorLockServer::Instance().GetNumberOfHolidaySchedulesSupported(endpointId, numberOfHolidaySchedules)) + { + ChipLogError( + Zcl, + "Unable to get number of supported holiday schedules when initializing lock endpoint, defaulting to 10 [endpointId=%d]", + endpointId); + numberOfHolidaySchedules = 10; + } + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); - err = LockMgr().Init(state, maxCredentialsPerUser, numberOfSupportedUsers); + err = LockMgr().Init(state, + ParamBuilder() + .SetNumberOfUsers(numberOfUsers) + .SetNumberOfCredentialsPerUser(numberOfCredentialsPerUser) + .SetNumberOfWeekdaySchedulesPerUser(numberOfWeekdaySchedulesPerUser) + .SetNumberOfYeardaySchedulesPerUser(numberOfYeardaySchedulesPerUser) + .SetNumberOfHolidaySchedules(numberOfHolidaySchedules) + .GetLockParam()); + 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 6398ff3f6f5483..b59b15b57c4110 100644 --- a/examples/lock-app/efr32/src/LockManager.cpp +++ b/examples/lock-app/efr32/src/LockManager.cpp @@ -31,27 +31,49 @@ LockManager LockManager::sLock; TimerHandle_t sLockTimer; using namespace ::chip::DeviceLayer::Internal; +using namespace EFR32DoorLock::LockInitParams; -CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state, - uint8_t maxNumberOfCredentialsPerUser, uint16_t numberOfSupportedUsers) +CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state, LockParam lockParam) { - for (uint8_t i = 0; i < ArraySize(mLockUsers); i++) + + LockParams = lockParam; + + if (LockParams.numberOfUsers > kMaxUsers) { - // Allocate buffer for credentials - if (!mCredentials[i].Alloc(maxNumberOfCredentialsPerUser)) - { - EFR32_LOG("Failed to allocate array for lock credentials"); - return APP_ERROR_ALLOCATION_FAILED; - } + EFR32_LOG("Max number of users is greater than %d, the maximum amount of users currently supported on this platform", + kMaxUsers); + return APP_ERROR_ALLOCATION_FAILED; + } + + if (LockParams.numberOfCredentialsPerUser > kMaxCredentialsPerUser) + { + EFR32_LOG("Max number of credentials per user is greater than %d, the maximum amount of users currently supported on this " + "platform", + kMaxCredentialsPerUser); + return APP_ERROR_ALLOCATION_FAILED; } - mMaxCredentialsPerUser = maxNumberOfCredentialsPerUser; + if (LockParams.numberOfWeekdaySchedulesPerUser > kMaxWeekdaySchedulesPerUser) + { + EFR32_LOG( + "Max number of schedules is greater than %d, the maximum amount of schedules currently supported on this platform", + kMaxWeekdaySchedulesPerUser); + return APP_ERROR_ALLOCATION_FAILED; + } - mMaxUsers = numberOfSupportedUsers; - if (mMaxUsers > DOOR_LOCK_MAX_USERS) + if (LockParams.numberOfYeardaySchedulesPerUser > kMaxYeardaySchedulesPerUser) { - EFR32_LOG("Max number of users is greater than %d, the maximum amount of users currently supported on this platform", - DOOR_LOCK_MAX_USERS); + EFR32_LOG( + "Max number of schedules is greater than %d, the maximum amount of schedules currently supported on this platform", + kMaxYeardaySchedulesPerUser); + return APP_ERROR_ALLOCATION_FAILED; + } + + if (LockParams.numberOfHolidaySchedules > kMaxHolidaySchedules) + { + EFR32_LOG( + "Max number of schedules is greater than %d, the maximum amount of schedules currently supported on this platform", + kMaxHolidaySchedules); return APP_ERROR_ALLOCATION_FAILED; } @@ -77,6 +99,37 @@ CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable(mCredentialData), sizeof(mCredentialData), outLen); - EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials[0].Get()), - sizeof(DlCredential) * mMaxUsers * mMaxCredentialsPerUser, outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), + sizeof(DlCredential) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser, + outLen); + + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), + sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * + LockParams.numberOfUsers, + outLen); + + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), + sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * + LockParams.numberOfUsers, + outLen); + + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_HolidaySchedules, reinterpret_cast(&(mHolidaySchedule)), + sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules, outLen); return true; } @@ -228,14 +295,17 @@ bool LockManager::Unlock(chip::EndpointId endpointId, const Optional 0, false); // indices are one-indexed - ChipLogProgress(Zcl, "Door Lock App: LockManager::GetUser [endpoint=%d,userIndex=%hu]", endpointId, adjustedUserIndex); + userIndex--; - // door-lock-server checks for valid user index - const auto & userInDb = mLockUsers[adjustedUserIndex]; + VerifyOrReturnValue(IsValidUserIndex(userIndex), false); + + ChipLogProgress(Zcl, "Door Lock App: LockManager::GetUser [endpoint=%d,userIndex=%hu]", endpointId, userIndex); + + const auto & userInDb = mLockUsers[userIndex]; user.userStatus = userInDb.userStatus; if (DlUserStatus::kAvailable == user.userStatus) @@ -245,7 +315,7 @@ bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, Ember } user.userName = chip::CharSpan(userInDb.userName.data(), userInDb.userName.size()); - user.credentials = chip::Span(mCredentials[adjustedUserIndex].Get(), userInDb.credentials.size()); + user.credentials = chip::Span(mCredentials[userIndex], userInDb.credentials.size()); user.userUniqueId = userInDb.userUniqueId; user.userType = userInDb.userType; user.credentialRule = userInDb.credentialRule; @@ -278,26 +348,29 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: endpointId, userIndex, creator, modifier, userName.data(), uniqueId, to_underlying(userStatus), to_underlying(usertype), to_underlying(credentialRule), credentials, totalCredentials); - uint16_t adjustedUserIndex = userIndex - 1; + VerifyOrReturnValue(userIndex > 0, false); // indices are one-indexed + + userIndex--; - // door-lock-server checks for valid user index - auto & userInStorage = mLockUsers[adjustedUserIndex]; + VerifyOrReturnValue(IsValidUserIndex(userIndex), false); + + auto & userInStorage = mLockUsers[userIndex]; if (userName.size() > DOOR_LOCK_MAX_USER_NAME_SIZE) { - ChipLogError(Zcl, "Cannot set user - user name is too long [endpoint=%d,index=%d]", endpointId, adjustedUserIndex); + ChipLogError(Zcl, "Cannot set user - user name is too long [endpoint=%d,index=%d]", endpointId, userIndex); return false; } - if (totalCredentials > mMaxCredentialsPerUser) + if (totalCredentials > LockParams.numberOfCredentialsPerUser) { ChipLogError(Zcl, "Cannot set user - total number of credentials is too big [endpoint=%d,index=%d,totalCredentials=%u]", - endpointId, adjustedUserIndex, totalCredentials); + endpointId, userIndex, totalCredentials); return false; } - chip::Platform::CopyString(mUserNames[adjustedUserIndex], userName); - userInStorage.userName = chip::CharSpan(mUserNames[adjustedUserIndex], userName.size()); + chip::Platform::CopyString(mUserNames[userIndex], userName); + userInStorage.userName = chip::CharSpan(mUserNames[userIndex], userName.size()); userInStorage.userUniqueId = uniqueId; userInStorage.userStatus = userStatus; userInStorage.userType = usertype; @@ -307,43 +380,53 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: for (size_t i = 0; i < totalCredentials; ++i) { - mCredentials[adjustedUserIndex][i] = credentials[i]; - mCredentials[adjustedUserIndex][i].CredentialType = 1; - mCredentials[adjustedUserIndex][i].CredentialIndex = i + 1; + mCredentials[userIndex][i] = credentials[i]; + mCredentials[userIndex][i].CredentialType = 1; + mCredentials[userIndex][i].CredentialIndex = i + 1; } - userInStorage.credentials = chip::Span(mCredentials[adjustedUserIndex].Get(), totalCredentials); + userInStorage.credentials = chip::Span(mCredentials[userIndex], totalCredentials); // Save user information in NVM flash EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), - sizeof(EmberAfPluginDoorLockUserInfo) * mMaxUsers); + sizeof(EmberAfPluginDoorLockUserInfo) * LockParams.numberOfUsers); - EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_UserCredentials, - reinterpret_cast(mCredentials[adjustedUserIndex].Get()), - sizeof(DlCredential) * totalCredentials); + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), + sizeof(DlCredential) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser); EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_LockUserName, reinterpret_cast(mUserNames), sizeof(mUserNames)); - ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", endpointId, adjustedUserIndex); + ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", endpointId, userIndex); return true; } bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType, - EmberAfPluginDoorLockCredentialInfo & credential) const + EmberAfPluginDoorLockCredentialInfo & credential) { - uint16_t adjustedCredentialIndex = credentialIndex - 1; + VerifyOrReturnValue(credentialIndex > 0, false); // indices are one-indexed + + credentialIndex--; + + VerifyOrReturnValue(IsValidCredentialIndex(credentialIndex, credentialType), false); ChipLogProgress(Zcl, "Lock App: LockManager::GetCredential [credentialType=%u], credentialIndex=%d", - to_underlying(credentialType), adjustedCredentialIndex); + to_underlying(credentialType), credentialIndex); - // door-lock-server checks for valid credential index - const auto & credentialInStorage = mLockCredentials[adjustedCredentialIndex]; + if (credentialType == DlCredentialType::kProgrammingPIN) + { + ChipLogError(Zcl, "Programming user not supported [credentialType=%u], credentialIndex=%d", to_underlying(credentialType), + credentialIndex); + + return true; + } + + const auto & credentialInStorage = mLockCredentials[credentialIndex]; credential.status = credentialInStorage.status; - ChipLogDetail(Zcl, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, adjustedCredentialIndex); + ChipLogDetail(Zcl, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, credentialIndex); if (DlCredentialStatus::kAvailable == credential.status) { @@ -369,35 +452,31 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential chip::FabricIndex modifier, DlCredentialStatus credentialStatus, DlCredentialType credentialType, const chip::ByteSpan & credentialData) { + + VerifyOrReturnValue(credentialIndex > 0, false); // indices are one-indexed + + credentialIndex--; + + VerifyOrReturnValue(IsValidCredentialIndex(credentialIndex, credentialType), false); + ChipLogProgress(Zcl, "Door Lock App: LockManager::SetCredential " "[credentialStatus=%u,credentialType=%u,credentialDataSize=%u,creator=%d,modifier=%d]", to_underlying(credentialStatus), to_underlying(credentialType), credentialData.size(), creator, modifier); - uint16_t adjustedCredentialIndex = credentialIndex - 1; - - // door-lock-server checks for valid credential index - auto & credentialInStorage = mLockCredentials[adjustedCredentialIndex]; + auto & credentialInStorage = mLockCredentials[credentialIndex]; - if (credentialData.size() > DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE) - { - ChipLogError(Zcl, - "Cannot get the credential - data size exceeds limit " - "[dataSize=%u,maxDataSize=%u]", - credentialData.size(), DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE); - return false; - } credentialInStorage.status = credentialStatus; credentialInStorage.credentialType = credentialType; credentialInStorage.createdBy = creator; credentialInStorage.lastModifiedBy = modifier; - memcpy(mCredentialData[adjustedCredentialIndex], credentialData.data(), credentialData.size()); - credentialInStorage.credentialData = chip::ByteSpan{ mCredentialData[adjustedCredentialIndex], credentialData.size() }; + memcpy(mCredentialData[credentialIndex], credentialData.data(), credentialData.size()); + credentialInStorage.credentialData = chip::ByteSpan{ mCredentialData[credentialIndex], credentialData.size() }; // Save credential information in NVM flash EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), - sizeof(EmberAfPluginDoorLockCredentialInfo) * mMaxCredentialsPerUser); + sizeof(EmberAfPluginDoorLockCredentialInfo) * LockParams.numberOfCredentialsPerUser); EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_CredentialData, reinterpret_cast(&mCredentialData), sizeof(mCredentialData)); @@ -407,6 +486,137 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential return true; } +DlStatus LockManager::GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + EmberAfPluginDoorLockWeekDaySchedule & schedule) +{ + + VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + weekdayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + schedule = mWeekdaySchedule[userIndex][weekdayIndex]; + + return DlStatus::kSuccess; +} + +DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + DlScheduleStatus status, DlDaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, + uint8_t endHour, uint8_t endMinute) +{ + + VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + weekdayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; + + scheduleInStorage.daysMask = daysMask; + scheduleInStorage.startHour = startHour; + scheduleInStorage.startMinute = startMinute; + scheduleInStorage.endHour = endHour; + scheduleInStorage.endMinute = endMinute; + + // Save schedule information in NVM flash + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), + sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * + LockParams.numberOfUsers); + + return DlStatus::kSuccess; +} + +DlStatus LockManager::GetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + EmberAfPluginDoorLockYearDaySchedule & schedule) +{ + VerifyOrReturnValue(yearDayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + yearDayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; + + schedule = scheduleInStorage; + + return DlStatus::kSuccess; +} + +DlStatus LockManager::SetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime) +{ + VerifyOrReturnValue(yearDayIndex > 0, DlStatus::kFailure); // indices are one-indexed + VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed + + yearDayIndex--; + userIndex--; + + VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); + VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; + + scheduleInStorage.localStartTime = localStartTime; + scheduleInStorage.localEndTime = localEndTime; + + // Save schedule information in NVM flash + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), + sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * + LockParams.numberOfUsers); + + return DlStatus::kSuccess; +} + +DlStatus LockManager::GetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, + EmberAfPluginDoorLockHolidaySchedule & schedule) +{ + VerifyOrReturnValue(holidayIndex > 0, DlStatus::kFailure); // indices are one-indexed + + holidayIndex--; + + VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; + + schedule = scheduleInStorage; + + return DlStatus::kSuccess; +} + +DlStatus LockManager::SetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, + uint32_t localStartTime, uint32_t localEndTime, DlOperatingMode operatingMode) +{ + VerifyOrReturnValue(holidayIndex > 0, DlStatus::kFailure); // indices are one-indexed + + holidayIndex--; + + VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); + + auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; + + scheduleInStorage.localStartTime = localStartTime; + scheduleInStorage.localEndTime = localEndTime; + scheduleInStorage.operatingMode = operatingMode; + + // Save schedule information in NVM flash + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_HolidaySchedules, + reinterpret_cast(&(mHolidaySchedule)), + sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules); + + return DlStatus::kSuccess; +} + const char * LockManager::lockStateToString(DlLockState lockState) const { switch (lockState) @@ -443,9 +653,9 @@ bool LockManager::setLockState(chip::EndpointId endpointId, DlLockState lockStat return true; } - // Check the RequirePINforRemoteOperation attribute - bool requirePin = false; - // chip::app::Clusters::DoorLock::Attributes::RequirePINforRemoteOperation::Get(endpointId, &requirePin); + // Assume pin is required until told otherwise + bool requirePin = true; + chip::app::Clusters::DoorLock::Attributes::RequirePINforRemoteOperation::Get(endpointId, &requirePin); // If a pin code is not given if (!pin.HasValue()) @@ -466,7 +676,7 @@ bool LockManager::setLockState(chip::EndpointId endpointId, DlLockState lockStat } // Check the PIN code - for (uint8_t i = 0; i < mMaxCredentialsPerUser; i++) + for (uint8_t i = 0; i < kMaxCredentials; i++) { if (mLockCredentials[i].credentialType != DlCredentialType::kPin || mLockCredentials[i].status == DlCredentialStatus::kAvailable) diff --git a/examples/lock-app/efr32/src/ZclCallbacks.cpp b/examples/lock-app/efr32/src/ZclCallbacks.cpp index 8fb775956a4c30..650aba7d2d73de 100644 --- a/examples/lock-app/efr32/src/ZclCallbacks.cpp +++ b/examples/lock-app/efr32/src/ZclCallbacks.cpp @@ -29,7 +29,6 @@ #include #include -using namespace ::chip; using namespace ::chip::app::Clusters; using namespace ::chip::DeviceLayer::Internal; @@ -55,10 +54,7 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & * @param endpoint Ver.: always * */ -void emberAfDoorLockClusterInitCallback(EndpointId endpoint) -{ - // TODO: implement any additional Cluster Server init actions -} +void emberAfDoorLockClusterInitCallback(EndpointId endpoint) {} bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const Optional & pinCode, DlOperationError & err) { @@ -113,28 +109,40 @@ bool emberAfPluginDoorLockSetUser(chip::EndpointId endpointId, uint16_t userInde credentials, totalCredentials); } -// TODO: These functions will be supported by door-lock-server in the future. These are set to return failure until implemented. DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, EmberAfPluginDoorLockWeekDaySchedule & schedule) { - return DlStatus::kFailure; + return LockMgr().GetWeekdaySchedule(endpointId, weekdayIndex, userIndex, schedule); } DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, EmberAfPluginDoorLockYearDaySchedule & schedule) { - return DlStatus::kFailure; + return LockMgr().GetYeardaySchedule(endpointId, yearDayIndex, userIndex, schedule); +} + +DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, + EmberAfPluginDoorLockHolidaySchedule & holidaySchedule) +{ + return LockMgr().GetHolidaySchedule(endpointId, holidayIndex, holidaySchedule); } DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, DlScheduleStatus status, DlDaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) { - return DlStatus::kFailure; + return LockMgr().SetWeekdaySchedule(endpointId, weekdayIndex, userIndex, status, daysMask, startHour, startMinute, endHour, + endMinute); } DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime) { - return DlStatus::kFailure; + return LockMgr().SetYeardaySchedule(endpointId, yearDayIndex, userIndex, status, localStartTime, localEndTime); +} + +DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, + uint32_t localStartTime, uint32_t localEndTime, DlOperatingMode operatingMode) +{ + return LockMgr().SetHolidaySchedule(endpointId, holidayIndex, status, localStartTime, localEndTime, operatingMode); } diff --git a/src/platform/EFR32/EFR32Config.h b/src/platform/EFR32/EFR32Config.h index 1095bb074a2bd1..09b07f6b240104 100644 --- a/src/platform/EFR32/EFR32Config.h +++ b/src/platform/EFR32/EFR32Config.h @@ -122,6 +122,9 @@ 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_WeekDaySchedules = EFR32ConfigKey(kMatterConfig_KeyBase, 0x15); + static constexpr Key kConfigKey_YearDaySchedules = EFR32ConfigKey(kMatterConfig_KeyBase, 0x16); + static constexpr Key kConfigKey_HolidaySchedules = EFR32ConfigKey(kMatterConfig_KeyBase, 0x17); static constexpr Key kConfigKey_GroupKeyMax = EFR32ConfigKey(kMatterConfig_KeyBase, 0x1E); // Allows 16 Group Keys to be created.