diff --git a/Android.mk b/Android.mk index 6aac0720a..8941a3339 100644 --- a/Android.mk +++ b/Android.mk @@ -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 \ diff --git a/src/posix/platform/Makefile.am b/src/posix/platform/Makefile.am index 8ea69708a..5f0c4b96b 100644 --- a/src/posix/platform/Makefile.am +++ b/src/posix/platform/Makefile.am @@ -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 diff --git a/src/posix/platform/flash.c b/src/posix/platform/flash.c deleted file mode 100644 index f7aceb2e8..000000000 --- a/src/posix/platform/flash.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include - -#include - -#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; -} diff --git a/src/posix/platform/flash.h b/src/posix/platform/flash.h deleted file mode 100644 index 659e787e6..000000000 --- a/src/posix/platform/flash.h +++ /dev/null @@ -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 - -#include - -#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 diff --git a/src/posix/platform/frame_queue.cpp b/src/posix/platform/frame_queue.cpp index 65d9fa3e4..5bfd6fa1f 100644 --- a/src/posix/platform/frame_queue.cpp +++ b/src/posix/platform/frame_queue.cpp @@ -240,4 +240,4 @@ int main(void) printf("All tests passed\n"); return 0; } -#endif +#endif // SELF_TEST diff --git a/src/posix/platform/settings.cpp b/src/posix/platform/settings.cpp index 47b013761..9a5e6d07e 100644 --- a/src/posix/platform/settings.cpp +++ b/src/posix/platform/settings.cpp @@ -32,418 +32,301 @@ * */ +#include "platform-posix.h" + #include +#include #include -#include -#include "utils/wrap_string.h" - -#include +#include +#include #include -#include +#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(&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(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(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(&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(&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(&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(kSettingsInUse)); - setSettingsFlag(oldBase, static_cast(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(&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(addBlock.data), getAlignLength(addBlock.block.length)); - - addBlock.block.flag &= (~kBlockAddCompleteFlag); - utilsFlashWrite(sSettingsBaseAddress + sSettingsUsedSize, reinterpret_cast(&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(&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(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(&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(&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(&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(&block), sizeof(block)); - } - - if (index == 1 && aIndex == 0) - { - block.flag &= (~kBlockIndex0Flag); - utilsFlashWrite(address, reinterpret_cast(&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(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 diff --git a/src/posix/platform/sim.c b/src/posix/platform/sim.c index ee1194760..f496f0819 100644 --- a/src/posix/platform/sim.c +++ b/src/posix/platform/sim.c @@ -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) { diff --git a/tests/toranj/start.sh b/tests/toranj/start.sh index 73bdf7d2e..3318bfb8c 100755 --- a/tests/toranj/start.sh +++ b/tests/toranj/start.sh @@ -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 diff --git a/third_party/openthread-test-driver/test-driver b/third_party/openthread-test-driver/test-driver index 3f1eb8152..03ae4fe5e 100755 --- a/third_party/openthread-test-driver/test-driver +++ b/third_party/openthread-test-driver/test-driver @@ -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