4f3596974b44ae78346fb7ad760913bfeb32e4e3
[platform/upstream/connectedhomeip.git] / third_party / openthread / repo / examples / platforms / efr32mg1 / flash.c
1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /**
30  * @file
31  *   This file implements the OpenThread platform abstraction for the non-volatile storage.
32  */
33
34 #include <openthread-core-config.h>
35 #include <openthread/config.h>
36
37 #if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE // Use OT NV system
38
39 #include "em_msc.h"
40 #include <string.h>
41 #include <openthread/instance.h>
42
43 #define FLASH_PAGE_NUM 2
44 #define FLASH_DATA_END_ADDR (FLASH_BASE + FLASH_SIZE)
45 #define FLASH_DATA_START_ADDR (FLASH_DATA_END_ADDR - (FLASH_PAGE_SIZE * FLASH_PAGE_NUM))
46 #define FLASH_SWAP_PAGE_NUM (FLASH_PAGE_NUM / 2)
47 #define FLASH_SWAP_SIZE (FLASH_PAGE_SIZE * FLASH_SWAP_PAGE_NUM)
48
49 static inline uint32_t mapAddress(uint8_t aSwapIndex, uint32_t aOffset)
50 {
51     uint32_t address;
52
53     address = FLASH_DATA_START_ADDR + aOffset;
54
55     if (aSwapIndex)
56     {
57         address += FLASH_SWAP_SIZE;
58     }
59
60     return address;
61 }
62
63 void otPlatFlashInit(otInstance *aInstance)
64 {
65     OT_UNUSED_VARIABLE(aInstance);
66 }
67
68 uint32_t otPlatFlashGetSwapSize(otInstance *aInstance)
69 {
70     OT_UNUSED_VARIABLE(aInstance);
71
72     return FLASH_SWAP_SIZE;
73 }
74
75 void otPlatFlashErase(otInstance *aInstance, uint8_t aSwapIndex)
76 {
77     OT_UNUSED_VARIABLE(aInstance);
78
79     uint32_t address = mapAddress(aSwapIndex, 0);
80
81     for (uint32_t n = 0; n < FLASH_SWAP_PAGE_NUM; n++, address += FLASH_PAGE_SIZE)
82     {
83         MSC_ErasePage((uint32_t *)address);
84     }
85 }
86
87 void otPlatFlashWrite(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
88 {
89     OT_UNUSED_VARIABLE(aInstance);
90
91     MSC_WriteWord((uint32_t *)mapAddress(aSwapIndex, aOffset), aData, aSize);
92 }
93
94 void otPlatFlashRead(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize)
95 {
96     OT_UNUSED_VARIABLE(aInstance);
97
98     memcpy(aData, (const uint8_t *)mapAddress(aSwapIndex, aOffset), aSize);
99 }
100
101 #else // Defaults to Silabs nvm3 system
102
103 #include "nvm3.h"
104 #include "nvm3_default.h"
105 #include <string.h>
106 #include <openthread/platform/settings.h>
107 #include "common/code_utils.hpp"
108 #include "common/logging.hpp"
109
110 #define NVM3KEY_DOMAIN_OPENTHREAD 0x20000U
111 #define NUM_INDEXED_SETTINGS \
112     OPENTHREAD_CONFIG_MLE_MAX_CHILDREN // Indexed key types are only supported for kKeyChildInfo (=='child table').
113 #define ENUM_NVM3_KEY_LIST_SIZE 4      // List size used when enumerating nvm3 keys.
114
115 static otError          addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
116 static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index);
117 static otError          mapNvm3Error(Ecode_t nvm3Res);
118
119 void otPlatSettingsInit(otInstance *aInstance)
120 {
121     OT_UNUSED_VARIABLE(aInstance);
122
123     if (mapNvm3Error(nvm3_open(nvm3_defaultHandle, nvm3_defaultInit)) != OT_ERROR_NONE)
124     {
125         otLogDebgPlat("Error initializing nvm3 instance");
126     }
127 }
128
129 void otPlatSettingsDeinit(otInstance *aInstance)
130 {
131     OT_UNUSED_VARIABLE(aInstance);
132     nvm3_close(nvm3_defaultHandle);
133 }
134
135 otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
136 {
137     // Searches through all matching nvm3 keys to find the one with the required
138     // 'index', then reads the nvm3 data into the destination buffer.
139     // (Repeatedly enumerates a list of matching keys from the nvm3 until the
140     // required index is found).
141
142     OT_UNUSED_VARIABLE(aInstance);
143
144     otError  err;
145     uint16_t valueLength = 0;
146
147     nvm3_ObjectKey_t nvm3Key  = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
148     bool             idxFound = false;
149     int              idx      = 0;
150     err                       = OT_ERROR_NOT_FOUND;
151     while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
152     {
153         // Get the next nvm3 key list.
154         nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
155         size_t           objCnt = nvm3_enumObjects(nvm3_defaultHandle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
156                                          makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
157         for (size_t i = 0; i < objCnt; ++i)
158         {
159             nvm3Key = keys[i];
160             if (idx == aIndex)
161             {
162                 uint32_t objType;
163                 size_t   objLen;
164                 err = mapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objType, &objLen));
165                 if (err == OT_ERROR_NONE)
166                 {
167                     valueLength = objLen;
168
169                     // Only perform read if an input buffer was passed in.
170                     if ((aValue != NULL) && (aValueLength != NULL))
171                     {
172                         // Read all nvm3 obj bytes into a tmp buffer, then copy the required
173                         // number of bytes to the read destination buffer.
174                         uint8_t *buf = malloc(valueLength);
175                         err          = mapNvm3Error(nvm3_readData(nvm3_defaultHandle, nvm3Key, buf, valueLength));
176                         if (err == OT_ERROR_NONE)
177                         {
178                             memcpy(aValue, buf, (valueLength < *aValueLength) ? valueLength : *aValueLength);
179                         }
180                         free(buf);
181                         SuccessOrExit(err);
182                     }
183                 }
184                 idxFound = true;
185                 break;
186             }
187             ++idx;
188         }
189         if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
190         {
191             // Stop searching (there are no more matching nvm3 objects).
192             break;
193         }
194         ++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
195     }
196
197 exit:
198     if (aValueLength != NULL)
199     {
200         *aValueLength = valueLength; // always return actual nvm3 object length.
201     }
202
203     return err;
204 }
205
206 otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
207 {
208     OT_UNUSED_VARIABLE(aInstance);
209
210     otError err;
211
212     // Delete all nvm3 objects matching the input key (i.e. the 'setting indexes' of the key).
213     err = otPlatSettingsDelete(aInstance, aKey, -1);
214     if ((err == OT_ERROR_NONE) || (err == OT_ERROR_NOT_FOUND))
215     {
216         // Add new setting object (i.e. 'index0' of the key).
217         err = addSetting(aKey, aValue, aValueLength);
218         SuccessOrExit(err);
219     }
220
221 exit:
222     return err;
223 }
224
225 otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
226 {
227     OT_UNUSED_VARIABLE(aInstance);
228     return addSetting(aKey, aValue, aValueLength);
229 }
230
231 otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
232 {
233     // Searches through all matching nvm3 keys to find the one with the required
234     // 'index' (or index = -1 to delete all), then deletes the nvm3 object.
235     // (Repeatedly enumerates a list of matching keys from the nvm3 until the
236     // required index is found).
237
238     OT_UNUSED_VARIABLE(aInstance);
239
240     otError          err;
241     nvm3_ObjectKey_t nvm3Key  = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
242     bool             idxFound = false;
243     int              idx      = 0;
244     err                       = OT_ERROR_NOT_FOUND;
245     while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
246     {
247         // Get the next nvm3 key list.
248         nvm3_ObjectKey_t keys[ENUM_NVM3_KEY_LIST_SIZE]; // List holds the next set of nvm3 keys.
249         size_t           objCnt = nvm3_enumObjects(nvm3_defaultHandle, keys, ENUM_NVM3_KEY_LIST_SIZE, nvm3Key,
250                                          makeNvm3ObjKey(aKey, NUM_INDEXED_SETTINGS));
251         for (size_t i = 0; i < objCnt; ++i)
252         {
253             nvm3Key = keys[i];
254             if ((idx == aIndex) || (aIndex == -1))
255             {
256                 uint32_t objType;
257                 size_t   objLen;
258                 err = mapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objType, &objLen));
259                 if (err == OT_ERROR_NONE)
260                 {
261                     // Delete the nvm3 object.
262                     err = mapNvm3Error(nvm3_deleteObject(nvm3_defaultHandle, nvm3Key));
263                     SuccessOrExit(err);
264                 }
265                 if (aIndex != -1)
266                 {
267                     idxFound = true;
268                     break;
269                 }
270             }
271             ++idx;
272         }
273         if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
274         {
275             // Stop searching (there are no more matching nvm3 objects).
276             break;
277         }
278         ++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
279     }
280
281 exit:
282     return err;
283 }
284
285 void otPlatSettingsWipe(otInstance *aInstance)
286 {
287     OT_UNUSED_VARIABLE(aInstance);
288
289     // Delete nvm3 objects for all OT Settings keys (and any of their associated 'indexes').
290     // Note- any OT User nvm3 objects in the OT nvm3 area are NOT be erased.
291     for (uint16_t aKey = 0; aKey < 8; ++aKey)
292     {
293         otPlatSettingsDelete(NULL, aKey, -1);
294     }
295 }
296
297 // Local functions..
298
299 static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
300 {
301     // Helper function- writes input buffer data to a NEW nvm3 object.
302     // nvm3 object is created at the first available Key + index.
303
304     otError err;
305
306     if ((aValueLength == 0) || (aValue == NULL))
307     {
308         err = OT_ERROR_INVALID_ARGS;
309     }
310     else
311     {
312         for (int idx = 0; idx <= NUM_INDEXED_SETTINGS; ++idx)
313         {
314             nvm3_ObjectKey_t nvm3Key;
315             nvm3Key = makeNvm3ObjKey(aKey, idx);
316
317             uint32_t objType;
318             size_t   objLen;
319             err = mapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objType, &objLen));
320             if (err == OT_ERROR_NOT_FOUND)
321             {
322                 // Use this index for the new nvm3 object.
323                 // Write the binary data to nvm3 (Creates nvm3 object if required).
324                 err = mapNvm3Error(nvm3_writeData(nvm3_defaultHandle, nvm3Key, aValue, aValueLength));
325                 break;
326             }
327             else if (err != OT_ERROR_NONE)
328             {
329                 break;
330             }
331         }
332     }
333
334     return err;
335 }
336
337 static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index)
338 {
339     return (NVM3KEY_DOMAIN_OPENTHREAD | (otSettingsKey << 8) | (index & 0xFF));
340 }
341
342 static otError mapNvm3Error(Ecode_t nvm3Res)
343 {
344     otError err;
345
346     switch (nvm3Res)
347     {
348     case ECODE_NVM3_OK:
349         err = OT_ERROR_NONE;
350         break;
351
352     case ECODE_NVM3_ERR_KEY_NOT_FOUND:
353         err = OT_ERROR_NOT_FOUND;
354         break;
355
356     default:
357         err = OT_ERROR_FAILED;
358         break;
359     }
360
361     return err;
362 }
363
364 #endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE