ソースを参照

Merge branch 'feature/host_side_storage_components' into 'master'

Runnable FS components on host

See merge request idf/esp-idf!2431
Ivan Grokhotkov 7 年 前
コミット
40596fa55a
66 ファイル変更1734 行追加478 行削除
  1. 20 0
      .gitlab-ci.yml
  2. 103 0
      components/fatfs/test_fatfs_host/Makefile
  3. 2 0
      components/fatfs/test_fatfs_host/main.cpp
  4. 6 0
      components/fatfs/test_fatfs_host/partition_table.csv
  5. 3 0
      components/fatfs/test_fatfs_host/sdkconfig.h
  6. 6 0
      components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_host.h
  7. 11 0
      components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_types.h
  8. 4 0
      components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/FreeRTOS.h
  9. 11 0
      components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/projdefs.h
  10. 16 0
      components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/semphr.h
  11. 45 0
      components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h
  12. 4 1
      components/fatfs/test_fatfs_host/stubs/log/log.c
  13. 3 0
      components/fatfs/test_fatfs_host/stubs/sdmmc/include/sdmmc_cmd.h
  14. 93 0
      components/fatfs/test_fatfs_host/test_fatfs.cpp
  15. 7 0
      components/fatfs/test_fatfs_host/test_utils.c
  16. 67 0
      components/spi_flash/sim/Makefile
  17. 126 0
      components/spi_flash/sim/SpiFlash.cpp
  18. 62 0
      components/spi_flash/sim/SpiFlash.h
  19. 65 0
      components/spi_flash/sim/flash_mock.cpp
  20. 57 0
      components/spi_flash/sim/flash_mock_util.c
  21. 2 0
      components/spi_flash/sim/sdkconfig.h
  22. 13 0
      components/spi_flash/sim/stubs/app_update/esp_ota_eps.c
  23. 8 0
      components/spi_flash/sim/stubs/freertos/include/freertos/FreeRTOS.h
  24. 11 0
      components/spi_flash/sim/stubs/freertos/include/freertos/projdefs.h
  25. 16 0
      components/spi_flash/sim/stubs/freertos/include/freertos/semphr.h
  26. 1 0
      components/spi_flash/sim/stubs/freertos/include/freertos/task.h
  27. 48 0
      components/spi_flash/sim/stubs/log/include/esp_log.h
  28. 22 0
      components/spi_flash/sim/stubs/log/log.c
  29. 17 0
      components/spi_flash/sim/stubs/newlib/include/sys/lock.h
  30. 21 0
      components/spi_flash/sim/stubs/newlib/lock.c
  31. 1 1
      components/spiffs/component.mk
  32. 5 93
      components/spiffs/esp_spiffs.c
  33. 93 0
      components/spiffs/spiffs_api.c
  34. 59 0
      components/spiffs/spiffs_api.h
  35. 97 0
      components/spiffs/test_spiffs_host/Makefile
  36. 3 0
      components/spiffs/test_spiffs_host/main.cpp
  37. 6 0
      components/spiffs/test_spiffs_host/partitions_table.csv
  38. 14 0
      components/spiffs/test_spiffs_host/sdkconfig.h
  39. 4 0
      components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/FreeRTOS.h
  40. 11 0
      components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/projdefs.h
  41. 16 0
      components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/semphr.h
  42. 1 0
      components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/task.h
  43. 51 0
      components/spiffs/test_spiffs_host/stubs/log/include/esp_log.h
  44. 22 0
      components/spiffs/test_spiffs_host/stubs/log/log.c
  45. 10 0
      components/spiffs/test_spiffs_host/stubs/newlib/include/sys/lock.h
  46. 21 0
      components/spiffs/test_spiffs_host/stubs/newlib/lock.c
  47. 6 0
      components/spiffs/test_spiffs_host/stubs/vfs/include/esp_vfs.h
  48. 107 0
      components/spiffs/test_spiffs_host/test_spiffs.cpp
  49. 7 0
      components/spiffs/test_spiffs_host/test_utils.c
  50. 2 0
      components/wear_levelling/Partition.cpp
  51. 1 2
      components/wear_levelling/doc/wl_sw_structure.rst
  52. 0 129
      components/wear_levelling/test_wl_host/Flash_Emulator.cpp
  53. 0 59
      components/wear_levelling/test_wl_host/Flash_Emulator.h
  54. 57 26
      components/wear_levelling/test_wl_host/Makefile
  55. 0 110
      components/wear_levelling/test_wl_host/TestPowerDown.cpp
  56. 1 1
      components/wear_levelling/test_wl_host/main.cpp
  57. 6 0
      components/wear_levelling/test_wl_host/partition_table.csv
  58. 3 0
      components/wear_levelling/test_wl_host/sdkconfig.h
  59. 64 0
      components/wear_levelling/test_wl_host/stubs/esp32/crc.cpp
  60. 44 0
      components/wear_levelling/test_wl_host/stubs/log/include/esp_log.h
  61. 21 0
      components/wear_levelling/test_wl_host/stubs/log/log.c
  62. 16 0
      components/wear_levelling/test_wl_host/stubs/newlib/include/sys/lock.h
  63. 21 0
      components/wear_levelling/test_wl_host/stubs/newlib/lock.c
  64. 7 0
      components/wear_levelling/test_wl_host/test_utils.c
  65. 87 0
      components/wear_levelling/test_wl_host/test_wl.cpp
  66. 0 56
      components/wear_levelling/test_wl_host/wl_tests_host.cpp

