blob: 2019fce5811ebaf0d54fb3ba9a613b4d00cc37f6 [file] [log] [blame]
/*
*
* 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 <platform/internal/CHIPDeviceLayerInternal.h>
#include <platform/nxp/k32w/k32w1/K32W1Config.h>
#include <lib/core/CHIPConfig.h>
#include <lib/core/CHIPEncoding.h>
#include <platform/internal/testing/ConfigUnitTest.h>
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#include <openthread-system.h>
#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 K32WConfig::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 K32WConfig::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 K32WConfig::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 K32WConfig::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 K32WConfig::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 K32WConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
{
return ReadConfigValueStr(key, (char *) buf, bufSize, outLen);
}
CHIP_ERROR K32WConfig::ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val)
{
Key key = kMinConfigKey_ChipCounter + counterIdx;
return ReadConfigValue(key, val);
}
CHIP_ERROR K32WConfig::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 K32WConfig::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 K32WConfig::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 K32WConfig::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 K32WConfig::WriteConfigValueStr(Key key, const char * str)
{
return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0);
}
CHIP_ERROR K32WConfig::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 K32WConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
{
return WriteConfigValueStr(key, (char *) data, dataLen);
}
CHIP_ERROR K32WConfig::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val)
{
Key key = kMinConfigKey_ChipCounter + counterIdx;
return WriteConfigValue(key, val);
}
CHIP_ERROR K32WConfig::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 K32WConfig::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 K32WConfig::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 K32WConfig::FactoryResetConfigInternal(Key firstKey, Key lastKey)
{
for (Key key = firstKey; key <= lastKey; key++)
{
ramStorageDelete(ramDescr, key, 0);
}
}
CHIP_ERROR K32WConfig::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 K32WConfig::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 K32WConfig::RunConfigUnitTest() {}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip