mirror of
https://github.com/espressif/esp-idf.git
synced 2024-09-19 14:26:01 -04:00
fatfs: Make fatfs runnable on host
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.
This commit is contained in:
parent
893003357a
commit
af629b3547
@ -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)
|
||||
|
||||
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
|
||||
|
2
components/fatfs/test_fatfs_host/main.cpp
Normal file
2
components/fatfs/test_fatfs_host/main.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch.hpp"
|
3
components/fatfs/test_fatfs_host/sdkconfig.h
Normal file
3
components/fatfs/test_fatfs_host/sdkconfig.h
Normal file
@ -0,0 +1,3 @@
|
||||
# pragma once
|
||||
|
||||
#define CONFIG_WL_SECTOR_SIZE 4096
|
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sdmmc_types.h"
|
||||
|
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef int sdmmc_card_t;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "projdefs.h"
|
||||
#include "semphr.h"
|
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define pdTRUE 1
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
@ -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
components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h
Normal file
45
components/fatfs/test_fatfs_host/stubs/log/include/esp_log.h
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" { // Make sure we have C-declarations in C++ programs
|
||||
#endif
|
||||
|
||||
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
|
||||
|
||||
typedef enum {
|
||||
ESP_LOG_NONE, /*!< No log output */
|
||||
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
|
||||
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
|
||||
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
|
||||
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
|
||||
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
|
||||
} esp_log_level_t;
|
||||
|
||||
#define LOG_COLOR_E
|
||||
#define LOG_COLOR_W
|
||||
#define LOG_COLOR_I
|
||||
#define LOG_COLOR_D
|
||||
#define LOG_COLOR_V
|
||||
#define LOG_RESET_COLOR
|
||||
|
||||
uint32_t esp_log_timestamp(void);
|
||||
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
|
||||
|
||||
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
|
||||
|
||||
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
|
||||
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
|
||||
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
|
||||
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
20
components/fatfs/test_fatfs_host/stubs/log/log.c
Normal file
20
components/fatfs/test_fatfs_host/stubs/log/log.c
Normal file
@ -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;
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
83
components/fatfs/test_fatfs_host/test_fatfs.cpp
Normal file
83
components/fatfs/test_fatfs_host/test_fatfs.cpp
Normal file
@ -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);
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user