| /* |
| * |
| * Copyright (c) 2020-2022 Project CHIP Authors |
| * Copyright (c) 2019-2020 Google LLC. |
| * Copyright (c) 2018 Nest Labs, Inc. |
| * All rights reserved. |
| * |
| * 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 interacting with multiple file partitions and maps |
| * key-value config calls to the correct partition. |
| */ |
| |
| #include <platform/internal/CHIPDeviceLayerInternal.h> |
| #include <platform/internal/testing/ConfigUnitTest.h> |
| |
| #include <lib/core/CHIPEncoding.h> |
| #include <lib/core/CHIPPersistentStorageDelegate.h> |
| #include <lib/support/CodeUtils.h> |
| #include <platform/cc13xx_26xx/CC13XX_26XXConfig.h> |
| |
| #include <ti/common/nv/nvintf.h> |
| #include <ti/common/nv/nvocmp.h> |
| |
| namespace chip { |
| namespace DeviceLayer { |
| namespace Internal { |
| |
| // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices. |
| |
| /* itemID and subID are limited to 10 bits, even though their types are uint16_t */ |
| |
| // Keys stored in the Chip-factory namespace |
| |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_SerialNum = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0001 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_MfrDeviceId = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0002 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_MfrDeviceCert = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0003 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_MfrDeviceICACerts = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0004 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_MfrDevicePrivateKey = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0005 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_HardwareVersion = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0006 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_ManufacturingDate = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0007 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_SetupPinCode = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0008 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_SetupDiscriminator = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0009 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_Spake2pIterationCount = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x000a } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_Spake2pSalt = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x000b } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_Spake2pVerifier = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x000c } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_LifeTimeCounter = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipFactory, .subID = 0x0010 } |
| }; |
| |
| // Keys stored in the Chip-counters namespace |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_BootCount = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipCounters, .subID = 0x000d } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_TotalOperationalHours = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipCounters, .subID = 0x000f } |
| }; |
| |
| // Keys stored in the Chip-config namespace |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_ServiceConfig = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x0012 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_PairedAccountId = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x0013 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_ServiceId = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x0014 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_LastUsedEpochKeyId = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x00017 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_FailSafeArmed = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x00018 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_WiFiStationSecType = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x00019 } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_RegulatoryLocation = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x0001a } |
| }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_CountryCode = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x0001b } |
| }; |
| // itemID 0x001c is unused (used to be breadcrumb). |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_UniqueId = { |
| { .systemID = kCC13XX_26XXMatter_SysID, .itemID = kCC13XX_26XXMatter_ItemID_ChipConfig, .subID = 0x0001d } |
| }; |
| |
| /* Internal for the KVS interface. */ |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_KVS_key = { { .systemID = kCC13XX_26XXMatter_SysID, |
| .itemID = kCC13XX_26XXMatter_ItemID_ChipKVS_key } }; |
| const CC13XX_26XXConfig::Key CC13XX_26XXConfig::kConfigKey_KVS_value = { { .systemID = kCC13XX_26XXMatter_SysID, |
| .itemID = kCC13XX_26XXMatter_ItemID_ChipKVS_value } }; |
| |
| /* Static local variables */ |
| static NVINTF_nvFuncts_t sNvoctpFps = { 0 }; |
| |
| CHIP_ERROR CC13XX_26XXConfig::Init() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| /* Load NVOCMP function pointers, extended API */ |
| NVOCMP_loadApiPtrsExt(&sNvoctpFps); |
| |
| /* Initialize NVOCMP */ |
| sNvoctpFps.initNV(NULL); |
| |
| return err; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ReadConfigValue(Key key, bool & val) |
| { |
| CHIP_ERROR ret; |
| size_t ignore; |
| uint8_t localVal; |
| |
| ret = ReadConfigValueBin(key, &localVal, sizeof(localVal), ignore); |
| |
| // reference CC13XX_26XXConfig::WriteConfigValue(Key key, bool val) for storage of boolean values |
| val = (localVal != 0); |
| |
| return ret; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ReadConfigValue(Key key, uint32_t & val) |
| { |
| size_t ignore; |
| |
| return ReadConfigValueBin(key, (uint8_t *) &val, sizeof(val), ignore); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ReadConfigValue(Key key, uint64_t & val) |
| { |
| size_t ignore; |
| |
| return ReadConfigValueBin(key, (uint8_t *) &val, sizeof(val), ignore); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen) |
| { |
| return ReadConfigValueBin(key, (uint8_t *) buf, bufSize, outLen); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| size_t len; |
| |
| len = sNvoctpFps.getItemLen(key.nvID); |
| VerifyOrExit(len > 0, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // key not found |
| VerifyOrExit(len <= bufSize, err = CHIP_ERROR_BUFFER_TOO_SMALL); |
| |
| VerifyOrExit(sNvoctpFps.readItem(key.nvID, 0, (uint16_t) len, buf) == NVINTF_SUCCESS, |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| |
| outLen = len; |
| |
| exit: |
| return err; |
| } |
| |
| static uint8_t FindKVSSubID(const char * key, uint16_t & subID) |
| { |
| char key_scratch[PersistentStorageDelegate::kKeyLengthMax + 1]; |
| NVINTF_nvProxy_t nvProxy = { 0 }; |
| uint8_t status = NVINTF_SUCCESS; |
| // Store first valid sub ID that has already been found in NV to prevent re-scanning the same page |
| uint16_t firstSubID = 0xffff; |
| |
| nvProxy.sysid = CC13XX_26XXConfig::kConfigKey_KVS_key.nvID.systemID; |
| nvProxy.itemid = CC13XX_26XXConfig::kConfigKey_KVS_key.nvID.itemID; |
| nvProxy.buffer = key_scratch; |
| nvProxy.len = sizeof(key_scratch); |
| nvProxy.flag = NVINTF_DOSTART | NVINTF_DOITMID | NVINTF_DOREAD; |
| |
| intptr_t lock_key = sNvoctpFps.lockNV(); |
| do |
| { |
| memset(key_scratch, 0, sizeof(key_scratch)); |
| status = sNvoctpFps.doNext(&nvProxy); |
| if (NVINTF_SUCCESS != status) |
| { |
| break; |
| } |
| if (0 == strcmp(key, (char *) nvProxy.buffer)) |
| { |
| subID = nvProxy.subid; |
| break; |
| } |
| if (firstSubID == 0xFFFF) |
| { |
| firstSubID = nvProxy.subid; |
| } |
| else if (firstSubID == nvProxy.subid) |
| { |
| // Scanned all of NV with no new subID found. |
| status = NVINTF_NOTFOUND; |
| break; |
| } |
| |
| } while (NVINTF_SUCCESS == status); |
| |
| sNvoctpFps.unlockNV(lock_key); |
| return status; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ReadKVS(const char * key, void * value, size_t value_size, size_t * read_bytes_size, |
| size_t offset_bytes) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| NVINTF_itemID_t val_item = CC13XX_26XXConfig::kConfigKey_KVS_value.nvID; |
| uint16_t subID; |
| size_t len; |
| uint16_t read_len; |
| |
| VerifyOrExit(FindKVSSubID(key, subID) == NVINTF_SUCCESS, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); |
| |
| val_item.subID = subID; |
| |
| len = sNvoctpFps.getItemLen(val_item); |
| |
| if (value_size >= (len - offset_bytes)) |
| { |
| // reading to end of element |
| read_len = len - offset_bytes; |
| } |
| else |
| { |
| read_len = value_size; |
| err = CHIP_ERROR_BUFFER_TOO_SMALL; |
| } |
| |
| if (read_len > 0) |
| { |
| VerifyOrExit(sNvoctpFps.readItem(val_item, (uint16_t) offset_bytes, read_len, value) == NVINTF_SUCCESS, |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| } |
| |
| if (read_bytes_size) |
| { |
| *read_bytes_size = read_len; |
| } |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::WriteConfigValue(Key key, bool val) |
| { |
| uint8_t localVal = val ? 1 : 0; |
| return WriteConfigValueBin(key, (const uint8_t *) &localVal, sizeof(localVal)); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::WriteConfigValue(Key key, uint32_t val) |
| { |
| return WriteConfigValueBin(key, (const uint8_t *) &val, sizeof(val)); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::WriteConfigValue(Key key, uint64_t val) |
| { |
| return WriteConfigValueBin(key, (const uint8_t *) &val, sizeof(val)); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::WriteConfigValueStr(Key key, const char * str) |
| { |
| size_t strLen = strlen(str); |
| return WriteConfigValueBin(key, (const uint8_t *) str, strLen); |
| } |
| CHIP_ERROR CC13XX_26XXConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen) |
| { |
| return WriteConfigValueBin(key, (const uint8_t *) str, strLen); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::WriteKVS(const char * key, const void * value, size_t value_size) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| uint16_t subID; |
| |
| NVINTF_itemID_t key_item = CC13XX_26XXConfig::kConfigKey_KVS_key.nvID; |
| NVINTF_itemID_t val_item = CC13XX_26XXConfig::kConfigKey_KVS_value.nvID; |
| |
| if (FindKVSSubID(key, subID) != NVINTF_SUCCESS) |
| { |
| // key item not found, find an empty subID |
| intptr_t lock_key = sNvoctpFps.lockNV(); |
| |
| /* Iterate through the subID range to find an unused subID in the |
| * keyspace. SubID is a 10 bit value, reference |
| * `<simplelink_sdk>/source/ti/common/nv/nvocmp.c:MVOCMP_MAXSUBID`. |
| */ |
| for (uint16_t i = 0; i < 0x3FF; i++) |
| { |
| key_item.subID = i; |
| if (sNvoctpFps.getItemLen(key_item) == 0U) |
| { |
| subID = i; |
| break; |
| } |
| } |
| sNvoctpFps.unlockNV(lock_key); |
| |
| // write they key item |
| VerifyOrExit(sNvoctpFps.writeItem(key_item, (uint16_t) strlen(key), (void *) key) == NVINTF_SUCCESS, |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| } |
| |
| key_item.subID = subID; |
| val_item.subID = subID; |
| |
| if (value_size == 0U) |
| { |
| // delete the value item if it exists |
| int8_t ret = sNvoctpFps.deleteItem(val_item); |
| if (ret != NVINTF_SUCCESS && ret != NVINTF_NOTFOUND) |
| { |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; |
| } |
| } |
| else |
| { |
| if (sNvoctpFps.writeItem(val_item, (uint16_t) value_size, (void *) value) != NVINTF_SUCCESS) |
| { |
| // try to delete the key item |
| sNvoctpFps.deleteItem(key_item); |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; |
| } |
| } |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(sNvoctpFps.writeItem(key.nvID, (uint16_t) dataLen, (void *) data) == NVINTF_SUCCESS, |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ClearKVS(const char * key) |
| { |
| CHIP_ERROR err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND; |
| uint16_t subID; |
| NVINTF_itemID_t key_item = CC13XX_26XXConfig::kConfigKey_KVS_key.nvID; |
| NVINTF_itemID_t val_item = CC13XX_26XXConfig::kConfigKey_KVS_value.nvID; |
| |
| if (FindKVSSubID(key, subID) == NVINTF_SUCCESS) |
| { |
| int8_t ret; |
| |
| key_item.subID = subID; |
| val_item.subID = subID; |
| // delete the value item if it exists |
| ret = sNvoctpFps.deleteItem(val_item); |
| if (ret != NVINTF_SUCCESS && ret != NVINTF_NOTFOUND) |
| { |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; |
| } |
| // delete the key item if it exists |
| ret = sNvoctpFps.deleteItem(key_item); |
| if (ret != NVINTF_SUCCESS && ret != NVINTF_NOTFOUND) |
| { |
| err = CHIP_ERROR_PERSISTED_STORAGE_FAILED; |
| } |
| |
| err = CHIP_NO_ERROR; |
| } |
| |
| return err; |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::ClearConfigValue(Key key) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| VerifyOrExit(sNvoctpFps.deleteItem(key.nvID) == NVINTF_SUCCESS, err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| exit: |
| return err; |
| } |
| |
| bool CC13XX_26XXConfig::ConfigValueExists(Key key) |
| { |
| /* 0 is an invalid length for an item, getting a length of 0 means there is no item */ |
| return (0 != sNvoctpFps.getItemLen(key.nvID)); |
| } |
| |
| CHIP_ERROR CC13XX_26XXConfig::FactoryResetConfig(void) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| NVINTF_nvProxy_t nvProxy = { 0 }; |
| uint8_t status = NVINTF_SUCCESS; |
| |
| // Delete items with the config, counter, kvs_key and kvs_value itemIDs. Items with the factory |
| // itemIDs are not deleted. |
| |
| intptr_t key = sNvoctpFps.lockNV(); |
| |
| /* Setup doNext call */ |
| nvProxy.sysid = kCC13XX_26XXMatter_SysID; |
| nvProxy.itemid = kCC13XX_26XXMatter_ItemID_ChipConfig; |
| nvProxy.flag = NVINTF_DOSTART | NVINTF_DOITMID | NVINTF_DODELETE; |
| |
| /* Lock and wipe all items with config itemid */ |
| do |
| { |
| status = sNvoctpFps.doNext(&nvProxy); |
| } while (NVINTF_SUCCESS == status); |
| /* check we ran out of elements */ |
| VerifyOrExit(status == NVINTF_NOTFOUND, err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| |
| /* Setup doNext call */ |
| nvProxy.sysid = kCC13XX_26XXMatter_SysID; |
| nvProxy.itemid = kCC13XX_26XXMatter_ItemID_ChipCounters; |
| nvProxy.flag = NVINTF_DOSTART | NVINTF_DOITMID | NVINTF_DODELETE; |
| |
| /* Lock and wipe all items with counters itemid */ |
| do |
| { |
| status = sNvoctpFps.doNext(&nvProxy); |
| } while (NVINTF_SUCCESS == status); |
| /* check we ran out of elements */ |
| VerifyOrExit(status == NVINTF_NOTFOUND, err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| |
| /* Setup doNext call */ |
| nvProxy.sysid = kCC13XX_26XXMatter_SysID; |
| nvProxy.itemid = kCC13XX_26XXMatter_ItemID_ChipKVS_key; |
| nvProxy.flag = NVINTF_DOSTART | NVINTF_DOITMID | NVINTF_DODELETE; |
| |
| /* Lock and wipe all items with kvs_key itemid */ |
| do |
| { |
| status = sNvoctpFps.doNext(&nvProxy); |
| } while (NVINTF_SUCCESS == status); |
| /* check we ran out of elements */ |
| VerifyOrExit(status == NVINTF_NOTFOUND, err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| |
| /* Setup doNext call */ |
| nvProxy.sysid = kCC13XX_26XXMatter_SysID; |
| nvProxy.itemid = kCC13XX_26XXMatter_ItemID_ChipKVS_value; |
| nvProxy.flag = NVINTF_DOSTART | NVINTF_DOITMID | NVINTF_DODELETE; |
| |
| /* Lock and wipe all items with key_value itemid */ |
| do |
| { |
| status = sNvoctpFps.doNext(&nvProxy); |
| } while (NVINTF_SUCCESS == status); |
| /* check we ran out of elements */ |
| VerifyOrExit(status == NVINTF_NOTFOUND, err = CHIP_ERROR_PERSISTED_STORAGE_FAILED); |
| |
| exit: |
| sNvoctpFps.unlockNV(key); |
| |
| if (err == CHIP_NO_ERROR) |
| { |
| /* force compaction */ |
| sNvoctpFps.compactNV(0); |
| } |
| return err; |
| } |
| |
| void CC13XX_26XXConfig::RunConfigUnitTest() |
| { |
| // Run common unit test. |
| ::chip::DeviceLayer::Internal::RunConfigUnitTest<CC13XX_26XXConfig>(); |
| } |
| |
| } // namespace Internal |
| } // namespace DeviceLayer |
| } // namespace chip |