| /* |
| * |
| * 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 |