Merge branch 'feature/linux_target' into 'master'

build system: Add Linux target

Closes IDF-2145

See merge request espressif/esp-idf!10076
This commit is contained in:
Ivan Grokhotkov
2020-12-16 16:25:38 +08:00
39 changed files with 2367 additions and 180 deletions

View File

@@ -1,3 +1,5 @@
idf_build_get_property(target IDF_TARGET)
set(srcs "src/nvs_api.cpp"
"src/nvs_cxx_api.cpp"
"src/nvs_item_hash_list.cpp"
@@ -11,10 +13,39 @@ set(srcs "src/nvs_api.cpp"
"src/nvs_partition_manager.cpp"
"src/nvs_types.cpp")
if(CONFIG_NVS_ENCRYPTION)
list(APPEND srcs "src/nvs_encrypted_partition.cpp")
endif()
set(public_req spi_flash)
set(include_dirs "include")
idf_component_register(SRCS "${srcs}"
REQUIRES spi_flash mbedtls
INCLUDE_DIRS include)
REQUIRES "${public_req}"
INCLUDE_DIRS "${include_dirs}")
# If we use the linux target, we need to redirect the crc functions to the linux
if(${target} STREQUAL "linux")
if(CONFIG_NVS_ENCRYPTION)
# mbedtls isn't configured for building with linux or as mock target. It will draw in all kind of dependencies
message(FATAL_ERROR "NVS currently doesn't support encryption if built for Linux.")
endif()
idf_component_get_property(spi_flash_dir spi_flash COMPONENT_DIR)
target_include_directories(${COMPONENT_LIB} PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}/mock/int"
"${spi_flash_dir}/sim/stubs/freertos/include")
target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/mock/int/crc.cpp")
target_compile_options(${COMPONENT_LIB} PUBLIC "-DLINUX_TARGET")
else()
# TODO: this is a workaround until IDF-2085 is fixed
idf_component_get_property(mbedtls_lib mbedtls COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls_lib})
endif()
if(CONFIG_NVS_ENCRYPTION)
target_sources(${COMPONENT_LIB} PRIVATE "src/nvs_encrypted_partition.cpp")
idf_component_get_property(mbedtls_lib mbedtls COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${mbedtls_lib})
endif()
if(${target} STREQUAL "linux")
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage)
target_link_libraries(${COMPONENT_LIB} PUBLIC --coverage)
endif()

View File

@@ -0,0 +1,429 @@
// 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.
#include "nvs_partition.hpp"
#include "nvs.h"
#include "nvs_page.hpp"
#include "nvs_storage.hpp"
#include <exception>
#include <string>
#ifdef CONFIG_NVS_ENCRYPTION
#include "nvs_encrypted_partition.hpp"
#endif
extern "C" {
#include "Mockesp_partition.h"
}
struct FixtureException : std::exception {
FixtureException(const std::string& msg) : msg(msg) { }
const char *what() {
return msg.c_str();
}
std::string msg;
};
class PartitionMock : public nvs::Partition {
public:
PartitionMock(uint32_t address, uint32_t size)
: partition(), address(address), size(size)
{
assert(size);
}
const char *get_partition_name() override
{
return "";
}
esp_err_t read_raw(size_t src_offset, void* dst, size_t size) override
{
return esp_partition_read_raw(&partition, src_offset, dst, size);
}
esp_err_t read(size_t src_offset, void* dst, size_t size) override
{
return esp_partition_read(&partition, src_offset, dst, size);
}
esp_err_t write_raw(size_t dst_offset, const void* src, size_t size) override
{
return esp_partition_write_raw(&partition, dst_offset, src, size);
}
esp_err_t write(size_t dst_offset, const void* src, size_t size) override
{
return esp_partition_write(&partition, dst_offset, src, size);
}
esp_err_t erase_range(size_t dst_offset, size_t size) override
{
return esp_partition_erase_range(&partition, dst_offset, size);
}
uint32_t get_address() override
{
return address;
}
uint32_t get_size() override
{
return size;
}
const esp_partition_t partition;
private:
uint32_t address;
uint32_t size;
};
#ifdef CONFIG_NVS_ENCRYPTION
struct EncryptedPartitionFixture {
EncryptedPartitionFixture(nvs_sec_cfg_t *cfg,
uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: esp_partition(), emu(start_sector + sector_size),
part(partition_name, &esp_partition) {
esp_partition.address = start_sector * SPI_FLASH_SEC_SIZE;
esp_partition.size = sector_size * SPI_FLASH_SEC_SIZE;
assert(part.init(cfg) == ESP_OK);
}
~EncryptedPartitionFixture() { }
esp_partition_t esp_partition;
SpiFlashEmulator emu;
nvs::NVSEncryptedPartition part;
};
#endif
struct PartitionMockFixture {
PartitionMockFixture(uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: part_mock(start_sector * SPI_FLASH_SEC_SIZE, sector_size * SPI_FLASH_SEC_SIZE) {
std::fill_n(raw_header, sizeof(raw_header)/sizeof(raw_header[0]), UINT8_MAX);
}
~PartitionMockFixture() { }
uint8_t raw_header[512];
PartitionMock part_mock;
};
struct NVSPageFixture : public PartitionMockFixture {
NVSPageFixture(uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: PartitionMockFixture(start_sector, sector_size, partition_name), page()
{
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 32);
for (int i = 0; i < 8; i++) {
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
}
if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
}
nvs::Page page;
};
struct NVSValidPageFixture : public PartitionMockFixture {
const static uint8_t NS_INDEX = 1;
// valid header
uint8_t raw_header_valid [32];
// entry table with one entry
uint8_t raw_entry_table [32];
uint8_t ns_entry [32];
uint8_t value_entry [32];
NVSValidPageFixture(uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: PartitionMockFixture(start_sector, sector_size, partition_name),
raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc},
ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l',
'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
page()
{
std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
raw_entry_table[0] = 0xfa;
// read page header
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
// read entry table
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
// read next free entry's header
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4);
// read namespace entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// read normal entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
// read normal entry second time during duplicated entry check
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
}
nvs::Page page;
};
struct NVSValidStorageFixture : public PartitionMockFixture {
const static uint8_t NS_INDEX = 1;
uint8_t ns_entry [32];
uint8_t empty_entry [32];
NVSValidStorageFixture(uint32_t start_sector = 0,
uint32_t sector_size = 3,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: PartitionMockFixture(start_sector, sector_size, partition_name),
ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
empty_entry(),
storage(&part_mock)
{
std::fill_n(empty_entry, sizeof(empty_entry)/sizeof(empty_entry[0]), 0xFF);
// entry table with one entry
uint8_t raw_entry_table [32];
uint8_t header_full_page [] = {
0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc};
uint8_t header_second_page [] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t header_third_page [] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// entry_table with all elements deleted except the namespace entry written and the last entry free
std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
raw_entry_table[0] = 0x02;
raw_entry_table[31] = 0xFC;
// read full page header
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(header_full_page, 32);
// read entry table
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
// reading entry table checks empty entry
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(empty_entry, 32);
// read namespace entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// read last two pages' headers, which trigger an automatic full read each because each page is empty
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(header_second_page, 32);
for (int i = 0; i < 8; i++) {
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
}
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(header_third_page, 32);
for (int i = 0; i < 8; i++) {
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 512);
}
// read namespace entry in duplicated header item check of pagemanager::load
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// storage finally actually reads namespace
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// storage looks for blob index entries
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// Storage::eraseOrphanDataBlobs() also wants to take it's turn...
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
if (storage.init(start_sector, sector_size) != ESP_OK) throw FixtureException("couldn't setup page");
}
nvs::Storage storage;
};
struct NVSValidBlobPageFixture : public PartitionMockFixture {
const static uint8_t NS_INDEX = 1;
const static size_t BLOB_DATA_SIZE = 32;
// valid header
uint8_t raw_header_valid [32];
// entry table with one entry
uint8_t raw_entry_table [32];
uint8_t ns_entry [32];
uint8_t blob_entry [32];
uint8_t blob_data [BLOB_DATA_SIZE];
uint8_t blob_index [32];
NVSValidBlobPageFixture(uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME)
: PartitionMockFixture(start_sector, sector_size, partition_name),
raw_header_valid {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc2, 0x16, 0xdd, 0xdc},
ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
blob_entry {0x01, 0x42, 0x02, 0x00, 0xaa, 0xf3, 0x23, 0x87, 't', 'e', 's', 't', '_', 'b', 'l', 'o',
'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0xff, 0xff, 0xc6, 0x96, 0x86, 0xd9},
blob_data {0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef},
blob_index {0x01, 0x48, 0x01, 0xff, 0x42, 0x6b, 0xdf, 0x66, 't', 'e', 's', 't', '_', 'b', 'l', 'o',
'b', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xff},
page()
{
std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0xFF);
raw_entry_table[0] = 0xaa;
// read page header
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
// read entry table
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
// read next free entry's header
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header, 4);
// read namespace entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// read normal blob entry + index, not the data
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32);
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(blob_index, 32);
// read normal entry second time during duplicated entry check
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(blob_entry, 32);
if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
}
nvs::Page page;
};
struct NVSFullPageFixture : public PartitionMockFixture {
const static uint8_t NS_INDEX = 1;
// valid header
uint8_t raw_header_valid [32];
// entry table with one entry
uint8_t raw_entry_table [32];
uint8_t ns_entry [32];
uint8_t value_entry [32];
NVSFullPageFixture(uint32_t start_sector = 0,
uint32_t sector_size = 1,
const char *partition_name = NVS_DEFAULT_PART_NAME,
bool load = true)
: PartitionMockFixture(start_sector, sector_size, partition_name),
raw_header_valid {0xfc, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa3, 0x48, 0x9f, 0x38},
ns_entry {0x00, 0x01, 0x01, 0xff, 0x68, 0xc5, 0x3f, 0x0b, 't', 'e', 's', 't', '_', 'n', 's', '\0',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
value_entry {0x01, 0x01, 0x01, 0xff, 0x3d, 0xf3, 0x99, 0xe5, 't', 'e', 's', 't', '_', 'v', 'a', 'l',
'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
page()
{
std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
raw_entry_table[0] = 0xfa;
// entry_table with all elements deleted except the namespace entry written and the last entry free
std::fill_n(raw_entry_table, sizeof(raw_entry_table)/sizeof(raw_entry_table[0]), 0);
raw_entry_table[0] = 0x0a;
raw_entry_table[31] = 0xFC;
// read page header
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_valid, 32);
// read entry table
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_entry_table, 32);
// no next free entry check, only one entry written
// read namespace entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(ns_entry, 32);
// read normal entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(value_entry, 32);
// no duplicated entry check
if (load) {
if (page.load(&part_mock, start_sector) != ESP_OK) throw FixtureException("couldn't setup page");
}
}
nvs::Page page;
};