+ 20 - 0
.gitlab-ci.yml

@@ -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

+ 103 - 0
components/fatfs/test_fatfs_host/Makefile

@@ -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

+ 2 - 0
components/fatfs/test_fatfs_host/main.cpp

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

+ 6 - 0
components/fatfs/test_fatfs_host/partition_table.csv

@@ -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,

+ 3 - 0
components/fatfs/test_fatfs_host/sdkconfig.h

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

+ 6 - 0
components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_host.h

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

+ 11 - 0
components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_types.h

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

+ 4 - 0
components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/FreeRTOS.h

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

+ 11 - 0
components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/projdefs.h

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

+ 16 - 0
components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/semphr.h

@@ -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

+ 45 - 0
components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h

@@ -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

+ 4 - 1
components/wear_levelling/test_wl_host/esp_log_stub.cpp → components/fatfs/test_fatfs_host/stubs/log/log.c

@@ -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;
-}
+}

+ 3 - 0
components/fatfs/test_fatfs_host/stubs/sdmmc/include/sdmmc_cmd.h

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

+ 93 - 0
components/fatfs/test_fatfs_host/test_fatfs.cpp

@@ -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);
+}

+ 7 - 0
components/fatfs/test_fatfs_host/test_utils.c

@@ -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);
+}

+ 67 - 0
components/spi_flash/sim/Makefile

@@ -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

+ 126 - 0
components/spi_flash/sim/SpiFlash.cpp

@@ -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];
+}

+ 62 - 0
components/spi_flash/sim/SpiFlash.h

@@ -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_

+ 65 - 0
components/spi_flash/sim/flash_mock.cpp

@@ -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);
+}

+ 57 - 0
components/spi_flash/sim/flash_mock_util.c

@@ -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;
+}

+ 2 - 0
components/spi_flash/sim/sdkconfig.h

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

+ 13 - 0
components/spi_flash/sim/stubs/app_update/esp_ota_eps.c

@@ -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;
+}

+ 8 - 0
components/spi_flash/sim/stubs/freertos/include/freertos/FreeRTOS.h

@@ -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()

+ 11 - 0
components/spi_flash/sim/stubs/freertos/include/freertos/projdefs.h

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

+ 16 - 0
components/spi_flash/sim/stubs/freertos/include/freertos/semphr.h

@@ -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

+ 1 - 0
components/spi_flash/sim/stubs/freertos/include/freertos/task.h

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

+ 48 - 0
components/spi_flash/sim/stubs/log/include/esp_log.h

@@ -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
+

+ 22 - 0
components/spi_flash/sim/stubs/log/log.c

@@ -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;
+}
+

+ 17 - 0
components/spi_flash/sim/stubs/newlib/include/sys/lock.h

@@ -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
+

+ 21 - 0
components/spi_flash/sim/stubs/newlib/lock.c

@@ -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;
+}

+ 1 - 1
components/spiffs/component.mk

@@ -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

+ 5 - 93
components/spiffs/esp_spiffs.c

@@ -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"
-
-static const char * TAG = "SPIFFS";
+#include "spiffs_api.h"
 
 
 #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);

