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; (void)aInstance; while (address < (sSettingsBaseAddress + sSettingsUsedSize)) { struct settingsBlock block; utilsFlashRead(address, reinterpret_cast<uint8_t *>(&block), sizeof(block)); if (block.key == aKey) { if (!(block.flag & kBlockIndex0Flag)) { index = 0; } if (!(block.flag & kBlockAddCompleteFlag) && (block.flag & kBlockDeleteFlag)) { if (index == aIndex) { uint16_t readLength = block.length; // only perform read if an input buffer was passed in if (aValue != NULL && aValueLength != NULL) { // adjust read length if input buffer length is smaller if (readLength > *aValueLength) { readLength = *aValueLength; } utilsFlashRead(address + sizeof(struct settingsBlock), aValue, readLength); } valueLength = block.length; error = OT_ERROR_NONE; } index++; } } address += (getAlignLength(block.length) + sizeof(struct settingsBlock)); } if (aValueLength != NULL) { *aValueLength = valueLength; } return error; }
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) { OT_UNUSED_VARIABLE(aInstance); otError error = OT_ERROR_NOT_FOUND; uint32_t address = sSettingsBaseAddress + OT_SETTINGS_FLAG_SIZE; uint16_t valueLength = 0; int index = 0; while (address < (sSettingsBaseAddress + sSettingsUsedSize)) { struct settingsBlock block; utilsFlashRead(address, (uint8_t *)(&block), sizeof(block)); if (block.key == aKey) { if (!(block.flag & OT_FLASH_BLOCK_INDEX_0_FLAG)) { index = 0; } if (!(block.flag & OT_FLASH_BLOCK_ADD_COMPLETE_FLAG) && (block.flag & OT_FLASH_BLOCK_DELETE_FLAG)) { if (index == aIndex) { uint16_t readLength = block.length; // only perform read if an input buffer was passed in if (aValue != NULL && aValueLength != NULL) { // adjust read length if input buffer length is smaller if (readLength > *aValueLength) { readLength = *aValueLength; } utilsFlashRead(address + sizeof(struct settingsBlock), aValue, readLength); } valueLength = block.length; error = OT_ERROR_NONE; } index++; } } address += (getAlignLength(block.length) + sizeof(struct settingsBlock)); } if (aValueLength != NULL) { *aValueLength = valueLength; } return error; }
// 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; (void)aInstance; sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS; utilsFlashInit(); for (index = 0; index < 2; index++) { uint32_t blockFlag; sSettingsBaseAddress += settingsSize * index; utilsFlashRead(sSettingsBaseAddress, reinterpret_cast<uint8_t *>(&blockFlag), sizeof(blockFlag)); if (blockFlag == kSettingsInUse) { break; } } if (index == 2) { initSettings(sSettingsBaseAddress, static_cast<uint32_t>(kSettingsInUse)); } sSettingsUsedSize = kSettingsFlagSize; while (sSettingsUsedSize < settingsSize) { struct settingsBlock block; utilsFlashRead(sSettingsBaseAddress + sSettingsUsedSize, reinterpret_cast<uint8_t *>(&block), sizeof(block)); if (!(block.flag & kBlockAddBeginFlag)) { sSettingsUsedSize += (getAlignLength(block.length) + sizeof(struct settingsBlock)); } else { break; } } }
// settings API void otPlatSettingsInit(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); uint8_t index; uint32_t settingsSize = SETTINGS_CONFIG_PAGE_SIZE * SETTINGS_CONFIG_PAGE_NUM / 2; sSettingsBaseAddress = SETTINGS_CONFIG_BASE_ADDRESS; utilsFlashInit(); for (index = 0; index < 2; index++) { uint32_t blockFlag; sSettingsBaseAddress += settingsSize * index; utilsFlashRead(sSettingsBaseAddress, (uint8_t *)(&blockFlag), sizeof(blockFlag)); if (blockFlag == OT_SETTINGS_IN_USE) { break; } } if (index == 2) { initSettings(sSettingsBaseAddress, (uint32_t)OT_SETTINGS_IN_USE); } sSettingsUsedSize = OT_SETTINGS_FLAG_SIZE; while (sSettingsUsedSize < settingsSize) { struct settingsBlock block; utilsFlashRead(sSettingsBaseAddress + sSettingsUsedSize, (uint8_t *)(&block), sizeof(block)); if (!(block.flag & OT_FLASH_BLOCK_ADD_BEGIN_FLAG)) { sSettingsUsedSize += (getAlignLength(block.length) + sizeof(struct settingsBlock)); } else { break; } } }
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) { otError error = OT_ERROR_NOT_FOUND; uint32_t address = sSettingsBaseAddress + kSettingsFlagSize; int index = 0; (void)aInstance; while (address < (sSettingsBaseAddress + sSettingsUsedSize)) { struct settingsBlock block; utilsFlashRead(address, reinterpret_cast<uint8_t *>(&block), sizeof(block)); if (block.key == aKey) { if (!(block.flag & kBlockIndex0Flag)) { index = 0; } if (!(block.flag & kBlockAddCompleteFlag) && (block.flag & kBlockDeleteFlag)) { 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++; } } address += (getAlignLength(block.length) + sizeof(struct settingsBlock)); } return error; }
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex) { OT_UNUSED_VARIABLE(aInstance); otError error = OT_ERROR_NOT_FOUND; uint32_t address = sSettingsBaseAddress + OT_SETTINGS_FLAG_SIZE; int index = 0; while (address < (sSettingsBaseAddress + sSettingsUsedSize)) { struct settingsBlock block; utilsFlashRead(address, (uint8_t *)(&block), sizeof(block)); if (block.key == aKey) { if (!(block.flag & OT_FLASH_BLOCK_INDEX_0_FLAG)) { index = 0; } if (!(block.flag & OT_FLASH_BLOCK_ADD_COMPLETE_FLAG) && (block.flag & OT_FLASH_BLOCK_DELETE_FLAG)) { if (aIndex == index || aIndex == -1) { error = OT_ERROR_NONE; block.flag &= (~OT_FLASH_BLOCK_DELETE_FLAG); utilsFlashWrite(address, (uint8_t *)(&block), sizeof(block)); } if (index == 1 && aIndex == 0) { block.flag &= (~OT_FLASH_BLOCK_INDEX_0_FLAG); utilsFlashWrite(address, (uint8_t *)(&block), sizeof(block)); } index++; } } address += (getAlignLength(block.length) + sizeof(struct settingsBlock)); } return error; }
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++) { ret = utilsFlashRead(aAddress + index, &byte, 1); otEXPECT(ret == 1); // Use bitwise AND to emulate the behavior of flash memory byte &= aData[index]; ret = (uint32_t)pwrite(sFlashFd, &byte, 1, (off_t)(aAddress + index)); otEXPECT(ret == 1); } exit: return index; }
static uint32_t swapSettingsBlock(otInstance *aInstance) { 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; (void)aInstance; otEXPECT(pageNum > 1); 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; }
static uint32_t swapSettingsBlock(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); uint32_t oldBase = sSettingsBaseAddress; uint32_t swapAddress = oldBase; uint32_t usedSize = sSettingsUsedSize; uint32_t settingsSize = SETTINGS_CONFIG_PAGE_SIZE * SETTINGS_CONFIG_PAGE_NUM / 2; sSettingsBaseAddress = (swapAddress == SETTINGS_CONFIG_BASE_ADDRESS) ? (swapAddress + settingsSize) : SETTINGS_CONFIG_BASE_ADDRESS; initSettings(sSettingsBaseAddress, (uint32_t)OT_SETTINGS_IN_SWAP); sSettingsUsedSize = OT_SETTINGS_FLAG_SIZE; swapAddress += OT_SETTINGS_FLAG_SIZE; while (swapAddress < (oldBase + usedSize)) { OT_TOOL_PACKED_BEGIN struct addSettingsBlock { struct settingsBlock block; uint8_t data[OT_SETTINGS_BLOCK_DATA_SIZE]; } OT_TOOL_PACKED_END addBlock; bool valid = true; utilsFlashRead(swapAddress, (uint8_t *)(&addBlock.block), sizeof(struct settingsBlock)); swapAddress += sizeof(struct settingsBlock); if (!(addBlock.block.flag & OT_FLASH_BLOCK_ADD_COMPLETE_FLAG) && (addBlock.block.flag & OT_FLASH_BLOCK_DELETE_FLAG)) { uint32_t address = swapAddress + getAlignLength(addBlock.block.length); while (address < (oldBase + usedSize)) { struct settingsBlock block; utilsFlashRead(address, (uint8_t *)(&block), sizeof(block)); if (!(block.flag & OT_FLASH_BLOCK_ADD_COMPLETE_FLAG) && (block.flag & OT_FLASH_BLOCK_DELETE_FLAG) && !(block.flag & OT_FLASH_BLOCK_INDEX_0_FLAG) && (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, (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, (uint32_t)OT_SETTINGS_IN_USE); setSettingsFlag(oldBase, (uint32_t)OT_SETTINGS_NOT_USED); return settingsSize - sSettingsUsedSize; }