View File

@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
idf_build_set_property(CONFIG_SPI_FLASH_MOCK 1)
idf_build_set_property(COMPILE_DEFINITIONS "-DNO_DEBUG_STORAGE" APPEND)
project(host_nvs_page_test)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/build/coverage.info"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build"
COMMAND lcov --capture --directory . --output-file coverage.info
COMMENT "Create coverage report"
)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/build/coverage_report/"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/build/coverage.info"
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build"
COMMAND genhtml coverage.info --output-directory coverage_report/
COMMENT "Turn coverage report into html-based visualization"
)
add_custom_target(coverage
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build"
DEPENDS "coverage_report/"
)

View File

@@ -0,0 +1,23 @@
NVS Page Test for Host
======================
Build
-----
First, make sure that the target is set to linux.
Run ``idf.py --preview set-target linux`` to be sure.
Then do a normal IDF build: ``idf.py build``.
Run
---
IDF monitor doesn't work yet for Linux.
You have to run the app manually: ``./build/host_nvs_page_test.elf``.
Coverage
---
To generate the coverage, run: ``idf.py coverage``.
Afterwards, you can view the coverage by opening ``build/coverage_report/index.html`` with your browser.
Note that you need to run the application at least once before generating the coverage information.
If you run it multiple times, the coverage information adds up.

View File

@@ -0,0 +1,10 @@
idf_component_register(SRCS "nvs_page_test.cpp"
INCLUDE_DIRS
"."
"${CMAKE_CURRENT_SOURCE_DIR}/../../fixtures"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../test_nvs_host"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../src"
REQUIRES cmock nvs_flash spi_flash)
target_compile_options(${COMPONENT_LIB} PUBLIC --coverage)
target_link_libraries(${COMPONENT_LIB} --coverage)

View File

