/* * * Copyright (c) 2020 Project CHIP Authors * Copyright (c) 2020 Google LLC. * Copyright (c) 2018 Nest Labs, Inc. * * 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 K32W SDK. */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #include #endif #include "FreeRTOS.h" #include "FunctionLib.h" #include "NVM_Interface.h" namespace chip { namespace DeviceLayer { namespace Internal { #ifndef CHIP_PLAT_NVM_SUPPORT #define CHIP_PLAT_NVM_SUPPORT 0 #endif #ifndef CHIP_PLAT_NVM_STATIC_ALLOC #define CHIP_PLAT_NVM_STATIC_ALLOC 1 #endif #define CHIP_CONFIG_RAM_BUFFER_SIZE 14336 #ifndef NVM_ID_CHIP_CONFIG_DATA #define NVM_ID_CHIP_CONFIG_DATA 0xf104 #endif #if 0 typedef struct { uint16_t chipConfigRamBufferLen; uint8_t chipConfigRamBuffer[3072]; } ChipConfigRamStruct_t; static ChipConfigRamStruct_t *chipConfigRamStruct; #endif #if CHIP_PLAT_NVM_STATIC_ALLOC static uint8_t chipConfigRamBuffer[CHIP_CONFIG_RAM_BUFFER_SIZE] = { 0 }; #endif static ramBufferDescriptor * ramDescr; #define RAM_DESC_HEADER_SIZE (sizeof(ramDescr->ramBufferLen + ramDescr->ramBufferMaxLen)) #if CHIP_PLAT_NVM_SUPPORT NVM_RegisterDataSet((void *) chipConfigRamBuffer, 1, sizeof(chipConfigRamBuffer), NVM_ID_CHIP_CONFIG_DATA, gNVM_MirroredInRam_c); #endif static rsError AddToRamStorage(ramBufferDescriptor * pBuffer, uint16_t aKey, const uint8_t * aValue, uint16_t aValueLength) { rsError err; #if !CHIP_PLAT_NVM_STATIC_ALLOC uint32_t allocSize = pBuffer->ramBufferMaxLen; if (allocSize <= pBuffer->ramBufferLen + aValueLength) { while (allocSize < pBuffer->ramBufferLen + aValueLength) { /* Need to realocate the memory buffer, increase size by 512B until nvm data fits */ allocSize += 512; } pBuffer->ramBufferLen = allocSize; allocSize += RAM_DESC_HEADER_SIZE; pBuffer = (ramBufferDescriptor *) realloc((void *) pBuffer, allocSize); VerifyOrExit((NULL != pBuffer), err = RS_ERROR_NO_BUFS); } #endif err = ramStorageSet(pBuffer, aKey, aValue, aValueLength); #if !CHIP_PLAT_NVM_STATIC_ALLOC exit: #endif return err; } CHIP_ERROR NXPConfig::Init() { CHIP_ERROR err = CHIP_NO_ERROR; bool bLoadDataFromNvm = true; uint32_t allocSize = CHIP_CONFIG_RAM_BUFFER_SIZE; /* Initialise the Persistent Data Manager */ #if CHIP_PLAT_NVM_SUPPORT /* Init the NVM module */ NvModuleInit(); #endif #if CHIP_PLAT_NVM_STATIC_ALLOC ramDescr = (ramBufferDescriptor *) chipConfigRamBuffer; #else ramDescr = (ramBufferDescriptor *) malloc(allocSize); VerifyOrExit((NULL != ramDescr), err = CHIP_ERROR_NO_MEMORY); #endif ramDescr->ramBufferLen = 0; if (bLoadDataFromNvm) { /* Try to load the dataset in RAM */ #if CHIP_PLAT_NVM_SUPPORT NvRestoreDataSet((void *) ramDescr, 0); #endif } ramDescr->ramBufferMaxLen = allocSize - RAM_DESC_HEADER_SIZE; #if !CHIP_PLAT_NVM_STATIC_ALLOC exit: #endif return err; } CHIP_ERROR NXPConfig::ReadConfigValue(Key key, bool & val) { CHIP_ERROR err; bool tempVal; rsError status; uint16_t sizeToRead = sizeof(tempVal); VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = ramStorageGet(ramDescr, key, 0, (uint8_t *) &tempVal, &sizeToRead); SuccessOrExit(err = MapRamStorageStatus(status)); val = tempVal; exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValue(Key key, uint32_t & val) { CHIP_ERROR err; uint32_t tempVal; rsError status; uint16_t sizeToRead = sizeof(tempVal); VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = ramStorageGet(ramDescr, key, 0, (uint8_t *) &tempVal, &sizeToRead); SuccessOrExit(err = MapRamStorageStatus(status)); val = tempVal; exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValue(Key key, uint64_t & val) { CHIP_ERROR err; uint32_t tempVal; rsError status; uint16_t sizeToRead = sizeof(tempVal); VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = ramStorageGet(ramDescr, key, 0, (uint8_t *) &tempVal, &sizeToRead); SuccessOrExit(err = MapRamStorageStatus(status)); val = tempVal; exit: return err; } CHIP_ERROR NXPConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) { CHIP_ERROR err; rsError status; uint16_t sizeToRead = bufSize; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. // We can call ramStorageGet with null pointer to only retrieve the size status = ramStorageGet(ramDescr, key, 0, (uint8_t *) buf, &sizeToRead); SuccessOrExit(err = MapRamStorageStatus(status)); outLen = sizeToRead; 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::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; rsError status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(bool)); SuccessOrExit(err = MapRamStorageStatus(status)); #if CHIP_PLAT_NVM_SUPPORT NvSaveOnIdle(ramDescr, false); #endif // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValueSync(Key key, bool val) { CHIP_ERROR err; rsError status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(bool)); SuccessOrExit(err = MapRamStorageStatus(status)); #if CHIP_PLAT_NVM_SUPPORT NvSyncSave(ramDescr, false); #endif // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValue(Key key, uint32_t val) { CHIP_ERROR err; rsError status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(uint32_t)); SuccessOrExit(err = MapRamStorageStatus(status)); #if CHIP_PLAT_NVM_SUPPORT NvSaveOnIdle(ramDescr, false); #endif // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); exit: return err; } CHIP_ERROR NXPConfig::WriteConfigValue(Key key, uint64_t val) { CHIP_ERROR err; rsError status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = AddToRamStorage(ramDescr, key, (uint8_t *) &val, sizeof(uint64_t)); SuccessOrExit(err = MapRamStorageStatus(status)); #if CHIP_PLAT_NVM_SUPPORT NvSaveOnIdle(ramDescr, false); #endif // ChipLogProgress(DeviceLayer, "WriteConfigValue done"); 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; rsError status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. if (str != NULL) { status = AddToRamStorage(ramDescr, key, (uint8_t *) str, strLen); SuccessOrExit(err = MapRamStorageStatus(status)); #if CHIP_PLAT_NVM_SUPPORT NvSaveOnIdle(ramDescr, false); #endif } else { err = ClearConfigValue(key); SuccessOrExit(err); } 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::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; rsError status; VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id. status = ramStorageDelete(ramDescr, key, 0); SuccessOrExit(err = MapRamStorageStatus(status)); #if CHIP_PLAT_NVM_SUPPORT NvSaveOnIdle(ramDescr, false); #endif exit: return err; } bool NXPConfig::ConfigValueExists(Key key) { rsError status; uint16_t sizeToRead; bool found = false; if (ValidConfigKey(key)) { status = ramStorageGet(ramDescr, key, 0, NULL, &sizeToRead); found = (status == RS_ERROR_NONE && sizeToRead != 0); } return found; } CHIP_ERROR NXPConfig::FactoryResetConfig(void) { CHIP_ERROR err = CHIP_NO_ERROR; FactoryResetConfigInternal(kMinConfigKey_ChipConfig, kMaxConfigKey_ChipConfig); FactoryResetConfigInternal(kMinConfigKey_ChipCounter, kMaxConfigKey_ChipCounter); FactoryResetConfigInternal(kMinConfigKey_KVSKey, kMaxConfigKey_KVSKey); FactoryResetConfigInternal(kMinConfigKey_KVSValue, kMaxConfigKey_KVSValue); #if CHIP_PLAT_NVM_SUPPORT /* Save in flash now */ NvSyncSave(ramDescr, false); #endif return err; } void NXPConfig::FactoryResetConfigInternal(Key firstKey, Key lastKey) { for (Key key = firstKey; key <= lastKey; key++) { ramStorageDelete(ramDescr, key, 0); } } CHIP_ERROR NXPConfig::MapRamStorageStatus(rsError rsStatus) { CHIP_ERROR err; switch (rsStatus) { case RS_ERROR_NONE: err = CHIP_NO_ERROR; break; case RS_ERROR_NOT_FOUND: err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND; break; default: err = CHIP_ERROR_BUFFER_TOO_SMALL; break; } return err; } 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_KVSValue)) { return true; } return false; } void NXPConfig::RunConfigUnitTest() {} } // namespace Internal } // namespace DeviceLayer } // namespace chip