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

View File

@ -183,7 +183,8 @@ static const esp_err_msg_t esp_err_msg_table[] = {
and call nvs_flash_init again. */
# endif
# ifdef ESP_ERR_NVS_VALUE_TOO_LONG
ERR_TBL_IT(ESP_ERR_NVS_VALUE_TOO_LONG), /* 4366 0x110e String or blob length is longer than
ERR_TBL_IT(ESP_ERR_NVS_VALUE_TOO_LONG), /* 4366 0x110e Value doesn't fit into the entry or
string or blob length is longer than
supported by the implementation */
# endif
# ifdef ESP_ERR_NVS_PART_NOT_FOUND

View File

@ -15,7 +15,8 @@ set(srcs "src/nvs_api.cpp"
idf_component_register(SRCS "${srcs}"
REQUIRES "spi_flash"
INCLUDE_DIRS "include")
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "private_include")
# If we use the linux target, we need to redirect the crc functions to the linux
if(${target} STREQUAL "linux")

View File

@ -20,4 +20,9 @@ menu "NVS"
IDF. Hence, if you have any devices where this flag is kept enabled in partition
table then enabling this config will allow to have same behavior as pre v4.3 IDF.
config NVS_ASSERT_ERROR_CHECK
bool "Use assertions for error checking"
default n
help
This option switches error checking type between assertions (y) or return codes (n).
endmenu

View File

@ -3,6 +3,8 @@ idf_component_register(SRCS "nvs_page_test.cpp"
"."
"${CMAKE_CURRENT_SOURCE_DIR}/../../fixtures"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src"
PRIV_INCLUDE_DIRS
"${CMAKE_CURRENT_SOURCE_DIR}/../../../private_include"
REQUIRES cmock nvs_flash spi_flash)
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage)

View File

@ -2,3 +2,4 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
CONFIG_COMPILER_HIDE_PATHS_MACROS=n
CONFIG_IDF_TARGET="linux"
CONFIG_COMPILER_CXX_EXCEPTIONS=y
CONFIG_NVS_ASSERT_ERROR_CHECK=y

View File