@@ -0,0 +1,934 @@
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "unity.h"
#include "test_fixtures.hpp"
extern "C" {
#include "Mockesp_partition.h"
}
using namespace std;
using namespace nvs;
void test_Page_load_reading_header_fails()
{
PartitionMock mock(0, 4096);
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_ERR_INVALID_ARG);
Page page;
TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state());
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, page.load(&mock, 0));
}
void test_Page_load_reading_data_fails()
{
uint8_t header[64];
std::fill_n(header, sizeof(header)/sizeof(header[0]), UINT8_MAX);
PartitionMock mock(0, 4096);
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(header, 32);
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_FAIL);
Page page;
TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state());
TEST_ASSERT_EQUAL(ESP_FAIL, page.load(&mock, 0));
}
void test_Page_load__uninitialized_page_has_0xfe()
{
PartitionMockFixture fix;
Page page;
fix.raw_header[511] = 0xfe;
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 32);
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 512);
// Page::load() should return ESP_OK, but state has to be corrupt
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0));
TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state());
}
void test_Page_load__initialized_corrupt_header()
{
PartitionMockFixture fix;
Page page;
uint8_t raw_header_corrupt [] = {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x16, 0xdd, 0xdc};
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_corrupt, 32);
// Page::load() should return ESP_OK, but state has to be corrupt
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0));
TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state());
}
void test_Page_load_success()
{
PartitionMockFixture fix;
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 32);
for (int i = 0; i < 8; i++) {
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 512);
}
Page page;
TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state());
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0));
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, page.state());
}
void test_Page_load_full_page()
{
NVSFullPageFixture fix(0, 1, NVS_DEFAULT_PART_NAME, false);
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
TEST_ASSERT_EQUAL(ESP_OK, fix.page.load(&fix.part_mock, 0));
TEST_ASSERT_EQUAL(Page::PageState::FULL, fix.page.state());
}
void test_Page_load__seq_number_0()
{
NVSValidPageFixture fix;
uint32_t seq_num;
fix.page.getSeqNumber(seq_num);
TEST_ASSERT_EQUAL(0, seq_num);
}
void test_Page_erase__write_fail()
{
NVSValidPageFixture fix;
esp_partition_erase_range_ExpectAndReturn(&fix.part_mock.partition, 0, 4096, ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.erase());
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
}
void test_Page_erase__success()
{
NVSValidPageFixture fix;
esp_partition_erase_range_ExpectAndReturn(&fix.part_mock.partition, 0, 4096, ESP_OK);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.erase());
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
}
void test_Page_write__initialize_write_failure()
{
PartitionMockFixture fix;
uint8_t write_data = 47;
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 32);
for (int i = 0; i < 8; i++) {
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(fix.raw_header, 512);
}
esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_FAIL);
Page page;
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0));
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, page.state());
TEST_ASSERT_EQUAL(ESP_FAIL, page.writeItem(1, nvs::ItemType::U8, "test", &write_data, sizeof(write_data)));
TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state());
}
void test_Page_write__write_data_fails()
{
NVSPageFixture fix;
uint8_t write_data = 47;
esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_write_ExpectAnyArgsAndReturn(ESP_FAIL);
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.writeItem(1, nvs::ItemType::U8, "test", &write_data, sizeof(write_data)));
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
}
void test_page_write__write_correct_entry_state()
{
NVSPageFixture fix;
uint8_t write_data = 47;
uint8_t raw_result [4];
std::fill_n(raw_result, sizeof(raw_result)/sizeof(raw_result[0]), UINT8_MAX);
// mark first entry as written
raw_result[0] = 0xfe;
// initialize page
esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK);
// write entry
esp_partition_write_ExpectAnyArgsAndReturn(ESP_OK);
// write entry state
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK);
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, nvs::ItemType::U8, "test_key", &write_data, sizeof(write_data)));
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_write__write_correct_data()
{
NVSPageFixture fix;
uint8_t write_data = 47;
uint8_t raw_result [32] = {0x01, 0x01, 0x01, 0xff, 0x98, 0x6f, 0x21, 0xfd, 't', 'e', 's', 't', '_', 'k', 'e', 'y',
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', 47, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
// initialize page
esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK);
// write entry
esp_partition_write_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 64, raw_result, 32, 32, ESP_OK);
// write entry state
esp_partition_write_raw_ExpectAnyArgsAndReturn(ESP_OK);
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
TEST_ASSERT_EQUAL(ESP_OK, fix.page.writeItem(1, nvs::ItemType::U8, "test_key", &write_data, sizeof(write_data)));
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_readItem__read_entry_fails()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
uint8_t read_value = 0;
esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value));
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
}
void test_Page_readItem__read_corrupted_entry()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
uint8_t read_value = 0;
// corrupting entry
fix.value_entry[0] = 0x0;
// first read the entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// erasing entry by setting bit in entry table (0xfa -> 0xf2)
uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00};
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK);
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value));
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(123, fix.page.getErasedEntryCount());
}
void test_Page_readItem__read_corrupted_second_read_fail()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
uint8_t read_value = 0;
// corrupting entry
fix.value_entry[0] = 0x0;
// first read the entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value));
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
}
void test_Page_readItem__read_corrupted_erase_fail()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
uint8_t read_value = 0;
// corrupting entry
fix.value_entry[0] = 0x0;
// first read the entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// erasing entry by setting bit in entry table (0xfa -> 0xf2)
uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00};
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value));
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
}
void test_Page_readItem__read_entry_suceeds()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
uint8_t read_value = 0;
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.readItem(NVSValidPageFixture::NS_INDEX, "test_value", read_value));
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(47, read_value);
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_readItem__blob_read_data_fails()
{
NVSValidBlobPageFixture fix;
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
uint8_t chunk_start = 0;
uint8_t read_data [32];
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32);
esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX,
ItemType::BLOB_DATA,
"test_blob",
read_data,
32,
chunk_start));
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_readItem__corrupt_data_erase_failure()
{
NVSValidBlobPageFixture fix;
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
uint8_t chunk_start = 0;
uint8_t read_data [32];
fix.blob_data[16] = 0xdf;
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32);
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_FAIL);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.readItem(NVSValidPageFixture::NS_INDEX,
ItemType::BLOB_DATA,
"test_blob",
read_data,
32,
chunk_start));
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_readItem__blob_corrupt_data()
{
NVSValidBlobPageFixture fix;
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
uint8_t chunk_start = 0;
uint8_t read_data [32];
fix.blob_data[16] = 0xdf;
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32);
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
// erasing entry by setting bit in entry table (0xfa -> 0xf2)
uint8_t raw_result [4] = {0xa2, 0xff, 0xff, 0xff};
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK);
esp_partition_erase_range_ExpectAndReturn(&fix.part_mock.partition, 96, 64, ESP_OK);
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.readItem(NVSValidPageFixture::NS_INDEX,
ItemType::BLOB_DATA,
"test_blob",
read_data,
32,
chunk_start));
TEST_ASSERT_EQUAL(3, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(1, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_readItem__blob_read_entry_suceeds()
{
NVSValidBlobPageFixture fix;
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
uint8_t chunk_start = 0;
uint8_t read_data [32];
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32);
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.readItem(NVSValidPageFixture::NS_INDEX,
ItemType::BLOB_DATA,
"test_blob",
read_data,
32,
chunk_start));
TEST_ASSERT_EQUAL_MEMORY(fix.blob_data, read_data, fix.BLOB_DATA_SIZE);
// make sure nothing was erased, i.e. checksums matched
TEST_ASSERT_EQUAL(4, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(0, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_cmp__uninitialized()
{
Page page;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_STATE, page.cmpItem(uint8_t(1) , "test", 47));
}
void test_Page_cmp__item_not_found()
{
NVSValidPageFixture fix;
// no expectations here since comparison uses the item hash list
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.cmpItem(uint8_t(1), "different", 47));
}
void test_Page_cmp__item_type_mismatch()
{
NVSValidPageFixture fix;
// read normal entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH, fix.page.cmpItem(uint8_t(1), "test_value", int(47)));
}
void test_Page_cmp__item_content_mismatch()
{
NVSValidPageFixture fix;
// read normal entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
TEST_ASSERT_EQUAL(ESP_ERR_NVS_CONTENT_DIFFERS, fix.page.cmpItem(uint8_t(1), "test_value", uint8_t(46)));
}
void test_Page_cmp__item_content_match()
{
NVSValidPageFixture fix;
// read normal entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.cmpItem(NVSValidPageFixture::NS_INDEX, "test_value", uint8_t(47)));
}
void test_Page_cmpItem__blob_data_mismatch()
{
NVSValidBlobPageFixture fix;
// read blob entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32);
// read blob data
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
uint8_t blob_data_different [] =
{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xee};
TEST_ASSERT_EQUAL(ESP_ERR_NVS_CONTENT_DIFFERS,
fix.page.cmpItem(uint8_t(1),
ItemType::BLOB_DATA,
"test_blob",
blob_data_different,
32));
}
void test_Page_cmpItem__blob_data_match()
{
NVSValidBlobPageFixture fix;
// read blob entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_entry, 32);
// read blob data
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.blob_data, fix.BLOB_DATA_SIZE);
uint8_t blob_data_same [] =
{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef,
0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef};
TEST_ASSERT_EQUAL(ESP_OK,
fix.page.cmpItem(NVSValidPageFixture::NS_INDEX,
ItemType::BLOB_DATA,
"test_blob",
blob_data_same,
32));
}
void test_Page_eraseItem__uninitialized()
{
Page page;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, page.eraseItem<uint8_t>(NVSValidPageFixture::NS_INDEX, "test_value"));
}
void test_Page_eraseItem__key_not_found()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND, fix.page.eraseItem<uint8_t>(NVSValidPageFixture::NS_INDEX, "different"));
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_eraseItem__write_fail()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
// first read the entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// erasing entry by setting bit in entry table (0xfa -> 0xf2)
uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00};
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.eraseItem<uint8_t>(NVSValidPageFixture::NS_INDEX, "test_value"));
TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(123, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
}
void test_Page_eraseItem__write_succeed()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(2, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(122, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
// first read the entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// Page::eraseEntryAndSpan() reads entry again
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
// erasing entry by setting bit in entry table (0xfa -> 0xf2)
uint8_t raw_result [4] = {0xf2, 0x00, 0x00, 0x00};
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, 1, 32, raw_result, 4, 4, ESP_OK);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.eraseItem<uint8_t>(NVSValidPageFixture::NS_INDEX, "test_value"));
TEST_ASSERT_EQUAL(1, fix.page.getUsedEntryCount());
TEST_ASSERT_EQUAL(123, fix.page.getErasedEntryCount());
TEST_ASSERT_EQUAL(Page::PageState::ACTIVE, fix.page.state());
}
void test_Page_findItem__uninitialized()
{
Page page;
size_t index = 0;
Item item;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND,
page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "test_value", index, item));
}
void test_Page_find__wrong_ns()
{
NVSValidPageFixture fix;
size_t index = 0;
Item item;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND,
fix.page.findItem(NVSValidPageFixture::NS_INDEX + 1, nvs::ItemType::U8, "test_value", index, item));
}
void test_Page_find__wrong_type()
{
NVSValidPageFixture fix;
size_t index = 0;
Item item;
// read normal entry
esp_partition_read_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_ReturnArrayThruPtr_dst(fix.value_entry, 32);
TEST_ASSERT_EQUAL(ESP_ERR_NVS_TYPE_MISMATCH,
fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::I8, "test_value", index, item));
}
void test_Page_find__key_empty()
{
NVSValidPageFixture fix;
size_t index = 0;
Item item;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND,
fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "", index, item));
}
void test_Page_find__wrong_key()
{
NVSValidPageFixture fix;
size_t index = 0;
Item item;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND,
fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "different", index, item));
}
void test_Page_find__too_large_index()
{
NVSValidPageFixture fix;
size_t index = 2;
Item item;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND,
fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "test_value", index, item));
}
void test_Page_findItem__without_read()
{
NVSValidPageFixture fix;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_NOT_FOUND,
fix.page.findItem(NVSValidPageFixture::NS_INDEX, nvs::ItemType::U8, "different"));
}
void test_Page_markFull__wrong_state()
{
NVSPageFixture fix;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_STATE, fix.page.markFull());
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
}
void test_Page_markFull__success()
{
NVSValidPageFixture fix;
Page::PageState expected_state = Page::PageState::FULL;
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, sizeof(fix.part_mock.partition), 0, &expected_state, sizeof(expected_state), 4, ESP_OK);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.markFull());
TEST_ASSERT_EQUAL(Page::PageState::FULL, fix.page.state());
}
void test_Page_markFull__write_fail()
{
NVSValidPageFixture fix;
Page::PageState expected_state = Page::PageState::FREEING;
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, sizeof(fix.part_mock.partition), 0, &expected_state, sizeof(expected_state), 4, ESP_FAIL);
TEST_ASSERT_EQUAL(ESP_FAIL, fix.page.markFreeing());
TEST_ASSERT_EQUAL(Page::PageState::INVALID, fix.page.state());
}
void test_Page_markFreeing__wrong_state()
{
NVSPageFixture fix;
TEST_ASSERT_EQUAL(ESP_ERR_NVS_INVALID_STATE, fix.page.markFreeing());
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
}
void test_Page_markFreeing__success()
{
NVSValidPageFixture fix;
Page::PageState expected_state = Page::PageState::FREEING;
esp_partition_write_raw_ExpectWithArrayAndReturn(&fix.part_mock.partition, sizeof(fix.part_mock.partition), 0, &expected_state, sizeof(expected_state), 4, ESP_OK);
TEST_ASSERT_EQUAL(ESP_OK, fix.page.markFreeing());
TEST_ASSERT_EQUAL(Page::PageState::FREEING, fix.page.state());
}
void test_Page_getVarDataTailroom__uninitialized_page()
{
NVSPageFixture fix;
TEST_ASSERT_EQUAL(Page::CHUNK_MAX_SIZE, fix.page.getVarDataTailroom());
}
void test_Page_getVarDataTailroom__success()
{
NVSValidPageFixture fix;
// blob data item, written namespace item, written normal item: 3 items
TEST_ASSERT_EQUAL((Page::ENTRY_COUNT - 3) * Page::ENTRY_SIZE, fix.page.getVarDataTailroom());
}
void test_Page_calcEntries__uninit()
{
NVSPageFixture fix;
TEST_ASSERT_EQUAL(Page::PageState::UNINITIALIZED, fix.page.state());
nvs_stats_t nvsStats = {0, 0, 0, 0};
TEST_ASSERT_EQUAL(ESP_OK, fix.page.calcEntries(nvsStats));
TEST_ASSERT_EQUAL(0, nvsStats.used_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.free_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries);
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
}
void test_Page_calcEntries__corrupt()
{
PartitionMockFixture fix;
Page page;
uint8_t raw_header_corrupt [] = {0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x16, 0xdd, 0xdc};
esp_partition_read_raw_ExpectAnyArgsAndReturn(ESP_OK);
esp_partition_read_raw_ReturnArrayThruPtr_dst(raw_header_corrupt, 32);
// Page::load() should return ESP_OK, but state has to be corrupt
TEST_ASSERT_EQUAL(ESP_OK, page.load(&fix.part_mock, 0));
TEST_ASSERT_EQUAL(Page::PageState::CORRUPT, page.state());
nvs_stats_t nvsStats = {0, 0, 0, 0};
TEST_ASSERT_EQUAL(ESP_OK, page.calcEntries(nvsStats));
TEST_ASSERT_EQUAL(0, nvsStats.used_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.free_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries);
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
}
void test_Page_calcEntries__active_wo_blob()
{
NVSValidPageFixture fix;
nvs_stats_t nvsStats = {0, 0, 0, 0};
TEST_ASSERT_EQUAL(ESP_OK, fix.page.calcEntries(nvsStats));
TEST_ASSERT_EQUAL(2, nvsStats.used_entries);
TEST_ASSERT_EQUAL(124, nvsStats.free_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries);
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
}
void test_Page_calcEntries__active_with_blob()
{
NVSValidBlobPageFixture fix;
nvs_stats_t nvsStats = {0, 0, 0, 0};
TEST_ASSERT_EQUAL(ESP_OK, fix.page.calcEntries(nvsStats));
TEST_ASSERT_EQUAL(4, nvsStats.used_entries);
TEST_ASSERT_EQUAL(122, nvsStats.free_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries);
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
}
void test_Page_calcEntries__invalid()
{
Page page;
nvs_stats_t nvsStats = {0, 0, 0, 0};
TEST_ASSERT_EQUAL(Page::PageState::INVALID, page.state());
// total entries always get updated
TEST_ASSERT_EQUAL(ESP_ERR_INVALID_STATE, page.calcEntries(nvsStats));
TEST_ASSERT_EQUAL(0, nvsStats.used_entries);
TEST_ASSERT_EQUAL(0, nvsStats.free_entries);
TEST_ASSERT_EQUAL(Page::ENTRY_COUNT, nvsStats.total_entries);
TEST_ASSERT_EQUAL(0, nvsStats.namespace_count);
}
int main(int argc, char **argv)
{
UNITY_BEGIN();
RUN_TEST(test_Page_load_reading_header_fails);
RUN_TEST(test_Page_load_reading_data_fails);
RUN_TEST(test_Page_load__uninitialized_page_has_0xfe);
RUN_TEST(test_Page_load__initialized_corrupt_header);
RUN_TEST(test_Page_load_success);
RUN_TEST(test_Page_load_full_page);
RUN_TEST(test_Page_load__seq_number_0);
RUN_TEST(test_Page_erase__write_fail);
RUN_TEST(test_Page_erase__success);
RUN_TEST(test_Page_write__initialize_write_failure);
RUN_TEST(test_Page_write__write_data_fails);
RUN_TEST(test_page_write__write_correct_entry_state);
RUN_TEST(test_Page_write__write_correct_data);
RUN_TEST(test_Page_readItem__read_entry_fails);
RUN_TEST(test_Page_readItem__read_corrupted_entry);
RUN_TEST(test_Page_readItem__read_corrupted_second_read_fail);
RUN_TEST(test_Page_readItem__read_corrupted_erase_fail);
RUN_TEST(test_Page_readItem__read_entry_suceeds);
RUN_TEST(test_Page_readItem__blob_read_data_fails);
RUN_TEST(test_Page_readItem__blob_corrupt_data);
RUN_TEST(test_Page_readItem__blob_read_entry_suceeds);
RUN_TEST(test_Page_cmp__uninitialized);
RUN_TEST(test_Page_cmp__item_not_found);
RUN_TEST(test_Page_cmp__item_type_mismatch);
RUN_TEST(test_Page_cmp__item_content_mismatch);
RUN_TEST(test_Page_cmp__item_content_match);
RUN_TEST(test_Page_cmpItem__blob_data_mismatch);
RUN_TEST(test_Page_cmpItem__blob_data_match);
RUN_TEST(test_Page_eraseItem__uninitialized);
RUN_TEST(test_Page_eraseItem__key_not_found);
RUN_TEST(test_Page_eraseItem__write_fail);
RUN_TEST(test_Page_readItem__corrupt_data_erase_failure);
RUN_TEST(test_Page_eraseItem__write_succeed);
RUN_TEST(test_Page_findItem__uninitialized);
RUN_TEST(test_Page_find__wrong_ns);
RUN_TEST(test_Page_find__wrong_type);
RUN_TEST(test_Page_find__key_empty);
RUN_TEST(test_Page_find__wrong_key);
RUN_TEST(test_Page_find__too_large_index);
RUN_TEST(test_Page_findItem__without_read);
RUN_TEST(test_Page_markFull__wrong_state);
RUN_TEST(test_Page_markFreeing__wrong_state);
RUN_TEST(test_Page_markFull__success);
RUN_TEST(test_Page_markFreeing__success);
RUN_TEST(test_Page_markFull__write_fail);
RUN_TEST(test_Page_getVarDataTailroom__uninitialized_page);
RUN_TEST(test_Page_getVarDataTailroom__success);
RUN_TEST(test_Page_calcEntries__uninit);
RUN_TEST(test_Page_calcEntries__corrupt);
RUN_TEST(test_Page_calcEntries__active_wo_blob);
RUN_TEST(test_Page_calcEntries__active_with_blob);
RUN_TEST(test_Page_calcEntries__invalid);
UNITY_END();
return 0;
}

