[posix-app] simplify saving settings (#3108)

This commit is contained in:
Yakun Xu
2018-10-10 02:12:56 +08:00
committed by Jonathan Hui
parent 5db4b0e295
commit 2af44beb74
9 changed files with 352 additions and 615 deletions
-1
View File
@@ -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 \
+12 -3
View File
@@ -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
-165
View File
@@ -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;
}
-129
View File
@@ -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
+1 -1
View File
@@ -240,4 +240,4 @@ int main(void)
printf("All tests passed\n");
return 0;
}
#endif
#endif // SELF_TEST
+336 -313
View File
@@ -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
+1 -1
View File
@@ -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)
{
+1 -1
View File
@@ -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
View File
@@ -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