]> granicus.if.org Git - esp-idf/commitdiff
fatfs: Make fatfs runnable on host
authorRenz Bagaporo <renz@espressif.com>
Thu, 17 May 2018 08:19:29 +0000 (16:19 +0800)
committerbot <bot@espressif.com>
Wed, 6 Jun 2018 17:35:30 +0000 (17:35 +0000)
Makes fatfs component runnable on host. Depends on the host library build
of wear levelling and flash emulator. Includes a basic sanity test of
mounting a volume, opening a file, writing to the file, reading the file,
closing the file and unmounting volume.

14 files changed:
components/fatfs/test_fatfs_host/Makefile
components/fatfs/test_fatfs_host/main.cpp [new file with mode: 0644]
components/fatfs/test_fatfs_host/sdkconfig.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_host.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/driver/include/driver/sdmmc_types.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/FreeRTOS.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/projdefs.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/freertos/include/freertos/semphr.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/log/log.c [new file with mode: 0644]
components/fatfs/test_fatfs_host/stubs/sdmmc/include/sdmmc_cmd.h [new file with mode: 0644]
components/fatfs/test_fatfs_host/test_fatfs.cpp [new file with mode: 0644]
components/spi_flash/sim/include/esp_partition.h
components/spi_flash/sim/partition.cpp

index 5b6d7a6e529ee4f8963448f1fc48677c15aa0a4d..76d75930de1a10186273115def0aa653bfee0c26 100644 (file)
@@ -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
+
+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
+
+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
 
-OBJ_FILES = $(SOURCE_FILES:.c=.o)
-$(OBJ_FILES): %.o: %.c
+$(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB): force
+       $(MAKE) -C $(TEST_PARTITION_SIM_DIR) lib
 
-$(TEST_PROGRAM): $(OBJ_FILES)
-       gcc $(LDFLAGS)  -o $(TEST_PROGRAM) $(OBJ_FILES) 
+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 (file)
index 0000000..0c7c351
--- /dev/null
@@ -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 (file)
index 0000000..b61f581
--- /dev/null
@@ -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 (file)
index 0000000..2e68110
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <stdlib.h>
+
+#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 (file)
index 0000000..22df97c
--- /dev/null
@@ -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 (file)
index 0000000..5bafa77
--- /dev/null
@@ -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 (file)
index 0000000..aa8c7a3
--- /dev/null
@@ -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 (file)
index 0000000..d49cafb
--- /dev/null
@@ -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 (file)
index 0000000..f905014
--- /dev/null
@@ -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
\ 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 (file)
index 0000000..4f0c12b
--- /dev/null
@@ -0,0 +1,20 @@
+#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;
+}
\ 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 (file)
index 0000000..d68711a
--- /dev/null
@@ -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 (file)
index 0000000..2c34da4
--- /dev/null
@@ -0,0 +1,83 @@
+#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"
+
+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
index c69df023d6a5aed23506bfdedbf6876d114ccf4a..f2904e7898c4c71498b941d10bfee5363c58ce31 100644 (file)
@@ -2,9 +2,14 @@
 
 #include <stdbool.h>
 
+#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
+
index e9568c0b0d110aa154a5d074705fe368de9b2900..9e9e69c38f34d2406fb358d37418b33bbaeac2dc 100644 (file)
@@ -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;