View File

@@ -0,0 +1,3 @@
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
CONFIG_IDF_TARGET="linux"
CONFIG_CXX_EXCEPTIONS=y

View File

@@ -52,7 +52,7 @@ static const unsigned int crc32_le_table[256] = {
extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len)
extern "C" uint32_t esp_rom_crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len)
{
unsigned int i;
crc = ~crc;

View File

@@ -20,7 +20,11 @@
extern "C" {
#endif
uint32_t crc32_le(uint32_t crc, const uint8_t* buf, size_t len);
/**
* Mock function to replace ESP ROM function used in IDF with a Linux implementation.
* Note: the name MUST have the prefix esp_rom_* since tools/ci/check_rom_apis.sh checks and complains otherwise.
*/
uint32_t esp_rom_crc32_le(uint32_t crc, const uint8_t* buf, size_t len);
#ifdef __cplusplus
}

View File

@@ -35,7 +35,7 @@ public:
Tenum get(size_t index) const
{
assert(index >= 0 && index < Nitems);
assert(index < Nitems);
size_t wordIndex = index / ITEMS_PER_WORD;
size_t offset = (index % ITEMS_PER_WORD) * Nbits;
@@ -44,7 +44,7 @@ public:
void set(size_t index, Tenum val)
{
assert(index >= 0 && index < Nitems);
assert(index < Nitems);
size_t wordIndex = index / ITEMS_PER_WORD;
size_t offset = (index % ITEMS_PER_WORD) * Nbits;

View File

@@ -22,17 +22,17 @@
#include <functional>
#include "nvs_handle_simple.hpp"
#ifdef ESP_PLATFORM
#ifdef LINUX_TARGET
#include "crc.h"
#define ESP_LOGD(...)
#else // LINUX_TARGET
#include <esp32/rom/crc.h>
// Uncomment this line to force output from this module
// #define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
static const char* TAG = "nvs";
#else
#include "crc.h"
#define ESP_LOGD(...)
#endif
#endif // ! LINUX_TARGET
class NVSHandleEntry : public intrusive_list_node<NVSHandleEntry> {
public:
@@ -56,9 +56,9 @@ uint32_t NVSHandleEntry::s_nvs_next_handle;
extern "C" void nvs_dump(const char *partName);
#ifdef ESP_PLATFORM
#ifndef LINUX_TARGET
SemaphoreHandle_t nvs::Lock::mSemaphore = nullptr;
#endif
#endif // ! LINUX_TARGET
using namespace std;
using namespace nvs;
@@ -125,7 +125,7 @@ extern "C" esp_err_t nvs_flash_init_partition_ptr(const esp_partition_t *partiti
return init_res;
}
#ifdef ESP_PLATFORM
#ifndef LINUX_TARGET
extern "C" esp_err_t nvs_flash_init_partition(const char *part_name)
{
Lock::init();
@@ -204,7 +204,7 @@ extern "C" esp_err_t nvs_flash_erase(void)
{
return nvs_flash_erase_partition(NVS_DEFAULT_PART_NAME);
}
#endif // ESP_PLATFORM
#endif // ! LINUX_TARGET
extern "C" esp_err_t nvs_flash_deinit_partition(const char* partition_name)
{
@@ -528,7 +528,7 @@ extern "C" esp_err_t nvs_get_used_entry_count(nvs_handle_t c_handle, size_t* use
return err;
}
#if (defined CONFIG_NVS_ENCRYPTION) && (defined ESP_PLATFORM)
#if (defined CONFIG_NVS_ENCRYPTION) && (!defined LINUX_TARGET)
extern "C" esp_err_t nvs_flash_generate_keys(const esp_partition_t* partition, nvs_sec_cfg_t* cfg)
{

View File

@@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "nvs_page.hpp"
#if defined(ESP_PLATFORM)
#include <esp32/rom/crc.h>
#else
#if defined(LINUX_TARGET)
#include "crc.h"
#else
#include <esp_rom_crc.h>
#endif
#include <cstdio>
#include <cstring>
@@ -27,7 +27,7 @@ Page::Page() : mPartition(nullptr) { }
uint32_t Page::Header::calculateCrc32()
{
return crc32_le(0xffffffff,
return esp_rom_crc32_le(0xffffffff,
reinterpret_cast<uint8_t*>(this) + offsetof(Header, mSeqNumber),
offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber));
}
@@ -137,7 +137,7 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
const uint8_t* buf = data;
#ifdef ESP_PLATFORM
#if !defined LINUX_TARGET
// TODO: check whether still necessary with esp_partition* API
/* On the ESP32, data can come from DROM, which is not accessible by spi_flash_write
* function. To work around this, we copy the data to heap if it came from DROM.
@@ -153,15 +153,15 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size)
}
memcpy((void*)buf, data, size);
}
#endif //ESP_PLATFORM
#endif // ! LINUX_TARGET
auto rc = mPartition->write(getEntryAddress(mNextFreeEntry), buf, size);
#ifdef ESP_PLATFORM
#if !defined LINUX_TARGET
if (buf != data) {
free((void*)buf);
}
#endif //ESP_PLATFORM
#endif // ! LINUX_TARGET
if (rc != ESP_OK) {
mState = PageState::INVALID;
return rc;
@@ -968,7 +968,7 @@ size_t Page::getVarDataTailroom() const
} else if (mState == PageState::FULL) {
return 0;
}
/* Skip one entry for header*/
/* Skip one entry for blob data item precessing the data */
return ((mNextFreeEntry < (ENTRY_COUNT-1)) ? ((ENTRY_COUNT - mNextFreeEntry - 1) * ENTRY_SIZE): 0);
}

View File

@@ -224,6 +224,9 @@ protected:
uint16_t mUsedEntryCount = 0;
uint16_t mErasedEntryCount = 0;
/**
* This hash list stores hashes of namespace index, key, and ChunkIndex for quick lookup when searching items.
*/
HashList mHashList;
Partition *mPartition;

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "string.h"
#include <cstdlib>
#include "nvs_partition.hpp"
namespace nvs {
@@ -22,7 +22,7 @@ NVSPartition::NVSPartition(const esp_partition_t* partition)
{
// ensure the class is in a valid state
if (partition == nullptr) {
abort();
std::abort();
}
}

View File

@@ -11,11 +11,23 @@
// 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.
#ifndef nvs_platform_h
#define nvs_platform_h
#pragma once
#ifdef LINUX_TARGET
namespace nvs
{
class Lock
{
public:
Lock() { }
~Lock() { }
static void init() {}
static void uninit() {}
};
} // namespace nvs
#else // LINUX_TARGET
#ifdef ESP_PLATFORM
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
@@ -63,19 +75,4 @@ public:
};
} // namespace nvs
#else // ESP_PLATFORM
namespace nvs
{
class Lock
{
public:
Lock() { }
~Lock() { }
static void init() {}
static void uninit() {}
};
} // namespace nvs
#endif // ESP_PLATFORM
#endif /* nvs_platform_h */
#endif // LINUX_TARGET

View File

@@ -14,9 +14,15 @@
#include "nvs_storage.hpp"
#ifndef ESP_PLATFORM
// We need NO_DEBUG_STORAGE here since the integration tests on the host add some debug code.
// The unit tests, however, don't want debug code since they check the behavior via data in/output and disturb
// the order of calling mocked functions.
#ifndef NO_DEBUG_STORAGE
#include <map>
#include <sstream>
#define DEBUG_STORAGE
#endif
#endif // !ESP_PLATFORM
namespace nvs
{
@@ -136,7 +142,7 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount)
// Purge the blob index list
blobIdxList.clearAndFreeNodes();
#ifndef ESP_PLATFORM
#ifdef DEBUG_STORAGE
debugCheck();
#endif
return ESP_OK;
@@ -165,7 +171,7 @@ esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const vo
uint8_t chunkCount = 0;
TUsedPageList usedPages;
size_t remainingSize = dataSize;
size_t offset=0;
size_t offset = 0;
esp_err_t err = ESP_OK;
/* Check how much maximum data can be accommodated**/
@@ -182,8 +188,8 @@ esp_err_t Storage::writeMultiPageBlob(uint8_t nsIndex, const char* key, const vo
do {
Page& page = getCurrentPage();
size_t tailroom = page.getVarDataTailroom();
size_t chunkSize =0;
if (!chunkCount && tailroom < dataSize && tailroom < Page::CHUNK_MAX_SIZE/10) {
size_t chunkSize = 0;
if (chunkCount == 0U && ((tailroom < dataSize) || (tailroom == 0 && dataSize == 0)) && tailroom < Page::CHUNK_MAX_SIZE/10) {
/** This is the first chunk and tailroom is too small ***/
if (page.state() != Page::PageState::FULL) {
err = page.markFull();
@@ -206,7 +212,7 @@ 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);
assert(tailroom != 0);
chunkSize = (remainingSize > tailroom)? tailroom : remainingSize;
remainingSize -= chunkSize;
@@ -383,7 +389,7 @@ esp_err_t Storage::writeItem(uint8_t nsIndex, ItemType datatype, const char* key
return err;
}
}
#ifndef ESP_PLATFORM
#ifdef DEBUG_STORAGE
debugCheck();
#endif
return ESP_OK;
@@ -666,7 +672,7 @@ void Storage::debugDump()
}
}
#ifndef ESP_PLATFORM
#ifdef DEBUG_STORAGE
void Storage::debugCheck()
{
std::map<std::string, Page*> keys;
@@ -691,7 +697,7 @@ void Storage::debugCheck()
assert(usedCount == p->getUsedEntryCount());
}
}
#endif //ESP_PLATFORM
#endif //DEBUG_STORAGE
esp_err_t Storage::fillStats(nvs_stats_t& nvsStats)
{

View File

@@ -13,10 +13,10 @@
// limitations under the License.
#include "nvs_types.hpp"
#if defined(ESP_PLATFORM)
#include <esp32/rom/crc.h>
#else
#if defined(LINUX_TARGET)
#include "crc.h"
#else
#include <esp_rom_crc.h>
#endif
namespace nvs
@@ -25,10 +25,10 @@ uint32_t Item::calculateCrc32() const
{
uint32_t result = 0xffffffff;
const uint8_t* p = reinterpret_cast<const uint8_t*>(this);
result = crc32_le(result, p + offsetof(Item, nsIndex),
result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex),
offsetof(Item, crc32) - offsetof(Item, nsIndex));
result = crc32_le(result, p + offsetof(Item, key), sizeof(key));
result = crc32_le(result, p + offsetof(Item, data), sizeof(data));
result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key));
result = esp_rom_crc32_le(result, p + offsetof(Item, data), sizeof(data));
return result;
}
@@ -36,17 +36,17 @@ uint32_t Item::calculateCrc32WithoutValue() const
{
uint32_t result = 0xffffffff;
const uint8_t* p = reinterpret_cast<const uint8_t*>(this);
result = crc32_le(result, p + offsetof(Item, nsIndex),
result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex),
offsetof(Item, datatype) - offsetof(Item, nsIndex));
result = crc32_le(result, p + offsetof(Item, key), sizeof(key));
result = crc32_le(result, p + offsetof(Item, chunkIndex), sizeof(chunkIndex));
result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key));
result = esp_rom_crc32_le(result, p + offsetof(Item, chunkIndex), sizeof(chunkIndex));
return result;
}
uint32_t Item::calculateCrc32(const uint8_t* data, size_t size)
{
uint32_t result = 0xffffffff;
result = crc32_le(result, data, size);
result = esp_rom_crc32_le(result, data, size);
return result;
}

