blob: c22f4c5a86231276f079f9f08d12643a43fa79d4 [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/k32w0/K32W0Config.h>
#include <lib/core/CHIPEncoding.h>
#include <platform/internal/testing/ConfigUnitTest.h>
#include "FreeRTOS.h"
namespace chip {
namespace DeviceLayer {
namespace Internal {
osaMutexId_t K32WConfig::pdmMutexHandle = NULL;
static ramBufferDescriptor * ramDescr = NULL;
constexpr uint16_t kNvmIdChipConfigData = 0x5000;
constexpr uint16_t kRamBufferInitialSize = 3072;
CHIP_ERROR K32WConfig::Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
int pdmStatus;
/* Initialise the Persistent Data Manager */
pdmMutexHandle = OSA_MutexCreate();
VerifyOrExit((NULL != pdmMutexHandle), err = CHIP_ERROR_NO_MEMORY);
pdmStatus = PDM_Init();
SuccessOrExit(err = MapPdmInitStatus(pdmStatus));
ramDescr = getRamBuffer(kNvmIdChipConfigData, kRamBufferInitialSize);
if (!ramDescr)
{
err = CHIP_ERROR_NO_MEMORY;
}
exit:
if (err != CHIP_NO_ERROR)
{
if (pdmMutexHandle)
{
OSA_MutexDestroy(pdmMutexHandle);
}
if (ramDescr)
{
free(ramDescr);
}
}
return err;
}
void K32WConfig::MutexLock(osaMutexId_t mutexId, uint32_t millisec)
{
osaStatus_t status = OSA_MutexLock(mutexId, millisec);
if (osaStatus_Success != status)
{
ChipLogProgress(DeviceLayer, "OSA mutex lock failed.");
}
}
void K32WConfig::MutexUnlock(osaMutexId_t mutexId)
{
osaStatus_t status = OSA_MutexUnlock(mutexId);
if (osaStatus_Success != status)
{
ChipLogProgress(DeviceLayer, "OSA mutex unlock failed.");
}
}
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;
PDM_teStatus pdmStatus;
rsError ramStatus = RS_ERROR_NONE;
VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
MutexLock(pdmMutexHandle, osaWaitForever_c);
/* first delete all occurrences of "key" */
ramStorageDelete(ramDescr, key, -1);
/* resize RAM Buffer if needed */
ramStatus = ramStorageResize(&ramDescr, key, (uint8_t *) &val, sizeof(bool));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* add to RAM buffer */
ramStatus = ramStorageSet(ramDescr, key, (uint8_t *) &val, sizeof(bool));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* schedule flash writing */
pdmStatus = PDM_eSaveRecordDataInIdleTask(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
SuccessOrExit(err = MapPdmStatus(pdmStatus));
exit:
MutexUnlock(pdmMutexHandle);
return err;
}
CHIP_ERROR K32WConfig::WriteConfigValueSync(Key key, bool val)
{
CHIP_ERROR err;
PDM_teStatus pdmStatus;
rsError ramStatus = RS_ERROR_NONE;
VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
MutexLock(pdmMutexHandle, osaWaitForever_c);
/* first delete all occurrences of "key" */
ramStorageDelete(ramDescr, key, -1);
/* resize RAM Buffer if needed */
ramStatus = ramStorageResize(&ramDescr, key, (uint8_t *) &val, sizeof(bool));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* add to RAM buffer */
ramStatus = ramStorageSet(ramDescr, key, (uint8_t *) &val, sizeof(bool));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
// Interrupts are disabled to ensure there is no context switch during the actual
// writing, thus avoiding race conditions.
OSA_InterruptDisable();
pdmStatus = PDM_eSaveRecordData(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
OSA_InterruptEnable();
SuccessOrExit(err = MapPdmStatus(pdmStatus));
exit:
MutexUnlock(pdmMutexHandle);
return err;
}
CHIP_ERROR K32WConfig::WriteConfigValue(Key key, uint32_t val)
{
CHIP_ERROR err;
PDM_teStatus pdmStatus;
rsError ramStatus = RS_ERROR_NONE;
VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
MutexLock(pdmMutexHandle, osaWaitForever_c);
/* first delete all occurrences of "key" */
ramStorageDelete(ramDescr, key, -1);
/* resize RAM Buffer if needed */
ramStatus = ramStorageResize(&ramDescr, key, (uint8_t *) &val, sizeof(uint32_t));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* add to RAM buffer */
ramStatus = ramStorageSet(ramDescr, key, (uint8_t *) &val, sizeof(uint32_t));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* schedule flash writing */
pdmStatus = PDM_eSaveRecordDataInIdleTask(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
SuccessOrExit(err = MapPdmStatus(pdmStatus));
exit:
MutexUnlock(pdmMutexHandle);
return err;
}
CHIP_ERROR K32WConfig::WriteConfigValue(Key key, uint64_t val)
{
CHIP_ERROR err;
PDM_teStatus pdmStatus;
rsError ramStatus = RS_ERROR_NONE;
VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
MutexLock(pdmMutexHandle, osaWaitForever_c);
/* first delete all occurrences of "key" */
ramStorageDelete(ramDescr, key, -1);
/* resize RAM Buffer if needed */
ramStatus = ramStorageResize(&ramDescr, key, (uint8_t *) &val, sizeof(uint64_t));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* add to RAM buffer */
ramStatus = ramStorageSet(ramDescr, key, (uint8_t *) &val, sizeof(uint64_t));
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* schedule flash writing */
pdmStatus = PDM_eSaveRecordDataInIdleTask(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
SuccessOrExit(err = MapPdmStatus(pdmStatus));
exit:
MutexUnlock(pdmMutexHandle);
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;
PDM_teStatus pdmStatus;
rsError ramStatus = RS_ERROR_NONE;
VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
MutexLock(pdmMutexHandle, osaWaitForever_c);
if (!str)
{
ramStatus = ramStorageDelete(ramDescr, key, -1);
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
}
else
{
/* first delete all occurrences of "key" */
ramStorageDelete(ramDescr, key, -1);
/* resize RAM Buffer if needed */
ramStatus = ramStorageResize(&ramDescr, key, (uint8_t *) str, strLen);
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* add to RAM buffer */
ramStatus = ramStorageSet(ramDescr, key, (uint8_t *) str, strLen);
SuccessOrExit(err = MapRamStorageStatus(ramStatus));
/* schedule flash writing */
pdmStatus = PDM_eSaveRecordDataInIdleTask(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
}
exit:
MutexUnlock(pdmMutexHandle);
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;
PDM_teStatus pdmStatus;
VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
MutexLock(pdmMutexHandle, osaWaitForever_c);
status = ramStorageDelete(ramDescr, key, -1);
SuccessOrExit(err = MapRamStorageStatus(status));
pdmStatus = PDM_eSaveRecordDataInIdleTask(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
SuccessOrExit(err = MapPdmStatus(pdmStatus));
exit:
MutexUnlock(pdmMutexHandle);
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;
PDM_teStatus pdmStatus;
MutexLock(pdmMutexHandle, osaWaitForever_c);
FactoryResetConfigInternal(kMinConfigKey_ChipConfig, kMaxConfigKey_ChipConfig);
FactoryResetConfigInternal(kMinConfigKey_KVSKey, kMaxConfigKey_KVSKey);
FactoryResetConfigInternal(kMinConfigKey_KVSValue, kMaxConfigKey_KVSValue);
pdmStatus = PDM_eSaveRecordData(kNvmIdChipConfigData, ramDescr, ramDescr->ramBufferLen + kRamDescHeaderSize);
SuccessOrExit(err = MapPdmStatus(pdmStatus));
exit:
free((void *) ramDescr);
ramDescr = NULL;
MutexUnlock(pdmMutexHandle);
return err;
}
void K32WConfig::FactoryResetConfigInternal(Key firstKey, Key lastKey)
{
for (Key key = firstKey; key <= lastKey; key++)
{
ramStorageDelete(ramDescr, key, -1);
}
}
CHIP_ERROR K32WConfig::MapPdmStatus(PDM_teStatus pdmStatus)
{
CHIP_ERROR err;
switch (pdmStatus)
{
case PDM_E_STATUS_OK:
err = CHIP_NO_ERROR;
break;
default:
err = CHIP_ERROR(ChipError::Range::kPlatform, pdmStatus);
break;
}
return err;
}
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;
}
CHIP_ERROR K32WConfig::MapPdmInitStatus(int pdmStatus)
{
return (pdmStatus == 0) ? CHIP_NO_ERROR : CHIP_ERROR(ChipError::Range::kPlatform, pdmStatus);
}
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