Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / EFR32 / EFR32Config.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019 Nest Labs, Inc.
5  *
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
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 /**
20  *    @file
21  *          Utilities for accessing persisted device configuration on
22  *          platforms based on the Silicon Labs SDK.
23  */
24 /* this file behaves like a config.h, comes first */
25 #include <platform/internal/CHIPDeviceLayerInternal.h>
26
27 #include <platform/EFR32/EFR32Config.h>
28
29 #include <core/CHIPEncoding.h>
30 #include <platform/internal/testing/ConfigUnitTest.h>
31
32 #include "FreeRTOS.h"
33 #include "nvm3.h"
34 #include "nvm3_hal_flash.h"
35
36 namespace chip {
37 namespace DeviceLayer {
38 namespace Internal {
39
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.
46
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))
51
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,                                                                                                \
56         sizeof(name##_nvm),                                                                                                        \
57         name##_cache,                                                                                                              \
58         sizeof(name##_cache) / sizeof(nvm3_CacheEntry_t),                                                                          \
59         maxObjectSize,                                                                                                             \
60         repackHeadroom,                                                                                                            \
61         &nvm3_halFlashHandle,                                                                                                      \
62     }
63
64 #define CHIP_NVM3_REPACK_HEADROOM 64 // Threshold for User non-forced nvm3 flash repacking.
65
66 #define EFR32_SEM_TIMEOUT_ms 5
67
68 static nvm3_Handle_t handle;
69 static SemaphoreHandle_t nvm3_Sem;
70 static StaticSemaphore_t nvm3_SemStruct;
71
72 // Declare NVM3 data area and cache.
73
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);
76
77 CHIP_NVM3_DEFINE_SECTION_INIT_DATA(chipNvm3, CHIP_DEVICE_CONFIG_NVM3_MAX_OBJECT_SIZE, CHIP_NVM3_REPACK_HEADROOM);
78
79 CHIP_ERROR EFR32Config::Init()
80 {
81     CHIP_ERROR err;
82
83     nvm3_Sem = xSemaphoreCreateBinaryStatic(&nvm3_SemStruct);
84
85     if (nvm3_Sem == NULL)
86     {
87         return CHIP_ERROR_NO_MEMORY;
88     }
89
90     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
91     SuccessOrExit(err);
92
93 exit:
94     OnExit();
95     return err;
96 }
97
98 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, bool & val)
99 {
100     CHIP_ERROR err;
101     uint32_t objectType;
102     size_t dataLen;
103     bool tmpVal;
104
105     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
106     {
107         err = CHIP_ERROR_TIMEOUT;
108         SuccessOrExit(err);
109     }
110
111     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
112
113     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
114     SuccessOrExit(err);
115
116     // Get nvm3 object info.
117     err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
118     SuccessOrExit(err);
119
120     // Read nvm3 bytes into tmp.
121     err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
122     SuccessOrExit(err);
123     val = tmpVal;
124
125 exit:
126     OnExit();
127     return err;
128 }
129
130 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, uint32_t & val)
131 {
132     CHIP_ERROR err;
133     uint32_t objectType;
134     size_t dataLen;
135     uint32_t tmpVal;
136
137     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
138     {
139         err = CHIP_ERROR_TIMEOUT;
140         SuccessOrExit(err);
141     }
142     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
143
144     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
145     SuccessOrExit(err);
146
147     // Get nvm3 object info.
148     err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
149     SuccessOrExit(err);
150
151     // Read nvm3 bytes into tmp.
152     err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
153     SuccessOrExit(err);
154     val = tmpVal;
155
156 exit:
157     OnExit();
158     return err;
159 }
160
161 CHIP_ERROR EFR32Config::ReadConfigValue(Key key, uint64_t & val)
162 {
163     CHIP_ERROR err;
164     uint32_t objectType;
165     size_t dataLen;
166     uint64_t tmpVal;
167
168     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
169     {
170         err = CHIP_ERROR_TIMEOUT;
171         SuccessOrExit(err);
172     }
173
174     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
175
176     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
177     SuccessOrExit(err);
178
179     // Get nvm3 object info.
180     err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
181     SuccessOrExit(err);
182
183     // Read nvm3 bytes into tmp.
184     err = MapNvm3Error(nvm3_readData(&handle, key, &tmpVal, dataLen));
185     SuccessOrExit(err);
186     val = tmpVal;
187
188 exit:
189     OnExit();
190     return err;
191 }
192
193 CHIP_ERROR EFR32Config::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
194 {
195     CHIP_ERROR err;
196     uint32_t objectType;
197     size_t dataLen;
198
199     outLen = 0;
200
201     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
202     {
203         err = CHIP_ERROR_TIMEOUT;
204         SuccessOrExit(err);
205     }
206
207     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
208
209     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
210     SuccessOrExit(err);
211
212     // Get nvm3 object info.
213     err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
214     SuccessOrExit(err);
215     VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
216
217     if (buf != NULL)
218     {
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
221         // terminator char).
222         VerifyOrExit((bufSize > dataLen), err = CHIP_ERROR_BUFFER_TOO_SMALL);
223
224         err = MapNvm3Error(nvm3_readData(&handle, key, buf, dataLen));
225         SuccessOrExit(err);
226
227         outLen      = ((dataLen == 1) && (buf[0] == 0)) ? 0 : dataLen;
228         buf[outLen] = 0; // Add the terminator char.
229     }
230     else
231     {
232         if (dataLen > 1)
233         {
234             outLen = dataLen;
235         }
236         else
237         {
238             // Read the first byte of the nvm3 string into a tmp var.
239             char firstByte;
240             err = MapNvm3Error(nvm3_readData(&handle, key, &firstByte, 1));
241             SuccessOrExit(err);
242
243             outLen = (firstByte == 0) ? 0 : dataLen;
244         }
245     }
246
247 exit:
248     OnExit();
249     return err;
250 }
251
252 CHIP_ERROR EFR32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
253 {
254     CHIP_ERROR err;
255     uint32_t objectType;
256     size_t dataLen;
257
258     outLen = 0;
259     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
260     {
261         err = CHIP_ERROR_TIMEOUT;
262         SuccessOrExit(err);
263     }
264
265     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
266
267     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
268     SuccessOrExit(err);
269
270     // Get nvm3 object info.
271     err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
272     SuccessOrExit(err);
273     VerifyOrExit(dataLen > 0, err = CHIP_ERROR_INVALID_STRING_LENGTH);
274
275     if (buf != NULL)
276     {
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);
280
281         err = MapNvm3Error(nvm3_readData(&handle, key, buf, dataLen));
282         SuccessOrExit(err);
283     }
284
285     outLen = dataLen;
286
287 exit:
288     OnExit();
289     return err;
290 }
291
292 CHIP_ERROR EFR32Config::ReadConfigValueCounter(uint8_t counterIdx, uint32_t & val)
293 {
294     CHIP_ERROR err;
295     uint32_t tmpVal;
296     Key key = kMinConfigKey_ChipCounter + counterIdx;
297
298     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
299     {
300         err = CHIP_ERROR_TIMEOUT;
301         SuccessOrExit(err);
302     }
303
304     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
305
306     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
307     SuccessOrExit(err);
308
309     // Read bytes into tmp.
310     err = MapNvm3Error(nvm3_readCounter(&handle, key, &tmpVal));
311     SuccessOrExit(err);
312     val = tmpVal;
313
314 exit:
315     OnExit();
316     return err;
317 }
318
319 CHIP_ERROR EFR32Config::WriteConfigValue(Key key, bool val)
320 {
321     CHIP_ERROR err;
322
323     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
324     {
325         err = CHIP_ERROR_TIMEOUT;
326         SuccessOrExit(err);
327     }
328
329     VerifyOrExit(ValidConfigKey(key), err = CHIP_ERROR_INVALID_ARGUMENT); // Verify key id.
330
331     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
332     SuccessOrExit(err);
333
334     err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
335     SuccessOrExit(err);
336
337 exit:
338     OnExit();
339     return err;
340 }
341
342 CHIP_ERROR EFR32Config::WriteConfigValue(Key key, uint32_t val)
343 {
344     CHIP_ERROR err;
345
346     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
347     {
348         err = CHIP_ERROR_TIMEOUT;
349         SuccessOrExit(err);
350     }
351
352     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
353
354     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
355     SuccessOrExit(err);
356
357     err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
358     SuccessOrExit(err);
359
360 exit:
361     OnExit();
362     return err;
363 }
364
365 CHIP_ERROR EFR32Config::WriteConfigValue(Key key, uint64_t val)
366 {
367     CHIP_ERROR err;
368
369     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
370     {
371         err = CHIP_ERROR_TIMEOUT;
372         SuccessOrExit(err);
373     }
374
375     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
376
377     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
378     SuccessOrExit(err);
379
380     err = MapNvm3Error(nvm3_writeData(&handle, key, &val, sizeof(val)));
381     SuccessOrExit(err);
382
383 exit:
384     OnExit();
385     return err;
386 }
387
388 CHIP_ERROR EFR32Config::WriteConfigValueStr(Key key, const char * str)
389 {
390     return WriteConfigValueStr(key, str, (str != NULL) ? strlen(str) : 0);
391 }
392
393 CHIP_ERROR EFR32Config::WriteConfigValueStr(Key key, const char * str, size_t strLen)
394 {
395     CHIP_ERROR err;
396
397     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
398     {
399         err = CHIP_ERROR_TIMEOUT;
400         SuccessOrExit(err);
401     }
402
403     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
404
405     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
406     SuccessOrExit(err);
407
408     if (str != NULL)
409     {
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));
413         SuccessOrExit(err);
414     }
415     else
416     {
417         nvm3_deleteObject(&handle, key); // no error checking here.
418     }
419
420 exit:
421     OnExit();
422     return err;
423 }
424
425 CHIP_ERROR EFR32Config::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
426 {
427     CHIP_ERROR err;
428
429     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
430     {
431         err = CHIP_ERROR_TIMEOUT;
432         SuccessOrExit(err);
433     }
434
435     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
436
437     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
438     SuccessOrExit(err);
439
440     if (data != NULL)
441     {
442         if (dataLen > 0)
443         {
444             // Write the binary data to nvm3.
445             err = MapNvm3Error(nvm3_writeData(&handle, key, data, dataLen));
446             SuccessOrExit(err);
447         }
448     }
449     else
450     {
451         nvm3_deleteObject(&handle, key); // no error checking here.
452     }
453
454 exit:
455     OnExit();
456     return err;
457 }
458
459 CHIP_ERROR EFR32Config::WriteConfigValueCounter(uint8_t counterIdx, uint32_t val)
460 {
461     CHIP_ERROR err;
462     Key key = kMinConfigKey_ChipCounter + counterIdx;
463
464     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
465     {
466         err = CHIP_ERROR_TIMEOUT;
467         SuccessOrExit(err);
468     }
469
470     VerifyOrExit(ValidConfigKey(key), err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND); // Verify key id.
471
472     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
473     SuccessOrExit(err);
474
475     err = MapNvm3Error(nvm3_writeCounter(&handle, key, val));
476     SuccessOrExit(err);
477
478 exit:
479     OnExit();
480     return err;
481 }
482
483 CHIP_ERROR EFR32Config::ClearConfigValue(Key key)
484 {
485     CHIP_ERROR err;
486
487     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
488     {
489         err = CHIP_ERROR_TIMEOUT;
490         SuccessOrExit(err);
491     }
492
493     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
494     SuccessOrExit(err);
495
496     // Delete the nvm3 object with the given key id.
497     err = MapNvm3Error(nvm3_deleteObject(&handle, key));
498     SuccessOrExit(err);
499
500 exit:
501     OnExit();
502     return err;
503 }
504
505 bool EFR32Config::ConfigValueExists(Key key)
506 {
507     CHIP_ERROR err;
508     uint32_t objectType;
509     size_t dataLen;
510
511     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
512     {
513         err = CHIP_ERROR_TIMEOUT;
514         SuccessOrExit(err);
515     }
516
517     err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
518     SuccessOrExit(err);
519
520     // Find object with key id.
521     err = MapNvm3Error(nvm3_getObjectInfo(&handle, key, &objectType, &dataLen));
522
523 exit:
524     OnExit();
525     return (err == CHIP_NO_ERROR);
526 }
527
528 CHIP_ERROR EFR32Config::FactoryResetConfig(void)
529 {
530     // Deletes all nvm3 'Config' type objects.
531     // Note- 'Factory' and 'Counter' type nvm3 objects are NOT deleted.
532
533     CHIP_ERROR err;
534
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 {
538                             CHIP_ERROR err2;
539
540                             err2 = ClearConfigValue(nvm3Key);
541                             SuccessOrExit(err2);
542
543                         exit:
544                             return err2;
545                         });
546
547     // Return success at end of iterations.
548     if (err == CHIP_END_OF_INPUT)
549     {
550         err = CHIP_NO_ERROR;
551     }
552
553     return err;
554 }
555
556 CHIP_ERROR EFR32Config::MapNvm3Error(Ecode_t nvm3Res)
557 {
558     CHIP_ERROR err;
559
560     switch (nvm3Res)
561     {
562     case ECODE_NVM3_OK:
563         err = CHIP_NO_ERROR;
564         break;
565     case ECODE_NVM3_ERR_KEY_NOT_FOUND:
566         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
567         break;
568     default:
569         err = (nvm3Res & 0xFF) + CHIP_DEVICE_CONFIG_EFR32_NVM3_ERROR_MIN;
570         break;
571     }
572
573     return err;
574 }
575
576 CHIP_ERROR EFR32Config::ForEachRecord(Key firstNvm3Key, Key lastNvm3Key, bool addNewRecord, ForEachRecordFunct funct)
577 {
578     // Iterates through the specified range of nvm3 object key ids.
579     // Invokes the callers CB function when appropriate.
580
581     CHIP_ERROR err = CHIP_NO_ERROR;
582     if (pdFALSE == xSemaphoreTake(nvm3_Sem, pdMS_TO_TICKS(EFR32_SEM_TIMEOUT_ms)))
583     {
584         err = CHIP_ERROR_TIMEOUT;
585         SuccessOrExit(err);
586     }
587
588     for (Key nvm3Key = firstNvm3Key; nvm3Key <= lastNvm3Key; ++nvm3Key)
589     {
590         Ecode_t nvm3Res;
591         uint32_t objectType;
592         size_t dataLen;
593
594         // Open nvm3 handle for reading on each iteration.
595         err = MapNvm3Error(nvm3_open(&handle, &chipNvm3));
596         SuccessOrExit(err);
597
598         // Find nvm3 object with current nvm3 iteration key.
599         nvm3Res = nvm3_getObjectInfo(&handle, nvm3Key, &objectType, &dataLen);
600         switch (nvm3Res)
601         {
602         case ECODE_NVM3_OK:
603             if (!addNewRecord)
604             {
605                 // Invoke the caller's function
606                 // (for retrieve,store,delete,enumerate GroupKey operations).
607                 err = funct(nvm3Key, dataLen);
608             }
609             break;
610         case ECODE_NVM3_ERR_KEY_NOT_FOUND:
611             if (addNewRecord)
612             {
613                 // Invoke caller's function
614                 // (for add GroupKey operation).
615                 err = funct(nvm3Key, dataLen);
616             }
617             break;
618         default:
619             err = MapNvm3Error(nvm3Res);
620             break;
621         }
622
623         SuccessOrExit(err);
624     }
625
626 exit:
627     OnExit();
628     return err;
629 }
630
631 bool EFR32Config::ValidConfigKey(Key key)
632 {
633     // Returns true if the key is in the valid CHIP Config nvm3 key range.
634
635     if ((key >= kMinConfigKey_ChipFactory) && (key <= kMaxConfigKey_ChipCounter))
636     {
637         return true;
638     }
639
640     return false;
641 }
642
643 void EFR32Config::RunConfigUnitTest()
644 {
645     // Run common unit test.
646     ::chip::DeviceLayer::Internal::RunConfigUnitTest<EFR32Config>();
647 }
648
649 void EFR32Config::RepackNvm3Flash(void)
650 {
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);
655 }
656
657 void EFR32Config::OnExit()
658 {
659     xSemaphoreGive(nvm3_Sem);
660     nvm3_close(&handle);
661 }
662
663 } // namespace Internal
664 } // namespace DeviceLayer
665 } // namespace chip