diff --git a/components/fatfs/test_fatfs_host/Makefile b/components/fatfs/test_fatfs_host/Makefile index 5b6d7a6e52..76d75930de 100644 --- a/components/fatfs/test_fatfs_host/Makefile +++ b/components/fatfs/test_fatfs_host/Makefile @@ -1,45 +1,83 @@ -TEST_PROGRAM=fatfs_host +TEST_PROGRAM=test_fatfs + +# Use wear levelling +TEST_WL_COMPONENT=$(IDF_PATH)/components/wear_levelling +TEST_WL_DIR=$(TEST_WL_COMPONENT)/test_wl_host +TEST_WL_LIB=libtest_wl.a + +TEST_PARTITION_SIM_DIR=$(IDF_PATH)/components/spi_flash/sim +TEST_PARTITION_SIM_LIB=libpartition_sim.a all: $(TEST_PROGRAM) SOURCE_FILES = \ - main.c \ + main.cpp \ + test_fatfs.cpp \ $(addprefix ../src/, \ diskio.c \ ff.c \ ffsystem.c \ - ffunicode.c \ - ) + ffunicode.c \ + diskio_spiflash.c \ + ) \ + $(addprefix ./stubs/, log/log.c) INCLUDE_FLAGS = $(addprefix -I,\ ../src \ - . \ - $(addprefix ./stubs/, \ - driver/include \ - freertos/include \ - sdmmc/include \ - ) \ - ../../esp32/include \ + . \ + $(addprefix ./stubs/, \ + driver/include \ + freertos/include \ + sdmmc/include \ + log/include \ + ) \ + ../../esp32/include \ + $(TEST_PARTITION_SIM_DIR)/include \ + $(TEST_WL_COMPONENT)/include \ + ../../../tools/catch \ ) -CPPFLAGS += $(INCLUDE_FLAGS) -g -CFLAGS += -fprofile-arcs -g -CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -g -LDFLAGS += -lstdc++ -fprofile-arcs +GCOV ?= gcov -OBJ_FILES = $(SOURCE_FILES:.c=.o) -$(OBJ_FILES): %.o: %.c +CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g +CFLAGS += -fprofile-arcs -ftest-coverage +CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage +LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage -$(TEST_PROGRAM): $(OBJ_FILES) - gcc $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) +OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o)) + +$(TEST_WL_DIR)/$(TEST_WL_LIB): force + $(MAKE) -C $(TEST_WL_DIR) lib + +$(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB): force + $(MAKE) -C $(TEST_PARTITION_SIM_DIR) lib + +force: $(TEST_PROGRAM): $(OBJ_FILES) $(TEST_WL_DIR)/$(TEST_WL_LIB) $(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB) g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) -L$(TEST_PARTITION_SIM_DIR) -l:$(TEST_PARTITION_SIM_LIB) -L$(TEST_WL_DIR) -l:$(TEST_WL_LIB) -test: $(TEST_PROGRAM) +run: $(TEST_PROGRAM) ./$(TEST_PROGRAM) -clean: +COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES:.o=.gc*) + +$(COVERAGE_FILES): $(TEST_PROGRAM) 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) $(TEST_PROGRAM) + $(MAKE) -C $(TEST_WL_DIR) clean + $(MAKE) -C $(TEST_PARTITION_SIM_DIR) clean + rm -f $(COVERAGE_FILES) *.gcov + rm -rf coverage_report/ + rm -f coverage.info .PHONY: clean all diff --git a/components/fatfs/test_fatfs_host/main.cpp b/components/fatfs/test_fatfs_host/main.cpp new file mode 100644 index 0000000000..0c7c351f43 --- /dev/null +++ b/components/fatfs/test_fatfs_host/main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/components/fatfs/test_fatfs_host/sdkconfig.h b/components/fatfs/test_fatfs_host/sdkconfig.h new file mode 100644 index 0000000000..b61f5811d1 --- /dev/null +++ b/components/fatfs/test_fatfs_host/sdkconfig.h @@ -0,0 +1,3 @@ +# pragma once + +#define CONFIG_WL_SECTOR_SIZE 4096 diff --git a/components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_host.h b/components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_host.h new file mode 100644 index 0000000000..2e68110374 --- /dev/null +++ b/components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_host.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +#include "sdmmc_types.h" + diff --git a/components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_types.h b/components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_types.h new file mode 100644 index 0000000000..22df97c5c0 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/FreeRTOS.h b/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/FreeRTOS.h new file mode 100644 index 0000000000..5bafa772df --- /dev/null +++ b/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/FreeRTOS.h @@ -0,0 +1,4 @@ +#pragma once + +#include "projdefs.h" +#include "semphr.h" diff --git a/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/projdefs.h b/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/projdefs.h new file mode 100644 index 0000000000..aa8c7a3de5 --- /dev/null +++ b/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 diff --git a/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/semphr.h b/components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/semphr.h new file mode 100644 index 0000000000..d49cafb99f --- /dev/null +++ b/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 diff --git a/components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h b/components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h new file mode 100644 index 0000000000..f90501430e --- /dev/null +++ b/components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#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 \ No newline at end of file diff --git a/components/fatfs/test_fatfs_host/stubs/log/log.c b/components/fatfs/test_fatfs_host/stubs/log/log.c new file mode 100644 index 0000000000..4f0c12bf82 --- /dev/null +++ b/components/fatfs/test_fatfs_host/stubs/log/log.c @@ -0,0 +1,20 @@ +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/components/fatfs/test_fatfs_host/stubs/sdmmc/include/sdmmc_cmd.h b/components/fatfs/test_fatfs_host/stubs/sdmmc/include/sdmmc_cmd.h new file mode 100644 index 0000000000..d68711a95f --- /dev/null +++ b/components/fatfs/test_fatfs_host/stubs/sdmmc/include/sdmmc_cmd.h @@ -0,0 +1,3 @@ +#pragma once + +#include "esp_err.h" diff --git a/components/fatfs/test_fatfs_host/test_fatfs.cpp b/components/fatfs/test_fatfs_host/test_fatfs.cpp new file mode 100644 index 0000000000..2c34da4f71 --- /dev/null +++ b/components/fatfs/test_fatfs_host/test_fatfs.cpp @@ -0,0 +1,83 @@ +#include +#include + +#include "ff.h" +#include "esp_partition.h" +#include "wear_levelling.h" +#include "diskio.h" +#include "diskio_spiflash.h" + +#include "catch.hpp" + +TEST_CASE("create volume, open file, write and read back data", "[fatfs]") +{ + FRESULT fr_result; + BYTE pdrv; + FATFS fs; + FIL file; + UINT bw; + + esp_err_t esp_result; + + // Create a 4MB partition + uint32_t size = 0x00400000; + int flash_handle = esp_flash_create(size, 4096, 1); + esp_partition_t partition = esp_partition_create(size, 0, flash_handle); + + // 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); + + const char data[] = "Hello, World!"; + char *read = (char*) malloc(sizeof(data)); + + fr_result = f_write(&file, data, sizeof(data), &bw); + REQUIRE(fr_result == FR_OK); + REQUIRE(bw == sizeof(data)); + + // Move to beginning of file + fr_result = f_lseek(&file, 0); + REQUIRE(fr_result == FR_OK); + + fr_result = f_read(&file, read, sizeof(data), &bw); + REQUIRE(fr_result == FR_OK); + REQUIRE(bw == sizeof(data)); + + REQUIRE(strcmp(data, read) == 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); + + esp_partition_delete(partition); + + free(read); +} \ No newline at end of file diff --git a/components/spi_flash/sim/include/esp_partition.h b/components/spi_flash/sim/include/esp_partition.h index c69df023d6..f2904e7898 100644 --- a/components/spi_flash/sim/include/esp_partition.h +++ b/components/spi_flash/sim/include/esp_partition.h @@ -2,9 +2,14 @@ #include +#include "sdkconfig.h" #include "esp_err.h" #include "esp_spi_flash.h" +#if defined(__cplusplus) +extern "C" { // Make sure we have C-declarations in C++ programs +#endif + /** * @brief Partition type * @note Keep this enum in sync with PartitionDefinition class gen_esp32part.py @@ -83,3 +88,7 @@ esp_partition_t esp_partition_create(uint32_t size, uint32_t start); void esp_partition_delete(esp_partition_t partition); +#if defined(__cplusplus) +} +#endif + diff --git a/components/spi_flash/sim/partition.cpp b/components/spi_flash/sim/partition.cpp index e9568c0b0d..9e9e69c38f 100644 --- a/components/spi_flash/sim/partition.cpp +++ b/components/spi_flash/sim/partition.cpp @@ -4,15 +4,15 @@ #include "esp_spi_flash.h" #include "Flash_Emulator.h" -#define PARTITIONS_MAX 8 +#define EMULATORS_MAX 8 -static Flash_Emulator* emulators[PARTITIONS_MAX]; +static Flash_Emulator* emulators[EMULATORS_MAX]; esp_partition_t esp_partition_create(uint32_t size, uint32_t start) { int handle = -1; - for (int i = 0; i < PARTITIONS_MAX; i++) { + for (int i = 0; i < EMULATORS_MAX; i++) { if (emulators[i] == NULL) { emulators[i] = new Flash_Emulator(start + size, SPI_FLASH_SEC_SIZE, SPI_FLASH_WRITE_SIZE); handle = i;