View File

@@ -3,6 +3,7 @@ all: $(TEST_PROGRAM)
SOURCE_FILES = \
esp_error_check_stub.cpp \
../mock/int/crc.cpp \
$(addprefix ../src/, \
nvs_types.cpp \
nvs_api.cpp \
@@ -28,7 +29,6 @@ SOURCE_FILES = \
test_nvs_partition.cpp \
test_nvs_cxx_api.cpp \
test_nvs_initialization.cpp \
crc.cpp \
main.cpp
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
@@ -37,9 +37,9 @@ else
COMPILER := gcc
endif
CPPFLAGS += -I../include -I../src -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
CXXFLAGS += -std=c++11 -Wall -Werror
CPPFLAGS += -I../include -I../src -I../mock/int -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
ifeq ($(COMPILER),clang)

View File

@@ -1,63 +1,131 @@
if(BOOTLOADER_BUILD)
if(CONFIG_IDF_TARGET_ESP32)
# ESP32 Bootloader needs SPIUnlock from this file, but doesn't
# need other parts of this component
set(srcs "esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
set(srcs "esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
set(srcs "esp32s3/spi_flash_rom_patch.c")
idf_build_get_property(spi_flash_mock CONFIG_SPI_FLASH_MOCK)
idf_build_get_property(target IDF_TARGET)
if(${spi_flash_mock})
message(STATUS "building SPI FLASH MOCKS")
set(IDF_PATH $ENV{IDF_PATH})
set(CMOCK_DIR "${IDF_PATH}/components/cmock/CMock")
set(MOCK_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/mocks")
file(MAKE_DIRECTORY ${MOCK_GEN_DIR})
set(MOCK_OUTPUT
"${MOCK_GEN_DIR}/Mockesp_partition.c" "${MOCK_GEN_DIR}/Mockesp_partition.h"
"${MOCK_GEN_DIR}/Mockesp_flash.c" "${MOCK_GEN_DIR}/Mockesp_flash.h"
"${MOCK_GEN_DIR}/Mockesp_spi_flash.c" "${MOCK_GEN_DIR}/Mockesp_spi_flash.h")
set(MOCK_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/esp_partition.h
${CMAKE_CURRENT_SOURCE_DIR}/include/esp_flash.h
${CMAKE_CURRENT_SOURCE_DIR}/include/esp_spi_flash.h
)
set(ENV{UNITY_DIR} "$ENV{IDF_PATH}/components/cmock/CMock")
set(include_dirs
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${MOCK_GEN_DIR}")
set(srcs "${MOCK_GEN_DIR}/Mockesp_partition.c"
"${MOCK_GEN_DIR}/Mockesp_spi_flash.c"
"${MOCK_GEN_DIR}/Mockesp_flash.c")
if(${target} STREQUAL "linux")
list(APPEND include_dirs
"${CMAKE_CURRENT_SOURCE_DIR}/../spi_flash/sim/stubs/soc/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../spi_flash/sim/stubs/xtensa")
endif()
set(cache_srcs "")
set(priv_requires bootloader_support soc)
else()
set(cache_srcs
"cache_utils.c"
"flash_mmap.c"
"flash_ops.c"
"${IDF_TARGET}/flash_ops_${IDF_TARGET}.c"
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ${include_dirs}
REQUIRES cmock)
add_custom_command(
OUTPUT ruby_found SYMBOLIC
COMMAND "ruby" "-v"
COMMENT "Try to find ruby. If this fails, you need to install ruby"
)
set(srcs
"partition.c")
if(CONFIG_IDF_TARGET_ESP32)
# This command builds the mocks.
# First, environment variable UNITY_DIR is set. This is necessary to prevent unity from looking in its own submodule
# which doesn't work in our CI yet...
# The rest is a straight forward call to cmock.rb, consult cmock's documentation for more information.
add_custom_command(
OUTPUT ${MOCK_OUTPUT}
DEPENDS ruby_found
COMMAND ${CMAKE_COMMAND} -E env "UNITY_DIR=${IDF_PATH}/components/unity/unity"
ruby
${CMOCK_DIR}/lib/cmock.rb
-o${CMAKE_CURRENT_SOURCE_DIR}/mock/mock_config.yaml
${MOCK_HEADERS}
)
else()
if(BOOTLOADER_BUILD)
if(CONFIG_IDF_TARGET_ESP32)
# ESP32 Bootloader needs SPIUnlock from this file, but doesn't
# need other parts of this component
set(srcs "esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
set(srcs "esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
set(srcs "esp32s3/spi_flash_rom_patch.c")
else()
# but on other platforms no source files are needed for bootloader
set(srcs)
endif()
set(cache_srcs "")
set(priv_requires bootloader_support soc)
else()
set(cache_srcs
"cache_utils.c"
"flash_mmap.c"
"flash_ops.c"
"${IDF_TARGET}/flash_ops_${IDF_TARGET}.c"
)
set(srcs
"partition.c")
if(CONFIG_IDF_TARGET_ESP32)
list(APPEND srcs
"esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
list(APPEND srcs
"esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
list(APPEND srcs
"esp32s3/spi_flash_rom_patch.c")
endif()
# New implementation after IDF v4.0
list(APPEND srcs
"esp32/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S2)
list(APPEND srcs
"esp32s2/spi_flash_rom_patch.c")
elseif(CONFIG_IDF_TARGET_ESP32S3)
list(APPEND srcs
"esp32s3/spi_flash_rom_patch.c")
"spi_flash_chip_drivers.c"
"spi_flash_chip_generic.c"
"spi_flash_chip_issi.c"
"spi_flash_chip_mxic.c"
"spi_flash_chip_gd.c"
"spi_flash_chip_winbond.c"
"memspi_host_driver.c")
list(APPEND cache_srcs
"esp_flash_api.c"
"esp_flash_spi_init.c"
"spi_flash_os_func_app.c"
"spi_flash_os_func_noos.c")
list(APPEND srcs ${cache_srcs})
set(priv_requires bootloader_support app_update soc esp_ipc)
endif()
# New implementation after IDF v4.0
list(APPEND srcs
"spi_flash_chip_drivers.c"
"spi_flash_chip_generic.c"
"spi_flash_chip_issi.c"
"spi_flash_chip_mxic.c"
"spi_flash_chip_gd.c"
"spi_flash_chip_winbond.c"
"memspi_host_driver.c")
idf_component_register(SRCS "${srcs}"
REQUIRES hal
PRIV_REQUIRES "${priv_requires}"
INCLUDE_DIRS include
PRIV_INCLUDE_DIRS private_include
LDFRAGMENTS linker.lf)
list(APPEND cache_srcs
"esp_flash_api.c"
"esp_flash_spi_init.c"
"spi_flash_os_func_app.c"
"spi_flash_os_func_noos.c")
# Avoid cache miss by unexpected inlineing when built by -Os
set_source_files_properties(${cache_srcs} PROPERTIES COMPILE_FLAGS
"-fno-inline-functions -fno-inline-small-functions -fno-inline-functions-called-once")
list(APPEND srcs ${cache_srcs})
set(priv_requires bootloader_support app_update soc esp_ipc)
endif()
idf_component_register(SRCS "${srcs}"
REQUIRES hal
PRIV_REQUIRES "${priv_requires}"
INCLUDE_DIRS include
PRIV_INCLUDE_DIRS private_include
LDFRAGMENTS linker.lf)
# Avoid cache miss by unexpected inlineing when built by -Os
set_source_files_properties(${cache_srcs} PROPERTIES COMPILE_FLAGS
"-fno-inline-functions -fno-inline-small-functions -fno-inline-functions-called-once")

View File

@@ -20,6 +20,7 @@
#include <stddef.h>
#include "esp_err.h"
#include "sdkconfig.h"
#include "esp_spi_flash_counters.h"
#ifdef __cplusplus
extern "C" {
@@ -419,43 +420,6 @@ extern const spi_flash_guard_funcs_t g_flash_guard_default_ops;
*/
extern const spi_flash_guard_funcs_t g_flash_guard_no_os_ops;
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
/**
* Structure holding statistics for one type of operation
*/
typedef struct {
uint32_t count; // number of times operation was executed
uint32_t time; // total time taken, in microseconds
uint32_t bytes; // total number of bytes
} spi_flash_counter_t;
typedef struct {
spi_flash_counter_t read;
spi_flash_counter_t write;
spi_flash_counter_t erase;
} spi_flash_counters_t;
/**
* @brief Reset SPI flash operation counters
*/
void spi_flash_reset_counters(void);
/**
* @brief Print SPI flash operation counters
*/
void spi_flash_dump_counters(void);
/**
* @brief Return current SPI flash operation counters
*
* @return pointer to the spi_flash_counters_t structure holding values
* of the operation counters
*/
const spi_flash_counters_t* spi_flash_get_counters(void);
#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,65 @@
// 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.
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "sdkconfig.h"
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
#ifdef __cplusplus
extern "C" {
#endif
/**
* Structure holding statistics for one type of operation
*/
typedef struct {
uint32_t count; // number of times operation was executed
uint32_t time; // total time taken, in microseconds
uint32_t bytes; // total number of bytes
} spi_flash_counter_t;
typedef struct {
spi_flash_counter_t read;
spi_flash_counter_t write;
spi_flash_counter_t erase;
} spi_flash_counters_t;
/**
* @brief Reset SPI flash operation counters
*/
void spi_flash_reset_counters(void);
/**
* @brief Print SPI flash operation counters
*/
void spi_flash_dump_counters(void);
/**
* @brief Return current SPI flash operation counters
*
* @return pointer to the spi_flash_counters_t structure holding values
* of the operation counters
*/
const spi_flash_counters_t* spi_flash_get_counters(void);
#ifdef __cplusplus
}
#endif
#endif //CONFIG_SPI_FLASH_ENABLE_COUNTERS

View File

@@ -0,0 +1,7 @@
:cmock:
:plugins:
- expect
- expect_any_args
- return_thru_ptr
- array
- callback

View File

@@ -0,0 +1,149 @@
// 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.
#pragma once
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef int32_t esp_err_t;
/* Definitions for error constants. */
#define ESP_OK 0 /*!< esp_err_t value indicating success (no error) */
#define ESP_FAIL -1 /*!< Generic esp_err_t code indicating failure */
#define ESP_ERR_NO_MEM 0x101 /*!< Out of memory */
#define ESP_ERR_INVALID_ARG 0x102 /*!< Invalid argument */
#define ESP_ERR_INVALID_STATE 0x103 /*!< Invalid state */
#define ESP_ERR_INVALID_SIZE 0x104 /*!< Invalid size */
#define ESP_ERR_NOT_FOUND 0x105 /*!< Requested resource not found */
#define ESP_ERR_NOT_SUPPORTED 0x106 /*!< Operation or feature not supported */
#define ESP_ERR_TIMEOUT 0x107 /*!< Operation timed out */
#define ESP_ERR_INVALID_RESPONSE 0x108 /*!< Received response was invalid */
#define ESP_ERR_INVALID_CRC 0x109 /*!< CRC or checksum was invalid */
#define ESP_ERR_INVALID_VERSION 0x10A /*!< Version was invalid */
#define ESP_ERR_INVALID_MAC 0x10B /*!< MAC address was invalid */
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
#define ESP_ERR_MESH_BASE 0x4000 /*!< Starting number of MESH error codes */
#define ESP_ERR_FLASH_BASE 0x6000 /*!< Starting number of flash error codes */
/**
* @brief Returns string for esp_err_t error codes
*
* This function finds the error code in a pre-generated lookup-table and
* returns its string representation.
*
* The function is generated by the Python script
* tools/gen_esp_err_to_name.py which should be run each time an esp_err_t
* error is modified, created or removed from the IDF project.
*
* @param code esp_err_t error code
* @return string error message
*/
const char *esp_err_to_name(esp_err_t code);
/**
* @brief Returns string for esp_err_t and system error codes
*
* This function finds the error code in a pre-generated lookup-table of
* esp_err_t errors and returns its string representation. If the error code
* is not found then it is attempted to be found among system errors.
*
* The function is generated by the Python script
* tools/gen_esp_err_to_name.py which should be run each time an esp_err_t
* error is modified, created or removed from the IDF project.
*
* @param code esp_err_t error code
* @param[out] buf buffer where the error message should be written
* @param buflen Size of buffer buf. At most buflen bytes are written into the buf buffer (including the terminating null byte).
* @return buf containing the string error message
*/
const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen);
/** @cond */
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn));
/** @cond */
void _esp_error_check_failed_without_abort(esp_err_t rc, const char *file, int line, const char *function, const char *expression);
#ifndef __ASSERT_FUNC
/* This won't happen on IDF, which defines __ASSERT_FUNC in assert.h, but it does happen when building on the host which
uses /usr/include/assert.h or equivalent.
*/
#ifdef __ASSERT_FUNCTION
#define __ASSERT_FUNC __ASSERT_FUNCTION /* used in glibc assert.h */
#else
#define __ASSERT_FUNC "??"
#endif
#endif
/** @endcond */
/**
* Macro which can be used to check the error code,
* and terminate the program in case the code is not ESP_OK.
* Prints the error code, error location, and the failed statement to serial output.
*
* Disabled if assertions are disabled.
*/
#ifdef NDEBUG
#define ESP_ERROR_CHECK(x) do { \
esp_err_t __err_rc = (x); \
(void) sizeof(__err_rc); \
} while(0)
#elif defined(CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT)
#define ESP_ERROR_CHECK(x) do { \
esp_err_t __err_rc = (x); \
if (__err_rc != ESP_OK) { \
abort(); \
} \
} while(0)
#else
#define ESP_ERROR_CHECK(x) do { \
esp_err_t __err_rc = (x); \
if (__err_rc != ESP_OK) { \
_esp_error_check_failed(__err_rc, __FILE__, __LINE__, \
__ASSERT_FUNC, #x); \
} \
} while(0)
#endif
/**
* Macro which can be used to check the error code. Prints the error code, error location, and the failed statement to
* serial output.
* In comparison with ESP_ERROR_CHECK(), this prints the same error message but isn't terminating the program.
*/
#ifdef NDEBUG
#define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \
esp_err_t __err_rc = (x); \
__err_rc; \
})
#else
#define ESP_ERROR_CHECK_WITHOUT_ABORT(x) ({ \
esp_err_t __err_rc = (x); \
if (__err_rc != ESP_OK) { \
_esp_error_check_failed_without_abort(__err_rc, __FILE__, __LINE__, \
__ASSERT_FUNC, #x); \
} \
__err_rc; \
})
#endif //NDEBUG
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,148 @@
// Copyright 2010-2019 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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/** Definition of a common transaction. Also holds the return value. */
typedef struct {
uint8_t command; ///< Command to send, always 8bits
uint8_t mosi_len; ///< Output data length, in bytes
uint8_t miso_len; ///< Input data length, in bytes
uint8_t address_bitlen; ///< Length of address in bits, set to 0 if command does not need an address
uint32_t address; ///< Address to perform operation on
const uint8_t *mosi_data; ///< Output data to salve
uint8_t *miso_data; ///< [out] Input data from slave, little endian
} spi_flash_trans_t;
/** @brief Mode used for reading from SPI flash */
typedef enum {
SPI_FLASH_SLOWRD = 0, ///< Data read using single I/O, some limits on speed
SPI_FLASH_FASTRD, ///< Data read using single I/O, no limit on speed
SPI_FLASH_DOUT, ///< Data read using dual I/O
SPI_FLASH_DIO, ///< Both address & data transferred using dual I/O
SPI_FLASH_QOUT, ///< Data read using quad I/O
SPI_FLASH_QIO, ///< Both address & data transferred using quad I/O
SPI_FLASH_READ_MODE_MAX, ///< The fastest io mode supported by the host is ``ESP_FLASH_READ_MODE_MAX-1``.
} esp_flash_io_mode_t;
struct spi_flash_host_driver_s;
typedef struct spi_flash_host_driver_s spi_flash_host_driver_t;
/** SPI Flash Host driver instance */
typedef struct {
const struct spi_flash_host_driver_s* driver; ///< Pointer to the implementation function table
// Implementations can wrap this structure into their own ones, and append other data here
} spi_flash_host_inst_t ;
/** Host driver configuration and context structure. */
struct spi_flash_host_driver_s {
/**
* Configure the device-related register before transactions. This saves
* some time to re-configure those registers when we send continuously
*/
esp_err_t (*dev_config)(spi_flash_host_inst_t *host);
/**
* Send an user-defined spi transaction to the device.
*/
esp_err_t (*common_command)(spi_flash_host_inst_t *host, spi_flash_trans_t *t);
/**
* Read flash ID.
*/
esp_err_t (*read_id)(spi_flash_host_inst_t *host, uint32_t *id);
/**
* Erase whole flash chip.
*/
void (*erase_chip)(spi_flash_host_inst_t *host);
/**
* Erase a specific sector by its start address.
*/
void (*erase_sector)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Erase a specific block by its start address.
*/
void (*erase_block)(spi_flash_host_inst_t *host, uint32_t start_address);
/**
* Read the status of the flash chip.
*/
esp_err_t (*read_status)(spi_flash_host_inst_t *host, uint8_t *out_sr);
/**
* Disable write protection.
*/
esp_err_t (*set_write_protect)(spi_flash_host_inst_t *host, bool wp);
/**
* Program a page of the flash. Check ``max_write_bytes`` for the maximum allowed writing length.
*/
void (*program_page)(spi_flash_host_inst_t *host, const void *buffer, uint32_t address, uint32_t length);
/** Check whether given buffer can be directly used to write */
bool (*supports_direct_write)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for write data. The `program_page` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to write
* @param len Length request to write
* @param align_addr Output of the aligned address to write to
* @param page_size Physical page size of the flash chip
* @return Length that can be actually written in one `program_page` call
*/
int (*write_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr,
uint32_t page_size);
/**
* Read data from the flash. Check ``max_read_bytes`` for the maximum allowed reading length.
*/
esp_err_t (*read)(spi_flash_host_inst_t *host, void *buffer, uint32_t address, uint32_t read_len);
/** Check whether given buffer can be directly used to read */
bool (*supports_direct_read)(spi_flash_host_inst_t *host, const void *p);
/**
* Slicer for read data. The `read` should be called iteratively with the return value
* of this function.
*
* @param address Beginning flash address to read
* @param len Length request to read
* @param align_addr Output of the aligned address to read
* @param page_size Physical page size of the flash chip
* @return Length that can be actually read in one `read` call
*/
int (*read_data_slicer)(spi_flash_host_inst_t *host, uint32_t address, uint32_t len, uint32_t *align_addr, uint32_t page_size);
/**
* Check whether the host is idle to perform new operations.
*/
bool (*host_idle)(spi_flash_host_inst_t *host);
/**
* Configure the host to work at different read mode. Responsible to compensate the timing and set IO mode.
*/
esp_err_t (*configure_host_io_mode)(spi_flash_host_inst_t *host, uint32_t command,
uint32_t addr_bitlen, int dummy_bitlen_base,
esp_flash_io_mode_t io_mode);
/**
* Internal use, poll the HW until the last operation is done.
*/
void (*poll_cmd_done)(spi_flash_host_inst_t *host);
/**
* For some host (SPI1), they are shared with a cache. When the data is
* modified, the cache needs to be flushed. Left NULL if not supported.
*/
esp_err_t (*flush_cache)(spi_flash_host_inst_t* host, uint32_t addr, uint32_t size);
};
///Slowest io mode supported by ESP32, currently SlowRd
#define SPI_FLASH_READ_MODE_MIN SPI_FLASH_SLOWRD
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,95 @@
// 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.
#ifndef __ESP_PARTITION_H__
#define __ESP_PARTITION_H__
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
ESP_PARTITION_TYPE_APP = 0x00, //!< Application partition type
ESP_PARTITION_TYPE_DATA = 0x01, //!< Data partition type
} esp_partition_type_t;
typedef enum {
ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00, //!< Factory application partition
ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10, //!< Base for OTA partition subtypes
ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0, //!< OTA partition 0
ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1, //!< OTA partition 1
ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2, //!< OTA partition 2
ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3, //!< OTA partition 3
ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4, //!< OTA partition 4
ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5, //!< OTA partition 5
ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6, //!< OTA partition 6
ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7, //!< OTA partition 7
ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8, //!< OTA partition 8
ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9, //!< OTA partition 9
ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10,//!< OTA partition 10
ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11,//!< OTA partition 11
ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12,//!< OTA partition 12
ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13,//!< OTA partition 13
ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14,//!< OTA partition 14
ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15,//!< OTA partition 15
ESP_PARTITION_SUBTYPE_APP_OTA_MAX = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 16,//!< Max subtype of OTA partition
ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, //!< Test application partition
ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, //!< OTA selection partition
ESP_PARTITION_SUBTYPE_DATA_PHY = 0x01, //!< PHY init data partition
ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02, //!< NVS partition
ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition
ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS = 0x04, //!< Partition for NVS keys
ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM = 0x05, //!< Partition for emulate eFuse bits
ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition
ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition
ESP_PARTITION_SUBTYPE_DATA_SPIFFS = 0x82, //!< SPIFFS partition
ESP_PARTITION_SUBTYPE_ANY = 0xff, //!< Used to search for partitions with any subtype
} esp_partition_subtype_t;
/**
* @brief Opaque partition iterator type
*/
typedef struct esp_partition_iterator_opaque_* esp_partition_iterator_t;
/**
* @brief partition information structure
*
* This is not the format in flash, that format is esp_partition_info_t.
*
* However, this is the format used by this API.
*/
typedef struct {
void* flash_chip; /*!< SPI flash chip on which the partition resides */
esp_partition_type_t type; /*!< partition type (app/data) */
esp_partition_subtype_t subtype; /*!< partition subtype */
uint32_t address; /*!< starting address of the partition in flash */
uint32_t size; /*!< size of the partition, in bytes */
char label[17]; /*!< partition label, zero-terminated ASCII string */
bool encrypted; /*!< flag is set to true if partition is encrypted */
} esp_partition_t;
#ifdef __cplusplus
}
#endif
#endif /* __ESP_PARTITION_H__ */

