mirror of
https://github.com/pellepl/spiffs.git
synced 2026-10-31 03:26:30 +00:00
inital commit
This commit is contained in:
Executable
BIN
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
build/main.o build/main.d : src/main.c /usr/include/stdio.h /usr/include/features.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/stypes.h src/spiffs.h \
|
||||
src/default/spiffs_config.h src/stypes.h src/spiffs_nucleus.h \
|
||||
src/testrunner.h /usr/include/x86_64-linux-gnu/sys/stat.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stat.h /usr/include/fcntl.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/fcntl.h /usr/include/dirent.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/dirent.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/local_lim.h \
|
||||
/usr/include/linux/limits.h /usr/include/unistd.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/posix_opt.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/environments.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h
|
||||
Binary file not shown.
@@ -0,0 +1,26 @@
|
||||
build/spiffs_cache.o build/spiffs_cache.d : src/spiffs_cache.c src/spiffs.h \
|
||||
src/default/spiffs_config.h src/stypes.h /usr/include/stdio.h \
|
||||
/usr/include/features.h /usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/spiffs_nucleus.h
|
||||
Binary file not shown.
@@ -0,0 +1,26 @@
|
||||
build/spiffs_hydrogen.o build/spiffs_hydrogen.d : src/spiffs_hydrogen.c src/spiffs.h \
|
||||
src/default/spiffs_config.h src/stypes.h /usr/include/stdio.h \
|
||||
/usr/include/features.h /usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/spiffs_nucleus.h
|
||||
Binary file not shown.
@@ -0,0 +1,26 @@
|
||||
build/spiffs_nucleus.o build/spiffs_nucleus.d : src/spiffs_nucleus.c src/spiffs.h \
|
||||
src/default/spiffs_config.h src/stypes.h /usr/include/stdio.h \
|
||||
/usr/include/features.h /usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/spiffs_nucleus.h
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
build/test_hydrogen.o build/test_hydrogen.d : src/test_hydrogen.c src/testrunner.h src/test_spiffs.h \
|
||||
src/spiffs.h src/default/spiffs_config.h src/stypes.h \
|
||||
/usr/include/stdio.h /usr/include/features.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/spiffs_nucleus.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/stat.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stat.h /usr/include/fcntl.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/fcntl.h /usr/include/dirent.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/dirent.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/local_lim.h \
|
||||
/usr/include/linux/limits.h /usr/include/unistd.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/posix_opt.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/environments.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
build/test_spiffs.o build/test_spiffs.d : src/test_spiffs.c /usr/include/stdio.h \
|
||||
/usr/include/features.h /usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/stypes.h src/spiffs.h \
|
||||
src/default/spiffs_config.h src/stypes.h src/spiffs_nucleus.h \
|
||||
src/testrunner.h src/test_spiffs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/stat.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stat.h /usr/include/fcntl.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/fcntl.h /usr/include/dirent.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/dirent.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/posix1_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/local_lim.h \
|
||||
/usr/include/linux/limits.h /usr/include/unistd.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/posix_opt.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/environments.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/confname.h /usr/include/getopt.h
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
build/testrunner.o build/testrunner.d : src/testrunner.c /usr/include/stdio.h \
|
||||
/usr/include/features.h /usr/include/x86_64-linux-gnu/bits/predefs.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/cdefs.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
|
||||
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stddef.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/types.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/typesizes.h /usr/include/libio.h \
|
||||
/usr/include/_G_config.h /usr/include/wchar.h \
|
||||
/usr/lib/gcc/x86_64-linux-gnu/4.6/include/stdarg.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h /usr/include/stdlib.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitflags.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/waitstatus.h /usr/include/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/endian.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/byteswap.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/types.h /usr/include/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/select.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/sigset.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/time.h \
|
||||
/usr/include/x86_64-linux-gnu/sys/sysmacros.h \
|
||||
/usr/include/x86_64-linux-gnu/bits/pthreadtypes.h /usr/include/alloca.h \
|
||||
/usr/include/string.h /usr/include/xlocale.h src/testrunner.h
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
build/testsuites.o build/testsuites.d : src/testsuites.c src/testrunner.h
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
FILES += spiffs_nucleus.c \
|
||||
spiffs_hydrogen.c \
|
||||
spiffs_cache.c
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
BINARY = linux_spiffs_test
|
||||
|
||||
############
|
||||
#
|
||||
# Paths
|
||||
#
|
||||
############
|
||||
|
||||
sourcedir = src
|
||||
builddir = build
|
||||
|
||||
|
||||
#############
|
||||
#
|
||||
# Build tools
|
||||
#
|
||||
#############
|
||||
|
||||
CC = gcc $(COMPILEROPTIONS)
|
||||
AS = gcc $(ASSEMBLEROPTIONS)
|
||||
LD = ld
|
||||
GDB = gdb
|
||||
OBJCOPY = objcopy
|
||||
OBJDUMP = objdump
|
||||
MKDIR = mkdir -p
|
||||
|
||||
###############
|
||||
#
|
||||
# Files and libs
|
||||
#
|
||||
###############
|
||||
|
||||
FILES = main.c \
|
||||
test_spiffs.c \
|
||||
test_hydrogen.c \
|
||||
testsuites.c \
|
||||
testrunner.c
|
||||
include files.mk
|
||||
INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default
|
||||
COMPILEROPTIONS = $(INCLUDE_DIRECTIVES)
|
||||
|
||||
############
|
||||
#
|
||||
# Tasks
|
||||
#
|
||||
############
|
||||
|
||||
vpath %.c ${sourcedir} ${sourcedir}/default
|
||||
|
||||
OBJFILES = $(FILES:%.c=${builddir}/%.o)
|
||||
|
||||
DEPFILES = $(FILES:%.c=${builddir}/%.d)
|
||||
|
||||
ALLOBJFILES += $(OBJFILES)
|
||||
|
||||
DEPENDENCIES = $(DEPFILES)
|
||||
|
||||
# link object files, create binary for flashing
|
||||
$(BINARY): $(ALLOBJFILES)
|
||||
@echo "... linking"
|
||||
@${CC} $(LINKEROPTIONS) -o ${builddir}/$(BINARY) $(ALLOBJFILES) $(LIBS)
|
||||
|
||||
-include $(DEPENDENCIES)
|
||||
|
||||
# compile c files
|
||||
$(OBJFILES) : ${builddir}/%.o:%.c
|
||||
@echo "... compile $@"
|
||||
@${CC} -g -c -o $@ $<
|
||||
|
||||
# make dependencies
|
||||
$(DEPFILES) : ${builddir}/%.d:%.c
|
||||
@echo "... depend $@"; \
|
||||
rm -f $@; \
|
||||
${CC} $(COMPILEROPTIONS) -M $< > $@.$$$$; \
|
||||
sed 's,\($*\)\.o[ :]*, ${builddir}/\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
rm -f $@.$$$$
|
||||
|
||||
all: mkdirs $(BINARY)
|
||||
|
||||
mkdirs:
|
||||
-@${MKDIR} ${builddir}
|
||||
|
||||
clean:
|
||||
@echo ... removing build files in ${builddir}
|
||||
@rm -f ${builddir}/*.o
|
||||
@rm -f ${builddir}/*.d
|
||||
@rm -f ${builddir}/*.out
|
||||
@rm -f ${builddir}/*.hex
|
||||
@rm -f ${builddir}/*.elf
|
||||
@rm -f ${builddir}/*.map
|
||||
@rm -f ${builddir}/*_disasm.s
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
|
||||
#include "stypes.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
// compile time switches
|
||||
|
||||
#define SPIFFS_DBG(...)
|
||||
#define SPIFFS_GC_DBG(...)
|
||||
#define SPIFFS_CACHE_DBG(...)
|
||||
|
||||
// define maximum number of gc runs to perform to reach desired free pages
|
||||
#define SPIFFS_GC_MAX_RUNS 3
|
||||
// enable/disable statistics on gc
|
||||
#define SPIFFS_GC_STATS 1
|
||||
|
||||
// enables/disable memory read caching of nucleus file system operations
|
||||
// if enabled, memory area must be provided for cache in SPIFFS_init
|
||||
#define SPIFFS_CACHE 1
|
||||
#if SPIFFS_CACHE
|
||||
// enables memory write caching for file descriptors in hydrogen
|
||||
#define SPIFFS_CACHE_WR 1
|
||||
// enable/disable statistics on caching
|
||||
#define SPIFFS_CACHE_STATS 1
|
||||
#endif
|
||||
|
||||
// checks header of each accessed page to validate state
|
||||
#define SPIFFS_PAGE_CHECK 1
|
||||
|
||||
// Garbage collecting examines all pages in a block which and sums up
|
||||
// to a block score. Deleted pages normally gives positive score and
|
||||
// used pages normally gives a negative score (as these must be moved).
|
||||
// The larger the score, the more likely it is that the block will
|
||||
// picked for garbage collection.
|
||||
|
||||
// garbage collecting heuristics - weight used for deleted pages
|
||||
#define SPIFFS_GC_HEUR_W_DELET (10)
|
||||
// garbage collecting heuristics - weight used for used pages
|
||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
||||
|
||||
// object name length
|
||||
#define SPIFFS_OBJ_NAME_LEN (32 - sizeof(spiffs_obj_type))
|
||||
|
||||
// size of buffer on stack used when copying data
|
||||
#define SPIFFS_COPY_BUFFER_STACK (64)
|
||||
|
||||
|
||||
// types and constants
|
||||
|
||||
// spiffs file descriptor index type
|
||||
typedef s16_t spiffs_file;
|
||||
// spiffs file descriptor attributes
|
||||
typedef u32_t spiffs_attr;
|
||||
// spiffs file descriptor mode
|
||||
typedef u32_t spiffs_mode;
|
||||
|
||||
// block index type
|
||||
typedef u16_t spiffs_block_ix; // (address-phys_addr) / block_size
|
||||
// page index type
|
||||
typedef u16_t spiffs_page_ix; // (address-phys_addr) / page_size
|
||||
// object id type - most significant bit is reserved for index flag
|
||||
typedef u16_t spiffs_obj_id;
|
||||
// object span index type
|
||||
typedef u16_t spiffs_span_ix;
|
||||
// object type
|
||||
typedef u8_t spiffs_obj_type;
|
||||
|
||||
// enable if only one spiffs instance with constant configuration will exist
|
||||
// on the system
|
||||
//#define SPIFFS_SINGLETON
|
||||
|
||||
#ifdef SPIFFS_SINGLETON
|
||||
// instead of giving parameters in config struct, singleton build must
|
||||
// give parameters in defines below
|
||||
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*1)
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536)
|
||||
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
|
||||
#endif
|
||||
|
||||
#endif /* SPIFFS_CONFIG_H_ */
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : spiffs_test_.c
|
||||
Author :
|
||||
Version :
|
||||
Copyright : Your copyright notice
|
||||
Description : Hello World in C, Ansi-style
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "stypes.h"
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#include "testrunner.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(void) {
|
||||
run_tests();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* spiffs.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef SPIFFS_H_
|
||||
#define SPIFFS_H_
|
||||
|
||||
#include "spiffs_config.h"
|
||||
|
||||
#define SPIFFS_OK 0
|
||||
#define SPIFFS_ERR_FULL -10000
|
||||
#define SPIFFS_ERR_NOT_FOUND -10001
|
||||
#define SPIFFS_ERR_END_OF_OBJECT -10002
|
||||
#define SPIFFS_ERR_DELETED -10003
|
||||
#define SPIFFS_ERR_NOT_FINALIZED -10004
|
||||
#define SPIFFS_ERR_NOT_INDEX -10005
|
||||
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10006
|
||||
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
|
||||
#define SPIFFS_ERR_FILE_CLOSED -10008
|
||||
#define SPIFFS_ERR_FILE_DELETED -10009
|
||||
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
|
||||
#define SPIFFS_ERR_IS_INDEX -10011
|
||||
#define SPIFFS_ERR_INDEX_WRONG_ID -10012
|
||||
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10013
|
||||
#define SPIFFS_ERR_DATA_WRONG_ID -10014
|
||||
|
||||
#define SPIFFS_COUNTINUE -11000
|
||||
|
||||
// spi read call type
|
||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
||||
// spi write call type
|
||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
||||
// spi erase call type
|
||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||
|
||||
// size of buffer on stack used when copying data
|
||||
#define SPIFFS_COPY_BUFFER_STACK (64)
|
||||
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) \
|
||||
print(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define SPIFFS_APPEND (1<<0)
|
||||
#define SPIFFS_TRUNC (1<<1)
|
||||
#define SPIFFS_CREAT (1<<2)
|
||||
#define SPIFFS_RDONLY (1<<3)
|
||||
#define SPIFFS_WRONLY (1<<4)
|
||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
||||
#define SPIFFS_DIRECT (1<<5)
|
||||
|
||||
#define SPIFFS_SEEK_SET (0)
|
||||
#define SPIFFS_SEEK_CUR (1)
|
||||
#define SPIFFS_SEEK_END (2)
|
||||
|
||||
#define SPIFFS_TYPE_FILE (1)
|
||||
#define SPIFFS_TYPE_DIR (2)
|
||||
#define SPIFFS_TYPE_HARD_LINK (3)
|
||||
#define SPIFFS_TYPE_SOFT_LINK (4)
|
||||
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// phys structs
|
||||
|
||||
// spiffs spi configuration struct
|
||||
typedef struct {
|
||||
// physical read function
|
||||
spiffs_read hal_read_f;
|
||||
// physical write function
|
||||
spiffs_write hal_write_f;
|
||||
// physical erase function
|
||||
spiffs_erase hal_erase_f;
|
||||
#ifndef SPIFFS_SINGLETON
|
||||
// physical size of the spi flash
|
||||
u32_t phys_size;
|
||||
// physical offset in spi flash used for spiffs,
|
||||
// must be on block boundary
|
||||
u32_t phys_addr;
|
||||
// physical size when erasing a block
|
||||
u32_t phys_erase_block;
|
||||
|
||||
// logical size of a block, must be on physical
|
||||
// block size boundary and must never be less than
|
||||
// a physical block
|
||||
u32_t log_block_size;
|
||||
// logical size of a page, must be at least
|
||||
// log_block_size / 8
|
||||
u32_t log_page_size;
|
||||
#endif
|
||||
} spiffs_config;
|
||||
|
||||
typedef struct {
|
||||
// file system configuration
|
||||
spiffs_config cfg;
|
||||
// number of logical blocks
|
||||
u32_t block_count;
|
||||
|
||||
// cursor for free blocks, block index
|
||||
spiffs_block_ix free_cursor_block_ix;
|
||||
// cursor for free blocks, entry index
|
||||
int free_cursor_obj_lu_entry;
|
||||
// cursor when searching, block index
|
||||
spiffs_block_ix cursor_block_ix;
|
||||
// cursor when searching, entry index
|
||||
int cursor_obj_lu_entry;
|
||||
|
||||
// primary work buffer, size of a logical page
|
||||
u8_t *lu_work;
|
||||
// secondary work buffer, size of a logical page
|
||||
u8_t *work;
|
||||
// file descriptor memory area
|
||||
u8_t *fd_space;
|
||||
// available file descriptors
|
||||
u32_t fd_count;
|
||||
|
||||
s32_t errno;
|
||||
|
||||
u32_t free_blocks;
|
||||
|
||||
u32_t stats_p_allocated;
|
||||
u32_t stats_p_deleted;
|
||||
#if SPIFFS_GC_STATS
|
||||
u32_t stats_gc_runs;
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
void *cache;
|
||||
u32_t cache_size;
|
||||
#if SPIFFS_CACHE_STATS
|
||||
u32_t cache_hits;
|
||||
u32_t cache_misses;
|
||||
#endif
|
||||
#endif
|
||||
} spiffs;
|
||||
|
||||
typedef struct {
|
||||
spiffs_obj_id obj_id;
|
||||
u32_t size;
|
||||
spiffs_obj_type type;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
} spiffs_stat;
|
||||
|
||||
struct spiffs_dirent {
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
spiffs_obj_type type;
|
||||
u32_t size;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
spiffs_block_ix block;
|
||||
int entry;
|
||||
} spiffs_DIR;
|
||||
|
||||
// functions
|
||||
|
||||
/**
|
||||
* Initializes the file system dynamic parameters
|
||||
* @param fs the file system struct
|
||||
* @param config the physical and logical configuration of the file system
|
||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
||||
* bytes used throughout all file system operations
|
||||
* @param fd_space memory for file descriptors
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
*/
|
||||
s32_t SPIFFS_init(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
void *cache, u32_t cache_size);
|
||||
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_attr attr);
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_attr attr, spiffs_mode mode);
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
||||
void SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||
s32_t SPIFFS_errno(spiffs *fs);
|
||||
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||
|
||||
#endif /* SPIFFS_H_ */
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
* spiffs_cache.c
|
||||
*
|
||||
* Created on: Jun 23, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
cp->pix == pix ) {
|
||||
SPIFFS_CACHE_DBG("CACHE_GET: have cache page %i for %04x\n", i, pix);
|
||||
cp->last_access = cache->last_access;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for %04x\n", pix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
spiffs_cache_page *cp = get_cache_page_hdr(fs, cache, ix);
|
||||
if (cache->cpage_use_map & (1<<ix)) {
|
||||
if (write_back &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||
u8_t *mem = get_cache_page(fs, cache, ix);
|
||||
res = fs->cfg.hal_write_f(SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||
}
|
||||
|
||||
cp->flags = 0;
|
||||
cache->cpage_use_map &= ~(1 << ix);
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i objid %04x\n", ix, cp->obj_id);
|
||||
} else {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page %i pix %04x\n", ix, cp->pix);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
||||
// at least one free cpage
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
// all busy, scan thru all to find the cpage which has oldest access
|
||||
int i;
|
||||
int cand_ix = -1;
|
||||
u32_t oldest_val = 0;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
||||
(cp->flags & flag_mask) == flags) {
|
||||
oldest_val = cache->last_access - cp->last_access;
|
||||
cand_ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cand_ix >= 0) {
|
||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
if (cache->cpage_use_map == 0xffffffff) {
|
||||
// out of cache memory
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
||||
spiffs_cache_page *cp = get_cache_page_hdr(fs, cache, i);
|
||||
cache->cpage_use_map |= (1<<i);
|
||||
cp->last_access = cache->last_access;
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page %i\n", i);
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
// out of cache entries
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
if (cp) {
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
}
|
||||
}
|
||||
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
||||
cache->last_access++;
|
||||
if (cp) {
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_hits++;
|
||||
#endif
|
||||
cp->last_access = cache->last_access;
|
||||
} else {
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||
return fs->cfg.hal_read_f(
|
||||
addr ,
|
||||
len,
|
||||
dst);
|
||||
}
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_misses++;
|
||||
#endif
|
||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp) {
|
||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
}
|
||||
|
||||
s32_t res2 = fs->cfg.hal_read_f(
|
||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||
get_cache_page(fs, cache, cp->ix));
|
||||
if (res2 != SPIFFS_OK) {
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
u8_t *mem = get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
return res;
|
||||
}
|
||||
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src) {
|
||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
|
||||
if (cp) {
|
||||
// have a cache page
|
||||
// copy in data to cache page
|
||||
|
||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
return fs->cfg.hal_write_f(addr, len, src);
|
||||
}
|
||||
|
||||
u8_t *mem = get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||
|
||||
cache->last_access++;
|
||||
cp->last_access = cache->last_access;
|
||||
|
||||
if (cp->flags && SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||
// page is being updated, no write-cache, just pass thru
|
||||
return fs->cfg.hal_write_f(addr, len, src);
|
||||
} else {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
} else {
|
||||
// no cache page, no write cache - just write thru
|
||||
return fs->cfg.hal_write_f(addr, len, src);
|
||||
}
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
||||
// all cpages free, no cpage cannot be assigned to obj_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
||||
cp->obj_id == fd->obj_id) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
// before this function is called, it is ensured that there is no already existing
|
||||
// cache page with same object id
|
||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp == 0) {
|
||||
// could not get cache page
|
||||
return 0;
|
||||
}
|
||||
|
||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
||||
cp->obj_id = fd->obj_id;
|
||||
fd->cache_page = cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
void spiffs_cache_fh_release(spiffs *fs, spiffs_cache_page *cp) {
|
||||
if (cp == 0) return;
|
||||
int i;
|
||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||
for (i = 0; i < fs->fd_count; i++) {
|
||||
spiffs_fd *cur_fd = &fds[i];
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
||||
cur_fd->cache_page = 0;
|
||||
}
|
||||
}
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
|
||||
cp->obj_id = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void spiffs_cache_init(spiffs *fs) {
|
||||
if (fs->cache == 0) return;
|
||||
u32_t sz = fs->cache_size;
|
||||
u32_t cache_mask = 0;
|
||||
int i;
|
||||
int cache_entries =
|
||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
if (cache_entries <= 0) return;
|
||||
|
||||
for (i = 0; i < cache_entries; i++) {
|
||||
cache_mask <<= 1;
|
||||
cache_mask |= 1;
|
||||
}
|
||||
|
||||
spiffs_cache cache;
|
||||
memset(&cache, 0, sizeof(spiffs_cache));
|
||||
cache.cpage_count = cache_entries;
|
||||
cache.cpages = (u8_t *)(fs->cache + sizeof(spiffs_cache));
|
||||
|
||||
cache.cpage_use_map = 0xffffffff;
|
||||
cache.cpage_use_mask = cache_mask;
|
||||
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
||||
|
||||
spiffs_cache *c = get_cache(fs);
|
||||
|
||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
|
||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||
for (i = 0; i < cache.cpage_count; i++) {
|
||||
get_cache_page_hdr(fs, c, i)->ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SPIFFS_CACHE
|
||||
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
* spiffs_hydrogen.c
|
||||
*
|
||||
* Created on: Jun 16, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
|
||||
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_attr attr) {
|
||||
SPIFFS_LOCK(fs);
|
||||
spiffs_obj_id obj_id;
|
||||
s32_t res;
|
||||
|
||||
res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
res = spiffs_object_create(fs, obj_id, (u8_t*)path, SPIFFS_TYPE_FILE, 0);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
SPIFFS_UNLOCK(fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_attr attr, spiffs_mode mode) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd *fd;
|
||||
spiffs_page_ix pix;
|
||||
|
||||
s32_t res = spiffs_fd_find_new(fs, &fd);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix);
|
||||
if ((mode & SPIFFS_CREAT) == 0) {
|
||||
if (res < SPIFFS_OK) {
|
||||
spiffs_fd_return(fs, fd->file_nbr);
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
}
|
||||
|
||||
if ((mode & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
|
||||
spiffs_obj_id obj_id;
|
||||
res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id);
|
||||
if (res < SPIFFS_OK) {
|
||||
spiffs_fd_return(fs, fd->file_nbr);
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
res = spiffs_object_create(fs, obj_id, (u8_t*)path, SPIFFS_TYPE_FILE, &pix);
|
||||
if (res < SPIFFS_OK) {
|
||||
spiffs_fd_return(fs, fd->file_nbr);
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
mode &= ~SPIFFS_TRUNC;
|
||||
} else {
|
||||
if (res < SPIFFS_OK) {
|
||||
spiffs_fd_return(fs, fd->file_nbr);
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
}
|
||||
res = spiffs_object_open_by_page(fs, pix, fd, attr, mode);
|
||||
if (res < SPIFFS_OK) {
|
||||
spiffs_fd_return(fs, fd->file_nbr);
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
if (mode & SPIFFS_TRUNC) {
|
||||
res = spiffs_object_truncate(fd, 0, 0);
|
||||
if (res < SPIFFS_OK) {
|
||||
spiffs_fd_return(fs, fd->file_nbr);
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
}
|
||||
|
||||
fd->fdoffset = 0;
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
|
||||
return fd->file_nbr;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd *fd;
|
||||
s32_t res;
|
||||
|
||||
res = spiffs_fd_get(fs, fh, &fd);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_fflush_cache(fs, fh);
|
||||
#endif
|
||||
|
||||
if (fd->fdoffset + len >= fd->size) {
|
||||
// reading beyond file size
|
||||
s32_t avail = fd->size - fd->fdoffset;
|
||||
if (avail <= 0) {
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT);
|
||||
}
|
||||
res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t*)buf);
|
||||
if (res == SPIFFS_ERR_END_OF_OBJECT) {
|
||||
fd->fdoffset += avail;
|
||||
SPIFFS_UNLOCK(fs);
|
||||
return avail;
|
||||
} else {
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
}
|
||||
} else {
|
||||
// reading within file size
|
||||
res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t*)buf);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
}
|
||||
fd->fdoffset += len;
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
s32_t remaining = len;
|
||||
if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) {
|
||||
s32_t m_len = MIN(fd->size - offset, len);
|
||||
res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
remaining -= m_len;
|
||||
buf += m_len;
|
||||
offset += m_len;
|
||||
}
|
||||
if (remaining > 0) {
|
||||
res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd *fd;
|
||||
s32_t res;
|
||||
u32_t offset;
|
||||
|
||||
res = spiffs_fd_get(fs, fh, &fd);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
offset = fd->fdoffset;
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
if (fd->cache_page == 0) {
|
||||
// see if object id is associated with cache already
|
||||
fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
|
||||
}
|
||||
#endif
|
||||
if (fd->mode & SPIFFS_APPEND) {
|
||||
if (fd->size == SPIFFS_UNDEFINED_LEN) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = fd->size;
|
||||
}
|
||||
#if SPIFFS_CACHE_WR
|
||||
if (fd->cache_page) {
|
||||
offset = MAX(offset, fd->cache_page->offset + fd->cache_page->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SPIFFS_DBG("SPIFFS_write %i %04x offs:%i len %i\n", fh, fd->obj_id, offset, len);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
if ((fd->mode & SPIFFS_DIRECT) == 0) {
|
||||
if (len < SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
|
||||
// small write, try to cache it
|
||||
u8_t alloc_cpage = 1;
|
||||
if (fd->cache_page) {
|
||||
// have a cached page for this fd already, check cache page boundaries
|
||||
if (offset < fd->cache_page->offset || // writing before cache
|
||||
offset > fd->cache_page->offset + fd->cache_page->size || // writing after cache
|
||||
offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
|
||||
{
|
||||
// boundary violation, write back cache first and allocate new
|
||||
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:&04x, boundary viol, offs:%i size:%i\n",
|
||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||
res = spiffs_hydro_write(fs, fd,
|
||||
get_cache_page(fs, get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size);
|
||||
spiffs_cache_fh_release(fs, fd->cache_page);
|
||||
} else {
|
||||
// writing within cache
|
||||
alloc_cpage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (alloc_cpage) {
|
||||
fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd);
|
||||
if (fd->cache_page) {
|
||||
fd->cache_page->offset = offset;
|
||||
fd->cache_page->size = 0;
|
||||
SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page %i for fd %i:%04x\n",
|
||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd->cache_page) {
|
||||
u32_t offset_in_cpage = offset - fd->cache_page->offset;
|
||||
SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page %i for fd %i:%04x, offs %i:%i len %i\n",
|
||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id,
|
||||
offset, offset_in_cpage, len);
|
||||
spiffs_cache *cache = get_cache(fs);
|
||||
u8_t *cpage_data = get_cache_page(fs, cache, fd->cache_page->ix);
|
||||
memcpy(&cpage_data[offset_in_cpage], buf, len);
|
||||
fd->cache_page->size = MAX(fd->cache_page->size, offset_in_cpage + len);
|
||||
fd->fdoffset += len;
|
||||
SPIFFS_UNLOCK(fs);
|
||||
return len;
|
||||
} else {
|
||||
res = spiffs_hydro_write(fs, fd, buf, offset, len);
|
||||
SPIFFS_API_CHECK_RES(fs, res);
|
||||
fd->fdoffset += len;
|
||||
SPIFFS_UNLOCK(fs);
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
// big write, no need to cache it - but first check if there is a cached write already
|
||||
if (fd->cache_page) {
|
||||
// write back cache first
|
||||
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, big write, offs:%i size:%i\n",
|
||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||
res = spiffs_hydro_write(fs, fd,
|
||||
get_cache_page(fs, get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size);
|
||||
spiffs_cache_fh_release(fs, fd->cache_page);
|
||||
res = spiffs_hydro_write(fs, fd, buf, offset, len);
|
||||
SPIFFS_API_CHECK_RES(fs, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
res = spiffs_hydro_write(fs, fd, buf, offset, len);
|
||||
SPIFFS_API_CHECK_RES(fs, res);
|
||||
fd->fdoffset += len;
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd *fd;
|
||||
s32_t res;
|
||||
res = spiffs_fd_get(fs, fh, &fd);
|
||||
SPIFFS_API_CHECK_RES(fs, res);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_fflush_cache(fs, fh);
|
||||
#endif
|
||||
|
||||
switch (whence) {
|
||||
case SPIFFS_SEEK_CUR:
|
||||
offs = fd->fdoffset+offs;
|
||||
break;
|
||||
case SPIFFS_SEEK_END:
|
||||
offs = (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size) + offs;
|
||||
break;
|
||||
}
|
||||
|
||||
if (offs > fd->size) {
|
||||
res = SPIFFS_ERR_END_OF_OBJECT;
|
||||
}
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
spiffs_span_ix data_spix = offs / SPIFFS_DATA_PAGE_SIZE(fs);
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
if (fd->cursor_objix_spix != objix_spix) {
|
||||
spiffs_page_ix pix;
|
||||
res = spiffs_obj_lu_find_id_and_index(
|
||||
fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, &pix);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
fd->cursor_objix_spix = objix_spix;
|
||||
fd->cursor_objix_pix = pix;
|
||||
}
|
||||
fd->fdoffset = offs;
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd fd;
|
||||
spiffs_page_ix pix;
|
||||
s32_t res;
|
||||
fd.file_nbr = 0;
|
||||
fd.fs = fs;
|
||||
res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
res = spiffs_object_open_by_page(fs, pix, &fd, 0,0);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
res = spiffs_object_truncate(&fd, 0, 1);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd *fd;
|
||||
s32_t res;
|
||||
res = spiffs_fd_get(fs, fh, &fd);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_fh_release(fs, fd->cache_page);
|
||||
#endif
|
||||
|
||||
res = spiffs_object_truncate(fd, 0, 1);
|
||||
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_fd *fd;
|
||||
s32_t res;
|
||||
spiffs_page_object_ix_header objix_hdr;
|
||||
|
||||
res = spiffs_fd_get(fs, fh, &fd);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_fflush_cache(fs, fh);
|
||||
#endif
|
||||
|
||||
res = spiffs_phys_rd(fs,
|
||||
#if SPIFFS_CACHE
|
||||
SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
|
||||
#endif
|
||||
SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
|
||||
|
||||
s->obj_id = objix_hdr.p_hdr.obj_id;
|
||||
s->type = objix_hdr.type;
|
||||
s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
|
||||
strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN);
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
#if SPIFFS_CACHE_WR
|
||||
|
||||
spiffs_fd *fd;
|
||||
res = spiffs_fd_get(fs, fh, &fd);
|
||||
SPIFFS_API_CHECK_RES(fs, res);
|
||||
|
||||
if ((fd->mode & SPIFFS_DIRECT) == 0) {
|
||||
if (fd->cache_page == 0) {
|
||||
// see if object id is associated with cache already
|
||||
fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
|
||||
}
|
||||
if (fd->cache_page) {
|
||||
SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page %i for fd %i:%04x, flush, offs:%i size:%i\n",
|
||||
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||
res = spiffs_hydro_write(fs, fd,
|
||||
get_cache_page(fs, get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size);
|
||||
spiffs_cache_fh_release(fs, fd->cache_page);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
#if SPIFFS_CACHE_WR
|
||||
SPIFFS_LOCK(fs);
|
||||
res = spiffs_fflush_cache(fs, fh);
|
||||
SPIFFS_API_CHECK_RES_UNLOCK(fs,res);
|
||||
SPIFFS_UNLOCK(fs);
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
spiffs_fflush_cache(fs, fh);
|
||||
#endif
|
||||
spiffs_fd_return(fs, fh);
|
||||
|
||||
SPIFFS_UNLOCK(fs);
|
||||
}
|
||||
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
|
||||
d->fs = fs;
|
||||
d->block = 0;
|
||||
d->entry = 0;
|
||||
return d;
|
||||
}
|
||||
|
||||
static s32_t spiffs_read_dir_v(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_block_ix bix,
|
||||
int ix_entry,
|
||||
u32_t user_data,
|
||||
void *user_p) {
|
||||
s32_t res;
|
||||
spiffs_page_object_ix_header objix_hdr;
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_ERASED ||
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
|
||||
return SPIFFS_COUNTINUE;
|
||||
}
|
||||
|
||||
spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
|
||||
if (res != SPIFFS_OK) return res;
|
||||
if ((objix_hdr.p_hdr.obj_id & SPIFFS_OBJ_ID_IX_FLAG) &&
|
||||
objix_hdr.p_hdr.span_ix == 0 &&
|
||||
(objix_hdr.p_hdr.flags& (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL)) == SPIFFS_PH_FLAG_DELET) {
|
||||
struct spiffs_dirent *e = (struct spiffs_dirent *)user_p;
|
||||
e->obj_id = objix_hdr.p_hdr.obj_id;
|
||||
strcpy((char *)e->name, (char *)objix_hdr.name);
|
||||
e->type = objix_hdr.type;
|
||||
e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
return SPIFFS_COUNTINUE;
|
||||
}
|
||||
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
|
||||
SPIFFS_LOCK(fs);
|
||||
|
||||
spiffs_block_ix bix;
|
||||
int entry;
|
||||
s32_t res;
|
||||
struct spiffs_dirent *ret = 0;
|
||||
|
||||
res = spiffs_obj_lu_find_entry_visitor(d->fs,
|
||||
d->block,
|
||||
d->entry,
|
||||
SPIFFS_VIS_NO_WRAP,
|
||||
0,
|
||||
spiffs_read_dir_v,
|
||||
0,
|
||||
e,
|
||||
&bix,
|
||||
&entry);
|
||||
if (res == SPIFFS_OK) {
|
||||
d->block = bix;
|
||||
d->entry = entry + 1;
|
||||
ret = e;
|
||||
} else {
|
||||
d->fs->errno = res;
|
||||
}
|
||||
SPIFFS_UNLOCK(fs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
* spiffs_nucleus.h
|
||||
*
|
||||
* Created on: Jun 15, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/* SPIFFS layout
|
||||
*
|
||||
* spiffs is designed for following spi flash characteristics:
|
||||
* - only big areas of data (blocks) can be erased
|
||||
* - erasing resets all bits in a block to ones
|
||||
* - writing pulls ones to zeroes
|
||||
* - zeroes cannot be pulled to ones, without erase
|
||||
* - wear leveling
|
||||
*
|
||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
*
|
||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
* Each block contains same number of pages. A page cannot be erased, but a
|
||||
* block can be erased.
|
||||
*
|
||||
* Entire area must be block_size * x
|
||||
* page_size must be block_size / (2^y) where y > 2
|
||||
*
|
||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
*
|
||||
* BLOCK 0 PAGE 0 object lookup 1
|
||||
* PAGE 1 object lookup 2
|
||||
* ...
|
||||
* PAGE n-1 object lookup n
|
||||
* PAGE n object data 1
|
||||
* PAGE n+1 object data 2
|
||||
* ...
|
||||
* PAGE n+m-1 object data m
|
||||
*
|
||||
* BLOCK 1 PAGE n+m object lookup 1
|
||||
* PAGE n+m+1 object lookup 2
|
||||
* ...
|
||||
* PAGE 2n+m-1 object lookup n
|
||||
* PAGE 2n+m object data 1
|
||||
* PAGE 2n+m object data 2
|
||||
* ...
|
||||
* PAGE 2n+2m-1 object data m
|
||||
* ...
|
||||
*
|
||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
* in a block by object id
|
||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
* thus, n+m is total number of pages in a block
|
||||
* : block_size / page_size
|
||||
*
|
||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
*
|
||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
* data page.
|
||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
* An object id being 0x0000 represents a deleted page.
|
||||
*
|
||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
* page 2 : data : data for object id 0008
|
||||
* page 3 : data : data for object id 0001
|
||||
* page 4 : data : data for object id 0aaa
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Object data pages can be either object index pages or object content.
|
||||
* All object data pages contains a data page header, containing object id and span index.
|
||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
||||
* This applies to both object index pages (when index spans more than one page of entries),
|
||||
* and object data pages.
|
||||
* An object index page contains page entries pointing to object content page. The entry index
|
||||
* in a object index page correlates to the span index in the actual object data page.
|
||||
* The first object index page (span index 0) is called object index header page, and also
|
||||
* contains object flags (directory/file), size, object name etc.
|
||||
*
|
||||
* ex:
|
||||
* BLOCK 1
|
||||
* PAGE 256: objectl lookup page 1
|
||||
* [*123] [ 123] [ 123] [ 123]
|
||||
* [ 123] [*123] [ 123] [ 123]
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 257: objectl lookup page 2
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 258: object index page (header)
|
||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
||||
* size:1600 name:ex.txt type:file
|
||||
* [259] [260] [261] [262]
|
||||
* PAGE 259: object data page
|
||||
* obj.id:0123 span.ix:0000 flags:DATA
|
||||
* PAGE 260: object data page
|
||||
* obj.id:0123 span.ix:0001 flags:DATA
|
||||
* PAGE 261: object data page
|
||||
* obj.id:0123 span.ix:0002 flags:DATA
|
||||
* PAGE 262: object data page
|
||||
* obj.id:0123 span.ix:0003 flags:DATA
|
||||
* PAGE 263: object index page
|
||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
||||
* [264] [265] [fre] [fre]
|
||||
* [fre] [fre] [fre] [fre]
|
||||
* PAGE 264: object data page
|
||||
* obj.id:0123 span.ix:0004 flags:DATA
|
||||
* PAGE 265: object data page
|
||||
* obj.id:0123 span.ix:0005 flags:DATA
|
||||
*
|
||||
*/
|
||||
#ifndef SPIFFS_NUCLEUS_H_
|
||||
#define SPIFFS_NUCLEUS_H_
|
||||
|
||||
#define SPIFFS_EV_IX_UPD 0
|
||||
#define SPIFFS_EV_IX_NEW 1
|
||||
#define SPIFFS_EV_IX_DEL 2
|
||||
|
||||
#define SPIFFS_OBJ_ID_IX_FLAG (1<<(8*sizeof(spiffs_obj_id)-1))
|
||||
|
||||
#define SPIFFS_UNDEFINED_LEN (-1)
|
||||
|
||||
#define SPIFFS_OBJ_ID_ERASED ((spiffs_obj_id)0)
|
||||
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
||||
|
||||
#ifndef SPIFFS_SINGLETON
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
||||
((fs)->cfg.log_page_size)
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
||||
((fs)->cfg.log_block_size)
|
||||
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
||||
((fs)->cfg.phys_size)
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
||||
((fs)->cfg.phys_erase_block)
|
||||
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
||||
((fs)->cfg.phys_addr)
|
||||
#endif
|
||||
|
||||
// total number of pages per block, including object lookup pages
|
||||
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
||||
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// number of object lookup pages per block
|
||||
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
||||
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
||||
// checks if page index belongs to object lookup
|
||||
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
||||
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// number of object lookup entries in all object lookup pages
|
||||
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// converts a block to physical address
|
||||
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
||||
// converts a object lookup entry to page index
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
||||
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
||||
// converts a object lookup entry to physical address of corresponding page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
||||
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a page to physical address
|
||||
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a physical address to page
|
||||
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// gives index in page for a physical address
|
||||
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// returns containing block for given page
|
||||
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
||||
((page) / SPIFFS_PAGES_PER_BLOCK(fs))
|
||||
// returns starting page for block
|
||||
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
||||
((block) * SPIFFS_PAGES_PER_BLOCK(fs))
|
||||
// converts page to entry in object lookup page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
||||
((page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// returns data size in a data page
|
||||
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
||||
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
||||
|
||||
// define helpers object
|
||||
|
||||
// entries in an object header page index
|
||||
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
||||
// entries in an object page index
|
||||
#define SPIFFS_OBJ_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
||||
// object index entry for given data span index
|
||||
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// object index span index number for given data span index or entry
|
||||
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
||||
|
||||
|
||||
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
||||
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
||||
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
||||
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
||||
#define SPIFFS_OP_C_DELE (0<<2)
|
||||
#define SPIFFS_OP_C_UPDT (1<<2)
|
||||
#define SPIFFS_OP_C_MOVS (2<<2)
|
||||
#define SPIFFS_OP_C_MOVD (3<<2)
|
||||
#define SPIFFS_OP_C_FLSH (4<<2)
|
||||
#define SPIFFS_OP_C_READ (5<<2)
|
||||
|
||||
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
||||
#define SPIFFS_OP_COM_MASK (7<<2)
|
||||
|
||||
|
||||
// if 0, writing is finalized, else under modification
|
||||
#define SPIFFS_PH_FLAG_FINAL (1<<0)
|
||||
// if 0, page is deleted, else valid
|
||||
#define SPIFFS_PH_FLAG_DELET (1<<1)
|
||||
// if 0, page is corrupt, else ok
|
||||
#define SPIFFS_PH_FLAG_CORRU (1<<2)
|
||||
// if 0, this is an index page, else a data page
|
||||
#define SPIFFS_PH_FLAG_INDEX (1<<3)
|
||||
|
||||
|
||||
#define SPIFFS_CHECK_RES(res) \
|
||||
do { \
|
||||
if ((res) < SPIFFS_OK) return (res); \
|
||||
} while (0);
|
||||
|
||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->errno = (res); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->errno = (res); \
|
||||
SPIFFS_UNLOCK(fs); \
|
||||
return -1; \
|
||||
}
|
||||
|
||||
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
||||
#define SPIFFS_VIS_NO_WRAP (1<<1)
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||||
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
||||
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
||||
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
||||
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
||||
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
||||
|
||||
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
||||
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
||||
|
||||
#define get_cache(fs) \
|
||||
((spiffs_cache *)((fs)->cache))
|
||||
|
||||
#define get_cache_page_hdr(fs, c, ix) \
|
||||
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
||||
|
||||
#define get_cache_page(fs, c, ix) \
|
||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||
|
||||
typedef struct {
|
||||
u8_t flags;
|
||||
u8_t ix;
|
||||
u32_t last_access;
|
||||
union {
|
||||
struct {
|
||||
// type read cache
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
#if SPIFFS_CACHE_WR
|
||||
struct {
|
||||
// type write cache
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t refs;
|
||||
u32_t offset;
|
||||
u16_t size;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
} spiffs_cache_page;
|
||||
|
||||
typedef struct {
|
||||
u8_t cpage_count;
|
||||
u32_t last_access;
|
||||
u32_t cpage_use_map;
|
||||
u32_t cpage_use_mask;
|
||||
u8_t *cpages;
|
||||
} spiffs_cache;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// spiffs nucleus file descriptor
|
||||
typedef struct {
|
||||
// the filesystem of this descriptor
|
||||
spiffs *fs;
|
||||
// number of file descriptor - if 0, the file descriptor is closed
|
||||
spiffs_file file_nbr;
|
||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||||
spiffs_obj_id obj_id;
|
||||
// size of the file
|
||||
u32_t size;
|
||||
// cached object index header page index
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
// cached offset object index page index
|
||||
spiffs_page_ix cursor_objix_pix;
|
||||
// cached offset object index span index
|
||||
spiffs_span_ix cursor_objix_spix;
|
||||
// current absolute offset
|
||||
u32_t offset;
|
||||
// current file descriptor offset
|
||||
u32_t fdoffset;
|
||||
// mode
|
||||
spiffs_mode mode;
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *cache_page;
|
||||
#endif
|
||||
} spiffs_fd;
|
||||
|
||||
|
||||
// object structs
|
||||
|
||||
// page header, part of each page except object lookup pages
|
||||
typedef struct __attribute(( packed )) {
|
||||
// object id
|
||||
spiffs_obj_id obj_id;
|
||||
// object span index
|
||||
spiffs_span_ix span_ix;
|
||||
// flags
|
||||
u8_t flags;
|
||||
} spiffs_page_header;
|
||||
|
||||
// object index header page header
|
||||
typedef struct __attribute(( packed )) {
|
||||
// common page header
|
||||
spiffs_page_header p_hdr;
|
||||
// alignment
|
||||
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
|
||||
// size of object
|
||||
u32_t size;
|
||||
// type of object
|
||||
spiffs_obj_type type;
|
||||
// name of object
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
} spiffs_page_object_ix_header;
|
||||
|
||||
// object index page header
|
||||
typedef struct __attribute(( packed )) {
|
||||
spiffs_page_header p_hdr;
|
||||
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
|
||||
} spiffs_page_object_ix;
|
||||
|
||||
// callback func for object lookup visitor
|
||||
|
||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||||
u32_t user_data, void *user_p);
|
||||
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
||||
#else
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (addr), (len), (src))
|
||||
#endif
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src);
|
||||
|
||||
s32_t spiffs_phys_cpy(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u32_t dst,
|
||||
u32_t src,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_phys_count_free_blocks(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_entry_visitor(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_index_entry,
|
||||
u8_t flags,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_visitor_f v,
|
||||
u32_t user_data,
|
||||
void *user_p,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *index_entry);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_obj_lu_scan(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free_obj_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id *obj_id);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_index_entry,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *index_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_index_entry,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *index_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_index(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_page_allocate_data(
|
||||
spiffs *fs,
|
||||
spiffs_page_header *ph,
|
||||
u8_t *data,
|
||||
u32_t len,
|
||||
u32_t page_offs,
|
||||
u8_t finalize,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_page_move(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u8_t *page_data,
|
||||
spiffs_page_header *page_hdr,
|
||||
spiffs_page_ix src_pix,
|
||||
spiffs_page_ix *dst_pix);
|
||||
|
||||
s32_t spiffs_page_delete(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_object_create(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_obj_type type,
|
||||
spiffs_page_ix *objix_hdr_pix);
|
||||
|
||||
s32_t spiffs_object_update_index_hdr(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
spiffs_page_ix objix_hdr_pix,
|
||||
u8_t *new_objix_hdr_data,
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
u32_t size,
|
||||
spiffs_page_ix *new_pix);
|
||||
|
||||
void spiffs_cb_object_event(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
int ev,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix new_pix,
|
||||
u32_t new_size);
|
||||
|
||||
s32_t spiffs_object_open_by_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_fd *f,
|
||||
spiffs_attr attr,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_open_by_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix,
|
||||
spiffs_fd *f,
|
||||
spiffs_attr attr,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_append(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_modify(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_read(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_object_truncate(
|
||||
spiffs_fd *fd,
|
||||
u32_t new_len,
|
||||
u8_t remove_object);
|
||||
|
||||
s32_t spiffs_object_find_object_index_header_by_name(
|
||||
spiffs *fs,
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidate,
|
||||
int *candidate_count);
|
||||
|
||||
s32_t spiffs_gc_clean(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_fd_find_new(
|
||||
spiffs *fs,
|
||||
spiffs_fd **fd);
|
||||
|
||||
s32_t spiffs_fd_return(
|
||||
spiffs *fs,
|
||||
spiffs_file f);
|
||||
|
||||
s32_t spiffs_fd_get(
|
||||
spiffs *fs,
|
||||
spiffs_file f,
|
||||
spiffs_fd **fd);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
void spiffs_cache_init(spiffs *fs);
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix);
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd);
|
||||
void spiffs_cache_fh_release(spiffs *fs, spiffs_cache_page *cp);
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void spiffs_test_list_objects(spiffs *fs);
|
||||
|
||||
#endif /* SPIFFS_NUCLEUS_H_ */
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* stypes.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef STYPES_H_
|
||||
#define STYPES_H_
|
||||
|
||||
#define print(...) printf(__VA_ARGS__)
|
||||
|
||||
#define ASSERT(c, m) real_assert((c),(m), __FILE__, __LINE__);
|
||||
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
void real_assert(int c, const char *n, const char *file, int l);
|
||||
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned char u8_t;
|
||||
|
||||
|
||||
#endif /* STYPES_H_ */
|
||||
+1514
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* test_spiffs.c
|
||||
*
|
||||
* Created on: Jun 19, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "stypes.h"
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#include "testrunner.h"
|
||||
|
||||
#include "test_spiffs.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SECTOR_SIZE 65536 //(0x10000)
|
||||
#define PAGE_SIZE 256 //256
|
||||
#define LOG_BLOCK 65536
|
||||
#define LOG_PAGE PAGE_SIZE
|
||||
|
||||
static unsigned char area[1024*1024*1];
|
||||
|
||||
static int erases[sizeof(area)/SECTOR_SIZE];
|
||||
static char _path[256];
|
||||
|
||||
spiffs __fs;
|
||||
static u8_t _work[LOG_PAGE*2];
|
||||
static u8_t _fds[256+128];
|
||||
static u8_t _cache[256*5];
|
||||
|
||||
#define TEST_PATH "/home/petera/proj/spiffs_test_/test_data/"
|
||||
|
||||
char *make_test_fname(const char *name) {
|
||||
sprintf(_path, "%s%s", TEST_PATH, name);
|
||||
return _path;
|
||||
}
|
||||
|
||||
void clear_test_path() {
|
||||
DIR *dp;
|
||||
struct dirent *ep;
|
||||
dp = opendir(TEST_PATH);
|
||||
|
||||
if (dp != NULL) {
|
||||
while ((ep = readdir(dp))) {
|
||||
if (ep->d_name[0] != '.') {
|
||||
sprintf(_path, "%s%s", TEST_PATH, ep->d_name);
|
||||
remove(_path);
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
}
|
||||
|
||||
static s32_t _read(u32_t addr, u32_t size, u8_t *dst) {
|
||||
memcpy(dst, &area[addr], size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32_t _write(u32_t addr, u32_t size, u8_t *src) {
|
||||
int i;
|
||||
//printf("wr %08x %i\n", addr, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (((addr + i) & (PAGE_SIZE-1)) != offsetof(spiffs_page_header, flags)) {
|
||||
if (((area[addr + i] ^ src[i]) & src[i])) {
|
||||
printf("trying to write %02x to %02x at addr %08x\n", src[i], area[addr + i], addr+i);
|
||||
spiffs_page_ix pix = (addr + i) / PAGE_SIZE;
|
||||
dump_page(&__fs, pix);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
area[addr + i] &= src[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static s32_t _erase(u32_t addr, u32_t size) {
|
||||
if (addr & (SECTOR_SIZE-1)) {
|
||||
return -1;
|
||||
}
|
||||
if (size & (SECTOR_SIZE-1)) {
|
||||
return -1;
|
||||
}
|
||||
erases[addr/SECTOR_SIZE]++;
|
||||
memset(&area[addr], 0xff, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hexdump_mem(u8_t *b, u32_t len) {
|
||||
while (len--) {
|
||||
if ((((u32_t)b)&0x1f) == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("%02x", *b++);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void hexdump(u32_t addr, u32_t len) {
|
||||
int remainder = (addr % 32) == 0 ? 0 : 32 - (addr % 32);
|
||||
u32_t a;
|
||||
for (a = addr - remainder; a < addr+len; a++) {
|
||||
if ((a & 0x1f) == 0) {
|
||||
if (a != addr) {
|
||||
printf(" ");
|
||||
int j;
|
||||
for (j = 0; j < 32; j++) {
|
||||
if (a-32+j < addr)
|
||||
printf(" ");
|
||||
else {
|
||||
printf("%c", (area[a-32+j] < 32 || area[a-32+j] >= 0x7f) ? '.' : area[a-32+j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("%s %08x: ", a<=addr ? "":"\n", a);
|
||||
}
|
||||
if (a < addr) {
|
||||
printf(" ");
|
||||
} else {
|
||||
printf("%02x", area[a]);
|
||||
}
|
||||
}
|
||||
int j;
|
||||
printf(" ");
|
||||
for (j = 0; j < 32; j++) {
|
||||
if (a-32+j < addr)
|
||||
printf(" ");
|
||||
else {
|
||||
printf("%c", (area[a-32+j] < 32 || area[a-32+j] >= 0x7f) ? '.' : area[a-32+j]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void dump_page(spiffs *fs, spiffs_page_ix p) {
|
||||
printf("page %04x ", p);
|
||||
u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, p);
|
||||
if (p % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
// obj lu page
|
||||
printf("OBJ_LU");
|
||||
} else {
|
||||
// data page
|
||||
spiffs_page_header *ph = (spiffs_page_header *)&area[addr];
|
||||
printf("DATA %04x:%04x ", ph->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, ph->span_ix);
|
||||
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_FINAL) == 0) ? "F" : "f");
|
||||
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_DELET) == 0) ? "D" : "d");
|
||||
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_INDEX) == 0) ? "I" : "i");
|
||||
printf("%s ", ((ph->flags & SPIFFS_PH_FLAG_CORRU) == 0) ? "C" : "c");
|
||||
if (ph->obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
|
||||
// object index
|
||||
printf("OBJ_IX");
|
||||
if (ph->span_ix == 0) {
|
||||
printf("_HDR ");
|
||||
spiffs_page_object_ix_header *oix_hdr = (spiffs_page_object_ix_header *)&area[addr];
|
||||
printf("'%s' %i bytes type:%02x", oix_hdr->name, oix_hdr->size, oix_hdr->type);
|
||||
}
|
||||
} else {
|
||||
// data page
|
||||
printf("CONTENT");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
u32_t len = fs->cfg.log_page_size;
|
||||
hexdump(addr, len);
|
||||
}
|
||||
|
||||
int read_and_verify(char *name) {
|
||||
s32_t res;
|
||||
int fd = SPIFFS_open(&__fs, name, 0, 0);
|
||||
if (fd < 0) {
|
||||
printf(" read_and_verify: could not open file %s\n", name);
|
||||
return fd;
|
||||
}
|
||||
int pfd = open(make_test_fname(name), O_RDONLY);
|
||||
spiffs_stat s;
|
||||
res = SPIFFS_fstat(&__fs, fd, &s);
|
||||
if (res < 0) {
|
||||
printf(" read_and_verify: could not stat file %s\n", name);
|
||||
return res;
|
||||
}
|
||||
if (s.size == 0) {
|
||||
SPIFFS_close(&__fs, fd);
|
||||
close(pfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//printf("verifying %s, len %i\n", name, s.size);
|
||||
int offs = 0;
|
||||
u8_t buf_d[256];
|
||||
u8_t buf_v[256];
|
||||
while (offs < s.size) {
|
||||
int read_len = MIN(s.size - offs, sizeof(buf_d));
|
||||
res = SPIFFS_read(&__fs, fd, buf_d, read_len);
|
||||
if (res < 0) {
|
||||
printf(" read_and_verify: could not read file %s offs:%i len:%i filelen:%i\n", name, offs, read_len, s.size);
|
||||
return res;
|
||||
}
|
||||
int pres = read(pfd, buf_v, read_len);
|
||||
(void)pres;
|
||||
//printf("reading offs:%i len:%i spiffs_res:%i posix_res:%i\n", offs, read_len, res, pres);
|
||||
int i;
|
||||
int veri_ok = 1;
|
||||
for (i = 0; veri_ok && i < read_len; i++) {
|
||||
if (buf_d[i] != buf_v[i]) {
|
||||
printf("file verification mismatch @ %i, %02x %c != %02x %c\n", offs+i, buf_d[i], buf_d[i], buf_v[i], buf_v[i]);
|
||||
int j = MAX(0, i-16);
|
||||
int k = MIN(sizeof(buf_d), i+16);
|
||||
k = MIN(s.size-offs, k);
|
||||
int l;
|
||||
for (l = j; l < k; l++) {
|
||||
printf("%c", buf_d[l] > 31 ? buf_d[l] : '.');
|
||||
}
|
||||
printf("\n");
|
||||
for (l = j; l < k; l++) {
|
||||
printf("%c", buf_v[l] > 31 ? buf_v[l] : '.');
|
||||
}
|
||||
printf("\n");
|
||||
veri_ok = 0;
|
||||
}
|
||||
}
|
||||
if (!veri_ok) {
|
||||
SPIFFS_close(&__fs, fd);
|
||||
close(pfd);
|
||||
printf("data mismatch\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
offs += read_len;
|
||||
}
|
||||
|
||||
SPIFFS_close(&__fs, fd);
|
||||
close(pfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fs_reset() {
|
||||
memset(area, 0xff, sizeof(area));
|
||||
spiffs_config c;
|
||||
c.hal_erase_f = _erase;
|
||||
c.hal_read_f = _read;
|
||||
c.hal_write_f = _write;
|
||||
c.log_block_size = LOG_BLOCK;
|
||||
c.log_page_size = LOG_PAGE;
|
||||
c.phys_addr = 0;
|
||||
c.phys_erase_block = SECTOR_SIZE;
|
||||
c.phys_size = sizeof(area);
|
||||
memset(erases,0,sizeof(erases));
|
||||
memset(_cache,0,sizeof(_cache));
|
||||
SPIFFS_init(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache));
|
||||
}
|
||||
|
||||
void real_assert(int c, const char *n, const char *file, int l) {
|
||||
if (c == 0) {
|
||||
printf("ASSERT: %s %s @ %i\n", (n ? n : ""), file, l);
|
||||
printf("fs errno:%i\n", __fs.errno);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* test_spiffs.h
|
||||
*
|
||||
* Created on: Jun 19, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef TEST_SPIFFS_H_
|
||||
#define TEST_SPIFFS_H_
|
||||
|
||||
#include "spiffs.h"
|
||||
|
||||
#define FS &__fs
|
||||
|
||||
extern spiffs __fs;
|
||||
|
||||
void fs_reset();
|
||||
int read_and_verify(char *name);
|
||||
void dump_page(spiffs *fs, spiffs_page_ix p);
|
||||
void hexdump(u32_t addr, u32_t len);
|
||||
char *make_test_fname(const char *name);
|
||||
void clear_test_path();
|
||||
|
||||
|
||||
#endif /* TEST_SPIFFS_H_ */
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* testrunner.c
|
||||
*
|
||||
* Created on: Jun 18, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "testrunner.h"
|
||||
|
||||
static struct {
|
||||
test *tests;
|
||||
test *_last_test;
|
||||
int test_count;
|
||||
void (*on_stop)(test *t);
|
||||
test_res *failed;
|
||||
test_res *failed_last;
|
||||
test_res *stopped;
|
||||
test_res *stopped_last;
|
||||
} test_main;
|
||||
|
||||
void test_init(void (*on_stop)(test *t)) {
|
||||
test_main.on_stop = on_stop;
|
||||
}
|
||||
|
||||
void add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)) {
|
||||
if (f == 0) return;
|
||||
DBGT("adding test %s\n", name);
|
||||
test *t = malloc(sizeof(test));
|
||||
memset(t, 0, sizeof(test));
|
||||
t->f = f;
|
||||
strcpy(t->name, name);
|
||||
t->setup = setup;
|
||||
t->teardown = teardown;
|
||||
if (test_main.tests == 0) {
|
||||
test_main.tests = t;
|
||||
} else {
|
||||
test_main._last_test->_next = t;
|
||||
}
|
||||
test_main._last_test = t;
|
||||
test_main.test_count++;
|
||||
}
|
||||
|
||||
static void add_res(test *t, test_res **head, test_res **last) {
|
||||
test_res *tr = malloc(sizeof(test_res));
|
||||
memset(tr,0,sizeof(test_res));
|
||||
strcpy(tr->name, t->name);
|
||||
if (*head == 0) {
|
||||
*head = tr;
|
||||
} else {
|
||||
(*last)->_next = tr;
|
||||
}
|
||||
*last = tr;
|
||||
}
|
||||
|
||||
static void dump_res(test_res **head) {
|
||||
test_res *tr = (*head);
|
||||
while (tr) {
|
||||
test_res *next_tr = tr->_next;
|
||||
printf(" %s\n", tr->name);
|
||||
free(tr);
|
||||
tr = next_tr;
|
||||
}
|
||||
}
|
||||
|
||||
void run_tests() {
|
||||
memset(&test_main, 0, sizeof(test_main));
|
||||
DBGT("adding suites...\n");
|
||||
add_suites();
|
||||
DBGT("%i tests added\n", test_main.test_count);
|
||||
DBGT("running tests...\n");
|
||||
int ok = 0;
|
||||
int failed = 0;
|
||||
int stopped = 0;
|
||||
test *cur_t = test_main.tests;
|
||||
int i = 1;
|
||||
while (cur_t) {
|
||||
cur_t->setup(cur_t);
|
||||
test *next_test = cur_t->_next;
|
||||
DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name);
|
||||
i++;
|
||||
int res = cur_t->f(cur_t);
|
||||
cur_t->teardown(cur_t);
|
||||
switch (res) {
|
||||
case TEST_RES_OK:
|
||||
ok++;
|
||||
printf(" .. ok\n");
|
||||
break;
|
||||
case TEST_RES_FAIL:
|
||||
failed++;
|
||||
printf(" .. FAILED\n");
|
||||
if (test_main.on_stop) test_main.on_stop(cur_t);
|
||||
add_res(cur_t, &test_main.failed, &test_main.failed_last);
|
||||
break;
|
||||
case TEST_RES_ASSERT:
|
||||
stopped++;
|
||||
printf(" .. ABORTED\n");
|
||||
if (test_main.on_stop) test_main.on_stop(cur_t);
|
||||
add_res(cur_t, &test_main.stopped, &test_main.stopped_last);
|
||||
break;
|
||||
}
|
||||
free(cur_t);
|
||||
cur_t = next_test;
|
||||
}
|
||||
DBGT("ran %i tests\n", test_main.test_count);
|
||||
printf("Test report, %i tests\n", test_main.test_count);
|
||||
printf("%i succeeded\n", ok);
|
||||
printf("%i failed\n", failed);
|
||||
dump_res(&test_main.failed);
|
||||
printf("%i stopped\n", stopped);
|
||||
dump_res(&test_main.stopped);
|
||||
if (ok < test_main.test_count) {
|
||||
printf("\nFAILED\n");
|
||||
} else {
|
||||
printf("\nALL TESTS OK\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* testrunner.h
|
||||
*
|
||||
* Created on: Jun 19, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
SUITE(mysuite)
|
||||
|
||||
void setup(test *t) {}
|
||||
|
||||
void teardown(test *t) {}
|
||||
|
||||
TEST(mytest) {
|
||||
printf("mytest runs now..\n");
|
||||
return 0;
|
||||
} TEST_END(mytest)
|
||||
|
||||
SUITE_END(mysuite)
|
||||
|
||||
|
||||
|
||||
SUITE(mysuite2)
|
||||
|
||||
void setup(test *t) {}
|
||||
|
||||
void teardown(test *t) {}
|
||||
|
||||
TEST(mytest2a) {
|
||||
printf("mytest2a runs now..\n");
|
||||
return 0;
|
||||
} TEST_END(mytest2a)
|
||||
|
||||
TEST(mytest2b) {
|
||||
printf("mytest2b runs now..\n");
|
||||
return 0;
|
||||
} TEST_END(mytest2b)
|
||||
|
||||
SUITE_END(mysuite2)
|
||||
|
||||
|
||||
|
||||
void add_suites() {
|
||||
ADD_SUITE(mysuite);
|
||||
ADD_SUITE(mysuite2);
|
||||
}
|
||||
*/
|
||||
|
||||
#ifndef TESTS_H_
|
||||
#define TESTS_H_
|
||||
|
||||
#define TEST_RES_OK 0
|
||||
#define TEST_RES_FAIL -1
|
||||
#define TEST_RES_ASSERT -2
|
||||
|
||||
struct test_s;
|
||||
|
||||
typedef int (*test_f)(struct test_s *t);
|
||||
|
||||
typedef struct test_s {
|
||||
test_f f;
|
||||
char name[256];
|
||||
void *data;
|
||||
void (*setup)(struct test_s *t);
|
||||
void (*teardown)(struct test_s *t);
|
||||
struct test_s *_next;
|
||||
} test;
|
||||
|
||||
typedef struct test_res_s {
|
||||
char name[256];
|
||||
struct test_res_s *_next;
|
||||
} test_res;
|
||||
|
||||
#define TEST_CHECK(x) if (!(x)) { \
|
||||
printf(" TEST FAIL %s:%i\n", __FILE__, __LINE__); \
|
||||
goto __fail_stop; \
|
||||
}
|
||||
#define TEST_ASSERT(x) if (!(x)) { \
|
||||
printf(" TEST ASSERT %s:%i\n", __FILE__, __LINE__); \
|
||||
goto __fail_assert; \
|
||||
}
|
||||
|
||||
#define DBGT(...) printf(__VA_ARGS__)
|
||||
|
||||
#define str(s) #s
|
||||
|
||||
#define SUITE(sui) \
|
||||
extern void __suite_##sui() {
|
||||
#define SUITE_END(sui) \
|
||||
}
|
||||
#define ADD_SUITE(sui) \
|
||||
__suite_##sui();
|
||||
#define TEST(tf) \
|
||||
int tf(struct test_s *t) { do
|
||||
#define TEST_END(tf) \
|
||||
while(0); \
|
||||
__fail_stop: return TEST_RES_FAIL; \
|
||||
__fail_assert: return TEST_RES_ASSERT; \
|
||||
} \
|
||||
add_test(tf, str(tf), setup, teardown);
|
||||
|
||||
|
||||
void add_suites();
|
||||
void test_init(void (*on_stop)(test *t));
|
||||
void add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t));
|
||||
void run_tests();
|
||||
|
||||
#endif /* TESTS_H_ */
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* testsuites.c
|
||||
*
|
||||
* Created on: Jun 19, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "testrunner.h"
|
||||
|
||||
void add_suites() {
|
||||
ADD_SUITE(hydrogen_tests)
|
||||
//ADD_SUITE(dev_tests);
|
||||
}
|
||||
Reference in New Issue
Block a user