Merge branch 'feature/host_side_storage_components' into 'master'

Runnable FS components on host

See merge request idf/esp-idf!2431
This commit is contained in:
Ivan Grokhotkov 2018-06-08 11:42:37 +08:00
commit 40596fa55a
66 changed files with 1734 additions and 478 deletions

View file

@ -285,6 +285,26 @@ test_wl_on_host:
- cd components/wear_levelling/test_wl_host - cd components/wear_levelling/test_wl_host
- make test - make test
test_fatfs_on_host:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- wl_host_test
dependencies: []
script:
- cd components/fatfs/test_fatfs_host/
- make test
test_spiffs_on_host:
stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
tags:
- wl_host_test
dependencies: []
script:
- cd components/spiffs/test_spiffs_host/
- make test
test_multi_heap_on_host: test_multi_heap_on_host:
stage: test stage: test
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG

View file

@ -0,0 +1,103 @@
COMPONENT=fatfs
TEST_PROGRAM=test_$(COMPONENT)
#Expose as a library
COMPONENT_LIB=lib$(COMPONENT).a
#Use wear levelling and flash simulation
WEAR_LEVELLING=wear_levelling
WEAR_LEVELLING_DIR=../../$(WEAR_LEVELLING)
WEAR_LEVELLING_HOST_DIR=$(WEAR_LEVELLING_DIR)/test_wl_host
WEAR_LEVELLING_LIB=lib$(WEAR_LEVELLING).a
SPI_FLASH=spi_flash
SPI_FLASH_DIR=../../$(SPI_FLASH)
SPI_FLASH_SIM_DIR=$(SPI_FLASH_DIR)/sim
SPI_FLASH_LIB=lib$(SPI_FLASH).a
all: $(TEST_PROGRAM)
SOURCE_FILES = \
$(addprefix ../src/, \
diskio.c \
ff.c \
ffsystem.c \
ffunicode.c \
diskio_spiflash.c \
) \
$(addprefix ./stubs/, log/log.c)
TEST_SOURCE_FILES = \
test_fatfs.cpp \
main.cpp \
test_utils.c
INCLUDE_FLAGS = $(addprefix -I,\
../src \
. \
$(addprefix ./stubs/, \
driver/include \
freertos/include \
sdmmc/include \
log/include \
) \
$(SPI_FLASH_DIR)/include \
$(WEAR_LEVELLING_DIR)/include \
../../esp32/include \
../../../tools/catch \
)
GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o))
$(WEAR_LEVELLING_HOST_DIR)/$(WEAR_LEVELLING_LIB): force
$(MAKE) -C $(WEAR_LEVELLING_HOST_DIR) lib
$(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB): force
$(MAKE) -C $(SPI_FLASH_SIM_DIR) lib
force:
$(COMPONENT_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^
lib: $(COMPONENT_LIB)
partition_table.bin: partition_table.csv
python ../../partition_table/gen_esp32part.py --verify $< $@
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB) $(WEAR_LEVELLING_HOST_DIR)/$(WEAR_LEVELLING_LIB) partition_table.bin
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(TEST_OBJ_FILES) -L$(abspath .) -l:$(COMPONENT_LIB) -L$(SPI_FLASH_SIM_DIR) -l:$(SPI_FLASH_LIB) -L$(WEAR_LEVELLING_HOST_DIR) -l:$(WEAR_LEVELLING_LIB) -g -m32
test: $(TEST_PROGRAM)
./$(TEST_PROGRAM)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): test
coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
lcov --capture --directory ../ --no-external --output-file coverage.info --gcov-tool $(GCOV)
coverage_report: coverage.info
genhtml coverage.info --output-directory coverage_report
@echo "Coverage report is in coverage_report/index.html"
clean:
rm -f $(OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(COMPONENT_LIB) partition_table.bin
$(MAKE) -C $(WEAR_LEVELLING_HOST_DIR) clean
$(MAKE) -C $(SPI_FLASH_SIM_DIR) clean
rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/
rm -f coverage.info
.PHONY: clean all test lib

View file

@ -0,0 +1,2 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View file

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M,

View file

@ -0,0 +1,3 @@
# pragma once
#define CONFIG_WL_SECTOR_SIZE 4096

View file

@ -0,0 +1,6 @@
#pragma once
#include <stdlib.h>
#include "sdmmc_types.h"

View file

@ -0,0 +1,11 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
typedef int sdmmc_card_t;
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,4 @@
#pragma once
#include "projdefs.h"
#include "semphr.h"

View file

@ -0,0 +1,11 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define pdTRUE 1
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,16 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define vSemaphoreDelete( xSemaphore )
#define xSemaphoreCreateMutex() ((void*)(1))
#define xSemaphoreGive( xSemaphore )
#define xSemaphoreTake( xSemaphore, xBlockTime ) pdTRUE
typedef void* SemaphoreHandle_t;
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,45 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#include "sdkconfig.h"
#if defined(__cplusplus)
extern "C" { // Make sure we have C-declarations in C++ programs
#endif
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
typedef enum {
ESP_LOG_NONE, /*!< No log output */
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
} esp_log_level_t;
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#define LOG_RESET_COLOR
uint32_t esp_log_timestamp(void);
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#if defined(__cplusplus)
}
#endif

View file

@ -1,4 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "esp_log.h" #include "esp_log.h"
void esp_log_write(esp_log_level_t level, void esp_log_write(esp_log_level_t level,
@ -14,4 +17,4 @@ void esp_log_write(esp_log_level_t level,
uint32_t esp_log_timestamp() uint32_t esp_log_timestamp()
{ {
return 0; return 0;
} }

View file

@ -0,0 +1,3 @@
#pragma once
#include "esp_err.h"

View file

@ -0,0 +1,93 @@
#include <stdio.h>
#include <string.h>
#include "ff.h"
#include "esp_partition.h"
#include "wear_levelling.h"
#include "diskio.h"
#include "diskio_spiflash.h"
#include "catch.hpp"
extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
TEST_CASE("create volume, open file, write and read back data", "[fatfs]")
{
init_spi_flash(0x00400000, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
FRESULT fr_result;
BYTE pdrv;
FATFS fs;
FIL file;
UINT bw;
esp_err_t esp_result;
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, "storage");
// Mount wear-levelled partition
wl_handle_t wl_handle;
esp_result = wl_mount(partition, &wl_handle);
REQUIRE(esp_result == ESP_OK);
// Get a physical drive
esp_result = ff_diskio_get_drive(&pdrv);
REQUIRE(esp_result == ESP_OK);
// Register physical drive as wear-levelled partition
esp_result = ff_diskio_register_wl_partition(pdrv, wl_handle);
// Create FAT volume on the entire disk
DWORD part_list[] = {100, 0, 0, 0};
BYTE work_area[FF_MAX_SS];
fr_result = f_fdisk(pdrv, part_list, work_area);
REQUIRE(fr_result == FR_OK);
fr_result = f_mkfs("", FM_ANY, 0, work_area, sizeof(work_area)); // Use default volume
// Mount the volume
fr_result = f_mount(&fs, "", 0);
REQUIRE(fr_result == FR_OK);
// Open, write and read data
fr_result = f_open(&file, "test.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
REQUIRE(fr_result == FR_OK);
// Generate data
uint32_t data_size = 100000;
char *data = (char*) malloc(data_size);
char *read = (char*) malloc(data_size);
for(uint32_t i = 0; i < data_size; i += sizeof(i))
{
*((uint32_t*)(data + i)) = i;
}
// Write generated data
fr_result = f_write(&file, data, data_size, &bw);
REQUIRE(fr_result == FR_OK);
REQUIRE(bw == data_size);
// Move to beginning of file
fr_result = f_lseek(&file, 0);
REQUIRE(fr_result == FR_OK);
// Read written data
fr_result = f_read(&file, read, data_size, &bw);
REQUIRE(fr_result == FR_OK);
REQUIRE(bw == data_size);
REQUIRE(memcmp(data, read, data_size) == 0);
// Close file
fr_result = f_close(&file);
REQUIRE(fr_result == FR_OK);
// Unmount default volume
fr_result = f_mount(0, "", 0);
REQUIRE(fr_result == FR_OK);
free(read);
free(data);
}

View file

@ -0,0 +1,7 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}

View file

@ -0,0 +1,67 @@
COMPONENT=spi_flash
COMPONENT_LIB=lib$(COMPONENT).a
all: lib
SOURCE_FILES = \
../partition.c \
../flash_ops.c \
SpiFlash.cpp \
flash_mock_util.c \
flash_mock.cpp \
$(addprefix stubs/, \
newlib/lock.c \
app_update/esp_ota_eps.c \
)
INCLUDE_FLAGS = $(addprefix -I,\
. \
../include \
../../esp32/include/ \
$(addprefix stubs/, \
newlib/include \
log/include \
freertos/include \
) \
$(addprefix ../../../components/, \
soc/esp32/include \
esp32/include \
bootloader_support/include \
app_update/include \
) \
../../../tools/catch \
)
GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
$(COMPONENT_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^
lib: $(COMPONENT_LIB)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): lib
coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
lcov --capture --directory ../ --no-external --output-file coverage.info --gcov-tool $(GCOV)
coverage_report: coverage.info
genhtml coverage.info --output-directory coverage_report
@echo "Coverage report is in coverage_report/index.html"
clean:
rm -f $(OBJ_FILES) $(COMPONENT_LIB)
rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/
rm -f coverage.info
.PHONY: clean lib all

View file

@ -0,0 +1,126 @@
// Copyright 2015-2017 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 "SpiFlash.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include "esp_flash_data_types.h"
using namespace std;
SpiFlash::SpiFlash()
{
return;
}
SpiFlash::~SpiFlash()
{
deinit();
}
void SpiFlash::init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin)
{
// De-initialize first
deinit();
this->chip_size = chip_size;
this->block_size = block_size;
this->sector_size = sector_size;
this->page_size = page_size;
this->memory = (uint8_t *) malloc(this->chip_size);
memset(this->memory, 0xFF, this->chip_size);
ifstream ifd(partitions_bin, ios::binary | ios::ate);
int size = ifd.tellg();
ifd.seekg(0, ios::beg);
vector<char> buffer;
buffer.resize(size);
ifd.read(buffer.data(), size);
memcpy(&this->memory[ESP_PARTITION_TABLE_ADDR], buffer.data(), buffer.size());
}
void SpiFlash::deinit()
{
if(inited)
{
free(this->memory);
}
}
size_t SpiFlash::get_chip_size()
{
return this->chip_size;
}
size_t SpiFlash::get_sector_size()
{
return this->sector_size;
}
esp_rom_spiflash_result_t SpiFlash::erase_block(uint32_t block)
{
memset(&this->memory[block * this->block_size], 0xFF, this->block_size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::erase_sector(size_t sector)
{
memset(&this->memory[sector * this->sector_size], 0xFF, this->sector_size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::erase_page(uint32_t page)
{
memset(&this->memory[page * this->page_size], 0xFF, this->page_size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::write(size_t dest_addr, const void *src, size_t size)
{
// Emulate inability to set programmed bits without erasing
for(uint32_t ctr = 0; ctr < size; ctr++)
{
uint8_t data = ((uint8_t*)src)[ctr];
uint8_t written = this->memory[dest_addr + ctr];
data &= written;
this->memory[dest_addr + ctr] = data;
}
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::read(size_t src_addr, void *dest, size_t size)
{
memcpy(dest, &this->memory[src_addr], size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
uint8_t* SpiFlash::get_memory_ptr(uint32_t src_address)
{
return &this->memory[src_address];
}

View file

@ -0,0 +1,62 @@
// Copyright 2015-2017 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 _SpiFlash_H_
#define _SpiFlash_H_
#include "esp_err.h"
#include "rom/spi_flash.h"
/**
* @brief This class is used to emulate flash devices.
*
*/
class SpiFlash
{
public:
SpiFlash();
~SpiFlash();
void init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin);
esp_rom_spiflash_result_t erase_block(uint32_t block);
esp_rom_spiflash_result_t erase_sector(uint32_t sector);
esp_rom_spiflash_result_t erase_page(uint32_t page);
esp_rom_spiflash_result_t write(size_t dest_addr, const void *src, size_t size);
esp_rom_spiflash_result_t read(size_t src_addr, void *dest, size_t size);
size_t get_chip_size();
size_t get_sector_size();
uint8_t* get_memory_ptr(uint32_t src_address);
private:
bool inited = false;
size_t chip_size;
size_t block_size;
size_t sector_size;
size_t page_size;
uint8_t* memory;
void* partitions;
uint8_t partitions_num;
void deinit();
};
#endif // _SpiFlash_H_

View file

@ -0,0 +1,65 @@
#include "SpiFlash.h"
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "esp_err.h"
#include "rom/spi_flash.h"
static SpiFlash spiflash = SpiFlash();
esp_rom_spiflash_chip_t g_rom_flashchip;
extern "C" void _spi_flash_init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin)
{
spiflash.init(chip_size, block_size, sector_size, page_size, partitions_bin);
g_rom_flashchip.chip_size = chip_size;
g_rom_flashchip.block_size = block_size;
g_rom_flashchip.sector_size = sector_size;
g_rom_flashchip.page_size = page_size;
}
esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
const void** out_ptr, spi_flash_mmap_handle_t* out_handle)
{
*out_handle = 0;
*out_ptr = (void*)spiflash.get_memory_ptr(src_addr);
return ESP_OK;
}
void spi_flash_munmap(spi_flash_mmap_handle_t handle)
{
return;
}
esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t target, uint32_t *dest, int32_t len)
{
return spiflash.read(target, dest, len);
}
esp_rom_spiflash_result_t esp_rom_spiflash_erase_block(uint32_t block)
{
return spiflash.erase_block(block);
}
esp_rom_spiflash_result_t esp_rom_spiflash_erase_sector(uint32_t sector)
{
return spiflash.erase_sector(sector);
}
esp_rom_spiflash_result_t esp_rom_spiflash_erase_page(uint32_t page)
{
return spiflash.erase_page(page);
}
esp_rom_spiflash_result_t esp_rom_spiflash_write(uint32_t target, const uint32_t *src, int32_t len)
{
return spiflash.write(target, src, len);
}
esp_rom_spiflash_result_t esp_rom_spiflash_write_encrypted(uint32_t flash_addr, uint32_t *data, uint32_t len)
{
return spiflash.write(flash_addr, data, len);
}

View file

@ -0,0 +1,57 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "esp_err.h"
#include "rom/spi_flash.h"
extern void _spi_flash_init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
void spi_flash_init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
_spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}
void spi_flash_mark_modified_region(size_t start_addr, size_t length)
{
return;
}
esp_rom_spiflash_result_t esp_rom_spiflash_unlock()
{
return ESP_ROM_SPIFLASH_RESULT_OK;
}
void spi_flash_init_lock()
{
return;
}
void spi_flash_op_lock()
{
return;
}
void spi_flash_op_unlock()
{
return;
}
void spi_flash_disable_interrupts_caches_and_other_cpu()
{
return;
}
void spi_flash_enable_interrupts_caches_and_other_cpu()
{
return;
}
void spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
{
return;
}
void spi_flash_enable_interrupts_caches_no_os()
{
return;
}

View file

@ -0,0 +1,2 @@
#pragma once

View file

@ -0,0 +1,13 @@
#include "esp_ota_ops.h"
#include "esp_partition.h"
const esp_partition_t* esp_ota_get_running_partition(void)
{
// Return first instance of an app partition
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
ESP_PARTITION_SUBTYPE_ANY,
NULL);
assert(partition != NULL);
return partition;
}

View file

@ -0,0 +1,8 @@
#pragma once
#include "projdefs.h"
#include "semphr.h"
// Avoid redefinition compile error. Put here since this is included
// in flash_ops.c.
#define spi_flash_init() overriden_spi_flash_init()

View file

@ -0,0 +1,11 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define pdTRUE 1
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,16 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define vSemaphoreDelete( xSemaphore )
#define xSemaphoreCreateMutex() ((void*)(1))
#define xSemaphoreGive( xSemaphore )
#define xSemaphoreTake( xSemaphore, xBlockTime ) pdTRUE
typedef void* SemaphoreHandle_t;
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1 @@
#pragma once

View file

@ -0,0 +1,48 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
typedef enum {
ESP_LOG_NONE, /*!< No log output */
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
} esp_log_level_t;
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#define LOG_RESET_COLOR
uint32_t esp_log_timestamp(void);
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
// Assume that flash encryption is not enabled. Put here since in partition.c
// esp_log.h is included later than esp_flash_encrypt.h.
#define esp_flash_encryption_enabled() false
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include "esp_log.h"
void esp_log_write(esp_log_level_t level,
const char *tag,
const char *format, ...)
{
va_list arg;
va_start(arg, format);
vprintf(format, arg);
va_end(arg);
}
uint32_t esp_log_timestamp()
{
return 0;
}

View file

@ -0,0 +1,17 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef int _lock_t;
void _lock_acquire(_lock_t *lock);
void _lock_close(_lock_t *lock);
void _lock_init(_lock_t *lock);
void _lock_release(_lock_t *lock);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,21 @@
#include "sys/lock.h"
void _lock_acquire(_lock_t *lock)
{
return;
}
void _lock_close(_lock_t *lock)
{
return;
}
void _lock_init(_lock_t *lock)
{
return;
}
void _lock_release(_lock_t *lock)
{
return;
}

View file

@ -1,5 +1,5 @@
COMPONENT_ADD_INCLUDEDIRS := include COMPONENT_ADD_INCLUDEDIRS := include
COMPONENT_PRIV_INCLUDEDIRS := spiffs/src COMPONENT_PRIV_INCLUDEDIRS := . spiffs/src
COMPONENT_SRCDIRS := . spiffs/src COMPONENT_SRCDIRS := . spiffs/src
COMPONENT_SUBMODULES := spiffs COMPONENT_SUBMODULES := spiffs

View file

@ -30,29 +30,12 @@
#include "esp_vfs.h" #include "esp_vfs.h"
#include "esp_err.h" #include "esp_err.h"
#include "rom/spi_flash.h" #include "rom/spi_flash.h"
#include "spiffs_api.h"
static const char * TAG = "SPIFFS";
#ifdef CONFIG_SPIFFS_USE_MTIME #ifdef CONFIG_SPIFFS_USE_MTIME
_Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t), _Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t),
"SPIFFS_META_LENGTH size should be >= sizeof(time_t)"); "SPIFFS_META_LENGTH size should be >= sizeof(time_t)");
#endif //CONFIG_SPIFFS_USE_MTIME #endif //CONFIG_SPIFFS_USE_MTIME
/**
* @brief SPIFFS definition structure
*/
typedef struct {
spiffs *fs; /*!< Handle to the underlying SPIFFS */
SemaphoreHandle_t lock; /*!< FS lock */
const esp_partition_t* partition; /*!< The partition on which SPIFFS is located */
char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */
bool by_label; /*!< Partition was mounted by label */
spiffs_config cfg; /*!< SPIFFS Mount configuration */
uint8_t *work; /*!< Work Buffer */
uint8_t *fds; /*!< File Descriptor Buffer */
uint32_t fds_sz; /*!< File Descriptor Buffer Length */
uint8_t *cache; /*!< Cache Buffer */
uint32_t cache_sz; /*!< Cache Buffer Length */
} esp_spiffs_t;
/** /**
* @brief SPIFFS DIR structure * @brief SPIFFS DIR structure
@ -89,77 +72,6 @@ static time_t vfs_spiffs_get_mtime(const spiffs_stat* s);
static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS]; static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS];
void spiffs_api_lock(spiffs *fs)
{
xSemaphoreTake(((esp_spiffs_t *)(fs->user_data))->lock, portMAX_DELAY);
}
void spiffs_api_unlock(spiffs *fs)
{
xSemaphoreGive(((esp_spiffs_t *)(fs->user_data))->lock);
}
static s32_t spiffs_api_read(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *dst)
{
esp_err_t err = esp_partition_read(((esp_spiffs_t *)(fs->user_data))->partition,
addr, dst, size);
if (err) {
ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", addr, size, err);
return -1;
}
return 0;
}
static s32_t spiffs_api_write(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *src)
{
esp_err_t err = esp_partition_write(((esp_spiffs_t *)(fs->user_data))->partition,
addr, src, size);
if (err) {
ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", addr, size, err);
return -1;
}
return 0;
}
static s32_t spiffs_api_erase(spiffs *fs, uint32_t addr, uint32_t size)
{
esp_err_t err = esp_partition_erase_range(((esp_spiffs_t *)(fs->user_data))->partition,
addr, size);
if (err) {
ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", addr, size, err);
return -1;
}
return 0;
}
static void spiffs_api_check(spiffs *fs, spiffs_check_type type,
spiffs_check_report report, uint32_t arg1, uint32_t arg2)
{
static const char * spiffs_check_type_str[3] = {
"LOOKUP",
"INDEX",
"PAGE"
};
static const char * spiffs_check_report_str[7] = {
"PROGRESS",
"ERROR",
"FIX INDEX",
"FIX LOOKUP",
"DELETE ORPHANED INDEX",
"DELETE PAGE",
"DELETE BAD FILE"
};
if (report != SPIFFS_CHECK_PROGRESS) {
ESP_LOGE(TAG, "CHECK: type:%s, report:%s, %x:%x", spiffs_check_type_str[type],
spiffs_check_report_str[report], arg1, arg2);
} else {
ESP_LOGV(TAG, "CHECK PROGRESS: report:%s, %x:%x",
spiffs_check_report_str[report], arg1, arg2);
}
}
static void esp_spiffs_free(esp_spiffs_t ** efs) static void esp_spiffs_free(esp_spiffs_t ** efs)
{ {
esp_spiffs_t * e = *efs; esp_spiffs_t * e = *efs;
@ -232,7 +144,7 @@ static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
esp_partition_subtype_t subtype = conf->partition_label ? esp_partition_subtype_t subtype = conf->partition_label ?
ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS; ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS;
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
subtype, conf->partition_label); subtype, conf->partition_label);
if (!partition) { if (!partition) {
ESP_LOGE(TAG, "spiffs partition could not be found"); ESP_LOGE(TAG, "spiffs partition could not be found");
@ -310,7 +222,7 @@ static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
efs->fs->user_data = (void *)efs; efs->fs->user_data = (void *)efs;
efs->partition = partition; efs->partition = partition;
s32_t res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz, s32_t res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
efs->cache, efs->cache_sz, spiffs_api_check); efs->cache, efs->cache_sz, spiffs_api_check);
if (conf->format_if_mount_failed && res != SPIFFS_OK) { if (conf->format_if_mount_failed && res != SPIFFS_OK) {
@ -323,7 +235,7 @@ static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
esp_spiffs_free(&efs); esp_spiffs_free(&efs);
return ESP_FAIL; return ESP_FAIL;
} }
res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz, res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
efs->cache, efs->cache_sz, spiffs_api_check); efs->cache, efs->cache_sz, spiffs_api_check);
} }
if (res != SPIFFS_OK) { if (res != SPIFFS_OK) {
@ -710,7 +622,7 @@ static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir)
return out_dirent; return out_dirent;
} }
static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry, static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry,
struct dirent** out_dirent) struct dirent** out_dirent)
{ {
assert(pdir); assert(pdir);

View file

@ -0,0 +1,93 @@
// Copyright 2015-2017 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 "freertos/FreeRTOS.h"
#include "esp_log.h"
#include "esp_partition.h"
#include "esp_spiffs.h"
#include "esp_vfs.h"
#include "spiffs_api.h"
const char* TAG = "SPIFFS";
void spiffs_api_lock(spiffs *fs)
{
xSemaphoreTake(((esp_spiffs_t *)(fs->user_data))->lock, portMAX_DELAY);
}
void spiffs_api_unlock(spiffs *fs)
{
xSemaphoreGive(((esp_spiffs_t *)(fs->user_data))->lock);
}
s32_t spiffs_api_read(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *dst)
{
esp_err_t err = esp_partition_read(((esp_spiffs_t *)(fs->user_data))->partition,
addr, dst, size);
if (err) {
ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", addr, size, err);
return -1;
}
return 0;
}
s32_t spiffs_api_write(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *src)
{
esp_err_t err = esp_partition_write(((esp_spiffs_t *)(fs->user_data))->partition,
addr, src, size);
if (err) {
ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", addr, size, err);
return -1;
}
return 0;
}
s32_t spiffs_api_erase(spiffs *fs, uint32_t addr, uint32_t size)
{
esp_err_t err = esp_partition_erase_range(((esp_spiffs_t *)(fs->user_data))->partition,
addr, size);
if (err) {
ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", addr, size, err);
return -1;
}
return 0;
}
void spiffs_api_check(spiffs *fs, spiffs_check_type type,
spiffs_check_report report, uint32_t arg1, uint32_t arg2)
{
static const char * spiffs_check_type_str[3] = {
"LOOKUP",
"INDEX",
"PAGE"
};
static const char * spiffs_check_report_str[7] = {
"PROGRESS",
"ERROR",
"FIX INDEX",
"FIX LOOKUP",
"DELETE ORPHANED INDEX",
"DELETE PAGE",
"DELETE BAD FILE"
};
if (report != SPIFFS_CHECK_PROGRESS) {
ESP_LOGE(TAG, "CHECK: type:%s, report:%s, %x:%x", spiffs_check_type_str[type],
spiffs_check_report_str[report], arg1, arg2);
} else {
ESP_LOGV(TAG, "CHECK PROGRESS: report:%s, %x:%x",
spiffs_check_report_str[report], arg1, arg2);
}
}

View file

@ -0,0 +1,59 @@
// Copyright 2015-2017 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 <stddef.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "spiffs.h"
#include "esp_vfs.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const char* TAG;
/**
* @brief SPIFFS definition structure
*/
typedef struct {
spiffs *fs; /*!< Handle to the underlying SPIFFS */
SemaphoreHandle_t lock; /*!< FS lock */
const esp_partition_t* partition; /*!< The partition on which SPIFFS is located */
char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */
bool by_label; /*!< Partition was mounted by label */
spiffs_config cfg; /*!< SPIFFS Mount configuration */
uint8_t *work; /*!< Work Buffer */
uint8_t *fds; /*!< File Descriptor Buffer */
uint32_t fds_sz; /*!< File Descriptor Buffer Length */
uint8_t *cache; /*!< Cache Buffer */
uint32_t cache_sz; /*!< Cache Buffer Length */
} esp_spiffs_t;
s32_t spiffs_api_read(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *dst);
s32_t spiffs_api_write(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *src);
s32_t spiffs_api_erase(spiffs *fs, uint32_t addr, uint32_t size);
void spiffs_api_check(spiffs *fs, spiffs_check_type type,
spiffs_check_report report, uint32_t arg1, uint32_t arg2);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,97 @@
COMPONENT=spiffs
TEST_PROGRAM=test_$(COMPONENT)
#Expose as a library
COMPONENT_LIB=lib$(COMPONENT).a
SPI_FLASH=spi_flash
SPI_FLASH_DIR=../../$(SPI_FLASH)
SPI_FLASH_SIM_DIR=$(SPI_FLASH_DIR)/sim
SPI_FLASH_LIB=lib$(SPI_FLASH).a
all: $(TEST_PROGRAM)
SOURCE_FILES = \
../spiffs_api.c \
$(addprefix ../spiffs/src/, \
spiffs_cache.c \
spiffs_check.c \
spiffs_gc.c \
spiffs_hydrogen.c \
spiffs_nucleus.c \
) \
$(addprefix ./stubs/, \
log/log.c \
)
TEST_SOURCE_FILES = \
test_spiffs.cpp \
main.cpp \
test_utils.c
INCLUDE_FLAGS = $(addprefix -I,\
. \
.. \
../spiffs/src \
../include \
$(addprefix ./stubs/, \
log/include \
freertos/include \
newlib/include \
vfs/include \
) \
../../esp32/include \
$(SPI_FLASH_DIR)/include \
../../../tools/catch \
)
GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o))
$(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB): force
$(MAKE) -C $(SPI_FLASH_SIM_DIR) lib
force:
$(COMPONENT_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^
lib: $(COMPONENT_LIB)
partitions_table.bin: partitions_table.csv
python ../../partition_table/gen_esp32part.py --verify $< $@
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB) partitions_table.bin
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(TEST_OBJ_FILES) -L$(abspath .) -l:$(COMPONENT_LIB) -L$(SPI_FLASH_SIM_DIR) -l:$(SPI_FLASH_LIB) -g -m32
test: $(TEST_PROGRAM)
./$(TEST_PROGRAM)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): test
coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
lcov --capture --directory ../ --no-external --output-file coverage.info --gcov-tool $(GCOV)
coverage_report: coverage.info
genhtml coverage.info --output-directory coverage_report
@echo "Coverage report is in coverage_report/index.html"
clean:
rm -f $(OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(COMPONENT_LIB) partitions_table.bin
$(MAKE) -C $(SPI_FLASH_SIM_DIR) clean
rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/
rm -f coverage.info
.PHONY: clean all test lib

View file

@ -0,0 +1,3 @@
#define CATCH_CONFIG_MAIN
#include "catch.hpp"

View file

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, spiffs, , 2M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, spiffs, , 2M,

View file

@ -0,0 +1,14 @@
#pragma once
#define CONFIG_SPIFFS_USE_MAGIC_LENGTH 1
#define CONFIG_SPIFFS_MAX_PARTITIONS 3
#define CONFIG_SPIFFS_OBJ_NAME_LEN 32
#define CONFIG_SPIFFS_PAGE_SIZE 256
#define CONFIG_SPIFFS_GC_MAX_RUNS 10
#define CONFIG_SPIFFS_CACHE_WR 1
#define CONFIG_SPIFFS_CACHE 1
#define CONFIG_SPIFFS_META_LENGTH 4
#define CONFIG_SPIFFS_USE_MAGIC 1
#define CONFIG_SPIFFS_PAGE_CHECK 1
#define CONFIG_SPIFFS_USE_MTIME 1
#define CONFIG_WL_SECTOR_SIZE 4096

View file

@ -0,0 +1,4 @@
#pragma once
#include "projdefs.h"
#include "semphr.h"

View file

@ -0,0 +1,11 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define pdTRUE 1
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,16 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define vSemaphoreDelete( xSemaphore )
#define xSemaphoreCreateMutex() ((void*)(1))
#define xSemaphoreGive( xSemaphore )
#define xSemaphoreTake( xSemaphore, xBlockTime ) pdTRUE
typedef void* SemaphoreHandle_t;
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1 @@
#pragma once

View file

@ -0,0 +1,51 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#include "sdkconfig.h"
#define strlcpy(a, b, c)
#define strlcat(a, b, c)
#if defined(__cplusplus)
extern "C" {
#endif
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
typedef enum {
ESP_LOG_NONE, /*!< No log output */
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
} esp_log_level_t;
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#define LOG_RESET_COLOR
#undef _Static_assert
#define _Static_assert(cond, message)
uint32_t esp_log_timestamp(void);
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "esp_log.h"
void esp_log_write(esp_log_level_t level,
const char *tag,
const char *format, ...)
{
va_list arg;
va_start(arg, format);
vprintf(format, arg);
va_end(arg);
}
uint32_t esp_log_timestamp()
{
return 0;
}

View file

@ -0,0 +1,10 @@
#pragma once
#include <time.h>
typedef int _lock_t;
void _lock_acquire(_lock_t *lock);
void _lock_close(_lock_t *lock);
void _lock_init(_lock_t *lock);
void _lock_release(_lock_t *lock);

View file

@ -0,0 +1,21 @@
#include "sys/lock.h"
void _lock_acquire(_lock_t *lock)
{
return;
}
void _lock_close(_lock_t *lock)
{
return;
}
void _lock_init(_lock_t *lock)
{
return;
}
void _lock_release(_lock_t *lock)
{
return;
}

View file

@ -0,0 +1,6 @@
#pragma once
#include "esp_err.h"
#define ESP_VFS_FLAG_CONTEXT_PTR 1
#define ESP_VFS_PATH_MAX 15

View file

@ -0,0 +1,107 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "esp_partition.h"
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include "spiffs_api.h"
#include "catch.hpp"
extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
TEST_CASE("format disk, open file, write and read file", "[spiffs]")
{
init_spi_flash(0x00400000, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partitions_table.bin");
spiffs fs;
spiffs_config cfg;
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
// Configure objects needed by SPIFFS
esp_spiffs_t esp_user_data;
esp_user_data.partition = partition;
fs.user_data = (void*)&esp_user_data;
cfg.hal_erase_f = spiffs_api_erase;
cfg.hal_read_f = spiffs_api_read;
cfg.hal_write_f = spiffs_api_write;
cfg.log_block_size = CONFIG_WL_SECTOR_SIZE;
cfg.log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
cfg.phys_addr = 0;
cfg.phys_erase_block = CONFIG_WL_SECTOR_SIZE;
cfg.phys_size = partition->size;
uint32_t max_files = 5;
uint32_t fds_sz = max_files * sizeof(spiffs_fd);
uint32_t work_sz = cfg.log_page_size * 2;
uint32_t cache_sz = sizeof(spiffs_cache) + max_files * (sizeof(spiffs_cache_page)
+ cfg.log_page_size);
uint8_t *work = (uint8_t*) malloc(work_sz);
uint8_t *fds = (uint8_t*) malloc(fds_sz);
uint8_t *cache = (uint8_t*) malloc(cache_sz);
s32_t spiffs_res;
// Special mounting procedure: mount, format, mount as per
// https://github.com/pellepl/spiffs/wiki/Using-spiffs
spiffs_res = SPIFFS_mount(&fs, &cfg, work, fds, fds_sz,
cache, cache_sz, spiffs_api_check);
REQUIRE(spiffs_res == SPIFFS_ERR_NOT_A_FS);
spiffs_res = SPIFFS_format(&fs);
REQUIRE(spiffs_res >= SPIFFS_OK);
spiffs_res = SPIFFS_mount(&fs, &cfg, work, fds, fds_sz,
cache, cache_sz, spiffs_api_check);
REQUIRE(spiffs_res >= SPIFFS_OK);
// Open test file
spiffs_res = SPIFFS_open(&fs, "test.txt", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0);
REQUIRE(spiffs_res >= SPIFFS_OK);
// Generate data
spiffs_file file = spiffs_res;
uint32_t data_size = 100000;
char *data = (char*) malloc(data_size);
char *read = (char*) malloc(data_size);
for(uint32_t i = 0; i < data_size; i += sizeof(i))
{
*((uint32_t*)(data + i)) = i;
}
s32_t bw;
// Write data to file
spiffs_res = SPIFFS_write(&fs, file, (void*)data, data_size);
REQUIRE(spiffs_res >= SPIFFS_OK);
REQUIRE(spiffs_res == data_size);
// Set the file object pointer to the beginning
spiffs_res = SPIFFS_lseek(&fs, file, 0, SPIFFS_SEEK_SET);
REQUIRE(spiffs_res >= SPIFFS_OK);
// Read the file
spiffs_res = SPIFFS_read(&fs, file, (void*)read, data_size);
REQUIRE(spiffs_res >= SPIFFS_OK);
REQUIRE(spiffs_res == data_size);
// Close the test file
spiffs_res = SPIFFS_close(&fs, file);
REQUIRE(spiffs_res >= SPIFFS_OK);
REQUIRE(memcmp(data, read, data_size) == 0);
// Unmount
SPIFFS_unmount(&fs);
free(read);
free(data);
}

View file

@ -0,0 +1,7 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}

View file

@ -31,6 +31,7 @@ esp_err_t Partition::erase_sector(size_t sector)
result = erase_range(sector * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE); result = erase_range(sector * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
return result; return result;
} }
esp_err_t Partition::erase_range(size_t start_address, size_t size) esp_err_t Partition::erase_range(size_t start_address, size_t size)
{ {
esp_err_t result = esp_partition_erase_range(this->partition, start_address, size); esp_err_t result = esp_partition_erase_range(this->partition, start_address, size);
@ -48,6 +49,7 @@ esp_err_t Partition::write(size_t dest_addr, const void *src, size_t size)
result = esp_partition_write(this->partition, dest_addr, src, size); result = esp_partition_write(this->partition, dest_addr, src, size);
return result; return result;
} }
esp_err_t Partition::read(size_t src_addr, void *dest, size_t size) esp_err_t Partition::read(size_t src_addr, void *dest, size_t size)
{ {
esp_err_t result = ESP_OK; esp_err_t result = ESP_OK;

View file

@ -10,10 +10,9 @@ The WLC Files
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
The WLC consist of few components that are implemented in different files. The list and brief description of these components written below. The WLC consist of few components that are implemented in different files. The list and brief description of these components written below.
- Flash_Access - memory access interface. Used to access the memory. A classes WL_Flash, Partition, SPI_Flash, Flash_Emulator are implements this interface. - Flash_Access - memory access interface. Used to access the memory. A classes WL_Flash, Partition, SPI_Flash are implements this interface.
- SPI_Flash - class implements the Flash_Access interface to provide access to the flash memory. - SPI_Flash - class implements the Flash_Access interface to provide access to the flash memory.
- Partition - class implements the Flash_Access interface to provide access to the partition. - Partition - class implements the Flash_Access interface to provide access to the partition.
- Flash_Emulator - class implements the Flash_Access interface to provide test functionality for WLC testing.
- WL_Flash - the main class that implements wear levelling functionality. - WL_Flash - the main class that implements wear levelling functionality.
- WL_State - contains state structure of the WLC. - WL_State - contains state structure of the WLC.
- WL_Config - contains structure to configure the WLC component at startup. - WL_Config - contains structure to configure the WLC component at startup.

View file

@ -1,129 +0,0 @@
// Copyright 2015-2017 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 "Flash_Emulator.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Flash_Emulator::Flash_Emulator(size_t size, size_t sector_sise, size_t min_size)
{
this->reset_count = 0x7fffffff;
this->size = size;
this->sector_sise = sector_sise;
this->min_size = min_size;
this->buff = (uint8_t *)malloc(this->size);
this->access_count = new uint32_t[this->size / this->sector_sise];
memset(this->access_count, 0, this->size / this->sector_sise * sizeof(uint32_t));
}
size_t Flash_Emulator::chip_size()
{
return this->size;
}
size_t Flash_Emulator::sector_size()
{
return this->sector_sise;
}
esp_err_t Flash_Emulator::erase_sector(size_t sector)
{
esp_err_t result = ESP_OK;
if ((this->reset_count != 0x7fffffff) && (this->reset_count != 0)) {
this->reset_count--;
}
if (this->reset_count <= 0) {
result = ESP_FAIL;
return result;
}
memset(&this->buff[sector * this->sector_sise], -1, this->sector_sise);
this->access_count[sector]++;
return result;
}
uint32_t Flash_Emulator::get_access_minmax()
{
uint32_t min = INT32_MAX;
uint32_t max = 0;
for (size_t i = 0; i < (this->size / this->sector_sise) - 2; i++) {
if (this->access_count[i] < min) {
min = this->access_count[i];
}
if (this->access_count[i] > max) {
max = this->access_count[i];
}
}
return max - min;
}
esp_err_t Flash_Emulator::erase_range(size_t start_address, size_t size)
{
esp_err_t result = ESP_OK;
uint32_t start_sector = start_address / this->sector_sise;
uint32_t count = (size + this->sector_sise - 1) / this->sector_sise;
for (size_t i = 0; i < count; i++) {
result |= this->erase_sector(start_sector + i);
}
return result;
}
esp_err_t Flash_Emulator::write(size_t dest_addr, const void *src, size_t size)
{
esp_err_t result = ESP_OK;
if ((size % this->min_size) != 0) {
result = ESP_ERR_INVALID_SIZE;
return result;
}
if ((dest_addr % this->min_size) != 0) {
result = ESP_ERR_INVALID_SIZE;
return result;
}
if ((this->reset_count != 0x7fffffff) && (this->reset_count != 0)) {
this->reset_count--;
}
if (this->reset_count <= 0) {
result = ESP_FAIL;
return result;
}
memcpy(&this->buff[dest_addr], src, size);
return result;
}
esp_err_t Flash_Emulator::read(size_t src_addr, void *dest, size_t size)
{
esp_err_t result = ESP_OK;
if (this->reset_count <= 0) {
result = ESP_FAIL;
return result;
}
memcpy(dest, &this->buff[src_addr], size);
return result;
}
Flash_Emulator::~Flash_Emulator()
{
free(this->buff);
delete this->access_count;
}
void Flash_Emulator::SetResetCount(uint32_t count)
{
this->reset_count = count;
}
void Flash_Emulator::SetResetSector(size_t sector)
{
this->reset_sector = sector;
}

View file

@ -1,59 +0,0 @@
// Copyright 2015-2017 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 _Flash_Emulator_H_
#define _Flash_Emulator_H_
#include "esp_err.h"
#include "Flash_Access.h"
/**
* @brief This class is used to emulate flash devices. Class implements Flash_Access interface
*
*/
class Flash_Emulator : public Flash_Access
{
public:
Flash_Emulator(size_t size, size_t sector_sise, size_t min_size);
virtual size_t chip_size();
virtual esp_err_t erase_sector(size_t sector);
virtual esp_err_t erase_range(size_t start_address, size_t size);
virtual esp_err_t write(size_t dest_addr, const void *src, size_t size);
virtual esp_err_t read(size_t src_addr, void *dest, size_t size);
virtual size_t sector_size();
virtual ~Flash_Emulator();
uint32_t get_access_minmax();
public:
size_t size;
size_t sector_sise;
size_t min_size;
uint8_t *buff;
uint32_t *access_count;
public:
uint32_t reset_count;
size_t reset_sector;
void SetResetCount(uint32_t count);
void SetResetSector(size_t sector);
};
#endif // _Flash_Emulator_H_

View file

@ -1,55 +1,85 @@
TEST_PROGRAM=test_wl COMPONENT=wear_levelling
TEST_PROGRAM=test_$(COMPONENT)
# Expose as a library for FS components that require wear_levelling
COMPONENT_LIB=lib$(COMPONENT).a
# Use simulated block device
SPI_FLASH=spi_flash
SPI_FLASH_DIR=../../$(SPI_FLASH)
SPI_FLASH_SIM_DIR=$(SPI_FLASH_DIR)/sim
SPI_FLASH_LIB=lib$(SPI_FLASH).a
all: $(TEST_PROGRAM) all: $(TEST_PROGRAM)
SOURCE_FILES = \ SOURCE_FILES = \
esp_error_check_stub.cpp \
$(addprefix ../, \ $(addprefix ../, \
crc32.cpp \ wear_levelling.cpp \
WL_Flash.cpp \ crc32.cpp \
../nvs_flash/test_nvs_host/crc.cpp\ WL_Flash.cpp \
Partition.cpp \
) \ ) \
Flash_Emulator.cpp \ $(addprefix stubs/, \
wl_tests_host.cpp \ newlib/lock.c \
TestPowerDown.cpp \ log/log.c \
esp_log_stub.cpp \ esp32/crc.cpp \
main.cpp )
TEST_SOURCE_FILES = \
test_wl.cpp \
main.cpp \
test_utils.c
INCLUDE_FLAGS = $(addprefix -I,\ INCLUDE_FLAGS = $(addprefix -I,\
. \
../ \ ../ \
../include \ ../include \
../private_include \ ../private_include \
$(addprefix stubs/, \
newlib/include \
log/include \
) \
$(SPI_FLASH_DIR)/include \
../../esp32/include \ ../../esp32/include \
../../soc/esp32/include \
../../log/include \
../../spi_flash/include \
../../nvs_flash/test_nvs_host \
../../../tools/catch \ ../../../tools/catch \
) )
GCOV ?= gcov GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(SOURCE_FILES:.cpp=.o) OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o))
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB): force
$(MAKE) -C $(SPI_FLASH_SIM_DIR) lib
$(OBJ_FILES): %.o: %.cpp $(COMPONENT_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^
$(TEST_PROGRAM): $(OBJ_FILES) force:
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES)
$(OUTPUT_DIR): lib: $(COMPONENT_LIB)
mkdir -p $(OUTPUT_DIR)
partition_table.bin: partition_table.csv
python ../../../components/partition_table/gen_esp32part.py --verify $< $@
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB) partition_table.bin
g++ $(LDFLAGS) -o $@ $(TEST_OBJ_FILES) -L$(abspath .) -l:$(COMPONENT_LIB) -L$(SPI_FLASH_SIM_DIR) -l:$(SPI_FLASH_LIB) -g -m32
test: $(TEST_PROGRAM) test: $(TEST_PROGRAM)
./$(TEST_PROGRAM) ./$(TEST_PROGRAM)
$(COVERAGE_FILES): $(TEST_PROGRAM) test $(OUTPUT_DIR):
mkdir -p $(OUTPUT_DIR)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): test
coverage.info: $(COVERAGE_FILES) coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} + find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
@ -60,9 +90,10 @@ coverage_report: coverage.info
@echo "Coverage report is in coverage_report/index.html" @echo "Coverage report is in coverage_report/index.html"
clean: clean:
rm -f $(OBJ_FILES) $(TEST_PROGRAM) $(MAKE) -C $(SPI_FLASH_SIM_DIR) clean
rm -f $(OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(COMPONENT_LIB) partition_table.bin
rm -f $(COVERAGE_FILES) *.gcov rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/ rm -rf coverage_report/
rm -f coverage.info rm -f coverage.info
.PHONY: clean all test .PHONY: clean all test lib

View file

@ -1,110 +0,0 @@
// Copyright 2015-2017 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 "WL_Config.h"
#include "WL_Flash.h"
#include "Flash_Emulator.h"
#ifdef _MSC_VER
#define CHECK(m)
#else
#include "catch.hpp"
#endif
extern Flash_Access *s_flash;
bool test_power_down(WL_Flash *wl_flash, Flash_Emulator *emul, uint32_t used_sectors_count)
{
REQUIRE(wl_flash->init() == ESP_OK);
s_flash = wl_flash;
uint32_t add_const = 0;
int32_t sectors_count = s_flash->chip_size() / s_flash->sector_size();
esp_err_t err = ESP_OK;
uint32_t *sector_data = new uint32_t[s_flash->sector_size() / sizeof(uint32_t)];
for (int32_t i = 0; i < sectors_count; i++) {
REQUIRE(s_flash->erase_sector(i) == ESP_OK);
for (uint32_t m = 0; m < s_flash->sector_size() / sizeof(uint32_t); m++) {
uint32_t temp_data = i * s_flash->sector_size() + add_const + m;
sector_data[m] = temp_data;
}
REQUIRE(s_flash->write(i * s_flash->sector_size(), sector_data, s_flash->sector_size()) == ESP_OK);
}
for (int32_t i = 0; i < sectors_count; i++) {
err |= s_flash->read(i * s_flash->sector_size(), sector_data, s_flash->sector_size());
for (uint32_t m = 0; m < s_flash->sector_size() / sizeof(uint32_t); m++) {
uint32_t temp_data = i * s_flash->sector_size() + add_const + m;
REQUIRE(temp_data == sector_data[m]);
if (temp_data != sector_data[m]) {
printf("Error - read: %08x, expected %08x\n", sector_data[m], temp_data);
}
}
}
int32_t max_count = 100;
int32_t max_check_count = used_sectors_count;
printf("used_sectors_count=%d\n", used_sectors_count);
for (int32_t k = 0; k < max_check_count; k++) {
emul->SetResetCount(max_count);
int32_t err_sector = -1;
for (int32_t i = 0; i < sectors_count; i++) {
err = ESP_OK;
err = s_flash->erase_sector(i);
if (err != ESP_OK) {
err_sector = i;
break;
}
for (uint32_t m = 0; m < s_flash->sector_size() / sizeof(uint32_t); m++) {
uint32_t temp_data = i * s_flash->sector_size() + add_const + m;
sector_data[m] = temp_data;
}
err = s_flash->write(i * s_flash->sector_size(), sector_data, s_flash->sector_size());
if (err != ESP_OK) {
err_sector = i;
break;
}
}
if (err_sector >= 0) {
max_count++;
} else {
max_count = 0;
}
emul->SetResetCount(INT32_MAX);
REQUIRE(wl_flash->init() == ESP_OK);
for (int32_t i = 0; i < sectors_count; i++) {
if (i != err_sector) {
err |= s_flash->read(i * s_flash->sector_size(), sector_data, s_flash->sector_size());
for (uint32_t m = 0; m < s_flash->sector_size() / sizeof(uint32_t); m++) {
uint32_t temp_data = i * s_flash->sector_size() + add_const + m;
REQUIRE(temp_data == sector_data[m]);
if (temp_data != sector_data[m]) {
printf("Error - read: %08x, expected %08x, m=%i, sector=%i\n", sector_data[m], temp_data, m, i);
}
}
}
}
if (err_sector != -1) {
err |= s_flash->erase_sector(err_sector);
for (uint32_t m = 0; m < s_flash->sector_size() / sizeof(uint32_t); m++) {
uint32_t temp_data = err_sector * s_flash->sector_size() + add_const + m;
sector_data[m] = temp_data;
}
err |= s_flash->write(err_sector * s_flash->sector_size(), sector_data, s_flash->sector_size());
}
printf("[%3.f%%] err_sector=%i\n", (float)k / ((float)max_check_count) * 100.0f, err_sector);
}
delete[] sector_data;
return true;
}

View file

@ -1,2 +1,2 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch.hpp" #include "catch.hpp"

View file

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M,

View file

@ -0,0 +1,3 @@
#pragma once
#define CONFIG_WL_SECTOR_SIZE 4096

View file

@ -0,0 +1,64 @@
// 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 <stdint.h>
#include <stdbool.h>
static const unsigned int crc32_le_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};
extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len)
{
unsigned int i;
crc = ~crc;
for(i=0;i<len;i++){
crc = crc32_le_table[(crc^buf[i])&0xff]^(crc>>8);
}
return ~crc;
}