View File

@@ -0,0 +1,149 @@
// 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.
#ifndef __ESP_ATTR_H__
#define __ESP_ATTR_H__
#include "sdkconfig.h"
#define ROMFN_ATTR
//Normally, the linker script will put all code and rodata in flash,
//and all variables in shared RAM. These macros can be used to redirect
//particular functions/variables to other memory regions.
// Forces code into IRAM instead of flash
#define IRAM_ATTR _SECTION_ATTR_IMPL(".iram1", __COUNTER__)
// Forces data into DRAM instead of flash
#define DRAM_ATTR _SECTION_ATTR_IMPL(".dram1", __COUNTER__)
#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
// Forces data into IRAM instead of DRAM
#define IRAM_DATA_ATTR __attribute__((section(".iram.data")))
// Forces data into IRAM instead of DRAM and map it to coredump
#define COREDUMP_IRAM_DATA_ATTR _SECTION_ATTR_IMPL(".iram.data.coredump", __COUNTER__)
// Forces bss into IRAM instead of DRAM
#define IRAM_BSS_ATTR __attribute__((section(".iram.bss")))
#else
#define COREDUMP_IRAM_DATA_ATTR
#define IRAM_DATA_ATTR
#define IRAM_BSS_ATTR
#endif
// Forces data to be 4 bytes aligned
#define WORD_ALIGNED_ATTR __attribute__((aligned(4)))
// Forces data to be placed to DMA-capable places
#define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR
// Forces a function to be inlined
#define FORCE_INLINE_ATTR static inline __attribute__((always_inline))
// Forces a string into DRAM instead of flash
// Use as esp_rom_printf(DRAM_STR("Hello world!\n"));
#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;}))
// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst"
#define RTC_IRAM_ATTR _SECTION_ATTR_IMPL(".rtc.text", __COUNTER__)
#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY
// Forces bss variable into external memory. "
#define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__)
#else
#define EXT_RAM_ATTR
#endif
// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst"
// Any variable marked with this attribute will keep its value
// during a deep sleep / wake cycle.
#define RTC_DATA_ATTR _SECTION_ATTR_IMPL(".rtc.data", __COUNTER__)
// Forces read-only data into RTC memory. See "docs/deep-sleep-stub.rst"
#define RTC_RODATA_ATTR _SECTION_ATTR_IMPL(".rtc.rodata", __COUNTER__)
// Allows to place data into RTC_SLOW memory.
#define RTC_SLOW_ATTR _SECTION_ATTR_IMPL(".rtc.force_slow", __COUNTER__)
// Allows to place data into RTC_FAST memory.
#define RTC_FAST_ATTR _SECTION_ATTR_IMPL(".rtc.force_fast", __COUNTER__)
// Forces data into noinit section to avoid initialization after restart.
#define __NOINIT_ATTR _SECTION_ATTR_IMPL(".noinit", __COUNTER__)
// Forces data into RTC slow memory of .noinit section.
// Any variable marked with this attribute will keep its value
// after restart or during a deep sleep / wake cycle.
#define RTC_NOINIT_ATTR _SECTION_ATTR_IMPL(".rtc_noinit", __COUNTER__)
// Forces code into DRAM instead of flash and map it to coredump
#define COREDUMP_DRAM_ATTR _SECTION_ATTR_IMPL(".dram1.coredump", __COUNTER__)
// Forces data into RTC memory and map it to coredump
#define COREDUMP_RTC_DATA_ATTR _SECTION_ATTR_IMPL(".rtc.coredump", __COUNTER__)
// Allows to place data into RTC_FAST memory and map it to coredump
#define COREDUMP_RTC_FAST_ATTR _SECTION_ATTR_IMPL(".rtc.fast.coredump", __COUNTER__)
// Forces to not inline function
#define NOINLINE_ATTR __attribute__((noinline))
// This allows using enum as flags in C++
// Format: FLAG_ATTR(flag_enum_t)
#ifdef __cplusplus
// Inline is required here to avoid multiple definition error in linker
#define FLAG_ATTR_IMPL(TYPE, INT_TYPE) \
FORCE_INLINE_ATTR constexpr TYPE operator~ (TYPE a) { return (TYPE)~(INT_TYPE)a; } \
FORCE_INLINE_ATTR constexpr TYPE operator| (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a | (INT_TYPE)b); } \
FORCE_INLINE_ATTR constexpr TYPE operator& (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a & (INT_TYPE)b); } \
FORCE_INLINE_ATTR constexpr TYPE operator^ (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a ^ (INT_TYPE)b); } \
FORCE_INLINE_ATTR constexpr TYPE operator>> (TYPE a, int b) { return (TYPE)((INT_TYPE)a >> b); } \
FORCE_INLINE_ATTR constexpr TYPE operator<< (TYPE a, int b) { return (TYPE)((INT_TYPE)a << b); } \
FORCE_INLINE_ATTR TYPE& operator|=(TYPE& a, TYPE b) { a = a | b; return a; } \
FORCE_INLINE_ATTR TYPE& operator&=(TYPE& a, TYPE b) { a = a & b; return a; } \
FORCE_INLINE_ATTR TYPE& operator^=(TYPE& a, TYPE b) { a = a ^ b; return a; } \
FORCE_INLINE_ATTR TYPE& operator>>=(TYPE& a, int b) { a >>= b; return a; } \
FORCE_INLINE_ATTR TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; }
#define FLAG_ATTR_U32(TYPE) FLAG_ATTR_IMPL(TYPE, uint32_t)
#define FLAG_ATTR FLAG_ATTR_U32
#else
#define FLAG_ATTR(TYPE)
#endif
// Implementation for a unique custom section
//
// This prevents gcc producing "x causes a section type conflict with y"
// errors if two variables in the same source file have different linkage (maybe const & non-const) but are placed in the same custom section
//
// Using unique sections also means --gc-sections can remove unused
// data with a custom section type set
#define _SECTION_ATTR_IMPL(SECTION, COUNTER) __attribute__((section(SECTION "." _COUNTER_STRINGIFY(COUNTER))))
#define _COUNTER_STRINGIFY(COUNTER) #COUNTER
/* Use IDF_DEPRECATED attribute to mark anything deprecated from use in
ESP-IDF's own source code, but not deprecated for external users.
*/
#ifdef IDF_CI_BUILD
#define IDF_DEPRECATED(REASON) __attribute__((deprecated(REASON)))
#else
#define IDF_DEPRECATED(REASON)
#endif
#endif /* __ESP_ATTR_H__ */

