Просмотр исходного кода

Merge branch 'feature/host_side_storage_components' into 'master'

Runnable FS components on host

See merge request idf/esp-idf!2431
Ivan Grokhotkov 7 лет назад
Родитель
Сommit
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
     - 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:
   stage: test
   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 <stdlib.h>
+#include <stdarg.h>
+
 #include "esp_log.h"
 
 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()
 {
     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_PRIV_INCLUDEDIRS := spiffs/src
+COMPONENT_PRIV_INCLUDEDIRS := . spiffs/src
 COMPONENT_SRCDIRS := . spiffs/src
 
 COMPONENT_SUBMODULES := spiffs

+ 5 - 93
components/spiffs/esp_spiffs.c

@@ -30,29 +30,12 @@
 #include "esp_vfs.h"
 #include "esp_err.h"
 #include "rom/spi_flash.h"
-
-static const char * TAG = "SPIFFS";
+#include "spiffs_api.h"
 
 #ifdef CONFIG_SPIFFS_USE_MTIME
 _Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(time_t),
         "SPIFFS_META_LENGTH size should be >= sizeof(time_t)");
 #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
@@ -89,77 +72,6 @@ static time_t vfs_spiffs_get_mtime(const spiffs_stat* s);
 
 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)
 {
     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_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);
     if (!partition) {
         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->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);
 
     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);
             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);
     }
     if (res != SPIFFS_OK) {
@@ -710,7 +622,7 @@ static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir)
     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)
 {
     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);
     return result;
 }
+
 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);
@@ -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);
     return result;
 }
+
 esp_err_t Partition::read(size_t src_addr, void *dest, size_t size)
 {
     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.
 
- - 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.
  - 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_State -  contains state structure of the WLC.
  - 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)
 
 SOURCE_FILES = \
-	esp_error_check_stub.cpp \
 	$(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 \
 	../private_include \
+	$(addprefix stubs/, \
+	newlib/include \
+	log/include \
+	) \
+	$(SPI_FLASH_DIR)/include \
 	../../esp32/include \
-	../../soc/esp32/include \
-	../../log/include \
-	../../spi_flash/include \
-	../../nvs_flash/test_nvs_host \
 	../../../tools/catch \
-) 
+)
 
 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
 CXXFLAGS += -std=c++11 -Wall -Werror  -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_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)
 	find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
@@ -60,9 +90,10 @@ coverage_report: coverage.info
 	@echo "Coverage report is in coverage_report/index.html"
 
 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 -rf coverage_report/
 	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
-#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);
-}
-
-