mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[posix-app] simplify saving settings (#3108)
This commit is contained in:
@@ -183,7 +183,6 @@ LOCAL_SRC_FILES := \
|
||||
src/posix/platform/random.c \
|
||||
src/posix/platform/system.c \
|
||||
src/posix/platform/uart.c \
|
||||
src/posix/platform/flash.c \
|
||||
src/posix/platform/spi-stubs.c \
|
||||
src/posix/platform/frame_queue.cpp \
|
||||
src/posix/platform/radio_spinel.cpp \
|
||||
|
||||
@@ -41,7 +41,6 @@ libopenthread_posix_a_CPPFLAGS = \
|
||||
|
||||
libopenthread_posix_a_SOURCES = \
|
||||
alarm.c \
|
||||
flash.c \
|
||||
frame_queue.cpp \
|
||||
logging.c \
|
||||
misc.c \
|
||||
@@ -67,7 +66,6 @@ inc_%: ../../ncp/%
|
||||
echo '#include "$<"' > $@
|
||||
|
||||
noinst_HEADERS = \
|
||||
flash.h \
|
||||
frame_queue.hpp \
|
||||
openthread-system.h \
|
||||
platform-posix.h \
|
||||
@@ -83,7 +81,7 @@ if OPENTHREAD_BUILD_COVERAGE
|
||||
CLEANFILES = $(wildcard *.gcda *.gcno)
|
||||
endif # OPENTHREAD_BUILD_COVERAGE
|
||||
|
||||
check_PROGRAMS = test-frame-queue
|
||||
check_PROGRAMS = test-frame-queue test-settings
|
||||
|
||||
test_frame_queue_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
@@ -95,8 +93,19 @@ test_frame_queue_SOURCES = \
|
||||
frame_queue.cpp \
|
||||
$(NULL)
|
||||
|
||||
test_settings_CPPFLAGS = \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/src/core \
|
||||
-DSELF_TEST \
|
||||
$(NULL)
|
||||
|
||||
test_settings_SOURCES = \
|
||||
settings.cpp \
|
||||
$(NULL)
|
||||
|
||||
TESTS = \
|
||||
test-frame-queue \
|
||||
test-settings \
|
||||
$(NULL)
|
||||
|
||||
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform-posix.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include "code_utils.h"
|
||||
#include "flash.h"
|
||||
|
||||
static int sFlashFd = -1;
|
||||
uint32_t sEraseAddress;
|
||||
|
||||
enum
|
||||
{
|
||||
FLASH_SIZE = 0x40000,
|
||||
FLASH_PAGE_SIZE = 0x800,
|
||||
FLASH_PAGE_NUM = 128,
|
||||
};
|
||||
|
||||
otError utilsFlashInit(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
const char *path = OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH;
|
||||
char fileName[sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32];
|
||||
struct stat st;
|
||||
bool create = false;
|
||||
const char *offset = getenv("PORT_OFFSET");
|
||||
uint16_t index = 0;
|
||||
|
||||
memset(&st, 0, sizeof(st));
|
||||
|
||||
if (stat(path, &st) == -1)
|
||||
{
|
||||
mkdir(path, 0777);
|
||||
}
|
||||
|
||||
if (offset == NULL)
|
||||
{
|
||||
offset = "0";
|
||||
}
|
||||
|
||||
snprintf(fileName, sizeof(fileName), "%s/%s_%" PRIx64 ".flash", path, offset, gNodeId);
|
||||
|
||||
if (access(fileName, 0))
|
||||
{
|
||||
create = true;
|
||||
}
|
||||
|
||||
sFlashFd = open(fileName, O_RDWR | O_CREAT, 0600);
|
||||
lseek(sFlashFd, 0, SEEK_SET);
|
||||
|
||||
otEXPECT_ACTION(sFlashFd >= 0, error = OT_ERROR_FAILED);
|
||||
|
||||
if (create)
|
||||
{
|
||||
for (index = 0; index < FLASH_PAGE_NUM; index++)
|
||||
{
|
||||
error = utilsFlashErasePage(index * FLASH_PAGE_SIZE);
|
||||
otEXPECT(error == OT_ERROR_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint32_t utilsFlashGetSize(void)
|
||||
{
|
||||
return FLASH_SIZE;
|
||||
}
|
||||
|
||||
otError utilsFlashErasePage(uint32_t aAddress)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint32_t address;
|
||||
uint8_t dummyPage[FLASH_SIZE];
|
||||
|
||||
otEXPECT_ACTION(sFlashFd >= 0, error = OT_ERROR_FAILED);
|
||||
otEXPECT_ACTION(aAddress < FLASH_SIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
// Get start address of the flash page that includes aAddress
|
||||
address = aAddress & (~(uint32_t)(FLASH_PAGE_SIZE - 1));
|
||||
|
||||
// set the page to the erased state.
|
||||
memset((void *)(&dummyPage[0]), 0xff, FLASH_PAGE_SIZE);
|
||||
|
||||
// Write the page
|
||||
ssize_t r;
|
||||
r = pwrite(sFlashFd, &(dummyPage[0]), FLASH_PAGE_SIZE, (off_t)address);
|
||||
otEXPECT_ACTION(((int)r) == ((int)(FLASH_PAGE_SIZE)), error = OT_ERROR_FAILED);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError utilsFlashStatusWait(uint32_t aTimeout)
|
||||
{
|
||||
(void)aTimeout;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint32_t utilsFlashWrite(uint32_t aAddress, uint8_t *aData, uint32_t aSize)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint32_t index = 0;
|
||||
uint8_t byte;
|
||||
|
||||
otEXPECT(sFlashFd >= 0 && aAddress < FLASH_SIZE);
|
||||
|
||||
for (index = 0; index < aSize; index++)
|
||||
{
|
||||
otEXPECT((ret = utilsFlashRead(aAddress + index, &byte, 1)) == 1);
|
||||
// Use bitwise AND to emulate the behavior of flash memory
|
||||
byte &= aData[index];
|
||||
otEXPECT((ret = (uint32_t)pwrite(sFlashFd, &byte, 1, (off_t)(aAddress + index))) == 1);
|
||||
}
|
||||
|
||||
exit:
|
||||
return index;
|
||||
}
|
||||
|
||||
uint32_t utilsFlashRead(uint32_t aAddress, uint8_t *aData, uint32_t aSize)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
otEXPECT(sFlashFd >= 0 && aAddress < FLASH_SIZE);
|
||||
ret = (uint32_t)pread(sFlashFd, aData, aSize, (off_t)aAddress);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file defines the flash interface used by settings.cpp.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_FLASH_H
|
||||
#define UTILS_FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Perform any initialization for flash driver.
|
||||
*
|
||||
* @retval ::OT_ERROR_NONE Initialize flash driver success.
|
||||
* @retval ::OT_ERROR_FAILED Initialize flash driver fail.
|
||||
*/
|
||||
otError utilsFlashInit(void);
|
||||
|
||||
/**
|
||||
* Get the size of flash that can be read/write by the caller.
|
||||
* The usable flash size is always the multiple of flash page size.
|
||||
*
|
||||
* @returns The size of the flash.
|
||||
*/
|
||||
uint32_t utilsFlashGetSize(void);
|
||||
|
||||
/**
|
||||
* Erase one flash page that include the input address.
|
||||
* This is a non-blocking function. It can work with utilsFlashStatusWait to check when erase is done.
|
||||
*
|
||||
* The flash address starts from 0, and this function maps the input address to the physical address of flash for
|
||||
* erasing. 0 is always mapped to the beginning of one flash page. The input address should never be mapped to the
|
||||
* firmware space or any other protected flash space.
|
||||
*
|
||||
* @param[in] aAddress The start address of the flash to erase.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Erase flash operation is started.
|
||||
* @retval OT_ERROR_FAILED Erase flash operation is not started.
|
||||
* @retval OT_ERROR_INVALID_ARGS aAddress is out of range of flash or not aligned.
|
||||
*/
|
||||
otError utilsFlashErasePage(uint32_t aAddress);
|
||||
|
||||
/**
|
||||
* Check whether flash is ready or busy.
|
||||
*
|
||||
* @param[in] aTimeout The interval in milliseconds waiting for the flash operation to be done and become ready again.
|
||||
* zero indicates that it is a polling function, and returns current status of flash immediately.
|
||||
* non-zero indicates that it is blocking there until the operation is done and become ready, or
|
||||
* timeout expires.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Flash is ready for any operation.
|
||||
* @retval OT_ERROR_BUSY Flash is busy.
|
||||
*/
|
||||
otError utilsFlashStatusWait(uint32_t aTimeout);
|
||||
|
||||
/**
|
||||
* Write flash. The write operation only clears bits, but never set bits.
|
||||
*
|
||||
* The flash address starts from 0, and this function maps the input address to the physical address of flash for
|
||||
* writing. 0 is always mapped to the beginning of one flash page. The input address should never be mapped to the
|
||||
* firmware space or any other protected flash space.
|
||||
*
|
||||
* @param[in] aAddress The start address of the flash to write.
|
||||
* @param[in] aData The pointer of the data to write.
|
||||
* @param[in] aSize The size of the data to write.
|
||||
*
|
||||
* @returns The actual size of octets write to flash.
|
||||
* It is expected the same as aSize, and may be less than aSize.
|
||||
* 0 indicates that something wrong happens when writing.
|
||||
*/
|
||||
uint32_t utilsFlashWrite(uint32_t aAddress, uint8_t *aData, uint32_t aSize);
|
||||
|
||||
/**
|
||||
* Read flash.
|
||||
*
|
||||
* The flash address starts from 0, and this function maps the input address to the physical address of flash for
|
||||
* reading. 0 is always mapped to the beginning of one flash page. The input address should never be mapped to the
|
||||
* firmware space or any other protected flash space.
|
||||
*
|
||||
* @param[in] aAddress The start address of the flash to read.
|
||||
* @param[Out] aData The pointer of buffer for reading.
|
||||
* @param[in] aSize The size of the data to read.
|
||||
*
|
||||
* @returns The actual size of octets read to buffer.
|
||||
* It is expected the same as aSize, and may be less than aSize.
|
||||
* 0 indicates that something wrong happens when reading.
|
||||
*/
|
||||
uint32_t utilsFlashRead(uint32_t aAddress, uint8_t *aData, uint32_t aSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // UTILS_FLASH_H
|
||||
@@ -240,4 +240,4 @@ int main(void)
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif // SELF_TEST
|
||||
|
||||
+336
-313
@@ -32,418 +32,301 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "platform-posix.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "utils/wrap_string.h"
|
||||
|
||||
#include <openthread-core-config.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <openthread/platform/misc.h>
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
#include <code_utils.h>
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#include "flash.h"
|
||||
#define VerifyOrDie(aCondition) \
|
||||
do \
|
||||
{ \
|
||||
if (!(aCondition)) \
|
||||
{ \
|
||||
perror(__func__); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
static const size_t kMaxFileNameSize = sizeof(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH) + 32;
|
||||
|
||||
enum
|
||||
static int sSettingsFd = -1;
|
||||
|
||||
static void getSettingsFileName(char aFileName[kMaxFileNameSize], bool aSwap)
|
||||
{
|
||||
kBlockAddBeginFlag = 0x1,
|
||||
kBlockAddCompleteFlag = 0x02,
|
||||
kBlockDeleteFlag = 0x04,
|
||||
kBlockIndex0Flag = 0x08,
|
||||
};
|
||||
const char *offset = getenv("PORT_OFFSET");
|
||||
|
||||
enum
|
||||
snprintf(aFileName, kMaxFileNameSize, OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH "/%s_%" PRIx64 ".%s",
|
||||
offset == NULL ? "0" : offset, gNodeId, (aSwap ? "swap" : "data"));
|
||||
}
|
||||
|
||||
static int swapOpen(void)
|
||||
{
|
||||
kSettingsFlagSize = 4,
|
||||
kSettingsBlockDataSize = 255,
|
||||
char fileName[kMaxFileNameSize];
|
||||
int fd;
|
||||
|
||||
kSettingsInSwap = 0xbe5cc5ef,
|
||||
kSettingsInUse = 0xbe5cc5ee,
|
||||
kSettingsNotUse = 0xbe5cc5ec,
|
||||
};
|
||||
getSettingsFileName(fileName, true);
|
||||
fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
VerifyOrDie(fd != -1);
|
||||
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct settingsBlock
|
||||
{
|
||||
uint16_t key;
|
||||
uint16_t flag;
|
||||
uint16_t length;
|
||||
uint16_t reserved;
|
||||
} OT_TOOL_PACKED_END;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @def SETTINGS_CONFIG_BASE_ADDRESS
|
||||
* This function reads @p aLength bytes from the data file and appends to the swap file.
|
||||
*
|
||||
* The base address of settings.
|
||||
* @param[in] aFd The file descriptor of the current swap file.
|
||||
* @param[in] aLength Number of bytes to copy.
|
||||
*
|
||||
*/
|
||||
#ifndef SETTINGS_CONFIG_BASE_ADDRESS
|
||||
#define SETTINGS_CONFIG_BASE_ADDRESS 0x39000
|
||||
#endif // SETTINGS_CONFIG_BASE_ADDRESS
|
||||
|
||||
/**
|
||||
* @def SETTINGS_CONFIG_PAGE_SIZE
|
||||
*
|
||||
* The page size of settings.
|
||||
*
|
||||
*/
|
||||
#ifndef SETTINGS_CONFIG_PAGE_SIZE
|
||||
#define SETTINGS_CONFIG_PAGE_SIZE 0x800
|
||||
#endif // SETTINGS_CONFIG_PAGE_SIZE
|
||||
|
||||
/**
|
||||
* @def SETTINGS_CONFIG_PAGE_NUM
|
||||
*
|
||||
* The page number of settings.
|
||||
*
|
||||
*/
|
||||
#ifndef SETTINGS_CONFIG_PAGE_NUM
|
||||
#define SETTINGS_CONFIG_PAGE_NUM 2
|
||||
#endif // SETTINGS_CONFIG_PAGE_NUM
|
||||
|
||||
static uint32_t sSettingsBaseAddress;
|
||||
static uint32_t sSettingsUsedSize;
|
||||
|
||||
static uint16_t getAlignLength(uint16_t length)
|
||||
static void swapWrite(int aFd, uint16_t aLength)
|
||||
{
|
||||
return (length + 3) & 0xfffc;
|
||||
}
|
||||
const size_t kBlockSize = 512;
|
||||
uint8_t buffer[kBlockSize];
|
||||
|
||||
static void setSettingsFlag(uint32_t aBase, uint32_t aFlag)
|
||||
{
|
||||
utilsFlashWrite(aBase, reinterpret_cast<uint8_t *>(&aFlag), sizeof(aFlag));
|
||||
}
|
||||
|
||||
static void initSettings(uint32_t aBase, uint32_t aFlag)
|
||||
{
|
||||
uint32_t address = aBase;
|
||||
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_NUM > 1 ? SETTINGS_CONFIG_PAGE_SIZE * SETTINGS_CONFIG_PAGE_NUM / 2
|
||||
: SETTINGS_CONFIG_PAGE_SIZE;
|
||||
|
||||
while (address < (aBase + settingsSize))
|
||||
while (aLength > 0)
|
||||
{
|
||||
utilsFlashErasePage(address);
|
||||
utilsFlashStatusWait(1000);
|
||||
address += SETTINGS_CONFIG_PAGE_SIZE;
|
||||
uint16_t count = aLength >= sizeof(buffer) ? sizeof(buffer) : aLength;
|
||||
ssize_t rval = read(sSettingsFd, buffer, count);
|
||||
|
||||
VerifyOrDie(rval > 0);
|
||||
count = static_cast<uint16_t>(rval);
|
||||
rval = write(aFd, buffer, count);
|
||||
assert(rval == count);
|
||||
VerifyOrDie(rval == count);
|
||||
aLength -= count;
|
||||
}
|
||||
|
||||
setSettingsFlag(aBase, aFlag);
|
||||
}
|
||||
|
||||
static uint32_t swapSettingsBlock(otInstance *aInstance)
|
||||
static void swapPersist(int aFd)
|
||||
{
|
||||
uint32_t oldBase = sSettingsBaseAddress;
|
||||
uint32_t swapAddress = oldBase;
|
||||
uint32_t usedSize = sSettingsUsedSize;
|
||||
uint8_t pageNum = SETTINGS_CONFIG_PAGE_NUM;
|
||||
uint32_t settingsSize = pageNum > 1 ? SETTINGS_CONFIG_PAGE_SIZE * pageNum / 2 : SETTINGS_CONFIG_PAGE_SIZE;
|
||||
char swapFile[kMaxFileNameSize];
|
||||
char dataFile[kMaxFileNameSize];
|
||||
|
||||
(void)aInstance;
|
||||
getSettingsFileName(swapFile, true);
|
||||
getSettingsFileName(dataFile, false);
|
||||
|
||||
otEXPECT(pageNum > 1);
|
||||
VerifyOrDie(0 == close(sSettingsFd));
|
||||
VerifyOrDie(0 == rename(swapFile, dataFile));
|
||||
VerifyOrDie(0 == fsync(aFd));
|
||||
|
||||
sSettingsBaseAddress =
|
||||
(swapAddress == SETTINGS_CONFIG_BASE_ADDRESS) ? (swapAddress + settingsSize) : SETTINGS_CONFIG_BASE_ADDRESS;
|
||||
|
||||
initSettings(sSettingsBaseAddress, static_cast<uint32_t>(kSettingsInSwap));
|
||||
sSettingsUsedSize = kSettingsFlagSize;
|
||||
swapAddress += kSettingsFlagSize;
|
||||
|
||||
while (swapAddress < (oldBase + usedSize))
|
||||
{
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct addSettingsBlock
|
||||
{
|
||||
struct settingsBlock block;
|
||||
uint8_t data[kSettingsBlockDataSize];
|
||||
} OT_TOOL_PACKED_END addBlock;
|
||||
bool valid = true;
|
||||
|
||||
utilsFlashRead(swapAddress, reinterpret_cast<uint8_t *>(&addBlock.block), sizeof(struct settingsBlock));
|
||||
swapAddress += sizeof(struct settingsBlock);
|
||||
|
||||
if (!(addBlock.block.flag & kBlockAddCompleteFlag) && (addBlock.block.flag & kBlockDeleteFlag))
|
||||
{
|
||||
uint32_t address = swapAddress + getAlignLength(addBlock.block.length);
|
||||
|
||||
while (address < (oldBase + usedSize))
|
||||
{
|
||||
struct settingsBlock block;
|
||||
|
||||
utilsFlashRead(address, reinterpret_cast<uint8_t *>(&block), sizeof(block));
|
||||
|
||||
if (!(block.flag & kBlockAddCompleteFlag) && (block.flag & kBlockDeleteFlag) &&
|
||||
!(block.flag & kBlockIndex0Flag) && (block.key == addBlock.block.key))
|
||||
{
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
address += (getAlignLength(block.length) + sizeof(struct settingsBlock));
|
||||
}
|
||||
|
||||
if (valid)
|
||||
{
|
||||
utilsFlashRead(swapAddress, addBlock.data, getAlignLength(addBlock.block.length));
|
||||
utilsFlashWrite(sSettingsBaseAddress + sSettingsUsedSize, reinterpret_cast<uint8_t *>(&addBlock),
|
||||
getAlignLength(addBlock.block.length) + sizeof(struct settingsBlock));
|
||||
sSettingsUsedSize += (sizeof(struct settingsBlock) + getAlignLength(addBlock.block.length));
|
||||
}
|
||||
}
|
||||
else if (addBlock.block.flag == 0xff)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
swapAddress += getAlignLength(addBlock.block.length);
|
||||
}
|
||||
|
||||
setSettingsFlag(sSettingsBaseAddress, static_cast<uint32_t>(kSettingsInUse));
|
||||
setSettingsFlag(oldBase, static_cast<uint32_t>(kSettingsNotUse));
|
||||
|
||||
exit:
|
||||
return settingsSize - sSettingsUsedSize;
|
||||
sSettingsFd = aFd;
|
||||
}
|
||||
|
||||
static otError addSetting(otInstance * aInstance,
|
||||
uint16_t aKey,
|
||||
bool aIndex0,
|
||||
const uint8_t *aValue,
|
||||
uint16_t aValueLength)
|
||||
static void swapDiscard(int aFd)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
struct addSettingsBlock
|
||||
{
|
||||
struct settingsBlock block;
|
||||
uint8_t data[kSettingsBlockDataSize];
|
||||
} OT_TOOL_PACKED_END addBlock;
|
||||
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_NUM > 1 ? SETTINGS_CONFIG_PAGE_SIZE * SETTINGS_CONFIG_PAGE_NUM / 2
|
||||
: SETTINGS_CONFIG_PAGE_SIZE;
|
||||
char swapFileName[kMaxFileNameSize];
|
||||
|
||||
addBlock.block.flag = 0xff;
|
||||
addBlock.block.key = aKey;
|
||||
|
||||
if (aIndex0)
|
||||
{
|
||||
addBlock.block.flag &= (~kBlockIndex0Flag);
|
||||
}
|
||||
|
||||
addBlock.block.flag &= (~kBlockAddBeginFlag);
|
||||
addBlock.block.length = aValueLength;
|
||||
|
||||
if ((sSettingsUsedSize + getAlignLength(addBlock.block.length) + sizeof(struct settingsBlock)) >= settingsSize)
|
||||
{
|
||||
otEXPECT_ACTION(swapSettingsBlock(aInstance) >=
|
||||
(getAlignLength(addBlock.block.length) + sizeof(struct settingsBlock)),
|
||||
error = OT_ERROR_NO_BUFS);
|
||||
}
|
||||
|
||||
utilsFlashWrite(sSettingsBaseAddress + sSettingsUsedSize, reinterpret_cast<uint8_t *>(&addBlock.block),
|
||||
sizeof(struct settingsBlock));
|
||||
|
||||
memset(addBlock.data, 0xff, kSettingsBlockDataSize);
|
||||
memcpy(addBlock.data, aValue, addBlock.block.length);
|
||||
|
||||
utilsFlashWrite(sSettingsBaseAddress + sSettingsUsedSize + sizeof(struct settingsBlock),
|
||||
reinterpret_cast<uint8_t *>(addBlock.data), getAlignLength(addBlock.block.length));
|
||||
|
||||
addBlock.block.flag &= (~kBlockAddCompleteFlag);
|
||||
utilsFlashWrite(sSettingsBaseAddress + sSettingsUsedSize, reinterpret_cast<uint8_t *>(&addBlock.block),
|
||||
sizeof(struct settingsBlock));
|
||||
sSettingsUsedSize += (sizeof(struct settingsBlock) + getAlignLength(addBlock.block.length));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
VerifyOrDie(0 == close(aFd));
|
||||
getSettingsFileName(swapFileName, true);
|
||||
VerifyOrDie(0 == unlink(swapFileName));
|
||||
}
|
||||
|
||||
// settings API
|
||||
void otPlatSettingsInit(otInstance *aInstance)
|
||||
{
|
||||
uint8_t index;
|
||||
uint32_t settingsSize = SETTINGS_CONFIG_PAGE_NUM > 1 ? SETTINGS_CONFIG_PAGE_SIZE * SETTINGS_CONFIG_PAGE_NUM / 2
|
||||
: SETTINGS_CONFIG_PAGE_SIZE;
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
(void)aInstance;
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS;
|
||||
|
||||
utilsFlashInit();
|
||||
|
||||
for (index = 0; index < 2; index++)
|
||||
{
|
||||
uint32_t blockFlag;
|
||||
struct stat st;
|
||||
|
||||
sSettingsBaseAddress += settingsSize * index;
|
||||
utilsFlashRead(sSettingsBaseAddress, reinterpret_cast<uint8_t *>(&blockFlag), sizeof(blockFlag));
|
||||
|
||||
if (blockFlag == kSettingsInUse)
|
||||
if (stat(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, &st) == -1)
|
||||
{
|
||||
break;
|
||||
mkdir(OPENTHREAD_CONFIG_POSIX_SETTINGS_PATH, 0755);
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 2)
|
||||
{
|
||||
initSettings(sSettingsBaseAddress, static_cast<uint32_t>(kSettingsInUse));
|
||||
char fileName[kMaxFileNameSize];
|
||||
|
||||
getSettingsFileName(fileName, false);
|
||||
sSettingsFd = open(fileName, O_RDWR | O_CREAT, 0600);
|
||||
}
|
||||
|
||||
sSettingsUsedSize = kSettingsFlagSize;
|
||||
VerifyOrDie(sSettingsFd != -1);
|
||||
|
||||
while (sSettingsUsedSize < settingsSize)
|
||||
for (off_t size = lseek(sSettingsFd, 0, SEEK_END), offset = lseek(sSettingsFd, 0, SEEK_SET); offset < size;)
|
||||
{
|
||||
struct settingsBlock block;
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
utilsFlashRead(sSettingsBaseAddress + sSettingsUsedSize, reinterpret_cast<uint8_t *>(&block), sizeof(block));
|
||||
rval = read(sSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
if (!(block.flag & kBlockAddBeginFlag))
|
||||
{
|
||||
sSettingsUsedSize += (getAlignLength(block.length) + sizeof(struct settingsBlock));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
rval = read(sSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
}
|
||||
}
|
||||
|
||||
otError otPlatSettingsBeginChange(otInstance *aInstance)
|
||||
{
|
||||
(void)aInstance;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatSettingsCommitChange(otInstance *aInstance)
|
||||
{
|
||||
(void)aInstance;
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatSettingsAbandonChange(otInstance *aInstance)
|
||||
{
|
||||
(void)aInstance;
|
||||
return OT_ERROR_NONE;
|
||||
exit:
|
||||
if (error == OT_ERROR_PARSE)
|
||||
{
|
||||
VerifyOrDie(ftruncate(sSettingsFd, 0) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
uint32_t address = sSettingsBaseAddress + kSettingsFlagSize;
|
||||
uint16_t valueLength = 0;
|
||||
int index = 0;
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
const off_t size = lseek(sSettingsFd, 0, SEEK_END);
|
||||
off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
|
||||
|
||||
(void)aInstance;
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_PARSE);
|
||||
|
||||
while (address < (sSettingsBaseAddress + sSettingsUsedSize))
|
||||
while (offset < size)
|
||||
{
|
||||
struct settingsBlock block;
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
utilsFlashRead(address, reinterpret_cast<uint8_t *>(&block), sizeof(block));
|
||||
rval = read(sSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
if (block.key == aKey)
|
||||
rval = read(sSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
if (key == aKey)
|
||||
{
|
||||
if (!(block.flag & kBlockIndex0Flag))
|
||||
if (aIndex == 0)
|
||||
{
|
||||
index = 0;
|
||||
}
|
||||
error = OT_ERROR_NONE;
|
||||
|
||||
if (!(block.flag & kBlockAddCompleteFlag) && (block.flag & kBlockDeleteFlag))
|
||||
{
|
||||
if (index == aIndex)
|
||||
if (aValueLength)
|
||||
{
|
||||
uint16_t readLength = block.length;
|
||||
|
||||
// only perform read if an input buffer was passed in
|
||||
if (aValue != NULL && aValueLength != NULL)
|
||||
if (aValue)
|
||||
{
|
||||
// adjust read length if input buffer length is smaller
|
||||
if (readLength > *aValueLength)
|
||||
{
|
||||
readLength = *aValueLength;
|
||||
}
|
||||
uint16_t readLength = (length <= *aValueLength ? length : *aValueLength);
|
||||
|
||||
utilsFlashRead(address + sizeof(struct settingsBlock), aValue, readLength);
|
||||
VerifyOrExit(read(sSettingsFd, aValue, readLength) == readLength, error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
valueLength = block.length;
|
||||
error = OT_ERROR_NONE;
|
||||
*aValueLength = length;
|
||||
}
|
||||
|
||||
index++;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
--aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
address += (getAlignLength(block.length) + sizeof(struct settingsBlock));
|
||||
}
|
||||
|
||||
if (aValueLength != NULL)
|
||||
{
|
||||
*aValueLength = valueLength;
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
}
|
||||
|
||||
exit:
|
||||
VerifyOrDie(error != OT_ERROR_PARSE);
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
return addSetting(aInstance, aKey, true, aValue, aValueLength);
|
||||
otPlatSettingsDelete(aInstance, aKey, -1);
|
||||
return otPlatSettingsAdd(aInstance, aKey, aValue, aValueLength);
|
||||
}
|
||||
|
||||
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
|
||||
{
|
||||
uint16_t length;
|
||||
bool index0;
|
||||
off_t size = lseek(sSettingsFd, 0, SEEK_END);
|
||||
int swapFd = swapOpen();
|
||||
|
||||
index0 = (otPlatSettingsGet(aInstance, aKey, 0, NULL, &length) == OT_ERROR_NOT_FOUND ? true : false);
|
||||
return addSetting(aInstance, aKey, index0, aValue, aValueLength);
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
VerifyOrDie(0 == lseek(sSettingsFd, 0, SEEK_SET));
|
||||
swapWrite(swapFd, size);
|
||||
}
|
||||
|
||||
VerifyOrDie(write(swapFd, &aKey, sizeof(aKey)) == sizeof(aKey) &&
|
||||
write(swapFd, &aValueLength, sizeof(aValueLength)) == sizeof(aValueLength) &&
|
||||
write(swapFd, aValue, aValueLength) == aValueLength);
|
||||
|
||||
swapPersist(swapFd);
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
{
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
uint32_t address = sSettingsBaseAddress + kSettingsFlagSize;
|
||||
int index = 0;
|
||||
otError error = OT_ERROR_NOT_FOUND;
|
||||
off_t size = lseek(sSettingsFd, 0, SEEK_END);
|
||||
off_t offset = lseek(sSettingsFd, 0, SEEK_SET);
|
||||
int swapFd = swapOpen();
|
||||
|
||||
(void)aInstance;
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
assert(swapFd != -1);
|
||||
assert(offset == 0);
|
||||
VerifyOrExit(offset == 0 && size >= 0, error = OT_ERROR_PARSE);
|
||||
|
||||
while (address < (sSettingsBaseAddress + sSettingsUsedSize))
|
||||
while (offset < size)
|
||||
{
|
||||
struct settingsBlock block;
|
||||
uint16_t key;
|
||||
uint16_t length;
|
||||
ssize_t rval;
|
||||
|
||||
utilsFlashRead(address, reinterpret_cast<uint8_t *>(&block), sizeof(block));
|
||||
rval = read(sSettingsFd, &key, sizeof(key));
|
||||
VerifyOrExit(rval == sizeof(key), error = OT_ERROR_PARSE);
|
||||
|
||||
if (block.key == aKey)
|
||||
rval = read(sSettingsFd, &length, sizeof(length));
|
||||
VerifyOrExit(rval == sizeof(length), error = OT_ERROR_PARSE);
|
||||
|
||||
offset += sizeof(key) + sizeof(length) + length;
|
||||
|
||||
if (aKey == key)
|
||||
{
|
||||
if (!(block.flag & kBlockIndex0Flag))
|
||||
if (aIndex == 0)
|
||||
{
|
||||
index = 0;
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
swapWrite(swapFd, size - offset);
|
||||
error = OT_ERROR_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(block.flag & kBlockAddCompleteFlag) && (block.flag & kBlockDeleteFlag))
|
||||
else if (aIndex == -1)
|
||||
{
|
||||
if (aIndex == index || aIndex == -1)
|
||||
{
|
||||
error = OT_ERROR_NONE;
|
||||
block.flag &= (~kBlockDeleteFlag);
|
||||
utilsFlashWrite(address, reinterpret_cast<uint8_t *>(&block), sizeof(block));
|
||||
}
|
||||
|
||||
if (index == 1 && aIndex == 0)
|
||||
{
|
||||
block.flag &= (~kBlockIndex0Flag);
|
||||
utilsFlashWrite(address, reinterpret_cast<uint8_t *>(&block), sizeof(block));
|
||||
}
|
||||
|
||||
index++;
|
||||
VerifyOrExit(offset == lseek(sSettingsFd, length, SEEK_CUR), error = OT_ERROR_PARSE);
|
||||
error = OT_ERROR_NONE;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
--aIndex;
|
||||
}
|
||||
}
|
||||
|
||||
address += (getAlignLength(block.length) + sizeof(struct settingsBlock));
|
||||
rval = write(swapFd, &key, sizeof(key));
|
||||
assert(rval == sizeof(key));
|
||||
VerifyOrDie(rval == sizeof(key));
|
||||
|
||||
rval = write(swapFd, &length, sizeof(length));
|
||||
assert(rval == sizeof(length));
|
||||
VerifyOrDie(rval == sizeof(length));
|
||||
|
||||
swapWrite(swapFd, length);
|
||||
}
|
||||
|
||||
exit:
|
||||
VerifyOrDie(error != OT_ERROR_PARSE);
|
||||
|
||||
if (error == OT_ERROR_NONE)
|
||||
{
|
||||
swapPersist(swapFd);
|
||||
}
|
||||
else if (error == OT_ERROR_NOT_FOUND)
|
||||
{
|
||||
swapDiscard(swapFd);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -451,10 +334,150 @@ otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
|
||||
|
||||
void otPlatSettingsWipe(otInstance *aInstance)
|
||||
{
|
||||
initSettings(sSettingsBaseAddress, static_cast<uint32_t>(kSettingsInUse));
|
||||
otPlatSettingsInit(aInstance);
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
VerifyOrDie(0 == ftruncate(sSettingsFd, 0));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#if SELF_TEST
|
||||
|
||||
uint64_t gNodeId = 1;
|
||||
|
||||
int main()
|
||||
{
|
||||
otInstance *instance = NULL;
|
||||
uint8_t data[60];
|
||||
|
||||
for (size_t i = 0; i < sizeof(data); ++i)
|
||||
{
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
otPlatSettingsInit(instance);
|
||||
|
||||
// verify empty situation
|
||||
otPlatSettingsWipe(instance);
|
||||
{
|
||||
uint8_t value[sizeof(data)];
|
||||
uint16_t length = sizeof(value);
|
||||
|
||||
assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NOT_FOUND);
|
||||
assert(otPlatSettingsDelete(instance, 0, 0) == OT_ERROR_NOT_FOUND);
|
||||
assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
|
||||
// verify write one record
|
||||
assert(otPlatSettingsSet(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
|
||||
{
|
||||
uint8_t value[sizeof(data)];
|
||||
uint16_t length = sizeof(value);
|
||||
|
||||
assert(otPlatSettingsGet(instance, 0, 0, NULL, NULL) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, NULL, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data) / 2);
|
||||
|
||||
length = sizeof(value);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data) / 2);
|
||||
assert(0 == memcmp(value, data, length));
|
||||
|
||||
// insufficient buffer
|
||||
length -= 1;
|
||||
value[length] = 0;
|
||||
assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
|
||||
// verify length becomes the actual length of the record
|
||||
assert(length == sizeof(data) / 2);
|
||||
// verify this byte is not changed
|
||||
assert(value[length] == 0);
|
||||
|
||||
// wrong index
|
||||
assert(otPlatSettingsGet(instance, 0, 1, NULL, NULL) == OT_ERROR_NOT_FOUND);
|
||||
// wrong key
|
||||
assert(otPlatSettingsGet(instance, 1, 0, NULL, NULL) == OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
otPlatSettingsWipe(instance);
|
||||
|
||||
// verify write two records
|
||||
assert(otPlatSettingsSet(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
|
||||
{
|
||||
uint8_t value[sizeof(data)];
|
||||
uint16_t length = sizeof(value);
|
||||
|
||||
assert(otPlatSettingsGet(instance, 0, 1, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data) / 2);
|
||||
assert(0 == memcmp(value, data, length));
|
||||
|
||||
length = sizeof(value);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data));
|
||||
assert(0 == memcmp(value, data, length));
|
||||
}
|
||||
otPlatSettingsWipe(instance);
|
||||
|
||||
// verify write two records of different keys
|
||||
assert(otPlatSettingsSet(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsAdd(instance, 1, data, sizeof(data) / 2) == OT_ERROR_NONE);
|
||||
{
|
||||
uint8_t value[sizeof(data)];
|
||||
uint16_t length = sizeof(value);
|
||||
|
||||
assert(otPlatSettingsGet(instance, 1, 0, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data) / 2);
|
||||
assert(0 == memcmp(value, data, length));
|
||||
|
||||
length = sizeof(value);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data));
|
||||
assert(0 == memcmp(value, data, length));
|
||||
}
|
||||
otPlatSettingsWipe(instance);
|
||||
|
||||
// verify delete record
|
||||
assert(otPlatSettingsAdd(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 2) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 3) == OT_ERROR_NONE);
|
||||
{
|
||||
uint8_t value[sizeof(data)];
|
||||
uint16_t length = sizeof(value);
|
||||
|
||||
// wrong key
|
||||
assert(otPlatSettingsDelete(instance, 1, 0) == OT_ERROR_NOT_FOUND);
|
||||
assert(otPlatSettingsDelete(instance, 1, -1) == OT_ERROR_NOT_FOUND);
|
||||
|
||||
// wrong index
|
||||
assert(otPlatSettingsDelete(instance, 0, 3) == OT_ERROR_NOT_FOUND);
|
||||
|
||||
// delete one record
|
||||
assert(otPlatSettingsDelete(instance, 0, 1) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsGet(instance, 0, 1, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data) / 3);
|
||||
assert(0 == memcmp(value, data, length));
|
||||
|
||||
// delete all records
|
||||
assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, NULL, NULL) == OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
otPlatSettingsWipe(instance);
|
||||
|
||||
// verify delete all records of a type
|
||||
assert(otPlatSettingsAdd(instance, 0, data, sizeof(data)) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsAdd(instance, 1, data, sizeof(data) / 2) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsAdd(instance, 0, data, sizeof(data) / 3) == OT_ERROR_NONE);
|
||||
{
|
||||
uint8_t value[sizeof(data)];
|
||||
uint16_t length = sizeof(value);
|
||||
|
||||
assert(otPlatSettingsDelete(instance, 0, -1) == OT_ERROR_NONE);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, value, &length) == OT_ERROR_NOT_FOUND);
|
||||
assert(otPlatSettingsGet(instance, 1, 0, value, &length) == OT_ERROR_NONE);
|
||||
assert(length == sizeof(data) / 2);
|
||||
assert(0 == memcmp(value, data, length));
|
||||
|
||||
assert(otPlatSettingsDelete(instance, 0, 0) == OT_ERROR_NOT_FOUND);
|
||||
assert(otPlatSettingsGet(instance, 0, 0, NULL, NULL) == OT_ERROR_NOT_FOUND);
|
||||
}
|
||||
otPlatSettingsWipe(instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,7 @@ static const int kUsPerSecond = 1000000; ///< Number of microseconds per sec
|
||||
static uint64_t sNow = 0; ///< Time of simulation.
|
||||
static int sSockFd = -1; ///< Socket used to communicating with simulator.
|
||||
static uint16_t sPortOffset = 0; ///< Port offset for simulation.
|
||||
int sNodeId = 0; ///< Node id of this simulated device.
|
||||
static int sNodeId = 0; ///< Node id of this simulated device.
|
||||
|
||||
void otSimInit(void)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,7 @@ die() {
|
||||
|
||||
cleanup() {
|
||||
# Clear logs and flash files
|
||||
sudo rm tmp/*.flash > /dev/null 2>&1
|
||||
sudo rm tmp/*.flash tmp/*.data tmp/*.swap > /dev/null 2>&1
|
||||
sudo rm *.log > /dev/null 2>&1
|
||||
|
||||
# Clear any wpantund instances
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ estatus=$?
|
||||
# Return the offset
|
||||
rm -rf "${lock_path}.${OFFSET}.lock.d"
|
||||
# Remove the flash files
|
||||
rm -f tmp/${OFFSET}_*.flash
|
||||
rm -f tmp/${OFFSET}_*.flash tmp/${OFFSET}_*.data tmp/${OFFSET}_*.swap
|
||||
|
||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
||||
tweaked_estatus=1
|
||||
|
||||
Reference in New Issue
Block a user