/* * * Copyright (c) 2023 Project CHIP Authors * * 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 * Utilities for accessing persisted device configuration on * platforms based on the NXP SDK. */ #include "NXPConfig.h" #include "FreeRTOS.h" #include "FunctionLib.h" #include "board.h" #include #include #include #include "fwk_file_cache.h" #include "fwk_fs_abstraction.h" #include "fwk_key_storage.h" #include "fwk_lfs_mflash.h" #if defined(DEBUG_NVM) && (DEBUG_NVM == 2) #include "fsl_debug_console.h" #define DBG_PRINTF PRINTF #define INFO_PRINTF PRINTF #elif defined(DEBUG_NVM) && (DEBUG_NVM == 1) #include "fsl_debug_console.h" #define DBG_PRINTF PRINTF #define INFO_PRINTF(...) #else #define DBG_PRINTF(...) #define INFO_PRINTF(...) #endif /* Temporary namespace for integer and string keys */ #define NS_INT "_fki" #define NS_STR "_fks" /* Set to 1 if you want to see the statistics about the keys and their length */ #define ENABLE_KEYS_STATS 0 /* Size of the ram memory section for the KS configuration */ /* following the study of the size of the Matter key storage files, we defined that a buffer size equal to 2265 is necessary. We decided to add a mark-up, bringing the buffer size to 5k to be safe */ #ifndef KS_MATTER_SCRATCH_AREA_SIZE_MAX #define KS_MATTER_SCRATCH_AREA_SIZE_MAX 5 * 1024 #endif static uint8_t mem_section[KS_MATTER_SCRATCH_AREA_SIZE_MAX]; static ks_config_t ks_config = { .size = KS_MATTER_SCRATCH_AREA_SIZE_MAX, .KS_name = "KSconf", .mem_p = mem_section, //.mem_p = NULL, }; static void * ks_handle_p = NULL; static bool isInitialized = false; #if (ENABLE_KEYS_STATS == 1) typedef struct { uint16_t writtenKeys_str; uint16_t deletedKeys_str; uint16_t writtenKeys_int; uint16_t deletedKeys_int; } ks_keys_stats_t; static ks_keys_stats_t keys_stats = { 0, 0, 0, 0 }; #endif namespace chip { namespace DeviceLayer { namespace Internal { CHIP_ERROR NXPConfig::Init() { if (!isInitialized) { ks_handle_p = KS_Init(&ks_config); isInitialized = true; } DBG_PRINTF("Init"); return CHIP_NO_ERROR; } CHIP_ERROR NXPConfig::ReadConfigValue(Key key, bool & val) { CHIP_ERROR err; ks_error_t status; int req_len; int outLen; bool tempVal; req_len = sizeof(bool); outLen = 0; tempVal = false; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_GetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) &tempVal, req_len, &outLen); SuccessOrExit(err = MapKeyStorageStatus(status)); val = tempVal; #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "ReadConfigValue bool = %u", val); #endif exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValue(Key key, uint32_t & val) { CHIP_ERROR err; ks_error_t status; int req_len; int outLen; uint32_t tempVal; req_len = sizeof(uint32_t); outLen = 0; tempVal = 0; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_GetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) &tempVal, req_len, &outLen); SuccessOrExit(err = MapKeyStorageStatus(status)); val = tempVal; #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "ReadConfigValue uint32_t = %lu", val); #endif exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValue(Key key, uint64_t & val) { CHIP_ERROR err; ks_error_t status; int req_len; int outLen; uint64_t tempVal; req_len = sizeof(uint64_t); outLen = 0; tempVal = 0; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_GetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) &tempVal, req_len, &outLen); SuccessOrExit(err = MapKeyStorageStatus(status)); val = tempVal; #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "ReadConfigValue uint64_t = " ChipLogFormatX64, ChipLogValueX64(val)); #endif exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) { CHIP_ERROR err; ks_error_t status; uint32_t sizeToRead; sizeToRead = bufSize; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_GetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) buf, (int) bufSize, (int *) &sizeToRead); SuccessOrExit(err = MapKeyStorageStatus(status)); outLen = sizeToRead; #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "ReadConfigValueStr bufSize = %u, lenRead = %u", bufSize, outLen); #endif exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) { return ReadConfigValueStr(key, (char *) buf, bufSize, outLen); } CHIP_ERROR NXPConfig::ReadConfigValueBin(const char * keyString, uint8_t * buf, size_t bufSize, size_t & outLen) { CHIP_ERROR err; ks_error_t status; uint32_t sizeToRead; sizeToRead = bufSize; VerifyOrExit(keyString != NULL, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_GetKeyString(ks_handle_p, (char *) keyString, strlen(keyString) + 1, (char *) NS_STR, (void *) buf, (int) bufSize, (int *) &sizeToRead); // +1 to add end \0 char SuccessOrExit(err = MapKeyStorageStatus(status)); outLen = sizeToRead; #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "ReadConfigValueStr lenRead = %u", outLen); #endif exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val) { Key key = kMinConfigKey_ChipCounter + counterIdx; return ReadConfigValue(key, val); } CHIP_ERROR NXPConfig::WriteConfigValue(Key key, bool val) { CHIP_ERROR err; ks_error_t status; int valSize; valSize = sizeof(bool); VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_SetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) &val, valSize); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("WriteConfigValue: MT write \r\n"); #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "WriteConfigValue done"); #endif #if (ENABLE_KEYS_STATS == 1) keys_stats.writtenKeys_int++; ChipLogProgress(DeviceLayer, "Data len: %u. Integer keys written until now: %u.", valSize, keys_stats.writtenKeys_int); #endif exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValue(Key key, uint32_t val) { CHIP_ERROR err; ks_error_t status; int valSize; valSize = sizeof(uint32_t); VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_SetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) &val, valSize); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("WriteConfigValue: MT write \r\n"); #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "WriteConfigValue done"); #endif #if (ENABLE_KEYS_STATS == 1) keys_stats.writtenKeys_int++; ChipLogProgress(DeviceLayer, "Data len: %u. Integer keys written until now: %u.", valSize, keys_stats.writtenKeys_int); #endif exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValue(Key key, uint64_t val) { CHIP_ERROR err; ks_error_t status; int valSize; valSize = sizeof(uint64_t); VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_SetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) &val, valSize); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("WriteConfigValue64: MT write \r\n"); #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "WriteConfigValue done"); #endif #if (ENABLE_KEYS_STATS == 1) keys_stats.writtenKeys_int++; ChipLogProgress(DeviceLayer, "Data len: %u. Integer keys written until now: %u.", valSize, keys_stats.writtenKeys_int); #endif exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValueStr(Key key, const char * str) { return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0); } CHIP_ERROR NXPConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen) { CHIP_ERROR err; ks_error_t status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_SetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, (void *) str, strLen); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("WriteConfigValueStr: MT write \r\n"); #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "WriteConfigValue done"); #endif #if (ENABLE_KEYS_STATS == 1) keys_stats.writtenKeys_int++; ChipLogProgress(DeviceLayer, "Data len: %u. Integer keys written until now: %u.", strLen, keys_stats.writtenKeys_int); #endif exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) { return WriteConfigValueStr(key, (char *) data, dataLen); } CHIP_ERROR NXPConfig::WriteConfigValueBin(const char * keyString, const uint8_t * data, size_t dataLen) { CHIP_ERROR err; ks_error_t status; int keyLen; keyLen = (int) strlen(keyString) + 1; // +1 to add end \0 char VerifyOrExit(keyString != NULL, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_SetKeyString(ks_handle_p, (char *) keyString, keyLen, (char *) NS_STR, (void *) data, (int) dataLen); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("WriteConfigValueBin: MT write \r\n"); #if (DEBUG_NVM > 0) ChipLogProgress(DeviceLayer, "WriteConfigValue done"); #endif #if (ENABLE_KEYS_STATS == 1) keys_stats.writtenKeys_str++; ChipLogProgress(DeviceLayer, "Data len: %u. Key len: %u. String keys written until now: %u.", dataLen, keyLen, keys_stats.writtenKeys_str); #endif exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val) { Key key = kMinConfigKey_ChipCounter + counterIdx; return WriteConfigValue(key, val); } CHIP_ERROR NXPConfig::ClearConfigValue(Key key) { CHIP_ERROR err = CHIP_NO_ERROR; ks_error_t status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_DeleteKeyInt(ks_handle_p, (int) key, (char *) NS_INT); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("ClearConfigValue: MT write \r\n"); #if (ENABLE_KEYS_STATS == 1) keys_stats.deletedKeys_int++; ChipLogProgress(DeviceLayer, "Integer keys deleted until now: %u.", keys_stats.deletedKeys_int); #endif exit: return err; } CHIP_ERROR NXPConfig::ClearConfigValue(const char * keyString) { CHIP_ERROR err = CHIP_NO_ERROR; ks_error_t status; int keyLen; keyLen = strlen(keyString) + 1; // +1 to add end \0 char VerifyOrExit(keyString != NULL, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = KS_DeleteKeyString(ks_handle_p, (char *) keyString, keyLen, (char *) NS_STR); SuccessOrExit(err = MapKeyStorageStatus(status)); DBG_PRINTF("WriteConfigValueBin: MT write \r\n"); #if (ENABLE_KEYS_STATS == 1) keys_stats.deletedKeys_str++; ChipLogProgress(DeviceLayer, "String keys deleted until now: %u.", keys_stats.deletedKeys_str); #endif exit: return err; } bool NXPConfig::ConfigValueExists(Key key) { ks_error_t status; bool found; void * readValue_p; int outLen; int bufSize; found = false; readValue_p = NULL; outLen = 0; bufSize = 0; if (ValidConfigKey(key)) { /* Get the first occurence */ status = KS_GetKeyInt(ks_handle_p, (int) key, (char *) NS_INT, readValue_p, bufSize, &outLen); found = (status != KS_ERROR_KEY_NOT_FOUND); } return found; } CHIP_ERROR NXPConfig::FactoryResetConfig(void) { /* * When a factory reset is required, shut down the KeyStorage (which * also flushes the FileCache) and then execute a simple format of the * the file system partition. */ KS_DeInit(ks_handle_p); FSA_Format(); DBG_PRINTF("FactoryResetConfig done\r\n"); return CHIP_NO_ERROR; } bool NXPConfig::ValidConfigKey(Key key) { // Returns true if the key is in the valid CHIP Config PDM key range. if ((key >= kMinConfigKey_ChipFactory) && (key <= kMaxConfigKey_KVS)) { return true; } return false; } CHIP_ERROR NXPConfig::MapKeyStorageStatus(ks_error_t ksStatus) { CHIP_ERROR err; switch (ksStatus) { case KS_ERROR_NONE: err = CHIP_NO_ERROR; break; case KS_ERROR_BUF_TOO_SMALL: err = CHIP_ERROR_BUFFER_TOO_SMALL; break; default: /* KS_ERROR_KEY_NOT_FOUND */ err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; break; } return err; } void NXPConfig::RunConfigUnitTest(void) {} void NXPConfig::RunSystemIdleTask(void) { if (isInitialized) { FC_Process(); INFO_PRINTF("str mt write \r\n"); } } } // namespace Internal } // namespace DeviceLayer } // namespace chip