+ 93 - 0
components/spiffs/spiffs_api.c

@@ -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);
+    }
+}

+ 59 - 0
components/spiffs/spiffs_api.h

@@ -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

+ 97 - 0
components/spiffs/test_spiffs_host/Makefile

@@ -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

+ 3 - 0
components/spiffs/test_spiffs_host/main.cpp

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

+ 6 - 0
components/spiffs/test_spiffs_host/partitions_table.csv

@@ -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, 

+ 14 - 0
components/spiffs/test_spiffs_host/sdkconfig.h

@@ -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

+ 4 - 0
components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/FreeRTOS.h

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

+ 11 - 0
components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/projdefs.h

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

+ 16 - 0
components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/semphr.h

@@ -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

+ 1 - 0
components/spiffs/test_spiffs_host/stubs/freertos/include/freertos/task.h

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

+ 51 - 0
components/spiffs/test_spiffs_host/stubs/log/include/esp_log.h

@@ -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

+ 22 - 0
components/spiffs/test_spiffs_host/stubs/log/log.c

@@ -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;
+}
+

+ 10 - 0
components/spiffs/test_spiffs_host/stubs/newlib/include/sys/lock.h

@@ -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);

+ 21 - 0
components/spiffs/test_spiffs_host/stubs/newlib/lock.c

@@ -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;
+}

+ 6 - 0
components/spiffs/test_spiffs_host/stubs/vfs/include/esp_vfs.h

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

+ 107 - 0
components/spiffs/test_spiffs_host/test_spiffs.cpp

@@ -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);
+}

+ 7 - 0
components/spiffs/test_spiffs_host/test_utils.c

@@ -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);
+}

+ 2 - 0
components/wear_levelling/Partition.cpp

@@ -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;

+ 1 - 2
components/wear_levelling/doc/wl_sw_structure.rst

@@ -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.

+ 0 - 129
components/wear_levelling/test_wl_host/Flash_Emulator.cpp

@@ -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;
-}

+ 0 - 59
components/wear_levelling/test_wl_host/Flash_Emulator.h

@@ -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_

+ 57 - 26
components/wear_levelling/test_wl_host/Makefile

@@ -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 \
-		WL_Flash.cpp \
-		../nvs_flash/test_nvs_host/crc.cpp\
+	wear_levelling.cpp \
+	crc32.cpp \
+	WL_Flash.cpp \
+	Partition.cpp \
 	) \
 	) \
-	Flash_Emulator.cpp \
-	wl_tests_host.cpp  \
-	TestPowerDown.cpp  \
-	esp_log_stub.cpp \
-	main.cpp
+	$(addprefix stubs/, \
+	newlib/lock.c \
+	log/log.c \
+	esp32/crc.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)
-	g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES)
+force:
 
 
-$(OUTPUT_DIR):
-	mkdir -p $(OUTPUT_DIR)
+lib: $(COMPONENT_LIB)
+
+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

+ 0 - 110
components/wear_levelling/test_wl_host/TestPowerDown.cpp

@@ -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;
-}

+ 1 - 1
components/wear_levelling/test_wl_host/main.cpp

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

+ 6 - 0
components/wear_levelling/test_wl_host/partition_table.csv

@@ -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,

+ 3 - 0
components/wear_levelling/test_wl_host/sdkconfig.h

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

+ 64 - 0
components/wear_levelling/test_wl_host/stubs/esp32/crc.cpp

@@ -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;
+}
+

+ 44 - 0
components/wear_levelling/test_wl_host/stubs/log/include/esp_log.h

@@ -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
+

+ 21 - 0
components/wear_levelling/test_wl_host/stubs/log/log.c

@@ -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;
+}

+ 16 - 0
components/wear_levelling/test_wl_host/stubs/newlib/include/sys/lock.h

@@ -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

+ 21 - 0
components/wear_levelling/test_wl_host/stubs/newlib/lock.c

@@ -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;
+}

+ 7 - 0
components/wear_levelling/test_wl_host/test_utils.c

@@ -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);
+}

+ 87 - 0
components/wear_levelling/test_wl_host/test_wl.cpp

@@ -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);
+}

+ 0 - 56
components/wear_levelling/test_wl_host/wl_tests_host.cpp

@@ -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);
-}
-
-