@ -40,7 +40,7 @@ typedef nvs_handle_t nvs_handle IDF_DEPRECATED("Replace with nvs_handle_t");
#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< NVS is in an inconsistent state due to a previous error. Call nvs_flash_init and nvs_open again, then retry. */
#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< String or blob length is not sufficient to store data */
#define ESP_ERR_NVS_NO_FREE_PAGES (ESP_ERR_NVS_BASE + 0x0d) /*!< NVS partition doesn't contain any empty pages. This may happen if NVS partition was truncated. Erase the whole partition and call nvs_flash_init again. */
#define ESP_ERR_NVS_VALUE_TOO_LONG (ESP_ERR_NVS_BASE + 0x0e) /*!< String or blob length is longer than supported by the implementation */
#define ESP_ERR_NVS_VALUE_TOO_LONG (ESP_ERR_NVS_BASE + 0x0e) /*!< Value doesn't fit into the entry or string or blob length is longer than supported by the implementation */
#define ESP_ERR_NVS_PART_NOT_FOUND (ESP_ERR_NVS_BASE + 0x0f) /*!< Partition with specified name is not found in the partition table */
#define ESP_ERR_NVS_NEW_VERSION_FOUND (ESP_ERR_NVS_BASE + 0x10) /*!< NVS partition contains data in new format and cannot be recognized by this version of code */
@ -124,6 +124,8 @@ typedef struct nvs_opaque_iterator_t *nvs_iterator_t;
*
* @return
* - ESP_OK if storage handle was opened successfully
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
* - ESP_ERR_NVS_PART_NOT_FOUND if the partition with label "nvs" is not found
* - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and
@ -151,6 +153,8 @@ esp_err_t nvs_open(const char* name, nvs_open_mode_t open_mode, nvs_handle_t *ou
*
* @return
* - ESP_OK if storage handle was opened successfully
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized
* - ESP_ERR_NVS_PART_NOT_FOUND if the partition with specified name is not found
* - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and
@ -175,6 +179,8 @@ esp_err_t nvs_open_from_partition(const char *part_name, const char* name, nvs_o
*
* @return
* - ESP_OK if value was set successfully
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
@ -282,6 +288,8 @@ esp_err_t nvs_set_str (nvs_handle_t handle, const char* key, const char* value);
*
* @return
* - ESP_OK if value was set successfully
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
@ -325,6 +333,8 @@ esp_err_t nvs_set_blob(nvs_handle_t handle, const char* key, const void* value,
*
* @return
* - ESP_OK if the value was retrieved successfully
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
@ -432,6 +442,8 @@ esp_err_t nvs_get_u64 (nvs_handle_t handle, const char* key, uint64_t* out_value
*
* @return
* - ESP_OK if the value was retrieved successfully
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
@ -459,6 +471,8 @@ esp_err_t nvs_get_blob(nvs_handle_t handle, const char* key, void* out_value, si
*
* @return
* - ESP_OK if erase operation was successful
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_READ_ONLY if handle was opened as read only
* - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
@ -476,6 +490,8 @@ esp_err_t nvs_erase_key(nvs_handle_t handle, const char* key);
*
* @return
* - ESP_OK if erase operation was successful
* - ESP_FAIL if there is an internal error; most likely due to corrupted
* NVS partition (only if NVS assertion checks are disabled)
* - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
* - ESP_ERR_NVS_READ_ONLY if handle was opened as read only
* - other error codes from the underlying storage driver

View File

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef NVS_INTERNAL_H
#define NVS_INTERNAL_H
#if CONFIG_NVS_ASSERT_ERROR_CHECK
#define NVS_ASSERT_OR_RETURN(condition, retcode) assert(condition);
#else
#define NVS_ASSERT_OR_RETURN(condition, retcode) \
if (!(condition)) { \
return retcode; \
}
#endif // CONFIG_NVS_ASSERT_ERROR_CHECK
#endif // NVS_INTERNAL_H

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef compressed_enum_table_h
#define compressed_enum_table_h
@ -18,6 +10,8 @@
#include <cstdint>
#include <cassert>
#include <type_traits>
#include "nvs_internal.h"
#include "esp_err.h"
template<typename Tenum, size_t Nbits, size_t Nitems>
class CompressedEnumTable
@ -33,23 +27,25 @@ public:
return mData;
}
Tenum get(size_t index) const
esp_err_t get(size_t index, Tenum *retval) const
{
assert(index < Nitems);
NVS_ASSERT_OR_RETURN(index < Nitems, ESP_FAIL);
size_t wordIndex = index / ITEMS_PER_WORD;
size_t offset = (index % ITEMS_PER_WORD) * Nbits;
return static_cast<Tenum>((mData[wordIndex] >> offset) & VALUE_MASK);
*retval = static_cast<Tenum>((mData[wordIndex] >> offset) & VALUE_MASK);
return ESP_OK;
}
void set(size_t index, Tenum val)
esp_err_t set(size_t index, Tenum val)
{
assert(index < Nitems);
NVS_ASSERT_OR_RETURN(index < Nitems, ESP_FAIL);
size_t wordIndex = index / ITEMS_PER_WORD;
size_t offset = (index % ITEMS_PER_WORD) * Nbits;
uint32_t v = static_cast<uint32_t>(val) << offset;
mData[wordIndex] = (mData[wordIndex] & ~(VALUE_MASK << offset)) | v;
return ESP_OK;
}
static constexpr size_t getWordIndex(size_t index)

View File

@ -1,25 +1,17 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef nvs_hpp
#define nvs_hpp
#include <memory>
#include "nvs.h"
#include "nvs_types.hpp"
#include "nvs_page.hpp"
#include "nvs_pagemanager.hpp"
#include "nvs_storage.hpp"
#include "nvs_internal.h"
#endif /* nvs_hpp */

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "nvs.hpp"
#include "nvs_flash.h"
@ -23,6 +15,7 @@
#include "nvs_handle_simple.hpp"
#include "esp_err.h"
#include <esp_rom_crc.h>
#include "nvs_internal.h"
// Uncomment this line to force output from this module
// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
@ -752,7 +745,7 @@ extern "C" nvs_iterator_t nvs_entry_find(const char *part_name, const char *name
extern "C" nvs_iterator_t nvs_entry_next(nvs_iterator_t it)
{
Lock lock;
assert(it);
NVS_ASSERT_OR_RETURN(it, nullptr);
bool entryFound = it->storage->nextEntry(it);
if (!entryFound) {

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;

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef nvs_page_hpp
#define nvs_page_hpp
@ -197,17 +189,18 @@ protected:
esp_err_t eraseEntryAndSpan(size_t index);
void updateFirstUsedEntry(size_t index, size_t span);
esp_err_t updateFirstUsedEntry(size_t index, size_t span);
static constexpr size_t getAlignmentForType(ItemType type)
{
return static_cast<uint8_t>(type) & 0x0f;
}
uint32_t getEntryAddress(size_t entry) const
esp_err_t getEntryAddress(size_t entry, uint32_t *address) const
{
assert(entry < ENTRY_COUNT);
return mBaseAddress + ENTRY_DATA_OFFSET + static_cast<uint32_t>(entry) * ENTRY_SIZE;
NVS_ASSERT_OR_RETURN(entry < ENTRY_COUNT, ESP_FAIL);
*address = mBaseAddress + ENTRY_DATA_OFFSET + static_cast<uint32_t>(entry) * ENTRY_SIZE;
return ESP_OK;
}
static const char* pageStateToName(PageState ps);

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nvs_pagemanager.hpp"
namespace nvs
@ -191,7 +183,7 @@ esp_err_t PageManager::requestNewPage()
}
#ifndef NDEBUG
assert(usedEntries == newPage->getUsedEntryCount());
NVS_ASSERT_OR_RETURN(usedEntries == newPage->getUsedEntryCount(), ESP_FAIL);
#endif
mPageList.erase(maxUnusedItemsPageIt);

View File

@ -6,6 +6,7 @@
#include "esp_partition.h"
#include "nvs_partition_manager.hpp"
#include "nvs_partition_lookup.hpp"
#include "nvs_internal.h"
#ifdef CONFIG_NVS_ENCRYPTION
#include "nvs_encrypted_partition.hpp"
@ -39,7 +40,7 @@ esp_err_t NVSPartitionManager::init_partition(const char *partition_label)
return ESP_OK;
}
assert(SPI_FLASH_SEC_SIZE != 0);
NVS_ASSERT_OR_RETURN(SPI_FLASH_SEC_SIZE != 0, ESP_FAIL);
NVSPartition *p = nullptr;
esp_err_t result = partition_lookup::lookup_nvs_partition(partition_label, &p);

View File

@ -110,14 +110,23 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount)
}
item.getKey(entry->mName, sizeof(entry->mName));
item.getValue(entry->mIndex);
err = item.getValue(entry->mIndex);
if (err != ESP_OK) {
return err;
}
mNamespaces.push_back(entry);
mNamespaceUsage.set(entry->mIndex, true);
if (mNamespaceUsage.set(entry->mIndex, true) != ESP_OK) {
return ESP_FAIL;
}
itemIndex += item.span;
}
}
mNamespaceUsage.set(0, true);
mNamespaceUsage.set(255, true);
if (mNamespaceUsage.set(0, true) != ESP_OK) {
return ESP_FAIL;
}
if (mNamespaceUsage.set(255, true) != ESP_OK) {
return ESP_FAIL;
}
mState = StorageState::ACTIVE;
// Populate list of multi-page index entries.
@ -204,15 +213,17 @@ esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const vo
}
/* Split the blob into two and store the chunk of available size onto the current page */
assert(tailroom != 0);
NVS_ASSERT_OR_RETURN(tailroom != 0, ESP_FAIL);
chunkSize = (remainingSize > tailroom)? tailroom : remainingSize;
remainingSize -= chunkSize;
err = page.writeItem(nsIndex, ItemType::BLOB_DATA, key,
static_cast<const uint8_t*> (data) + offset, chunkSize, static_cast<uint8_t> (chunkStart) + chunkCount);
chunkCount++;
assert(err != ESP_ERR_NVS_PAGE_FULL);
if (err != ESP_OK) {
NVS_ASSERT_OR_RETURN(err != ESP_ERR_NVS_PAGE_FULL, err);
break;
} else {
UsedPageNode* node = new (std::nothrow) UsedPageNode();
@ -245,7 +256,7 @@ esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const vo
item.blobIndex.chunkStart = chunkStart;
err = getCurrentPage().writeItem(nsIndex, ItemType::BLOB_IDX, key, item.data, sizeof(item.data));
assert(err != ESP_ERR_NVS_PAGE_FULL);
NVS_ASSERT_OR_RETURN(err != ESP_ERR_NVS_PAGE_FULL, err);
break;
}
} while (1);
@ -298,7 +309,8 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key
}
/* Get the version of the previous index with same <ns,key> */
prevStart = item.blobIndex.chunkStart;
assert(prevStart == VerOffset::VER_0_OFFSET || prevStart == VerOffset::VER_1_OFFSET);
NVS_ASSERT_OR_RETURN(prevStart == VerOffset::VER_0_OFFSET || prevStart == VerOffset::VER_1_OFFSET, ESP_FAIL);
/* Toggle the version by changing the offset */
nextStart
@ -401,8 +413,12 @@ esp_err_t Storage::createOrOpenNamespace(const char* nsName, bool canCreate, uin
}
uint8_t ns;
bool ns_state;
for (ns = 1; ns < 255; ++ns) {
if (mNamespaceUsage.get(ns) == false) {
if (mNamespaceUsage.get(ns, &ns_state) != ESP_OK) {
return ESP_FAIL;
}
if (!ns_state) {
break;
}
}
@ -415,7 +431,9 @@ esp_err_t Storage::createOrOpenNamespace(const char* nsName, bool canCreate, uin
if (err != ESP_OK) {
return err;
}
mNamespaceUsage.set(ns, true);
if (mNamespaceUsage.set(ns, true) != ESP_OK) {
return ESP_FAIL;
}
nsIndex = ns;
NamespaceEntry* entry = new (std::nothrow) NamespaceEntry;
@ -449,7 +467,7 @@ esp_err_t Storage::readMultiPageBlob(uint8_t nsIndex, const char* key, void* dat
VerOffset chunkStart = item.blobIndex.chunkStart;
size_t offset = 0;
assert(dataSize == item.blobIndex.dataSize);
NVS_ASSERT_OR_RETURN(dataSize == item.blobIndex.dataSize, ESP_FAIL);
/* Now read corresponding chunks */
for (uint8_t chunkNum = 0; chunkNum < chunkCount; chunkNum++) {
@ -464,12 +482,12 @@ esp_err_t Storage::readMultiPageBlob(uint8_t nsIndex, const char* key, void* dat
if (err != ESP_OK) {
return err;
}
assert(static_cast<uint8_t> (chunkStart) + chunkNum == item.chunkIndex);
NVS_ASSERT_OR_RETURN(static_cast<uint8_t> (chunkStart) + chunkNum == item.chunkIndex, ESP_FAIL);
offset += item.varLength.dataSize;
}
if (err == ESP_OK) {
assert(offset == dataSize);
}
NVS_ASSERT_OR_RETURN(offset == dataSize, ESP_FAIL);
if (err == ESP_ERR_NVS_NOT_FOUND) {
eraseMultiPageBlob(nsIndex, key); // cleanup if a chunk is not found
}
@ -509,12 +527,12 @@ esp_err_t Storage::cmpMultiPageBlob(uint8_t nsIndex, const char* key, const void
if (err != ESP_OK) {
return err;
}
assert(static_cast<uint8_t> (chunkStart) + chunkNum == item.chunkIndex);
NVS_ASSERT_OR_RETURN(static_cast<uint8_t> (chunkStart) + chunkNum == item.chunkIndex, ESP_FAIL);
offset += item.varLength.dataSize;
}
if (err == ESP_OK) {
assert(offset == dataSize);
}
NVS_ASSERT_OR_RETURN(offset == dataSize, ESP_FAIL);
return err;
}
@ -564,7 +582,7 @@ esp_err_t Storage::eraseMultiPageBlob(uint8_t nsIndex, const char* key, VerOffse
if (chunkStart == VerOffset::VER_ANY) {
chunkStart = item.blobIndex.chunkStart;
} else {
assert(chunkStart == item.blobIndex.chunkStart);
NVS_ASSERT_OR_RETURN(chunkStart == item.blobIndex.chunkStart, ESP_FAIL);
}
/* Now erase corresponding chunks*/

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef nvs_types_h
#define nvs_types_h
@ -110,10 +102,11 @@ public:
}
template<typename T>
void getValue(T& dst)
esp_err_t getValue(T& dst)
{
assert(itemTypeOf(dst) == datatype);
NVS_ASSERT_OR_RETURN(itemTypeOf(dst) == datatype, ESP_FAIL);
dst = *reinterpret_cast<T*>(data);
return ESP_OK;
}
};

View File

@ -38,7 +38,7 @@ else
COMPILER := gcc
endif
CPPFLAGS += -I../include -I../src -I../../esp_rom/include -I../../esp_rom/include/linux -I../../log/include -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../hal/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
CPPFLAGS += -I../private_include -I../include -I../src -I../../esp_rom/include -I../../esp_rom/include/linux -I../../log/include -I./ -I../../esp_common/include -I../../esp32/include -I ../../mbedtls/mbedtls/include -I ../../spi_flash/include -I ../../hal/include -I ../../xtensa/include -I ../../../tools/catch -fprofile-arcs -ftest-coverage -g2 -ggdb
CFLAGS += -fprofile-arcs -ftest-coverage -DLINUX_TARGET
CXXFLAGS += -std=c++11 -Wall -Werror -DLINUX_TARGET
LDFLAGS += -lstdc++ -Wall -fprofile-arcs -ftest-coverage

View File

@ -4,3 +4,4 @@
#define CONFIG_LOG_MAXIMUM_LEVEL 3
#define CONFIG_LOG_TIMESTAMP_SOURCE_RTOS 1
#define CONFIG_IDF_TARGET_LINUX 1
#define CONFIG_NVS_ASSERT_ERROR_CHECK 1

View File

@ -1,16 +1,8 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "catch.hpp"
#include "compressed_enum_table.hpp"
#include <cstring>
@ -27,26 +19,28 @@ TEST_CASE("test if CompressedEnumTable works as expected", "[enumtable]")
};
CompressedEnumTable<TEnum1, 2, 252> table;
memset(table.data(), 0xff, table.byteSize());
TEnum1 tmp;
for (size_t i = 0; i < table.count(); ++i) {
CHECK(table.get(i) == TEnum1::THREE);
CHECK(table.get(i, &tmp) == ESP_OK);
CHECK(tmp == TEnum1::THREE);
}
table.set(0, TEnum1::ONE);
table.set(1, TEnum1::TWO);
table.set(2, TEnum1::ZERO);
table.set(3, TEnum1::ONE);
table.set(4, TEnum1::TWO);
table.set(5, TEnum1::ZERO);
table.set(6, TEnum1::ONE);
table.set(7, TEnum1::TWO);
table.set(8, TEnum1::ZERO);
table.set(9, TEnum1::ZERO);
table.set(10, TEnum1::ONE);
table.set(11, TEnum1::TWO);
CHECK(table.set(0, TEnum1::ONE) == ESP_OK);
CHECK(table.set(1, TEnum1::TWO) == ESP_OK);
CHECK(table.set(2, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(3, TEnum1::ONE) == ESP_OK);
CHECK(table.set(4, TEnum1::TWO) == ESP_OK);
CHECK(table.set(5, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(6, TEnum1::ONE) == ESP_OK);
CHECK(table.set(7, TEnum1::TWO) == ESP_OK);
CHECK(table.set(8, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(9, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(10, TEnum1::ONE) == ESP_OK);
CHECK(table.set(11, TEnum1::TWO) == ESP_OK);
// table.set(12, ...
table.set(13, TEnum1::ZERO);
table.set(14, TEnum1::ONE);
table.set(15, TEnum1::TWO);
CHECK(table.set(13, TEnum1::ZERO) == ESP_OK);
CHECK(table.set(14, TEnum1::ONE) == ESP_OK);
CHECK(table.set(15, TEnum1::TWO) == ESP_OK);
// b10010011100100001001001001001001
// h 9 3 9 0 9 2 4 9

View File

@ -1096,10 +1096,7 @@ components/nvs_flash/host_test/nvs_page_test/main/nvs_page_test.cpp
components/nvs_flash/include/nvs_flash.h
components/nvs_flash/include/nvs_handle.hpp
components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py
components/nvs_flash/src/compressed_enum_table.hpp
components/nvs_flash/src/intrusive_list.h
components/nvs_flash/src/nvs.hpp
components/nvs_flash/src/nvs_api.cpp
components/nvs_flash/src/nvs_cxx_api.cpp
components/nvs_flash/src/nvs_encrypted_partition.cpp
components/nvs_flash/src/nvs_encrypted_partition.hpp
@ -1109,8 +1106,6 @@ components/nvs_flash/src/nvs_handle_simple.cpp
components/nvs_flash/src/nvs_handle_simple.hpp
components/nvs_flash/src/nvs_item_hash_list.cpp
components/nvs_flash/src/nvs_item_hash_list.hpp
components/nvs_flash/src/nvs_page.hpp
components/nvs_flash/src/nvs_pagemanager.cpp
components/nvs_flash/src/nvs_pagemanager.hpp
components/nvs_flash/src/nvs_partition.cpp
components/nvs_flash/src/nvs_partition.hpp
@ -1121,7 +1116,6 @@ components/nvs_flash/src/nvs_platform.hpp
components/nvs_flash/src/nvs_storage.hpp
components/nvs_flash/src/nvs_test_api.h
components/nvs_flash/src/nvs_types.cpp
components/nvs_flash/src/nvs_types.hpp
components/nvs_flash/src/partition.hpp
components/nvs_flash/test/test_nvs.c
components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp
@ -1129,7 +1123,6 @@ components/nvs_flash/test_nvs_host/main.cpp
components/nvs_flash/test_nvs_host/sdkconfig.h
components/nvs_flash/test_nvs_host/spi_flash_emulation.cpp
components/nvs_flash/test_nvs_host/spi_flash_emulation.h
components/nvs_flash/test_nvs_host/test_compressed_enum_table.cpp
components/nvs_flash/test_nvs_host/test_fixtures.hpp
components/nvs_flash/test_nvs_host/test_intrusive_list.cpp
components/nvs_flash/test_nvs_host/test_nvs.cpp

View File

@ -30,3 +30,4 @@ CONFIG_MQTT_TEST_BROKER_URI="mqtt://${EXAMPLE_MQTT_BROKER_TCP}"
# size of the storage partition divided by flash sector size.
# See esp_spiffs_gc description for more info.
CONFIG_SPIFFS_GC_MAX_RUNS=132
CONFIG_NVS_ASSERT_ERROR_CHECK=y