add: Kconfig assert or errorcode option

add: private include header
add: macro encapsulation for assertion or error check
add: ESP_FAIL return code documentation in public headers
change: replaced all assertions by NVS_ASSERT_OR_RETURN macro
change: few internal function return values from void to esp_err_t
change: ESP_ERR_NVS_VALUE_TOO_LONG macro comment
This commit is contained in:
Matus Fabo
2022-04-08 15:06:30 +02:00
committed by Martin Vychodil
parent 1f6fad6f48
commit 58cca07104
21 changed files with 300 additions and 201 deletions
+136 -48
View File
@@ -7,6 +7,7 @@
#include <esp_rom_crc.h>
#include <cstdio>
#include <cstring>
#include "nvs_internal.h"
namespace nvs
{
@@ -79,7 +80,7 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
case PageState::FULL:
case PageState::ACTIVE:
case PageState::FREEING:
mLoadEntryTable();
return mLoadEntryTable();
break;
default:
@@ -92,9 +93,13 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
esp_err_t Page::writeEntry(const Item& item)
{
esp_err_t err;
uint32_t phyAddr;
esp_err_t err = getEntryAddress(mNextFreeEntry, &phyAddr);
if (err != ESP_OK) {
return err;
}
err = mPartition->write(phyAddr, &item, sizeof(item));
err = mPartition->write(getEntryAddress(mNextFreeEntry), &item, sizeof(item));
if (err != ESP_OK) {
mState = PageState::INVALID;
@@ -118,9 +123,9 @@ esp_err_t Page::writeEntry(const Item& item)
esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
{
assert(size % ENTRY_SIZE == 0);
assert(mNextFreeEntry != INVALID_ENTRY);
assert(mFirstUsedEntry != INVALID_ENTRY);
NVS_ASSERT_OR_RETURN(size % ENTRY_SIZE == 0, ESP_FAIL);
NVS_ASSERT_OR_RETURN(mNextFreeEntry != INVALID_ENTRY, ESP_FAIL);
NVS_ASSERT_OR_RETURN(mFirstUsedEntry != INVALID_ENTRY, ESP_FAIL);
const uint16_t count = size / ENTRY_SIZE;
const uint8_t* buf = data;
@@ -143,7 +148,11 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
}
#endif // ! LINUX_TARGET
auto rc = mPartition->write(getEntryAddress(mNextFreeEntry), buf, size);
uint32_t phyAddr;
esp_err_t rc = getEntryAddress(mNextFreeEntry, &phyAddr);
if (rc == ESP_OK) {
rc = mPartition->write(phyAddr, buf, size);
}
#if !defined LINUX_TARGET
if (buf != data) {
@@ -205,8 +214,8 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c
}
// primitive types should fit into one entry
assert(totalSize == ENTRY_SIZE ||
isVariableLengthType(datatype));
NVS_ASSERT_OR_RETURN(totalSize == ENTRY_SIZE ||
isVariableLengthType(datatype), ESP_ERR_NVS_VALUE_TOO_LONG);
if (mNextFreeEntry == INVALID_ENTRY || mNextFreeEntry + entriesCount > ENTRY_COUNT) {
// page will not fit this amount of data
@@ -388,7 +397,12 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
{
uint32_t seq_num;
getSeqNumber(seq_num);
auto state = mEntryTable.get(index);
EntryState state;
esp_err_t err = mEntryTable.get(index, &state);
if (err != ESP_OK) {
return err;
}
size_t span = 1;
if (state == EntryState::WRITTEN) {
@@ -409,7 +423,11 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
mHashList.erase(index);
span = item.span;
for (ptrdiff_t i = index + span - 1; i >= static_cast<ptrdiff_t>(index); --i) {
if (mEntryTable.get(i) == EntryState::WRITTEN) {
rc = mEntryTable.get(i, &state);
if (rc != ESP_OK) {
return rc;
}
if (state == EntryState::WRITTEN) {
--mUsedEntryCount;
}
++mErasedEntryCount;
@@ -431,7 +449,10 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
}
if (index == mFirstUsedEntry) {
updateFirstUsedEntry(index, span);
auto rc = updateFirstUsedEntry(index, span);
if (rc != ESP_OK) {
return rc;
}
}
if (index + span > mNextFreeEntry) {
@@ -441,20 +462,27 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
return ESP_OK;
}
void Page::updateFirstUsedEntry(size_t index, size_t span)
esp_err_t Page::updateFirstUsedEntry(size_t index, size_t span)
{
assert(index == mFirstUsedEntry);
NVS_ASSERT_OR_RETURN(index == mFirstUsedEntry, ESP_FAIL);
mFirstUsedEntry = INVALID_ENTRY;
size_t end = mNextFreeEntry;
EntryState state;
esp_err_t err;
if (end > ENTRY_COUNT) {
end = ENTRY_COUNT;
}
for (size_t i = index + span; i < end; ++i) {
if (mEntryTable.get(i) == EntryState::WRITTEN) {
err = mEntryTable.get(i, &state);
if (err != ESP_OK) {
return err;
}
if (state == EntryState::WRITTEN) {
mFirstUsedEntry = i;
break;
}
}
return ESP_OK;
}
esp_err_t Page::copyItems(Page& other)
@@ -472,15 +500,20 @@ esp_err_t Page::copyItems(Page& other)
Item entry;
size_t readEntryIndex = mFirstUsedEntry;
EntryState state;
esp_err_t err;
while (readEntryIndex < ENTRY_COUNT) {
if (mEntryTable.get(readEntryIndex) != EntryState::WRITTEN) {
assert(readEntryIndex != mFirstUsedEntry);
err = mEntryTable.get(readEntryIndex, &state);
if (err != ESP_OK) {
return err;
}
if (state != EntryState::WRITTEN) {
NVS_ASSERT_OR_RETURN(readEntryIndex != mFirstUsedEntry, ESP_FAIL);
readEntryIndex++;
continue;
}
auto err = readEntry(readEntryIndex, entry);
err = readEntry(readEntryIndex, entry);
if (err != ESP_OK) {
return err;
}
@@ -497,7 +530,7 @@ esp_err_t Page::copyItems(Page& other)
size_t span = entry.span;
size_t end = readEntryIndex + span;
assert(end <= ENTRY_COUNT);
NVS_ASSERT_OR_RETURN(end <= ENTRY_COUNT, ESP_FAIL);
for (size_t i = readEntryIndex + 1; i < end; ++i) {
readEntry(i, entry);
@@ -526,16 +559,21 @@ esp_err_t Page::mLoadEntryTable()
}
}
EntryState state;
esp_err_t err;
mErasedEntryCount = 0;
mUsedEntryCount = 0;
for (size_t i = 0; i < ENTRY_COUNT; ++i) {
auto s = mEntryTable.get(i);
if (s == EntryState::WRITTEN) {
err = mEntryTable.get(i, &state);
if (err != ESP_OK) {
return err;
}
if (state == EntryState::WRITTEN) {
if (mFirstUsedEntry == INVALID_ENTRY) {
mFirstUsedEntry = i;
}
++mUsedEntryCount;
} else if (s == EntryState::ERASED) {
} else if (state == EntryState::ERASED) {
++mErasedEntryCount;
}
}
@@ -544,7 +582,11 @@ esp_err_t Page::mLoadEntryTable()
// as such, we need to figure out where the first unused entry is
if (mState == PageState::ACTIVE) {
for (size_t i = 0; i < ENTRY_COUNT; ++i) {
if (mEntryTable.get(i) == EntryState::EMPTY) {
err = mEntryTable.get(i, &state);
if (err != ESP_OK) {
return err;
}
if (state == EntryState::EMPTY) {
mNextFreeEntry = i;
break;
}
@@ -555,7 +597,11 @@ esp_err_t Page::mLoadEntryTable()
// entry state table may actually be half-written.
// this is easy to check by reading EntryHeader (i.e. first word)
while (mNextFreeEntry < ENTRY_COUNT) {
uint32_t entryAddress = getEntryAddress(mNextFreeEntry);
uint32_t entryAddress;
err = getEntryAddress(mNextFreeEntry, &entryAddress);
if (err != ESP_OK) {
return err;
}
uint32_t header;
auto rc = mPartition->read_raw(entryAddress, &header, sizeof(header));
if (rc != ESP_OK) {
@@ -563,8 +609,12 @@ esp_err_t Page::mLoadEntryTable()
return rc;
}
if (header != 0xffffffff) {
auto oldState = mEntryTable.get(mNextFreeEntry);
auto err = alterEntryState(mNextFreeEntry, EntryState::ERASED);
auto oldState = state;
rc = mEntryTable.get(mNextFreeEntry, &oldState);
if (rc != ESP_OK) {
return rc;
}
err = alterEntryState(mNextFreeEntry, EntryState::ERASED);
if (err != ESP_OK) {
mState = PageState::INVALID;
return err;
@@ -590,12 +640,16 @@ esp_err_t Page::mLoadEntryTable()
size_t span;
for (size_t i = 0; i < end; i += span) {
span = 1;
if (mEntryTable.get(i) == EntryState::ERASED) {
err = mEntryTable.get(i, &state);
if (err != ESP_OK) {
return err;
}
if (state == EntryState::ERASED) {
lastItemIndex = INVALID_ENTRY;
continue;
}
if (mEntryTable.get(i) == EntryState::ILLEGAL) {
if (state == EntryState::ILLEGAL) {
lastItemIndex = INVALID_ENTRY;
auto err = eraseEntryAndSpan(i);
if (err != ESP_OK) {
@@ -635,7 +689,11 @@ esp_err_t Page::mLoadEntryTable()
span = item.span;
bool needErase = false;
for (size_t j = i; j < i + span; ++j) {
if (mEntryTable.get(j) != EntryState::WRITTEN) {
err = mEntryTable.get(j, &state);
if (err != ESP_OK) {
return err;
}
if (state != EntryState::WRITTEN) {
needErase = true;
lastItemIndex = INVALID_ENTRY;
break;
@@ -675,11 +733,15 @@ esp_err_t Page::mLoadEntryTable()
// Do the same for the case when page is in full or freeing state.
Item item;
for (size_t i = mFirstUsedEntry; i < ENTRY_COUNT; ++i) {
if (mEntryTable.get(i) != EntryState::WRITTEN) {
auto err = mEntryTable.get(i, &state);
if (err != ESP_OK) {
return err;
}
if (state != EntryState::WRITTEN) {
continue;
}
auto err = readEntry(i, item);
err = readEntry(i, item);
if (err != ESP_OK) {
mState = PageState::INVALID;
return err;
@@ -694,7 +756,7 @@ esp_err_t Page::mLoadEntryTable()
continue;
}
assert(item.span > 0);
NVS_ASSERT_OR_RETURN(item.span > 0, ESP_FAIL);
err = mHashList.insert(item, i);
if (err != ESP_OK) {
@@ -706,7 +768,11 @@ esp_err_t Page::mLoadEntryTable()
if (isVariableLengthType(item.datatype)) {
for (size_t j = i + 1; j < i + span; ++j) {
if (mEntryTable.get(j) != EntryState::WRITTEN) {
err = mEntryTable.get(j, &state);
if (err != ESP_OK) {
return err;
}
if (state != EntryState::WRITTEN) {
eraseEntryAndSpan(i);
break;
}
@@ -724,7 +790,7 @@ esp_err_t Page::mLoadEntryTable()
esp_err_t Page::initialize()
{
assert(mState == PageState::UNINITIALIZED);
NVS_ASSERT_OR_RETURN(mState == PageState::UNINITIALIZED, ESP_FAIL);
mState = PageState::ACTIVE;
Header header;
header.mState = mState;
@@ -745,26 +811,33 @@ esp_err_t Page::initialize()
esp_err_t Page::alterEntryState(size_t index, EntryState state)
{
assert(index < ENTRY_COUNT);
mEntryTable.set(index, state);
NVS_ASSERT_OR_RETURN(index < ENTRY_COUNT, ESP_FAIL);
esp_err_t err = mEntryTable.set(index, state);
if (err != ESP_OK) {
return err;
}
size_t wordToWrite = mEntryTable.getWordIndex(index);
uint32_t word = mEntryTable.data()[wordToWrite];
auto rc = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordToWrite) * 4,
err = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordToWrite) * 4,
&word, sizeof(word));
if (rc != ESP_OK) {
if (err != ESP_OK) {
mState = PageState::INVALID;
return rc;
return err;
}
return ESP_OK;
}
esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state)
{
assert(end <= ENTRY_COUNT);
assert(end > begin);
NVS_ASSERT_OR_RETURN(end <= ENTRY_COUNT, ESP_FAIL);
NVS_ASSERT_OR_RETURN(end > begin, ESP_FAIL);
size_t wordIndex = mEntryTable.getWordIndex(end - 1);
esp_err_t err;
for (ptrdiff_t i = end - 1; i >= static_cast<ptrdiff_t>(begin); --i) {
mEntryTable.set(i, state);
err = mEntryTable.set(i, state);
if (err != ESP_OK){
return err;
}
size_t nextWordIndex;
if (i == static_cast<ptrdiff_t>(begin)) {
nextWordIndex = (size_t) -1;
@@ -798,7 +871,12 @@ esp_err_t Page::alterPageState(PageState state)
esp_err_t Page::readEntry(size_t index, Item& dst) const
{
auto rc = mPartition->read(getEntryAddress(index), &dst, sizeof(dst));
uint32_t phyAddr;
esp_err_t rc = getEntryAddress(index, &phyAddr);
if (rc != ESP_OK) {
return rc;
}
rc = mPartition->read(phyAddr, &dst, sizeof(dst));
if (rc != ESP_OK) {
return rc;
}
@@ -836,13 +914,19 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si
}
size_t next;
EntryState state;
esp_err_t rc;
for (size_t i = start; i < end; i = next) {
next = i + 1;
if (mEntryTable.get(i) != EntryState::WRITTEN) {
rc = mEntryTable.get(i, &state);
if (rc != ESP_OK) {
return rc;
}
if (state != EntryState::WRITTEN) {
continue;
}
auto rc = readEntry(i, item);
rc = readEntry(i, item);
if (rc != ESP_OK) {
mState = PageState::INVALID;
return rc;
@@ -1009,7 +1093,11 @@ void Page::debugDump() const
size_t skip = 0;
for (size_t i = 0; i < ENTRY_COUNT; ++i) {
printf("%3d: ", static_cast<int>(i));
EntryState state = mEntryTable.get(i);
EntryState state;
if (mEntryTable.get(i, &state) != ESP_OK) {
printf("Failed to read entry state\n");
return;
}
if (state == EntryState::EMPTY) {
printf("E\n");
} else if (state == EntryState::ERASED) {
@@ -1034,7 +1122,7 @@ void Page::debugDump() const
esp_err_t Page::calcEntries(nvs_stats_t &nvsStats)
{
assert(mState != PageState::FREEING);
NVS_ASSERT_OR_RETURN(mState != PageState::FREEING, ESP_FAIL);
nvsStats.total_entries += ENTRY_COUNT;