View file

@ -0,0 +1,44 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
typedef enum {
ESP_LOG_NONE, /*!< No log output */
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
} esp_log_level_t;
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#define LOG_RESET_COLOR
uint32_t esp_log_timestamp(void);
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include "esp_log.h"
void esp_log_write(esp_log_level_t level,
const char *tag,
const char *format, ...)
{
va_list arg;
va_start(arg, format);
vprintf(format, arg);
va_end(arg);
}
uint32_t esp_log_timestamp()
{
return 0;
}

View file

@ -0,0 +1,16 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef int _lock_t;
void _lock_acquire(_lock_t *lock);
void _lock_close(_lock_t *lock);
void _lock_init(_lock_t *lock);
void _lock_release(_lock_t *lock);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,21 @@
#include "sys/lock.h"
void _lock_acquire(_lock_t *lock)
{
return;
}
void _lock_close(_lock_t *lock)
{
return;
}
void _lock_init(_lock_t *lock)
{
return;
}
void _lock_release(_lock_t *lock)
{
return;
}

View file

@ -0,0 +1,7 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}

View file

@ -0,0 +1,87 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "wear_levelling.h"
#include "WL_Flash.h"
#include "catch.hpp"
#include "sdkconfig.h"
extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
TEST_CASE("write and read back data", "[wear_levelling]")
{
init_spi_flash(0x00400000, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
esp_err_t result;
wl_handle_t wl_handle;
int flash_handle;
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, "storage");
// Mount wear-levelled partition
result = wl_mount(partition, &wl_handle);
REQUIRE(result == ESP_OK);
// Get the sector size
uint32_t sector_size = wl_sector_size(wl_handle);
REQUIRE(sector_size == CONFIG_WL_SECTOR_SIZE);
uint8_t* data = (uint8_t*) malloc(partition->size);
uint8_t* read = (uint8_t*) malloc(partition->size);
uint32_t sectors = partition->size / sector_size;
// Generate data
for(uint32_t sector = 0; sector < sectors; sector++)
{
uint32_t sector_address = sector * sector_size;
for(uint32_t i = 0; i < sector_size / sizeof(i); i++)
{
((uint32_t*) data)[i] = sector_address + i;
}
}
// Write data
result = wl_write(wl_handle, 0, data, partition->size);
REQUIRE(result == ESP_OK);
// Read data
result = wl_read(wl_handle, 0, read, partition->size);
REQUIRE(result == ESP_OK);
// Verify that written and read data match
REQUIRE(memcmp(data, read, partition->size));
// Erase some ranges
result = wl_erase_range(wl_handle, 0, sector_size);
REQUIRE(result == ESP_OK);
result = wl_erase_range(wl_handle, 12288, sector_size * 2);
REQUIRE(result == ESP_OK);
result = wl_erase_range(wl_handle, 28672, sector_size * 3);
REQUIRE(result == ESP_OK);
// Expected data after erasure
memset(data + 0, 0xFF, sector_size);
memset(data + 12288, 0xFF, sector_size * 2);
memset(data + 28672, 0xFF, sector_size * 3);
// Read again, with erased ranges
result = wl_read(wl_handle, 0, read, partition->size);
REQUIRE(result == ESP_OK);
// Verify that written and read data match
REQUIRE(memcmp(data, read, partition->size));
// Unmount
result = wl_unmount(wl_handle);
REQUIRE(result == ESP_OK);
free(data);
free(read);
}