View File

@@ -1,6 +1,9 @@
set(srcs
"unity/src/unity.c"
"unity_port_esp32.c")
"unity/src/unity.c")
set(includes
"include"
"unity/src")
if(CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL)
list(APPEND COMPONENT_PRIV_INCLUDEDIRS "include/priv")
@@ -12,13 +15,24 @@ endif()
if(CONFIG_UNITY_ENABLE_FIXTURE)
list(APPEND srcs "unity/extras/fixture/src/unity_fixture.c")
list(APPEND includes "unity/extras/fixture/src")
endif()
if(${IDF_TARGET} STREQUAL "linux")
message(STATUS "adding linux stuff...")
idf_component_get_property(spi_flash_dir spi_flash COMPONENT_DIR)
list(APPEND includes "${spi_flash_dir}/sim/stubs/esp_common")
else()
list(APPEND srcs "unity_port_esp32.c")
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include" "unity/src" "unity/extras/fixture/src")
INCLUDE_DIRS ${includes})
target_compile_definitions(${COMPONENT_LIB} PUBLIC
-DUNITY_INCLUDE_CONFIG_H
)
if(NOT ${IDF_TARGET} STREQUAL "linux")
target_compile_definitions(${COMPONENT_LIB} PUBLIC
-DUNITY_INCLUDE_CONFIG_H
)
endif()
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-unused-const-variable)

