| /* |
| * |
| * Copyright (c) 2021-2022 Project CHIP Authors |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file |
| * Platform-specific key value storage implementation for SILABS |
| */ |
| |
| #include <lib/support/CHIPMemString.h> |
| #include <lib/support/CodeUtils.h> |
| #include <platform/CHIPDeviceLayer.h> |
| #include <platform/KeyValueStoreManager.h> |
| #include <platform/silabs/SilabsConfig.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| using namespace ::chip; |
| using namespace ::chip::DeviceLayer::Internal; |
| |
| #define CONVERT_KEYMAP_INDEX_TO_NVM3KEY(index) (SILABSConfig::kConfigKey_KvsFirstKeySlot + index) |
| #define CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key) (nvm3Key - SILABSConfig::kConfigKey_KvsFirstKeySlot) |
| |
| namespace chip { |
| namespace DeviceLayer { |
| namespace PersistedStorage { |
| |
| KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; |
| char mKvsStoredKeyString[KeyValueStoreManagerImpl::kMaxEntries][PersistentStorageDelegate::kKeyLengthMax + 1]; |
| |
| CHIP_ERROR KeyValueStoreManagerImpl::Init(void) |
| { |
| CHIP_ERROR err; |
| err = SILABSConfig::Init(); |
| SuccessOrExit(err); |
| |
| memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); |
| size_t outLen; |
| err = SILABSConfig::ReadConfigValueBin(SILABSConfig::kConfigKey_KvsStringKeyMap, |
| reinterpret_cast<uint8_t *>(mKvsStoredKeyString), sizeof(mKvsStoredKeyString), outLen); |
| |
| if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) // Initial boot |
| { |
| err = CHIP_NO_ERROR; |
| } |
| |
| exit: |
| return err; |
| } |
| |
| bool KeyValueStoreManagerImpl::IsValidKvsNvm3Key(uint32_t nvm3Key) const |
| { |
| return ((SILABSConfig::kConfigKey_KvsFirstKeySlot <= nvm3Key) && (nvm3Key <= SILABSConfig::kConfigKey_KvsLastKeySlot)); |
| } |
| |
| CHIP_ERROR KeyValueStoreManagerImpl::MapKvsKeyToNvm3(const char * key, uint32_t & nvm3Key, bool isSlotNeeded) const |
| { |
| CHIP_ERROR err; |
| uint8_t firstEmptyKeySlot = kMaxEntries; |
| for (uint8_t keyIndex = 0; keyIndex < kMaxEntries; keyIndex++) |
| { |
| if (strcmp(key, mKvsStoredKeyString[keyIndex]) == 0) |
| { |
| nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(keyIndex); |
| VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true); |
| return CHIP_NO_ERROR; |
| } |
| |
| if (isSlotNeeded && (firstEmptyKeySlot == kMaxEntries) && (mKvsStoredKeyString[keyIndex][0] == 0)) |
| { |
| firstEmptyKeySlot = keyIndex; |
| } |
| } |
| |
| if (isSlotNeeded) |
| { |
| if (firstEmptyKeySlot != kMaxEntries) |
| { |
| nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(firstEmptyKeySlot); |
| VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true); |
| err = CHIP_NO_ERROR; |
| } |
| else |
| { |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; |
| } |
| } |
| else |
| { |
| err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; |
| } |
| return err; |
| } |
| |
| void KeyValueStoreManagerImpl::ForceKeyMapSave() |
| { |
| OnScheduledKeyMapSave(nullptr, nullptr); |
| } |
| |
| void KeyValueStoreManagerImpl::OnScheduledKeyMapSave(System::Layer * systemLayer, void * appState) |
| { |
| SILABSConfig::WriteConfigValueBin(SILABSConfig::kConfigKey_KvsStringKeyMap, |
| reinterpret_cast<const uint8_t *>(mKvsStoredKeyString), sizeof(mKvsStoredKeyString)); |
| } |
| |
| void KeyValueStoreManagerImpl::ScheduleKeyMapSave(void) |
| { |
| /* |
| During commissioning, the key map will be modified multiples times subsequently. |
| Commit the key map in nvm once it as stabilized. |
| */ |
| SystemLayer().StartTimer( |
| std::chrono::duration_cast<System::Clock::Timeout>(System::Clock::Seconds32(SILABS_KVS_SAVE_DELAY_SECONDS)), |
| KeyValueStoreManagerImpl::OnScheduledKeyMapSave, NULL); |
| } |
| |
| CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, |
| size_t offset_bytes) const |
| { |
| VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| uint32_t nvm3Key; |
| CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key); |
| VerifyOrReturnError(err == CHIP_NO_ERROR, err); |
| |
| size_t outLen; |
| err = SILABSConfig::ReadConfigValueBin(nvm3Key, reinterpret_cast<uint8_t *>(value), value_size, outLen, offset_bytes); |
| if (read_bytes_size) |
| { |
| *read_bytes_size = outLen; |
| } |
| |
| if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) |
| { |
| return CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; |
| } |
| |
| return err; |
| } |
| |
| CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size) |
| { |
| VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| uint32_t nvm3Key; |
| CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key, /* isSlotNeeded */ true); |
| VerifyOrReturnError(err == CHIP_NO_ERROR, err); |
| |
| err = SILABSConfig::WriteConfigValueBin(nvm3Key, reinterpret_cast<const uint8_t *>(value), value_size); |
| if (err == CHIP_NO_ERROR) |
| { |
| uint32_t keyIndex = nvm3Key - SILABSConfig::kConfigKey_KvsFirstKeySlot; |
| Platform::CopyString(mKvsStoredKeyString[keyIndex], key); |
| ScheduleKeyMapSave(); |
| } |
| |
| return err; |
| } |
| |
| CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) |
| { |
| VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); |
| |
| uint32_t nvm3Key; |
| CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key); |
| VerifyOrReturnError(err == CHIP_NO_ERROR, err); |
| |
| err = SILABSConfig::ClearConfigValue(nvm3Key); |
| if (err == CHIP_NO_ERROR) |
| { |
| uint32_t keyIndex = CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key); |
| memset(mKvsStoredKeyString[keyIndex], 0, sizeof(mKvsStoredKeyString[keyIndex])); |
| ScheduleKeyMapSave(); |
| } |
| |
| return err; |
| } |
| |
| CHIP_ERROR KeyValueStoreManagerImpl::ErasePartition(void) |
| { |
| // Iterate over all the Matter Kvs nvm3 records and delete each one... |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| for (uint32_t nvm3Key = SILABSConfig::kMinConfigKey_MatterKvs; nvm3Key < SILABSConfig::kMaxConfigKey_MatterKvs; nvm3Key++) |
| { |
| err = SILABSConfig::ClearConfigValue(nvm3Key); |
| |
| if (err != CHIP_NO_ERROR) |
| { |
| break; |
| } |
| } |
| |
| memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); |
| return err; |
| } |
| |
| } // namespace PersistedStorage |
| } // namespace DeviceLayer |
| } // namespace chip |