3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2019 Nest Labs, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * Utilities for accessing persisted device configuration on
22 * platforms based on the Silicon Labs SDK.
24 /* this file behaves like a config.h, comes first */
25 #include <platform/internal/CHIPDeviceLayerInternal.h>
27 #include <platform/EFR32/EFR32Config.h>
29 #include <core/CHIPEncoding.h>
30 #include <platform/internal/testing/ConfigUnitTest.h>
34 #include "nvm3_hal_flash.h"
37 namespace DeviceLayer {
40 // Two macros are provided to support the creation of the Silicon Labs NVM3 area and
41 // initialization data- NVM3_DEFINE_SECTION_STATIC_DATA() and NVM3_DEFINE_SECTION_INIT_DATA().
42 // A linker section called 'name'_section is defined by NVM3_DEFINE_SECTION_STATIC_DATA().
43 // The NVM3 area is placed at the top of the device FLASH section by the linker
44 // script file: chip-efr32-bringup-MG12P.ld. An error is returned
45 // by nvm3_open() on alignment or size violation.
47 // Local version of SDK macro (avoids uninitialized var compile error).
48 #define CHIP_NVM3_DEFINE_SECTION_STATIC_DATA(name, nvmSize, cacheSize) \
49 static nvm3_CacheEntry_t name##_cache[cacheSize]; \
50 static uint8_t name##_nvm[nvmSize] SL_ATTRIBUTE_SECTION(STRINGIZE(name##_section))
52 // Local version of SDK macro (allows CHIP to configure the maximum nvm3 object size and headroom).
53 #define CHIP_NVM3_DEFINE_SECTION_INIT_DATA(name, maxObjectSize, repackHeadroom) \
54 static nvm3_Init_t name = { \
55 (nvm3_HalPtr_t) name##_nvm, \
58 sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t), \
61 &nvm3_halFlashHandle, \
64 #define CHIP_NVM3_REPACK_HEADROOM 64 // Threshold for User non-forced nvm3 flash repacking.
66 #define EFR32_SEM_TIMEOUT_ms 5
68 static nvm3_Handle_t handle;
69 static SemaphoreHandle_t nvm3_Sem;
70 static StaticSemaphore_t nvm3_SemStruct;
72 // Declare NVM3 data area and cache.
74 CHIP_NVM3_DEFINE_SECTION_STATIC_DATA(chipNvm3, CHIP_DEVICE_CONFIG_NVM3_NUM_FLASH_PAGES_FOR_STORAGE * FLASH_PAGE_SIZE,
75 CHIP_DEVICE_CONFIG_NVM3_MAX_NUM_OBJECTS);
77 CHIP_NVM3_DEFINE_SECTION_INIT_DATA(chipNvm3, CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE, CHIP_NVM3_REPACK_HEADROOM);
79 CHIP_ERROR EFR32Config::Init()
83 nvm3_Sem = xSemaphoreCreateBinaryStatic(&nvm3_SemStruct);
87 return CHIP_ERROR_NO_MEMORY;
90 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
98 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, bool & val)
105 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
107 err = CHIP_ERROR_TIMEOUT;
111 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
113 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
116 // Get nvm3 object info.
117 err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
120 // Read nvm3 bytes into tmp.
121 err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
130 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, uint32_t & val)
137 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
139 err = CHIP_ERROR_TIMEOUT;
142 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
144 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
147 // Get nvm3 object info.
148 err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
151 // Read nvm3 bytes into tmp.
152 err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
161 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, uint64_t & val)
168 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
170 err = CHIP_ERROR_TIMEOUT;
174 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
176 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
179 // Get nvm3 object info.
180 err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
183 // Read nvm3 bytes into tmp.
184 err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
193 CHIP_ERROR EFR32Config::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
201 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
203 err = CHIP_ERROR_TIMEOUT;
207 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
209 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
212 // Get nvm3 object info.
213 err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
215 VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
219 // Read nvm3 bytes directly into the output buffer- check buffer is
220 // long enough to take the string (nvm3 string does not include the
222 VerifyOrExit((bufSize > dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);
224 err = MapNvm3Error(nvm3_readData(&handle, key, buf, dataLen));
227 outLen = ((dataLen == 1) && (buf[0] == 0)) ? 0 : dataLen;
228 buf[outLen] = 0; // Add the terminator char.
238 // Read the first byte of the nvm3 string into a tmp var.
240 err = MapNvm3Error(nvm3_readData(&handle, key, &firstByte, 1));
243 outLen = (firstByte == 0) ? 0 : dataLen;
252 CHIP_ERROR EFR32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
259 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
261 err = CHIP_ERROR_TIMEOUT;
265 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
267 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
270 // Get nvm3 object info.
271 err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
273 VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
277 // Read nvm3 bytes directly into output buffer- check buffer is long
278 // enough to take the data.
279 VerifyOrExit((bufSize >= dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);
281 err = MapNvm3Error(nvm3_readData(&handle, key, buf, dataLen));
292 CHIP_ERROR EFR32Config::ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val)
296 Key key = kMinConfigKey_ChipCounter + counterIdx;
298 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
300 err = CHIP_ERROR_TIMEOUT;
304 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
306 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
309 // Read bytes into tmp.
310 err = MapNvm3Error(nvm3_readCounter(&handle, key, &tmpVal));
319 CHIP_ERROR EFR32Config::WriteConfigValue(Key key, bool val)
323 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
325 err = CHIP_ERROR_TIMEOUT;
329 VerifyOrExit(ValidConfigKey(key), err = CHIP_ERROR_INVALID_ARGUMENT); // Verify key id.
331 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
334 err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
342 CHIP_ERROR EFR32Config::WriteConfigValue(Key key, uint32_t val)
346 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
348 err = CHIP_ERROR_TIMEOUT;
352 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
354 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
357 err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
365 CHIP_ERROR EFR32Config::WriteConfigValue(Key key, uint64_t val)
369 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
371 err = CHIP_ERROR_TIMEOUT;
375 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
377 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
380 err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
388 CHIP_ERROR EFR32Config::WriteConfigValueStr(Key key, const char * str)
390 return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0);
393 CHIP_ERROR EFR32Config::WriteConfigValueStr(Key key, const char * str, size_t strLen)
397 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
399 err = CHIP_ERROR_TIMEOUT;
403 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
405 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
410 // Write the string to nvm3 without the terminator char (apart from
411 // empty strings where only the terminator char is stored in nvm3).
412 err = MapNvm3Error(nvm3_writeData(&handle, key, str, (strLen > 0) ? strLen : 1));
417 nvm3_deleteObject(&handle, key); // no error checking here.
425 CHIP_ERROR EFR32Config::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
429 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
431 err = CHIP_ERROR_TIMEOUT;
435 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
437 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
444 // Write the binary data to nvm3.
445 err = MapNvm3Error(nvm3_writeData(&handle, key, data, dataLen));
451 nvm3_deleteObject(&handle, key); // no error checking here.
459 CHIP_ERROR EFR32Config::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val)
462 Key key = kMinConfigKey_ChipCounter + counterIdx;
464 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
466 err = CHIP_ERROR_TIMEOUT;
470 VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
472 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
475 err = MapNvm3Error(nvm3_writeCounter(&handle, key, val));
483 CHIP_ERROR EFR32Config::ClearConfigValue(Key key)
487 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
489 err = CHIP_ERROR_TIMEOUT;
493 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
496 // Delete the nvm3 object with the given key id.
497 err = MapNvm3Error(nvm3_deleteObject(&handle, key));
505 bool EFR32Config::ConfigValueExists(Key key)
511 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
513 err = CHIP_ERROR_TIMEOUT;
517 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
520 // Find object with key id.
521 err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
525 return (err == CHIP_NO_ERROR);
528 CHIP_ERROR EFR32Config::FactoryResetConfig(void)
530 // Deletes all nvm3 'Config' type objects.
531 // Note- 'Factory' and 'Counter' type nvm3 objects are NOT deleted.
535 // Iterate over all the CHIP Config nvm3 records and delete each one...
536 err = ForEachRecord(kMinConfigKey_ChipConfig, kMaxConfigKey_ChipConfig, false,
537 [](const Key & nvm3Key, const size_t & length) -> CHIP_ERROR {
540 err2 = ClearConfigValue(nvm3Key);
547 // Return success at end of iterations.
548 if (err == CHIP_END_OF_INPUT)
556 CHIP_ERROR EFR32Config::MapNvm3Error(Ecode_t nvm3Res)
565 case ECODE_NVM3_ERR_KEY_NOT_FOUND:
566 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
569 err = (nvm3Res & 0xFF) + CHIP_DEVICE_CONFIG_EFR32_NVM3_ERROR_MIN;
576 CHIP_ERROR EFR32Config::ForEachRecord(Key firstNvm3Key, Key lastNvm3Key, bool addNewRecord, ForEachRecordFunct funct)
578 // Iterates through the specified range of nvm3 object key ids.
579 // Invokes the callers CB function when appropriate.
581 CHIP_ERROR err = CHIP_NO_ERROR;
582 if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
584 err = CHIP_ERROR_TIMEOUT;
588 for (Key nvm3Key = firstNvm3Key; nvm3Key <= lastNvm3Key; ++nvm3Key)
594 // Open nvm3 handle for reading on each iteration.
595 err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
598 // Find nvm3 object with current nvm3 iteration key.
599 nvm3Res = nvm3_getObjectInfo(&handle, nvm3Key, &objectType, &dataLen);
605 // Invoke the caller's function
606 // (for retrieve,store,delete,enumerate GroupKey operations).
607 err = funct(nvm3Key, dataLen);
610 case ECODE_NVM3_ERR_KEY_NOT_FOUND:
613 // Invoke caller's function
614 // (for add GroupKey operation).
615 err = funct(nvm3Key, dataLen);
619 err = MapNvm3Error(nvm3Res);
631 bool EFR32Config::ValidConfigKey(Key key)
633 // Returns true if the key is in the valid CHIP Config nvm3 key range.
635 if ((key >= kMinConfigKey_ChipFactory) && (key <= kMaxConfigKey_ChipCounter))
643 void EFR32Config::RunConfigUnitTest()
645 // Run common unit test.
646 ::chip::DeviceLayer::Internal::RunConfigUnitTest<EFR32Config>();
649 void EFR32Config::RepackNvm3Flash(void)
651 // Repack nvm3 flash if nvm3 space < headroom threshold.
652 // Note- checking periodically during idle periods should prevent
653 // forced repack events on any write operation.
654 nvm3_repack(&handle);
657 void EFR32Config::OnExit()
659 xSemaphoreGive(nvm3_Sem);
663 } // namespace Internal
664 } // namespace DeviceLayer