View File

@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
set(COMPONENTS main)
project(linux_host_app)

View File

@@ -0,0 +1,8 @@
| Supported Targets | Linux |
| ----------------- | ----- |
# Build
`idf.py build` (sdkconfig.defaults sets the linux target by default)
# Run
`build/linux_host_app.elf`

View File

@@ -0,0 +1 @@
idf_component_register(SRCS "linux_host_app.cpp")

View File

@@ -0,0 +1,20 @@
/* Hello World Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "stdio.h"
void app_main() {
printf("Hello, Host!\n");
}
int main(int argc, char **argv)
{
app_main();
return 0;
}

View File

@@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="linux"
CONFIG_CXX_EXCEPTIONS=y

View File

@@ -151,12 +151,16 @@ function(__build_init idf_path)
endif()
endforeach()
# Set components required by all other components in the build
#
# - lwip is here so that #include <sys/socket.h> works without any special provisions
# - esp_hw_support is here for backward compatibility
set(requires_common cxx newlib freertos esp_hw_support heap log lwip soc hal esp_rom esp_common esp_system)
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${requires_common}")
idf_build_get_property(target IDF_TARGET)
if(NOT target STREQUAL "linux")
# Set components required by all other components in the build
#
# - lwip is here so that #include <sys/socket.h> works without any special provisions
# - esp_hw_support is here for backward compatibility
set(requires_common cxx newlib freertos esp_hw_support heap log lwip soc hal esp_rom esp_common esp_system)
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "${requires_common}")
endif()
__build_get_idf_git_revision()
__kconfig_init()
@@ -397,7 +401,13 @@ macro(idf_build_process target)
# Check for required Python modules
__build_check_python()
idf_build_set_property(__COMPONENT_REQUIRES_COMMON ${target} APPEND)
idf_build_get_property(target IDF_TARGET)
if(NOT target STREQUAL "linux")
idf_build_set_property(__COMPONENT_REQUIRES_COMMON ${target} APPEND)
else()
idf_build_set_property(__COMPONENT_REQUIRES_COMMON "")
endif()
# Perform early expansion of component CMakeLists.txt in CMake scripting mode.
# It is here we retrieve the public and private requirements of each component.

View File

@@ -463,7 +463,9 @@ function(idf_component_register)
idf_build_get_property(compile_definitions COMPILE_DEFINITIONS GENERATOR_EXPRESSION)
add_compile_options("${compile_definitions}")
list(REMOVE_ITEM common_reqs ${component_lib})
if(common_reqs) # check whether common_reqs exists, this may be the case in minimalistic host unit test builds
list(REMOVE_ITEM common_reqs ${component_lib})
endif()
link_libraries(${common_reqs})
idf_build_get_property(config_dir CONFIG_DIR)
@@ -475,7 +477,7 @@ function(idf_component_register)
__component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" PUBLIC)
__component_add_include_dirs(${component_lib} "${__PRIV_INCLUDE_DIRS}" PRIVATE)
__component_add_include_dirs(${component_lib} "${config_dir}" PUBLIC)
set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME})
set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME} LINKER_LANGUAGE C)
__ldgen_add_component(${component_lib})
else()
add_library(${component_lib} INTERFACE)

View File

@@ -9,6 +9,8 @@ function(__add_dfu_targets)
set(dfu_pid "2")
elseif("${target}" STREQUAL "esp32s3")
set(dfu_pid "4")
elseif("${target}" STREQUAL "linux")
return()
else()
message(FATAL_ERROR "DFU PID unknown for ${target}")
endif()

View File

@@ -0,0 +1,8 @@
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER gcc)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_ASM_COMPILER gcc)
set(CMAKE_C_FLAGS "-Wno-frame-address" CACHE STRING "C Compiler Base Flags")
set(CMAKE_CXX_FLAGS "-Wno-frame-address" CACHE STRING "C++ Compiler Base Flags")

View File

@@ -289,12 +289,13 @@ class BuildSystem:
Objects of these classes aren't instantiated, instead the class (type object) is used.
"""
NAME = "undefined"
SUPPORTED_TARGETS_REGEX = re.compile(r'Supported [Tt]argets((?:[\s|]+(?:ESP[0-9A-Z\-]+))+)')
SUPPORTED_TARGETS_REGEX = re.compile(r'Supported [Tt]argets((?:[ |]+(?:[0-9a-zA-Z\-]+))+)')
FORMAL_TO_USUAL = {
'ESP32': 'esp32',
'ESP32-S2': 'esp32s2',
'ESP32-S3': 'esp32s3',
'Linux': 'linux',
}
@classmethod

View File

@@ -46,7 +46,9 @@ ignore_files = [os.path.join('components', 'mdns', 'test_afl_fuzz_host', 'esp32_
]
# add directories here which should not be parsed, this is a tuple since it will be used with *.startswith()
ignore_dirs = (os.path.join('examples'), os.path.join('components', 'cmock', 'CMock', 'test'))
ignore_dirs = (os.path.join('examples'),
os.path.join('components', 'cmock', 'CMock', 'test'),
os.path.join('components', 'spi_flash', 'sim'))
# macros from here have higher priorities in case of collisions
priority_headers = [os.path.join('components', 'esp_common', 'include', 'esp_err.h')]

View File

@@ -38,4 +38,4 @@ GENERATORS = collections.OrderedDict([
SUPPORTED_TARGETS = ["esp32", "esp32s2"]
PREVIEW_TARGETS = ["esp32s3"]
PREVIEW_TARGETS = ["esp32s3", "linux"]