diff --git a/examples/lock-app/silabs/include/LockManager.h b/examples/lock-app/silabs/include/LockManager.h index 671aedb81c4e56..ae22a1a9f4b855 100644 --- a/examples/lock-app/silabs/include/LockManager.h +++ b/examples/lock-app/silabs/include/LockManager.h @@ -27,7 +27,9 @@ #include #include -struct WeekDaysScheduleInfo +#include + +struct WeekDayScheduleInfo { DlScheduleStatus status; EmberAfPluginDoorLockWeekDaySchedule schedule; @@ -112,6 +114,30 @@ class ParamBuilder using namespace ::chip; using namespace EFR32DoorLock::ResourceRanges; +struct LockUserInfo +{ + char userName[DOOR_LOCK_MAX_USER_NAME_SIZE]; + size_t userNameSize; + uint32_t userUniqueId; + UserStatusEnum userStatus; + UserTypeEnum userType; + CredentialRuleEnum credentialRule; + chip::EndpointId endpointId; + chip::FabricIndex createdBy; + chip::FabricIndex lastModifiedBy; + uint16_t currentCredentialCount; +}; + +struct LockCredentialInfo +{ + DlCredentialStatus status; + CredentialTypeEnum credentialType; + chip::FabricIndex createdBy; + chip::FabricIndex lastModifiedBy; + uint8_t credentialData[kMaxCredentialSize]; + size_t credentialDataSize; +}; + class LockManager { public: @@ -135,7 +161,7 @@ class LockManager } State; CHIP_ERROR Init(chip::app::DataModel::Nullable state, - EFR32DoorLock::LockInitParams::LockParam lockParam); + EFR32DoorLock::LockInitParams::LockParam lockParam, PersistentStorageDelegate * storage); bool NextState(); bool IsActionInProgress(); bool InitiateAction(int32_t aActor, Action_t aAction); @@ -192,8 +218,6 @@ class LockManager OperationErrorEnum & err); const char * lockStateToString(DlLockState lockState) const; - bool ReadConfigValues(); - void UnlockAfterUnlatch(); private: @@ -244,17 +268,44 @@ class LockManager static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); osTimerId_t mLockTimer; - EmberAfPluginDoorLockUserInfo mLockUsers[kMaxUsers]; - EmberAfPluginDoorLockCredentialInfo mLockCredentials[kNumCredentialTypes][kMaxCredentials]; - WeekDaysScheduleInfo mWeekdaySchedule[kMaxUsers][kMaxWeekdaySchedulesPerUser]; - YearDayScheduleInfo mYeardaySchedule[kMaxUsers][kMaxYeardaySchedulesPerUser]; - HolidayScheduleInfo mHolidaySchedule[kMaxHolidaySchedules]; - - char mUserNames[MATTER_ARRAY_SIZE(mLockUsers)][DOOR_LOCK_MAX_USER_NAME_SIZE]; - uint8_t mCredentialData[kNumCredentialTypes][kMaxCredentials][kMaxCredentialSize]; - CredentialStruct mCredentials[kMaxUsers][kMaxCredentials]; EFR32DoorLock::LockInitParams::LockParam LockParams; + + // Stores LockUserInfo corresponding to a user index + static StorageKeyName LockUserEndpoint(uint16_t userIndex, chip::EndpointId endpoint) + { + return StorageKeyName::Formatted("g/lu/%x/e/%x", userIndex, endpoint); + } + // Stores LockCredentialInfo corresponding to a credential index and type + static StorageKeyName LockCredentialEndpoint(uint16_t credentialIndex, CredentialTypeEnum credentialType, + chip::EndpointId endpoint) + { + return StorageKeyName::Formatted("g/lc/%x/t/%x/e/%x", credentialIndex, static_cast(credentialType), endpoint); + } + // Stores all the credential indices that belong to a user + static StorageKeyName LockUserCredentialMap(uint16_t userIndex) { return StorageKeyName::Formatted("g/lu/%x/lc", userIndex); } + // Stores WeekDayScheduleInfo corresponding to a user and schedule index + static StorageKeyName LockUserWeekDayScheduleEndpoint(uint16_t userIndex, uint16_t scheduleIndex, chip::EndpointId endpoint) + { + return StorageKeyName::Formatted("g/lu/%x/lw/%x/e/%x", userIndex, scheduleIndex, endpoint); + } + // Stores YearDayScheduleInfo corresponding to a user and schedule index + static StorageKeyName LockUserYearDayScheduleEndpoint(uint16_t userIndex, uint16_t scheduleIndex, chip::EndpointId endpoint) + { + return StorageKeyName::Formatted("g/lu/%x/ly/%x/e/%x", userIndex, scheduleIndex, endpoint); + } + // Stores HolidayScheduleInfo corresponding to a schedule index + static StorageKeyName LockHolidayScheduleEndpoint(uint16_t scheduleIndex, chip::EndpointId endpoint) + { + return StorageKeyName::Formatted("g/lh/%x/e/%x", scheduleIndex, endpoint); + } + + // Pointer to the PeristentStorage + PersistentStorageDelegate * mStorage = nullptr; + + LockUserInfo mUserInStorage; + LockCredentialInfo mCredentialInStorage; + CredentialStruct mCredentials[kMaxCredentialsPerUser]; }; LockManager & LockMgr(); diff --git a/examples/lock-app/silabs/src/AppTask.cpp b/examples/lock-app/silabs/src/AppTask.cpp index 3dd0a0ba7c9c69..06c66f49a4e8c2 100644 --- a/examples/lock-app/silabs/src/AppTask.cpp +++ b/examples/lock-app/silabs/src/AppTask.cpp @@ -206,7 +206,8 @@ CHIP_ERROR AppTask::Init() .SetNumberOfWeekdaySchedulesPerUser(numberOfWeekdaySchedulesPerUser) .SetNumberOfYeardaySchedulesPerUser(numberOfYeardaySchedulesPerUser) .SetNumberOfHolidaySchedules(numberOfHolidaySchedules) - .GetLockParam()); + .GetLockParam(), + &Server::GetInstance().GetPersistentStorage()); if (err != CHIP_NO_ERROR) { @@ -266,9 +267,6 @@ void AppTask::AppTaskMain(void * pvParameter) SILABS_LOG("App Task started"); - // Users and credentials should be checked once from nvm flash on boot - LockMgr().ReadConfigValues(); - while (true) { osStatus_t eventReceived = osMessageQueueGet(sAppEventQueue, &event, NULL, osWaitForever); diff --git a/examples/lock-app/silabs/src/LockManager.cpp b/examples/lock-app/silabs/src/LockManager.cpp index 66050da62a1bec..0ae355d82e4bf4 100644 --- a/examples/lock-app/silabs/src/LockManager.cpp +++ b/examples/lock-app/silabs/src/LockManager.cpp @@ -18,13 +18,13 @@ */ #include "LockManager.h" - #include "AppConfig.h" #include "AppTask.h" #include #include #include +using chip::app::DataModel::MakeNullable; using namespace ::chip::DeviceLayer::Internal; using namespace EFR32DoorLock::LockInitParams; @@ -37,7 +37,8 @@ LockManager & LockMgr() return sLock; } -CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state, LockParam lockParam) +CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state, LockParam lockParam, + PersistentStorageDelegate * storage) { LockParams = lockParam; @@ -94,6 +95,10 @@ CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable(&mLockUsers), - sizeof(EmberAfPluginDoorLockUserInfo) * MATTER_ARRAY_SIZE(mLockUsers), outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), - sizeof(EmberAfPluginDoorLockCredentialInfo) * kMaxCredentials * kNumCredentialTypes, outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_LockUserName, reinterpret_cast(mUserNames), - sizeof(mUserNames), outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_CredentialData, reinterpret_cast(mCredentialData), - sizeof(mCredentialData), outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), - sizeof(CredentialStruct) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser, - outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), - sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * - LockParams.numberOfUsers, - outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), - sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * - LockParams.numberOfUsers, - outLen); - - SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_HolidaySchedules, reinterpret_cast(&(mHolidaySchedule)), - sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules, outLen); - - return true; -} - void LockManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) { mActionInitiated_CB = aActionInitiated_CB; @@ -353,34 +323,84 @@ bool LockManager::Unbolt(chip::EndpointId endpointId, const Nullable 0, false); // indices are one-indexed userIndex--; VerifyOrReturnValue(IsValidUserIndex(userIndex), false); + VerifyOrReturnValue(kInvalidEndpointId != endpointId, false); + ChipLogProgress(Zcl, "Door Lock App: LockManager::GetUser [endpoint=%d,userIndex=%hu]", endpointId, userIndex); - const auto & userInDb = mLockUsers[userIndex]; + chip::StorageKeyName userKey = LockUserEndpoint(userIndex, endpointId); + + uint16_t size = static_cast(sizeof(LockUserInfo)); - user.userStatus = userInDb.userStatus; - if (UserStatusEnum::kAvailable == user.userStatus) + error = mStorage->SyncGetKeyValue(userKey.KeyName(), &mUserInStorage, size); + // If no data is found at user key + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) { - ChipLogDetail(Zcl, "Found unoccupied user [endpoint=%d]", endpointId); + user.userStatus = UserStatusEnum::kAvailable; + + ChipLogError(Zcl, "No user data found"); return true; } + // Else if KVS read was successful + else if (error == CHIP_NO_ERROR) + { + user.userStatus = mUserInStorage.userStatus; - user.userName = chip::CharSpan(userInDb.userName.data(), userInDb.userName.size()); - user.credentials = chip::Span(mCredentials[userIndex], userInDb.credentials.size()); - user.userUniqueId = userInDb.userUniqueId; - user.userType = userInDb.userType; - user.credentialRule = userInDb.credentialRule; + if (mUserInStorage.userStatus == UserStatusEnum::kAvailable) + { + ChipLogDetail(Zcl, "Found unoccupied user [endpoint=%d]", endpointId); + return true; + } + } + else + { + ChipLogError(Zcl, "Error reading from KVS key"); + return false; + } + + user.userName = chip::CharSpan(mUserInStorage.userName, mUserInStorage.userNameSize); + user.userUniqueId = mUserInStorage.userUniqueId; + user.userType = mUserInStorage.userType; + user.credentialRule = mUserInStorage.credentialRule; // So far there's no way to actually create the credential outside Matter, so here we always set the creation/modification // source to Matter user.creationSource = DlAssetSource::kMatterIM; - user.createdBy = userInDb.createdBy; + user.createdBy = mUserInStorage.createdBy; user.modificationSource = DlAssetSource::kMatterIM; - user.lastModifiedBy = userInDb.lastModifiedBy; + user.lastModifiedBy = mUserInStorage.lastModifiedBy; + + // Ensure mUserInStorage.currentCredentialCount <= kMaxCredentialsPerUser to avoid buffer overflow + VerifyOrReturnValue(mUserInStorage.currentCredentialCount <= kMaxCredentialsPerUser, false); + + // Get credential struct from nvm3 + chip::StorageKeyName credentialKey = LockUserCredentialMap(userIndex); + + uint16_t credentialSize = static_cast(sizeof(CredentialStruct) * mUserInStorage.currentCredentialCount); + + error = mStorage->SyncGetKeyValue(credentialKey.KeyName(), mCredentials, credentialSize); + + // If no data is found at credential key + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + // No credentials found for this user + } + // Else if KVS read was successful + else if (error == CHIP_NO_ERROR) + { + user.credentials = chip::Span{ mCredentials, mUserInStorage.currentCredentialCount }; + } + else + { + ChipLogError(Zcl, "Error reading KVS key"); + return false; + } ChipLogDetail(Zcl, "Found occupied user " @@ -397,6 +417,9 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: const chip::CharSpan & userName, uint32_t uniqueId, UserStatusEnum userStatus, UserTypeEnum usertype, CredentialRuleEnum credentialRule, const CredentialStruct * credentials, size_t totalCredentials) { + + CHIP_ERROR error; + ChipLogProgress(Zcl, "Door Lock App: LockManager::SetUser " "[endpoint=%d,userIndex=%d,creator=%d,modifier=%d,userName=%s,uniqueId=%ld " @@ -404,14 +427,14 @@ 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); + VerifyOrReturnValue(kInvalidEndpointId != endpointId, false); + VerifyOrReturnValue(userIndex > 0, false); // indices are one-indexed userIndex--; 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, userIndex); @@ -425,31 +448,39 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: return false; } - chip::Platform::CopyString(mUserNames[userIndex], userName); - userInStorage.userName = chip::CharSpan(mUserNames[userIndex], userName.size()); - userInStorage.userUniqueId = uniqueId; - userInStorage.userStatus = userStatus; - userInStorage.userType = usertype; - userInStorage.credentialRule = credentialRule; - userInStorage.lastModifiedBy = modifier; - userInStorage.createdBy = creator; + memcpy(mUserInStorage.userName, userName.data(), userName.size()); + mUserInStorage.userNameSize = userName.size(); + mUserInStorage.userUniqueId = uniqueId; + mUserInStorage.userStatus = userStatus; + mUserInStorage.userType = usertype; + mUserInStorage.credentialRule = credentialRule; + mUserInStorage.lastModifiedBy = modifier; + mUserInStorage.createdBy = creator; + + mUserInStorage.currentCredentialCount = totalCredentials; + + // Save credential struct in nvm3 + chip::StorageKeyName credentialKey = LockUserCredentialMap(userIndex); + + error = mStorage->SyncSetKeyValue(credentialKey.KeyName(), credentials, + static_cast(sizeof(CredentialStruct) * totalCredentials)); - for (size_t i = 0; i < totalCredentials; ++i) + if ((error != CHIP_NO_ERROR)) { - mCredentials[userIndex][i] = credentials[i]; + ChipLogError(Zcl, "Error reading from KVS key"); + return false; } - userInStorage.credentials = chip::Span(mCredentials[userIndex], totalCredentials); - - // Save user information in NVM flash - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), - sizeof(EmberAfPluginDoorLockUserInfo) * LockParams.numberOfUsers); + // Save user in nvm3 + chip::StorageKeyName userKey = LockUserEndpoint(userIndex, endpointId); - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), - sizeof(CredentialStruct) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser); + error = mStorage->SyncSetKeyValue(userKey.KeyName(), &mUserInStorage, static_cast(sizeof(LockUserInfo))); - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_LockUserName, reinterpret_cast(mUserNames), - sizeof(mUserNames)); + if ((error != CHIP_NO_ERROR)) + { + ChipLogError(Zcl, "Error reading from KVS key"); + return false; + } ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", endpointId, userIndex); @@ -459,6 +490,9 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType, EmberAfPluginDoorLockCredentialInfo & credential) { + CHIP_ERROR error; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, false); VerifyOrReturnValue(IsValidCredentialType(credentialType), false); @@ -475,20 +509,41 @@ bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credential ChipLogProgress(Zcl, "Lock App: LockManager::GetCredential [credentialType=%u], credentialIndex=%d", to_underlying(credentialType), credentialIndex); - const auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex]; + uint16_t size = static_cast(sizeof(LockCredentialInfo)); + + chip::StorageKeyName key = LockCredentialEndpoint(credentialIndex, credentialType, endpointId); + + error = mStorage->SyncGetKeyValue(key.KeyName(), &mCredentialInStorage, size); + + // If no data is found at credential key + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) + { + // No credentials found + credential.status = DlCredentialStatus::kAvailable; - credential.status = credentialInStorage.status; - ChipLogDetail(Zcl, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, credentialIndex); + return true; + } + // Else if KVS read was successful + else if (error == CHIP_NO_ERROR) + { + credential.status = mCredentialInStorage.status; + ChipLogDetail(Zcl, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, credentialIndex); + } + else + { + ChipLogError(Zcl, "Error reading KVS key"); + return false; + } if (DlCredentialStatus::kAvailable == credential.status) { ChipLogDetail(Zcl, "Found unoccupied credential "); return true; } - credential.credentialType = credentialInStorage.credentialType; - credential.credentialData = credentialInStorage.credentialData; - credential.createdBy = credentialInStorage.createdBy; - credential.lastModifiedBy = credentialInStorage.lastModifiedBy; + credential.credentialType = mCredentialInStorage.credentialType; + credential.credentialData = chip::ByteSpan{ mCredentialInStorage.credentialData, mCredentialInStorage.credentialDataSize }; + credential.createdBy = mCredentialInStorage.createdBy; + credential.lastModifiedBy = mCredentialInStorage.lastModifiedBy; // So far there's no way to actually create the credential outside Matter, so here we always set the creation/modification // source to Matter credential.creationSource = DlAssetSource::kMatterIM; @@ -504,6 +559,9 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential chip::FabricIndex modifier, DlCredentialStatus credentialStatus, CredentialTypeEnum credentialType, const chip::ByteSpan & credentialData) { + CHIP_ERROR error; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, false); VerifyOrReturnValue(IsValidCredentialType(credentialType), false); @@ -522,23 +580,26 @@ 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[to_underlying(credentialType)][credentialIndex]; + mCredentialInStorage.status = credentialStatus; + mCredentialInStorage.credentialType = credentialType; + mCredentialInStorage.createdBy = creator; + mCredentialInStorage.lastModifiedBy = modifier; + mCredentialInStorage.credentialDataSize = credentialData.size(); - credentialInStorage.status = credentialStatus; - credentialInStorage.credentialType = credentialType; - credentialInStorage.createdBy = creator; - credentialInStorage.lastModifiedBy = modifier; + memcpy(mCredentialInStorage.credentialData, credentialData.data(), mCredentialInStorage.credentialDataSize); - memcpy(mCredentialData[to_underlying(credentialType)][credentialIndex], credentialData.data(), credentialData.size()); - credentialInStorage.credentialData = - chip::ByteSpan{ mCredentialData[to_underlying(credentialType)][credentialIndex], credentialData.size() }; + chip::StorageKeyName key = LockCredentialEndpoint(credentialIndex, credentialType, endpointId); - // Save credential information in NVM flash - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), - sizeof(EmberAfPluginDoorLockCredentialInfo) * kMaxCredentials * kNumCredentialTypes); + error = mStorage->SyncSetKeyValue(key.KeyName(), &mCredentialInStorage, static_cast(sizeof(LockCredentialInfo))); - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_CredentialData, reinterpret_cast(&mCredentialData), - sizeof(mCredentialData)); + // Clear mCredentialInStorage.credentialData + memset(mCredentialInStorage.credentialData, 0, sizeof(uint8_t) * kMaxCredentialSize); + + if ((error != CHIP_NO_ERROR)) + { + ChipLogError(Zcl, "Error reading from KVS key"); + return false; + } ChipLogProgress(Zcl, "Successfully set the credential [credentialType=%u]", to_underlying(credentialType)); @@ -548,6 +609,11 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential DlStatus LockManager::GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, EmberAfPluginDoorLockWeekDaySchedule & schedule) { + CHIP_ERROR error; + + WeekDayScheduleInfo weekDayScheduleInStorage; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, DlStatus::kFailure); VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed @@ -558,13 +624,35 @@ DlStatus LockManager::GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - const auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; - if (DlScheduleStatus::kAvailable == scheduleInStorage.status) + // Get schedule data from nvm3 + chip::StorageKeyName scheduleDataKey = LockUserWeekDayScheduleEndpoint(userIndex, weekdayIndex, endpointId); + + uint16_t scheduleSize = static_cast(sizeof(WeekDayScheduleInfo)); + + error = mStorage->SyncGetKeyValue(scheduleDataKey.KeyName(), &weekDayScheduleInStorage, scheduleSize); + + // If no data is found at scheduleUserMapKey key + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) { + ChipLogError(Zcl, "No schedule data found for user"); return DlStatus::kNotFound; } + // Else if KVS read was successful + else if (error == CHIP_NO_ERROR) + { + + if (weekDayScheduleInStorage.status == DlScheduleStatus::kAvailable) + { + return DlStatus::kNotFound; + } + } + else + { + ChipLogError(Zcl, "Error reading from KVS key"); + return DlStatus::kFailure; + } - schedule = scheduleInStorage.schedule; + schedule = weekDayScheduleInStorage.schedule; return DlStatus::kSuccess; } @@ -573,6 +661,11 @@ DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we DlScheduleStatus status, DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) { + CHIP_ERROR error; + + WeekDayScheduleInfo weekDayScheduleInStorage; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, DlStatus::kFailure); VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed @@ -583,19 +676,24 @@ DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; + weekDayScheduleInStorage.schedule.daysMask = daysMask; + weekDayScheduleInStorage.schedule.startHour = startHour; + weekDayScheduleInStorage.schedule.startMinute = startMinute; + weekDayScheduleInStorage.schedule.endHour = endHour; + weekDayScheduleInStorage.schedule.endMinute = endMinute; + weekDayScheduleInStorage.status = status; - scheduleInStorage.schedule.daysMask = daysMask; - scheduleInStorage.schedule.startHour = startHour; - scheduleInStorage.schedule.startMinute = startMinute; - scheduleInStorage.schedule.endHour = endHour; - scheduleInStorage.schedule.endMinute = endMinute; - scheduleInStorage.status = status; + // Save schedule data in nvm3 + chip::StorageKeyName scheduleDataKey = LockUserWeekDayScheduleEndpoint(userIndex, weekdayIndex, endpointId); - // Save schedule information in NVM flash - SilabsConfig::WriteConfigValueBin( - SilabsConfig::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), - sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * LockParams.numberOfUsers); + error = mStorage->SyncSetKeyValue(scheduleDataKey.KeyName(), &weekDayScheduleInStorage, + static_cast(sizeof(WeekDayScheduleInfo))); + + if ((error != CHIP_NO_ERROR)) + { + ChipLogError(Zcl, "Error reading from KVS key"); + return DlStatus::kFailure; + } return DlStatus::kSuccess; } @@ -603,6 +701,12 @@ DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we DlStatus LockManager::GetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, EmberAfPluginDoorLockYearDaySchedule & schedule) { + CHIP_ERROR error; + + YearDayScheduleInfo yearDayScheduleInStorage; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, DlStatus::kFailure); + VerifyOrReturnValue(yearDayIndex > 0, DlStatus::kFailure); // indices are one-indexed VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed @@ -612,13 +716,35 @@ DlStatus LockManager::GetYeardaySchedule(chip::EndpointId endpointId, uint8_t ye VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - const auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; - if (DlScheduleStatus::kAvailable == scheduleInStorage.status) + // Get schedule data from nvm3 + chip::StorageKeyName scheduleDataKey = LockUserYearDayScheduleEndpoint(userIndex, yearDayIndex, endpointId); + + uint16_t scheduleSize = static_cast(sizeof(YearDayScheduleInfo)); + + error = mStorage->SyncGetKeyValue(scheduleDataKey.KeyName(), &yearDayScheduleInStorage, scheduleSize); + + // If no data is found at scheduleUserMapKey key + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) { + ChipLogError(Zcl, "No schedule data found for user"); return DlStatus::kNotFound; } + // Else if KVS read was successful + else if (error == CHIP_NO_ERROR) + { + + if (yearDayScheduleInStorage.status == DlScheduleStatus::kAvailable) + { + return DlStatus::kNotFound; + } + } + else + { + ChipLogError(Zcl, "Error reading from KVS key"); + return DlStatus::kFailure; + } - schedule = scheduleInStorage.schedule; + schedule = yearDayScheduleInStorage.schedule; return DlStatus::kSuccess; } @@ -626,6 +752,12 @@ DlStatus LockManager::GetYeardaySchedule(chip::EndpointId endpointId, uint8_t ye DlStatus LockManager::SetYeardaySchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime) { + CHIP_ERROR error; + + YearDayScheduleInfo yearDayScheduleInStorage; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, DlStatus::kFailure); + VerifyOrReturnValue(yearDayIndex > 0, DlStatus::kFailure); // indices are one-indexed VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed @@ -635,16 +767,21 @@ DlStatus LockManager::SetYeardaySchedule(chip::EndpointId endpointId, uint8_t ye VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; + yearDayScheduleInStorage.schedule.localStartTime = localStartTime; + yearDayScheduleInStorage.schedule.localEndTime = localEndTime; + yearDayScheduleInStorage.status = status; - scheduleInStorage.schedule.localStartTime = localStartTime; - scheduleInStorage.schedule.localEndTime = localEndTime; - scheduleInStorage.status = status; + // Save schedule data in nvm3 + chip::StorageKeyName scheduleDataKey = LockUserYearDayScheduleEndpoint(userIndex, yearDayIndex, endpointId); - // Save schedule information in NVM flash - SilabsConfig::WriteConfigValueBin( - SilabsConfig::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), - sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * LockParams.numberOfUsers); + error = mStorage->SyncSetKeyValue(scheduleDataKey.KeyName(), &yearDayScheduleInStorage, + static_cast(sizeof(YearDayScheduleInfo))); + + if ((error != CHIP_NO_ERROR)) + { + ChipLogError(Zcl, "Error reading from KVS key"); + return DlStatus::kFailure; + } return DlStatus::kSuccess; } @@ -652,19 +789,47 @@ DlStatus LockManager::SetYeardaySchedule(chip::EndpointId endpointId, uint8_t ye DlStatus LockManager::GetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, EmberAfPluginDoorLockHolidaySchedule & schedule) { + CHIP_ERROR error; + + HolidayScheduleInfo holidayScheduleInStorage; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, DlStatus::kFailure); + VerifyOrReturnValue(holidayIndex > 0, DlStatus::kFailure); // indices are one-indexed holidayIndex--; VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); - const auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; - if (DlScheduleStatus::kAvailable == scheduleInStorage.status) + // Get schedule data from nvm3 + chip::StorageKeyName scheduleDataKey = LockHolidayScheduleEndpoint(holidayIndex, endpointId); + + uint16_t scheduleSize = static_cast(sizeof(HolidayScheduleInfo)); + + error = mStorage->SyncGetKeyValue(scheduleDataKey.KeyName(), &holidayScheduleInStorage, scheduleSize); + + // If no data is found at scheduleUserMapKey key + if (error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) { + ChipLogError(Zcl, "No schedule data found for user"); return DlStatus::kNotFound; } + // Else if KVS read was successful + else if (error == CHIP_NO_ERROR) + { + + if (holidayScheduleInStorage.status == DlScheduleStatus::kAvailable) + { + return DlStatus::kNotFound; + } + } + else + { + ChipLogError(Zcl, "Error reading from KVS key"); + return DlStatus::kFailure; + } - schedule = scheduleInStorage.schedule; + schedule = holidayScheduleInStorage.schedule; return DlStatus::kSuccess; } @@ -672,23 +837,34 @@ DlStatus LockManager::GetHolidaySchedule(chip::EndpointId endpointId, uint8_t ho DlStatus LockManager::SetHolidaySchedule(chip::EndpointId endpointId, uint8_t holidayIndex, DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime, OperatingModeEnum operatingMode) { + CHIP_ERROR error; + + HolidayScheduleInfo holidayScheduleInStorage; + + VerifyOrReturnValue(kInvalidEndpointId != endpointId, DlStatus::kFailure); + VerifyOrReturnValue(holidayIndex > 0, DlStatus::kFailure); // indices are one-indexed holidayIndex--; VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); - auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; + holidayScheduleInStorage.schedule.localStartTime = localStartTime; + holidayScheduleInStorage.schedule.localEndTime = localEndTime; + holidayScheduleInStorage.schedule.operatingMode = operatingMode; + holidayScheduleInStorage.status = status; + + // Save schedule data in nvm3 + chip::StorageKeyName scheduleDataKey = LockHolidayScheduleEndpoint(holidayIndex, endpointId); - scheduleInStorage.schedule.localStartTime = localStartTime; - scheduleInStorage.schedule.localEndTime = localEndTime; - scheduleInStorage.schedule.operatingMode = operatingMode; - scheduleInStorage.status = status; + error = mStorage->SyncSetKeyValue(scheduleDataKey.KeyName(), &holidayScheduleInStorage, + static_cast(sizeof(HolidayScheduleInfo))); - // Save schedule information in NVM flash - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_HolidaySchedules, - reinterpret_cast(&(mHolidaySchedule)), - sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules); + if ((error != CHIP_NO_ERROR)) + { + ChipLogError(Zcl, "Error reading from KVS key"); + return DlStatus::kFailure; + } return DlStatus::kSuccess; } @@ -717,6 +893,10 @@ bool LockManager::setLockState(chip::EndpointId endpointId, const Nullable(sizeof(LockUserInfo)); + + error = mStorage->SyncGetKeyValue(userKey.KeyName(), &mUserInStorage, size); - if (currentCredential.status == DlCredentialStatus::kAvailable) + // No user exists at this index + if (error != CHIP_NO_ERROR) { continue; } - if (currentCredential.credentialData.data_equal(pin.Value())) + chip::StorageKeyName credentialKey = LockUserCredentialMap(userIndex); + + uint16_t credentialStructSize = static_cast(sizeof(CredentialStruct) * mUserInStorage.currentCredentialCount); + + // Get array of credential indices and types associated to user + error = mStorage->SyncGetKeyValue(credentialKey.KeyName(), &mCredentials, credentialStructSize); + + // No credential data associated with user + if (error != CHIP_NO_ERROR) { - ChipLogDetail(Zcl, - "Lock App: specified PIN code was found in the database, setting lock state to \"%s\" [endpointId=%d]", - lockStateToString(lockState), endpointId); + continue; + } - DoorLockServer::Instance().SetLockState(endpointId, lockState, OperationSourceEnum::kRemote, NullNullable, NullNullable, - fabricIdx, nodeId); + for (int j = 0; j < mUserInStorage.currentCredentialCount; j++) + { + // If the current credential is a pin type, then check it against pin input. Otherwise ignore + if (mCredentials[j].credentialType == CredentialTypeEnum::kPin) + { + // Read the individual credential at credentialIndex j + uint16_t credentialSize = static_cast(sizeof(LockCredentialInfo)); - return true; + chip::StorageKeyName key = + LockCredentialEndpoint(mCredentials[j].credentialIndex, mCredentials[j].credentialType, endpointId); + + error = mStorage->SyncGetKeyValue(key.KeyName(), &mCredentialInStorage, credentialSize); + + if ((error != CHIP_NO_ERROR) && (error != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND)) + { + ChipLogError(Zcl, "Error reading credential"); + return false; + } + + // See if it matches the provided PIN + if (mCredentialInStorage.status == DlCredentialStatus::kAvailable) + { + continue; + } + + chip::ByteSpan currentCredential = + chip::ByteSpan{ mCredentialInStorage.credentialData, mCredentialInStorage.credentialDataSize }; + + if (currentCredential.data_equal(pin.Value())) + { + ChipLogDetail( + Zcl, "Lock App: specified PIN code was found in the database, setting lock state to \"%s\" [endpointId=%d]", + lockStateToString(lockState), endpointId); + + LockOpCredentials userCredential[] = { { CredentialTypeEnum::kPin, mCredentials[j].credentialIndex } }; + auto userCredentials = MakeNullable>(userCredential); + + DoorLockServer::Instance().SetLockState(endpointId, lockState, OperationSourceEnum::kRemote, userIndex, + userCredentials, fabricIdx, nodeId); + + return true; + } + } } }