diff --git a/examples/platform/silabs/efr32/BaseApplication.cpp b/examples/platform/silabs/efr32/BaseApplication.cpp old mode 100755 new mode 100644 index 44e1658001ecf8..285a107e8bf406 --- a/examples/platform/silabs/efr32/BaseApplication.cpp +++ b/examples/platform/silabs/efr32/BaseApplication.cpp @@ -103,13 +103,12 @@ app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); #endif /* SL_WIFI */ -#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) +bool sIsProvisioned = false; -bool sIsProvisioned = false; +#if !(defined(CHIP_DEVICE_CONFIG_ENABLE_SED) && CHIP_DEVICE_CONFIG_ENABLE_SED) bool sIsEnabled = false; bool sIsAttached = false; bool sHaveBLEConnections = false; - #endif // CHIP_DEVICE_CONFIG_ENABLE_SED EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; @@ -236,6 +235,9 @@ CHIP_ERROR BaseApplication::Init(Identify * identifyObj) SILABS_LOG("Getting QR code failed!"); } + PlatformMgr().AddEventHandler(OnPlatformEvent, 0); + sIsProvisioned = ConnectivityMgr().IsThreadProvisioned(); + return err; } @@ -287,7 +289,7 @@ void BaseApplication::FunctionEventHandler(AppEvent * aEvent) StopStatusLEDTimer(); #endif // CHIP_DEVICE_CONFIG_ENABLE_SED - chip::Server::GetInstance().ScheduleFactoryReset(); + ScheduleFactoryReset(); } } @@ -307,9 +309,8 @@ void BaseApplication::LightEventHandler() sIsAttached = ConnectivityMgr().IsWiFiStationConnected(); #endif /* SL_WIFI */ #if CHIP_ENABLE_OPENTHREAD - sIsProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsEnabled = ConnectivityMgr().IsThreadEnabled(); - sIsAttached = ConnectivityMgr().IsThreadAttached(); + sIsEnabled = ConnectivityMgr().IsThreadEnabled(); + sIsAttached = ConnectivityMgr().IsThreadAttached(); #endif /* CHIP_ENABLE_OPENTHREAD */ sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); PlatformMgr().UnlockChipStack(); @@ -427,7 +428,7 @@ void BaseApplication::ButtonHandler(AppEvent * aEvent) #ifdef SL_WIFI if (!ConnectivityMgr().IsWiFiStationProvisioned()) #else - if (!ConnectivityMgr().IsThreadProvisioned()) + if (!sIsProvisioned) #endif /* !SL_WIFI */ { // Open Basic CommissioningWindow. Will start BLE advertisements @@ -570,3 +571,19 @@ void BaseApplication::DispatchEvent(AppEvent * aEvent) SILABS_LOG("Event received with no handler. Dropping event."); } } + +void BaseApplication::ScheduleFactoryReset() +{ + PlatformMgr().ScheduleWork([](intptr_t) { + PlatformMgr().HandleServerShuttingDown(); + ConfigurationMgr().InitiateFactoryReset(); + }); +} + +void BaseApplication::OnPlatformEvent(const ChipDeviceEvent * event, intptr_t) +{ + if (event->Type == DeviceEventType::kServiceProvisioningChange) + { + sIsProvisioned = event->ServiceProvisioningChange.IsServiceProvisioned; + } +} diff --git a/examples/platform/silabs/efr32/BaseApplication.h b/examples/platform/silabs/efr32/BaseApplication.h index f8372661bf4b14..eeb49702099993 100644 --- a/examples/platform/silabs/efr32/BaseApplication.h +++ b/examples/platform/silabs/efr32/BaseApplication.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #ifdef DISPLAY_ENABLED @@ -187,6 +188,16 @@ class BaseApplication */ static void LightEventHandler(); + /** + * @brief Start the factory Reset process + * Almost identical to Server::ScheduleFactoryReset() + * but doesn't call GetFabricTable().DeleteAllFabrics(); which deletes Key per key. + * With our KVS platform implementation this is a lot slower than deleting the whole kvs section + * our silabs nvm3 driver which end up being doing in ConfigurationManagerImpl::DoFactoryReset(intptr_t arg). + */ + static void ScheduleFactoryReset(); + + static void OnPlatformEvent(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t); /********************************************************** * Protected Attributes declaration *********************************************************/ diff --git a/src/platform/silabs/KeyValueStoreManagerImpl.h b/src/platform/silabs/KeyValueStoreManagerImpl.h index d8d288604af9da..0c63b0d4f594be 100644 --- a/src/platform/silabs/KeyValueStoreManagerImpl.h +++ b/src/platform/silabs/KeyValueStoreManagerImpl.h @@ -42,18 +42,20 @@ class KeyValueStoreManagerImpl final : public KeyValueStoreManager CHIP_ERROR _Put(const char * key, const void * value, size_t value_size); CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0) const; CHIP_ERROR _Delete(const char * key); - CHIP_ERROR ErasePartition(void); + void ErasePartition(void); static constexpr size_t kMaxEntries = KVS_MAX_ENTRIES; static void ForceKeyMapSave(); + static void KvsMapMigration(); private: static void OnScheduledKeyMapSave(System::Layer * systemLayer, void * appState); void ScheduleKeyMapSave(void); bool IsValidKvsNvm3Key(const uint32_t nvm3Key) const; - CHIP_ERROR MapKvsKeyToNvm3(const char * key, uint32_t & nvm3Key, bool isSlotNeeded = false) const; + uint16_t hashKvsKeyString(const char * key) const; + CHIP_ERROR MapKvsKeyToNvm3(const char * key, uint16_t hash, uint32_t & nvm3Key, bool isSlotNeeded = false) const; // ===== Members for internal use by the following friends. friend KeyValueStoreManager & KeyValueStoreMgr(); diff --git a/src/platform/silabs/SilabsConfig.cpp b/src/platform/silabs/SilabsConfig.cpp index 9c08d6720a4a94..1d5fab99c71e5b 100644 --- a/src/platform/silabs/SilabsConfig.cpp +++ b/src/platform/silabs/SilabsConfig.cpp @@ -33,17 +33,17 @@ #include "nvm3.h" #include "nvm3_default.h" #include "nvm3_hal_flash.h" +#include // Substitute the GSDK weak nvm3_lockBegin and nvm3_lockEnd // for an application controlled re-entrance protection -#define SILABS_SEM_TIMEOUT_ms 5 static SemaphoreHandle_t nvm3_Sem; static StaticSemaphore_t nvm3_SemStruct; void nvm3_lockBegin(void) { VerifyOrDie(nvm3_Sem != NULL); - xSemaphoreTake(nvm3_Sem, SILABS_SEM_TIMEOUT_ms); + xSemaphoreTake(nvm3_Sem, portMAX_DELAY); } void nvm3_lockEnd(void) @@ -69,7 +69,7 @@ CHIP_ERROR SilabsConfig::Init() { return CHIP_ERROR_NO_MEMORY; } - + xSemaphoreGive(nvm3_Sem); return MapNvm3Error(nvm3_open(nvm3_defaultHandle, nvm3_defaultInit)); } diff --git a/src/platform/silabs/SilabsConfig.h b/src/platform/silabs/SilabsConfig.h index 53d820c249eb80..cee73df868a7aa 100644 --- a/src/platform/silabs/SilabsConfig.h +++ b/src/platform/silabs/SilabsConfig.h @@ -32,7 +32,7 @@ #include "nvm3_hal_flash.h" #ifndef KVS_MAX_ENTRIES -#define KVS_MAX_ENTRIES 75 // Available key slot count for Kvs Key mapping. +#define KVS_MAX_ENTRIES 255 // Available key slot count for Kvs Key mapping. #endif // Delay before Key/Value is actually saved in NVM @@ -145,6 +145,7 @@ class SilabsConfig static constexpr Key kConfigKey_BootCount = SilabsConfigKey(kMatterCounter_KeyBase, 0x00); static constexpr Key kConfigKey_TotalOperationalHours = SilabsConfigKey(kMatterCounter_KeyBase, 0x01); static constexpr Key kConfigKey_LifeTimeCounter = SilabsConfigKey(kMatterCounter_KeyBase, 0x02); + static constexpr Key kConfigKey_MigrationCounter = SilabsConfigKey(kMatterCounter_KeyBase, 0x03); // Matter KVS storage Keys static constexpr Key kConfigKey_KvsStringKeyMap = SilabsConfigKey(kMatterKvs_KeyBase, 0x00); @@ -161,8 +162,8 @@ class SilabsConfig static constexpr Key kMinConfigKey_MatterCounter = SilabsConfigKey(kMatterCounter_KeyBase, 0x00); static constexpr Key kMaxConfigKey_MatterCounter = SilabsConfigKey(kMatterCounter_KeyBase, 0x1F); - static constexpr Key kMinConfigKey_MatterKvs = SilabsConfigKey(kMatterKvs_KeyBase, 0x00); - static constexpr Key kMaxConfigKey_MatterKvs = SilabsConfigKey(kMatterKvs_KeyBase, 0xFF); + static constexpr Key kMinConfigKey_MatterKvs = kConfigKey_KvsStringKeyMap; + static constexpr Key kMaxConfigKey_MatterKvs = kConfigKey_KvsLastKeySlot; static CHIP_ERROR Init(void); static void DeInit(void); diff --git a/src/platform/silabs/efr32/BUILD.gn b/src/platform/silabs/efr32/BUILD.gn index f9b2ce0053ae53..f294a8d2d10846 100644 --- a/src/platform/silabs/efr32/BUILD.gn +++ b/src/platform/silabs/efr32/BUILD.gn @@ -67,6 +67,7 @@ static_library("efr32") { "../../SingletonConfigurationManager.cpp", "ConfigurationManagerImpl.cpp", "KeyValueStoreManagerImpl.cpp", + "MigrationManager.cpp", "PlatformManagerImpl.cpp", ] diff --git a/src/platform/silabs/efr32/KeyValueStoreManagerImpl.cpp b/src/platform/silabs/efr32/KeyValueStoreManagerImpl.cpp index 9bca8221fcb229..dc5b3267564e1b 100644 --- a/src/platform/silabs/efr32/KeyValueStoreManagerImpl.cpp +++ b/src/platform/silabs/efr32/KeyValueStoreManagerImpl.cpp @@ -21,8 +21,8 @@ * Platform-specific key value storage implementation for SILABS */ -#include -#include +#include "MigrationManager.h" +#include #include #include #include @@ -30,6 +30,7 @@ #include using namespace ::chip; +using namespace ::chip::Crypto; using namespace ::chip::DeviceLayer::Internal; #define CONVERT_KEYMAP_INDEX_TO_NVM3KEY(index) (SilabsConfig::kConfigKey_KvsFirstKeySlot + index) @@ -40,7 +41,7 @@ namespace DeviceLayer { namespace PersistedStorage { KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; -char mKvsStoredKeyString[KeyValueStoreManagerImpl::kMaxEntries][PersistentStorageDelegate::kKeyLengthMax + 1]; +uint16_t mKvsKeyMap[KeyValueStoreManagerImpl::kMaxEntries] = { 0 }; CHIP_ERROR KeyValueStoreManagerImpl::Init(void) { @@ -48,10 +49,12 @@ CHIP_ERROR KeyValueStoreManagerImpl::Init(void) err = SilabsConfig::Init(); SuccessOrExit(err); - memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); + EFR32::EFR32Migration::GetMigrationManager().applyMigrations(); + + memset(mKvsKeyMap, 0, sizeof(mKvsKeyMap)); size_t outLen; - err = SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_KvsStringKeyMap, - reinterpret_cast(mKvsStoredKeyString), sizeof(mKvsStoredKeyString), outLen); + err = SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_KvsStringKeyMap, reinterpret_cast(mKvsKeyMap), + sizeof(mKvsKeyMap), outLen); if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) // Initial boot { @@ -67,25 +70,63 @@ 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 +uint16_t KeyValueStoreManagerImpl::hashKvsKeyString(const char * key) const +{ + uint8_t hash256[Crypto::kSHA256_Hash_Length] = { 0 }; + Crypto::Hash_SHA256(reinterpret_cast(key), strlen(key), hash256); + + uint16_t hash16, i = 0; + + while (!hash16 && (i < (Crypto::kSHA256_Hash_Length - 1))) + { + hash16 = (hash256[i] | (hash256[i + 1] << 8)); + i++; + } + return hash16; +} + +CHIP_ERROR KeyValueStoreManagerImpl::MapKvsKeyToNvm3(const char * key, uint16_t hash, uint32_t & nvm3Key, bool isSlotNeeded) const { CHIP_ERROR err; + char * strPrefix = nullptr; uint8_t firstEmptyKeySlot = kMaxEntries; for (uint8_t keyIndex = 0; keyIndex < kMaxEntries; keyIndex++) { - if (strcmp(key, mKvsStoredKeyString[keyIndex]) == 0) + if (mKvsKeyMap[keyIndex] == hash) { - nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(keyIndex); - VerifyOrDie(IsValidKvsNvm3Key(nvm3Key) == true); - return CHIP_NO_ERROR; + uint32_t tempNvm3key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(keyIndex); + VerifyOrDie(IsValidKvsNvm3Key(tempNvm3key) == true); + + size_t readCount; + size_t length = strlen(key); + if (strPrefix == nullptr) + { + // Use a calloc to initialize all bits to 0. alloc +1 for a null char + strPrefix = static_cast(Platform::MemoryCalloc(1, length + 1)); + VerifyOrDie(strPrefix != nullptr); + } + + // Collision prevention + // Read the data from NVM3 it should be prefixed by the kvsString + // else we will look for another matching hash in the map + SilabsConfig::ReadConfigValueBin(tempNvm3key, reinterpret_cast(strPrefix), length, readCount, 0); + if (strcmp(key, strPrefix) == 0) + { + // String matches we have confirmed the hash pointed us the right key data + nvm3Key = tempNvm3key; + Platform::MemoryFree(strPrefix); + return CHIP_NO_ERROR; + } } - if (isSlotNeeded && (firstEmptyKeySlot == kMaxEntries) && (mKvsStoredKeyString[keyIndex][0] == 0)) + if (isSlotNeeded && (firstEmptyKeySlot == kMaxEntries) && (mKvsKeyMap[keyIndex] == 0)) { firstEmptyKeySlot = keyIndex; } } + Platform::MemoryFree(strPrefix); + if (isSlotNeeded) { if (firstEmptyKeySlot != kMaxEntries) @@ -113,8 +154,8 @@ void KeyValueStoreManagerImpl::ForceKeyMapSave() void KeyValueStoreManagerImpl::OnScheduledKeyMapSave(System::Layer * systemLayer, void * appState) { - SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_KvsStringKeyMap, - reinterpret_cast(mKvsStoredKeyString), sizeof(mKvsStoredKeyString)); + SilabsConfig::WriteConfigValueBin(SilabsConfig::kConfigKey_KvsStringKeyMap, reinterpret_cast(mKvsKeyMap), + sizeof(mKvsKeyMap)); } void KeyValueStoreManagerImpl::ScheduleKeyMapSave(void) @@ -134,11 +175,15 @@ CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); uint32_t nvm3Key; - CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key); + uint16_t hash = hashKvsKeyString(key); + CHIP_ERROR err = MapKvsKeyToNvm3(key, hash, nvm3Key); VerifyOrReturnError(err == CHIP_NO_ERROR, err); size_t outLen; - err = SilabsConfig::ReadConfigValueBin(nvm3Key, reinterpret_cast(value), value_size, outLen, offset_bytes); + // The user doesn't need the KeyString prefix, Read data after it + size_t KeyStringLen = strlen(key); + err = SilabsConfig::ReadConfigValueBin(nvm3Key, reinterpret_cast(value), value_size, outLen, + (offset_bytes + KeyStringLen)); if (read_bytes_size) { *read_bytes_size = outLen; @@ -157,17 +202,25 @@ CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); uint32_t nvm3Key; - CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key, /* isSlotNeeded */ true); + uint16_t hash = hashKvsKeyString(key); + CHIP_ERROR err = MapKvsKeyToNvm3(key, hash, nvm3Key, /* isSlotNeeded */ true); VerifyOrReturnError(err == CHIP_NO_ERROR, err); - err = SilabsConfig::WriteConfigValueBin(nvm3Key, reinterpret_cast(value), value_size); + // add the string Key as prefix to the stored data as a collision prevention mechanism. + size_t keyStringLen = strlen(key); + uint8_t * prefixedData = static_cast(Platform::MemoryAlloc(keyStringLen + value_size)); + VerifyOrDie(prefixedData != nullptr); + memcpy(prefixedData, key, keyStringLen); + memcpy(prefixedData + keyStringLen, value, value_size); + + err = SilabsConfig::WriteConfigValueBin(nvm3Key, prefixedData, keyStringLen + value_size); if (err == CHIP_NO_ERROR) { - uint32_t keyIndex = nvm3Key - SilabsConfig::kConfigKey_KvsFirstKeySlot; - Platform::CopyString(mKvsStoredKeyString[keyIndex], key); + uint32_t keyIndex = CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key); + mKvsKeyMap[keyIndex] = hash; ScheduleKeyMapSave(); } - + Platform::MemoryFree(prefixedData); return err; } @@ -176,36 +229,74 @@ CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key) VerifyOrReturnError(key != nullptr, CHIP_ERROR_INVALID_ARGUMENT); uint32_t nvm3Key; - CHIP_ERROR err = MapKvsKeyToNvm3(key, nvm3Key); + uint16_t hash = hashKvsKeyString(key); + CHIP_ERROR err = MapKvsKeyToNvm3(key, hash, 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])); + uint32_t keyIndex = CONVERT_NVM3KEY_TO_KEYMAP_INDEX(nvm3Key); + mKvsKeyMap[keyIndex] = 0; ScheduleKeyMapSave(); } return err; } -CHIP_ERROR KeyValueStoreManagerImpl::ErasePartition(void) +void 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++) + for (uint32_t nvm3Key = SilabsConfig::kMinConfigKey_MatterKvs; nvm3Key <= SilabsConfig::kMaxConfigKey_MatterKvs; nvm3Key++) { - err = SilabsConfig::ClearConfigValue(nvm3Key); + SilabsConfig::ClearConfigValue(nvm3Key); + } + + memset(mKvsKeyMap, 0, sizeof(mKvsKeyMap)); +} - if (err != CHIP_NO_ERROR) +void KeyValueStoreManagerImpl::KvsMapMigration(void) +{ + size_t readlen = 0; + constexpr uint8_t oldMaxEntires = 120; + char mKvsStoredKeyString[oldMaxEntires][PersistentStorageDelegate::kKeyLengthMax + 1] = { 0 }; + CHIP_ERROR err = + SilabsConfig::ReadConfigValueBin(SilabsConfig::kConfigKey_KvsStringKeyMap, reinterpret_cast(mKvsStoredKeyString), + sizeof(mKvsStoredKeyString), readlen); + + if (err == CHIP_NO_ERROR) + { + for (uint8_t i = 0; i < oldMaxEntires; i++) { - break; + if (mKvsStoredKeyString[i][0] != 0) + { + size_t dataLen = 0; + uint32_t nvm3Key = CONVERT_KEYMAP_INDEX_TO_NVM3KEY(i); + + if (SilabsConfig::ConfigValueExists(nvm3Key, dataLen)) + { + // Read old data and prefix it with the string Key for the collision prevention mechanism. + size_t keyStringLen = strlen(mKvsStoredKeyString[i]); + uint8_t * prefixedData = static_cast(Platform::MemoryAlloc(keyStringLen + dataLen)); + VerifyOrDie(prefixedData != nullptr); + memcpy(prefixedData, mKvsStoredKeyString[i], keyStringLen); + + SilabsConfig::ReadConfigValueBin(nvm3Key, prefixedData + keyStringLen, dataLen, readlen); + SilabsConfig::WriteConfigValueBin(nvm3Key, prefixedData, keyStringLen + dataLen); + mKvsKeyMap[i] = KeyValueStoreMgrImpl().hashKvsKeyString(mKvsStoredKeyString[i]); + Platform::MemoryFree(prefixedData); + } + } } + ForceKeyMapSave(); + } + else if (err != CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND) + { + // Error reading the old String Keymap. Cannot not resolve stored data for migration. + ChipLogError(DeviceLayer, "Migration failed ! Kvs Key map could not be recovered %" CHIP_ERROR_FORMAT, err.Format()); + // start with a fresh kvs section. + KeyValueStoreMgrImpl().ErasePartition(); } - - memset(mKvsStoredKeyString, 0, sizeof(mKvsStoredKeyString)); - return err; } } // namespace PersistedStorage diff --git a/src/platform/silabs/efr32/MigrationManager.cpp b/src/platform/silabs/efr32/MigrationManager.cpp new file mode 100644 index 00000000000000..abd0bcbc834adf --- /dev/null +++ b/src/platform/silabs/efr32/MigrationManager.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 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. + */ + +#include "MigrationManager.h" +#include +#include +#include +#include + +using namespace ::chip::DeviceLayer::Internal; +using namespace ::chip::DeviceLayer::PersistedStorage; + +namespace chip { +namespace DeviceLayer { +namespace EFR32 { + +namespace { +typedef void (*func_ptr)(); +typedef struct +{ + uint32_t migrationGroup; + func_ptr migrationFunc; +} migrationData_t; + +#define COUNT_OF(A) (sizeof(A) / sizeof((A)[0])) +static migrationData_t migrationTable[] = { + { .migrationGroup = 1, .migrationFunc = &KeyValueStoreMgrImpl().KvsMapMigration }, + // add any additional migration neccesary. migrationGroup should stay equal if done in the same commit or increment by 1 for + // each new entry. +}; + +} // namespace + +void EFR32Migration::applyMigrations() +{ + uint32_t lastMigationGroupDone = 0; + SilabsConfig::ReadConfigValue(SilabsConfig::kConfigKey_MigrationCounter, lastMigationGroupDone); + + uint32_t completedMigrationGroup = lastMigationGroupDone; + for (uint32_t i = 0; i < COUNT_OF(migrationTable); i++) + { + if (lastMigationGroupDone < migrationTable[i].migrationGroup) + { + (*migrationTable[i].migrationFunc)(); + completedMigrationGroup = max(migrationTable[i].migrationGroup, completedMigrationGroup); + } + } + SilabsConfig::WriteConfigValue(SilabsConfig::kConfigKey_MigrationCounter, completedMigrationGroup); +} + +EFR32Migration & EFR32Migration::GetMigrationManager() +{ + static EFR32Migration sMigrationManager; + return sMigrationManager; +} + +} // namespace EFR32 +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/silabs/efr32/MigrationManager.h b/src/platform/silabs/efr32/MigrationManager.h new file mode 100644 index 00000000000000..59ea29d0769152 --- /dev/null +++ b/src/platform/silabs/efr32/MigrationManager.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 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. + */ + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace EFR32 { + +class EFR32Migration +{ + friend class KeyValueStoreManagerImpl; + +public: + /** + * The EFR32 migration manager is implemented as a singleton + * User should get the object from this getter. + */ + static EFR32Migration & GetMigrationManager(); + static void applyMigrations(); + +private: + EFR32Migration(){}; + ~EFR32Migration(){}; +}; + +} // namespace EFR32 +} // namespace DeviceLayer +} // namespace chip diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index cb43cb73826bf8..5964be1d27e429 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -31,7 +31,7 @@ declare_args() { use_silabs_thread_lib = false enable_openthread_cli = true - kvs_max_entries = 75 + kvs_max_entries = 255 # Use Silabs factory data provider example. # Users can implement their own.