View file

@ -1,56 +0,0 @@
// Copyright 2015-2017 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 <string.h>
#include "WL_Config.h"
#include "WL_Flash.h"
#include "Flash_Emulator.h"
#include "catch.hpp"
#define FLASH_SECTOR_SIZE 512
#define FLASH_USED_SECTOR (1024 - 3)
#define FLASH_ACCESS_SIZE (FLASH_SECTOR_SIZE*(FLASH_USED_SECTOR + 1 + 2))
#define FLASH_START_ADDR 0x1000
#define FLASH_PAGE_SIZE FLASH_SECTOR_SIZE*1
#define FLASH_UPDATERATE 3
#define FLASH_TEMP_SIZE FLASH_SECTOR_SIZE
#define FLASH_WR_BLOCK_SIZE 16
static const char *TAG = "wl_test_host";
Flash_Access *s_flash;
extern bool test_power_down(WL_Flash *wl_flash, Flash_Emulator *emul, uint32_t used_sectors_count);
#define TEST_COUNT_MAX 100
TEST_CASE("flash starts with all bytes == 0xff", "[spi_flash_emu]")
{
wl_config_t *wl = new wl_config_t();
wl->full_mem_size = FLASH_ACCESS_SIZE;
wl->start_addr = FLASH_START_ADDR;
wl->sector_size = FLASH_SECTOR_SIZE;
wl->page_size = FLASH_PAGE_SIZE;
wl->updaterate = FLASH_UPDATERATE;
wl->temp_buff_size = FLASH_TEMP_SIZE;
wl->wr_size = FLASH_WR_BLOCK_SIZE;
WL_Flash *wl_flash = new WL_Flash();
Flash_Emulator *emul = new Flash_Emulator(FLASH_ACCESS_SIZE + FLASH_START_ADDR, FLASH_SECTOR_SIZE, FLASH_WR_BLOCK_SIZE);
CHECK(wl_flash->config(wl, emul) == ESP_OK);
test_power_down(wl_flash, emul, TEST_COUNT_MAX);
}