2 * Copyright (c) 2020, The OpenThread Authors.
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.
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.
31 * This file implements the OpenThread platform abstraction for the non-volatile storage.
34 #include <openthread-core-config.h>
35 #include <openthread/config.h>
37 #if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE // Use OT NV system
41 #include <openthread/instance.h>
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)
49 static inline uint32_t mapAddress(uint8_t aSwapIndex, uint32_t aOffset)
53 address = FLASH_DATA_START_ADDR + aOffset;
57 address += FLASH_SWAP_SIZE;
63 void otPlatFlashInit(otInstance *aInstance)
65 OT_UNUSED_VARIABLE(aInstance);
68 uint32_t otPlatFlashGetSwapSize(otInstance *aInstance)
70 OT_UNUSED_VARIABLE(aInstance);
72 return FLASH_SWAP_SIZE;
75 void otPlatFlashErase(otInstance *aInstance, uint8_t aSwapIndex)
77 OT_UNUSED_VARIABLE(aInstance);
79 uint32_t address = mapAddress(aSwapIndex, 0);
81 for (uint32_t n = 0; n < FLASH_SWAP_PAGE_NUM; n++, address += FLASH_PAGE_SIZE)
83 MSC_ErasePage((uint32_t *)address);
87 void otPlatFlashWrite(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, const void *aData, uint32_t aSize)
89 OT_UNUSED_VARIABLE(aInstance);
91 MSC_WriteWord((uint32_t *)mapAddress(aSwapIndex, aOffset), aData, aSize);
94 void otPlatFlashRead(otInstance *aInstance, uint8_t aSwapIndex, uint32_t aOffset, void *aData, uint32_t aSize)
96 OT_UNUSED_VARIABLE(aInstance);
98 memcpy(aData, (const uint8_t *)mapAddress(aSwapIndex, aOffset), aSize);
101 #else // Defaults to Silabs nvm3 system
104 #include "nvm3_default.h"
106 #include <openthread/platform/settings.h>
107 #include "common/code_utils.hpp"
108 #include "common/logging.hpp"
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.
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);
119 void otPlatSettingsInit(otInstance *aInstance)
121 OT_UNUSED_VARIABLE(aInstance);
123 if (mapNvm3Error(nvm3_open(nvm3_defaultHandle, nvm3_defaultInit)) != OT_ERROR_NONE)
125 otLogDebgPlat("Error initializing nvm3 instance");
129 void otPlatSettingsDeinit(otInstance *aInstance)
131 OT_UNUSED_VARIABLE(aInstance);
132 nvm3_close(nvm3_defaultHandle);
135 otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
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).
142 OT_UNUSED_VARIABLE(aInstance);
145 uint16_t valueLength = 0;
147 nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
148 bool idxFound = false;
150 err = OT_ERROR_NOT_FOUND;
151 while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
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)
164 err = mapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objType, &objLen));
165 if (err == OT_ERROR_NONE)
167 valueLength = objLen;
169 // Only perform read if an input buffer was passed in.
170 if ((aValue != NULL) && (aValueLength != NULL))
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)
178 memcpy(aValue, buf, (valueLength < *aValueLength) ? valueLength : *aValueLength);
189 if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
191 // Stop searching (there are no more matching nvm3 objects).
194 ++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
198 if (aValueLength != NULL)
200 *aValueLength = valueLength; // always return actual nvm3 object length.
206 otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
208 OT_UNUSED_VARIABLE(aInstance);
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))
216 // Add new setting object (i.e. 'index0' of the key).
217 err = addSetting(aKey, aValue, aValueLength);
225 otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
227 OT_UNUSED_VARIABLE(aInstance);
228 return addSetting(aKey, aValue, aValueLength);
231 otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
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).
238 OT_UNUSED_VARIABLE(aInstance);
241 nvm3_ObjectKey_t nvm3Key = makeNvm3ObjKey(aKey, 0); // The base nvm3 key value.
242 bool idxFound = false;
244 err = OT_ERROR_NOT_FOUND;
245 while ((idx <= NUM_INDEXED_SETTINGS) && (!idxFound))
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)
254 if ((idx == aIndex) || (aIndex == -1))
258 err = mapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objType, &objLen));
259 if (err == OT_ERROR_NONE)
261 // Delete the nvm3 object.
262 err = mapNvm3Error(nvm3_deleteObject(nvm3_defaultHandle, nvm3Key));
273 if (objCnt < ENUM_NVM3_KEY_LIST_SIZE)
275 // Stop searching (there are no more matching nvm3 objects).
278 ++nvm3Key; // Inc starting value for next nvm3 key list enumeration.
285 void otPlatSettingsWipe(otInstance *aInstance)
287 OT_UNUSED_VARIABLE(aInstance);
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)
293 otPlatSettingsDelete(NULL, aKey, -1);
299 static otError addSetting(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
301 // Helper function- writes input buffer data to a NEW nvm3 object.
302 // nvm3 object is created at the first available Key + index.
306 if ((aValueLength == 0) || (aValue == NULL))
308 err = OT_ERROR_INVALID_ARGS;
312 for (int idx = 0; idx <= NUM_INDEXED_SETTINGS; ++idx)
314 nvm3_ObjectKey_t nvm3Key;
315 nvm3Key = makeNvm3ObjKey(aKey, idx);
319 err = mapNvm3Error(nvm3_getObjectInfo(nvm3_defaultHandle, nvm3Key, &objType, &objLen));
320 if (err == OT_ERROR_NOT_FOUND)
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));
327 else if (err != OT_ERROR_NONE)
337 static nvm3_ObjectKey_t makeNvm3ObjKey(uint16_t otSettingsKey, int index)
339 return (NVM3KEY_DOMAIN_OPENTHREAD | (otSettingsKey << 8) | (index & 0xFF));
342 static otError mapNvm3Error(Ecode_t nvm3Res)
352 case ECODE_NVM3_ERR_KEY_NOT_FOUND:
353 err = OT_ERROR_NOT_FOUND;
357 err = OT_ERROR_FAILED;
364 #endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE