diff --git a/Makefile.dep b/Makefile.dep index 9cd813d3b2..4bfb0e869b 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -619,6 +619,13 @@ ifneq (,$(filter sock_dns,$(USEMODULE))) USEMODULE += sock_util endif +ifneq (,$(filter spiffs,$(USEMODULE))) + USEPKG += spiffs + USEMODULE += vfs + USEMODULE += spiffs_fs + USEMODULE += mtd +endif + # include package dependencies -include $(USEPKG:%=$(RIOTPKG)/%/Makefile.dep) diff --git a/pkg/spiffs/Makefile b/pkg/spiffs/Makefile new file mode 100644 index 0000000000..d40ea98d32 --- /dev/null +++ b/pkg/spiffs/Makefile @@ -0,0 +1,19 @@ +PKG_NAME=spiffs +PKG_URL=https://github.com/pellepl/spiffs.git +PKG_VERSION=39937743fbbec4b82308ee08332bf9180408d23b +PKG_BUILDDIR ?= $(PKGDIRBASE)/$(PKG_NAME) + +CFLAGS += -std=c11 + +.PHONY: all + +all: git-download + @mkdir -p "$(PKG_BUILDDIR)/riotbuild" + @cp $(PKG_BUILDDIR)/src/*.c $(PKG_BUILDDIR)/src/*.h $(PKG_BUILDDIR)/riotbuild + + @echo 'MODULE:=spiffs' > $(PKG_BUILDDIR)/riotbuild/Makefile + @echo 'include $$(RIOTBASE)/Makefile.base' >> $(PKG_BUILDDIR)/riotbuild/Makefile + + "$(MAKE)" -C $(PKG_BUILDDIR)/riotbuild + +include $(RIOTBASE)/pkg/pkg.mk diff --git a/pkg/spiffs/Makefile.include b/pkg/spiffs/Makefile.include new file mode 100644 index 0000000000..975c3ddc2f --- /dev/null +++ b/pkg/spiffs/Makefile.include @@ -0,0 +1,6 @@ +INCLUDES += -I$(RIOTPKG)/spiffs/include +INCLUDES += -I$(PKGDIRBASE)/spiffs/riotbuild/ + +ifneq (,$(filter spiffs_fs,$(USEMODULE))) + DIRS += $(RIOTBASE)/pkg/spiffs/fs +endif diff --git a/pkg/spiffs/fs/Makefile b/pkg/spiffs/fs/Makefile new file mode 100644 index 0000000000..6557bca99e --- /dev/null +++ b/pkg/spiffs/fs/Makefile @@ -0,0 +1,3 @@ +MODULE := spiffs_fs + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/spiffs/fs/spiffs_fs.c b/pkg/spiffs/fs/spiffs_fs.c new file mode 100644 index 0000000000..220edd47b5 --- /dev/null +++ b/pkg/spiffs/fs/spiffs_fs.c @@ -0,0 +1,489 @@ +/* + * Copyright (C) 2016 OTA keys S.A. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup fs + * @{ + * + * @file + * @brief SPIFFS integration with vfs + * + * @author Vincent Dupont + * + * @} + */ + + +#include +#include +#include + +#include "fs/spiffs_fs.h" + +#include "kernel_defines.h" + +#define ENABLE_DEBUG (0) +#include + +static int spiffs_err_to_errno(s32_t err); + +#if SPIFFS_HAL_CALLBACK_EXTRA == 1 +static int32_t _dev_read(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst) +{ + mtd_dev_t *dev = (mtd_dev_t *)fs->user_data; + + DEBUG("spiffs: read: from addr 0x%" PRIx32 " size 0x%" PRIx32 "\n", addr, size); + + if (mtd_read(dev, dst, addr, size) > 0) { + return 0; + } + else { + return -EIO; + } +} + +static int32_t _dev_write(struct spiffs_t *fs, u32_t addr, u32_t size, const u8_t *src) +{ + mtd_dev_t *dev = (mtd_dev_t *)fs->user_data; + + DEBUG("spiffs: write: from addr 0x%" PRIx32 " size 0x%" PRIx32 "\n", addr, size); + + if (mtd_write(dev, src, addr, size) > 0) { + return 0; + } + else { + return -EIO; + } +} + +static int32_t _dev_erase(struct spiffs_t *fs, u32_t addr, u32_t size) +{ + mtd_dev_t *dev = (mtd_dev_t *)fs->user_data; + + DEBUG("spiffs: erase: from addr 0x%" PRIx32" size 0x%" PRIx32 "\n", addr, size); + + return mtd_erase(dev, addr, size); +} +#else +#ifndef SPIFFS_MTD_DEV +#error "SPIFFS needs SPIFFS_HAL_CALLBACK_EXTRA or SPIFFS_MTD_DEV" +#endif +static int32_t _dev_read(u32_t addr, u32_t size, u8_t *dst) +{ + DEBUG("spiffs: read: from addr 0x%" PRIx32 " size 0x%" PRIx32 "\n", addr, size); + + if (mtd_read(SPIFFS_MTD_DEV, dst, addr, size) > 0) { + return 0; + } + else { + return -EIO; + } +} + +static int32_t _dev_write(u32_t addr, u32_t size, const u8_t *src) +{ + DEBUG("spiffs: write: from addr 0x%" PRIx32 " size 0x%" PRIx32 "\n", addr, size); + + if (mtd_write(SPIFFS_MTD_DEV, src, addr, size) > 0) { + return 0; + } + else { + return -EIO; + } +} + +static int32_t _dev_erase(u32_t addr, u32_t size) +{ + DEBUG("spiffs: erase: from addr 0x%" PRIx32" size 0x%" PRIx32 "\n", addr, size); + + return mtd_erase(SPIFFS_MTD_DEV, addr, size); +} +#endif + +void spiffs_lock(struct spiffs_t *fs) +{ + spiffs_desc_t *fs_desc = container_of(fs, spiffs_desc_t, fs); + + DEBUG("spiffs: lock: fs_desc %p\n", (void*)fs_desc); + mutex_lock(&fs_desc->lock); +} +void spiffs_unlock(struct spiffs_t *fs) +{ + spiffs_desc_t *fs_desc = container_of(fs, spiffs_desc_t, fs); + + DEBUG("spiffs: unlock: fs_desc %p\n", (void*)fs_desc); + mutex_unlock(&fs_desc->lock); +} + +static int _mount(vfs_mount_t *mountp) +{ + spiffs_desc_t *fs_desc = mountp->private_data; +#if SPIFFS_HAL_CALLBACK_EXTRA == 1 + mtd_dev_t *dev = fs_desc->dev; + fs_desc->fs.user_data = dev; +#else + mtd_dev_t *dev = SPIFFS_MTD_DEV; +#endif + + DEBUG("spiffs: mount: private_data = %p\n", mountp->private_data); + + fs_desc->config.hal_read_f = _dev_read; + fs_desc->config.hal_write_f = _dev_write; + fs_desc->config.hal_erase_f = _dev_erase; + +#if SPIFFS_SINGLETON == 0 + DEBUG("spiffs: mount: mtd page_size=%" PRIu32 ", pages_per_sector=%" PRIu32 + ", sector_count=%" PRIu32 "\n", dev->page_size, dev->pages_per_sector, dev->sector_count); + fs_desc->config.phys_size = dev->page_size * dev->pages_per_sector * dev->sector_count; + fs_desc->config.log_block_size = dev->page_size * dev->pages_per_sector; + fs_desc->config.log_page_size = dev->page_size; + fs_desc->config.phys_addr = 0; + fs_desc->config.phys_erase_block = dev->page_size * dev->pages_per_sector; +#endif + + mtd_init(dev); + + s32_t ret = SPIFFS_mount(&fs_desc->fs, + &fs_desc->config, + fs_desc->work, + fs_desc->fd_space, + SPIFFS_FS_FD_SPACE_SIZE, +#if SPIFFS_CACHE == 1 + fs_desc->cache, + SPIFFS_FS_CACHE_SIZE, +#else + NULL, + 0, +#endif + NULL); + + if (ret != 0) { + DEBUG("spiffs: mount: ret %" PRId32 "\n", ret); + switch (ret) { + case SPIFFS_ERR_NOT_A_FS: + DEBUG("spiffs: mount: formatting fs\n"); + ret = SPIFFS_format(&fs_desc->fs); + DEBUG("spiffs: mount: format ret %" PRId32 "\n", ret); + if (ret < 0) { + return spiffs_err_to_errno(ret); + } + ret = SPIFFS_mount(&fs_desc->fs, + &fs_desc->config, + fs_desc->work, + fs_desc->fd_space, + SPIFFS_FS_FD_SPACE_SIZE, +#if SPIFFS_CACHE == 1 + fs_desc->cache, + SPIFFS_FS_CACHE_SIZE, +#else + NULL, + 0, +#endif + NULL); + DEBUG("spiffs: mount: ret %" PRId32 "\n", ret); + break; + } + } + + return spiffs_err_to_errno(ret); +} + +static int _umount(vfs_mount_t *mountp) +{ + spiffs_desc_t *fs_desc = mountp->private_data; + + SPIFFS_unmount(&fs_desc->fs); + + return 0; +} + +static int _unlink(vfs_mount_t *mountp, const char *name) +{ + spiffs_desc_t *fs_desc = mountp->private_data; + + return spiffs_err_to_errno(SPIFFS_remove(&fs_desc->fs, name)); +} + +static int _rename(vfs_mount_t *mountp, const char *from_path, const char *to_path) +{ + spiffs_desc_t *fs_desc = mountp->private_data; + + return spiffs_err_to_errno(SPIFFS_rename(&fs_desc->fs, from_path, to_path)); +} + +static int _open(vfs_file_t *filp, const char *name, int flags, mode_t mode, const char *abs_path) +{ + spiffs_desc_t *fs_desc = filp->mp->private_data; + (void) abs_path; + DEBUG("spiffs: open: private_data = %p\n", filp->mp->private_data); + + spiffs_flags s_flags = 0; + if ((flags & O_ACCMODE) == O_RDONLY) { + s_flags |= SPIFFS_O_RDONLY; + } + if ((flags & O_APPEND) == O_APPEND) { + s_flags |= SPIFFS_O_APPEND; + } + if ((flags & O_TRUNC) == O_TRUNC) { + s_flags |= SPIFFS_O_TRUNC; + } + if ((flags & O_CREAT) == O_CREAT) { + s_flags |= SPIFFS_O_CREAT; + } + if ((flags & O_ACCMODE) == O_WRONLY) { + s_flags |= SPIFFS_O_WRONLY; + } + if ((flags & O_ACCMODE) == O_RDWR) { + s_flags |= SPIFFS_O_RDWR; + } +#ifdef __O_DIRECT + if ((flags & __O_DIRECT) == __O_DIRECT) { + s_flags |= SPIFFS_O_DIRECT; + } +#endif + if ((flags & O_EXCL) == O_EXCL) { + s_flags |= SPIFFS_O_EXCL; + } + + DEBUG("spiffs: open: %s (abs_path: %s), flags: 0x%x, mode: %d\n", name, abs_path, (int) s_flags, (int) mode); + + s32_t ret = SPIFFS_open(&fs_desc->fs, name, s_flags, mode); + if (ret >= 0) { + filp->private_data.value = ret; + return ret; + } + else { + return spiffs_err_to_errno(ret); + } +} + +static int _close(vfs_file_t *filp) +{ + spiffs_desc_t *fs_desc = filp->mp->private_data; + + return spiffs_err_to_errno(SPIFFS_close(&fs_desc->fs, filp->private_data.value)); +} + +static ssize_t _write(vfs_file_t *filp, const void *src, size_t nbytes) +{ + spiffs_desc_t *fs_desc = filp->mp->private_data; + + return spiffs_err_to_errno(SPIFFS_write(&fs_desc->fs, filp->private_data.value, src, nbytes)); +} + +static ssize_t _read(vfs_file_t *filp, void *dest, size_t nbytes) +{ + spiffs_desc_t *fs_desc = filp->mp->private_data; + + return spiffs_err_to_errno(SPIFFS_read(&fs_desc->fs, filp->private_data.value, dest, nbytes)); +} + +static off_t _lseek(vfs_file_t *filp, off_t off, int whence) +{ + spiffs_desc_t *fs_desc = filp->mp->private_data; + + int s_whence = 0; + if (whence == SEEK_SET) { + s_whence = SPIFFS_SEEK_SET; + } + else if (whence == SEEK_CUR) { + s_whence = SPIFFS_SEEK_CUR; + } + else if (whence == SEEK_END) { + s_whence = SPIFFS_SEEK_END; + } + + return spiffs_err_to_errno(SPIFFS_lseek(&fs_desc->fs, filp->private_data.value, off, s_whence)); +} + +static int _fstat(vfs_file_t *filp, struct stat *buf) +{ + spiffs_desc_t *fs_desc = filp->mp->private_data; + spiffs_stat stat; + s32_t ret; + + memset(buf, 0, sizeof(*buf)); + + ret = SPIFFS_fstat(&fs_desc->fs, filp->private_data.value, &stat); + + if (ret < 0) { + return ret; + } + /* stat.name; */ + buf->st_ino = stat.obj_id; + /* stat.pix; */ + buf->st_size = stat.size; + /* stat.type;*/ + buf->st_mode = S_IFREG; + + return spiffs_err_to_errno(ret); +} + +static int _opendir(vfs_DIR *dirp, const char *dirname, const char *abs_path) +{ + spiffs_desc_t *fs_desc = dirp->mp->private_data; + spiffs_DIR *d = (spiffs_DIR *)&dirp->private_data.buffer[0]; + (void) abs_path; + + spiffs_DIR *res = SPIFFS_opendir(&fs_desc->fs, dirname, d); + if (res == NULL) { + return -ENOENT; + } + + return 0; +} + +static int _readdir(vfs_DIR *dirp, vfs_dirent_t *entry) +{ + spiffs_DIR *d = (spiffs_DIR *)&dirp->private_data.buffer[0]; + struct spiffs_dirent e; + struct spiffs_dirent *ret; + + ret = SPIFFS_readdir(d, &e); + if (ret == NULL) { + s32_t err = SPIFFS_errno(d->fs); + if (err != SPIFFS_OK && err > SPIFFS_ERR_INTERNAL) { + DEBUG("spiffs: readdir: err=%" PRId32 "\n", err); + return -EIO; + } + } + + if (ret) { + entry->d_ino = e.obj_id; + strncpy(entry->d_name, (char*) e.name, VFS_NAME_MAX); + return 1; + } + else { + return 0; + } +} + +static int _closedir(vfs_DIR *dirp) +{ + spiffs_DIR *d = (spiffs_DIR *)&dirp->private_data.buffer[0]; + + return spiffs_err_to_errno(SPIFFS_closedir(d)); +} + +static int spiffs_err_to_errno (s32_t err) +{ + if (err >= 0) { + return (int) err; + } + + DEBUG("spiffs: error=%" PRId32 "\n", err); + + switch (err) { + case SPIFFS_OK: + return 0; + case SPIFFS_ERR_NOT_MOUNTED: + return -EINVAL; + case SPIFFS_ERR_FULL: + return -ENOSPC; + case SPIFFS_ERR_NOT_FOUND: + return -ENOENT; + case SPIFFS_ERR_END_OF_OBJECT: + return 0; + case SPIFFS_ERR_DELETED: + return -ENOENT; + case SPIFFS_ERR_MOUNTED: + return -EBUSY; + case SPIFFS_ERR_ERASE_FAIL: + return -EIO; + case SPIFFS_ERR_MAGIC_NOT_POSSIBLE: + return -ENOSPC; + case SPIFFS_ERR_NO_DELETED_BLOCKS: + return 0; + case SPIFFS_ERR_FILE_EXISTS: + return -EEXIST; + case SPIFFS_ERR_NOT_A_FILE: + return -ENOENT; + case SPIFFS_ERR_RO_NOT_IMPL: + return -EROFS; + case SPIFFS_ERR_RO_ABORTED_OPERATION: + return -SPIFFS_ERR_RO_ABORTED_OPERATION; + case SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS: + return -ENOSPC; + case SPIFFS_ERR_PROBE_NOT_A_FS: + return -ENODEV; + case SPIFFS_ERR_NAME_TOO_LONG: + return -ENAMETOOLONG; + case SPIFFS_ERR_NOT_FINALIZED: + return -ENODEV; + case SPIFFS_ERR_NOT_INDEX: + return -ENODEV; + case SPIFFS_ERR_OUT_OF_FILE_DESCS: + return -ENFILE; + case SPIFFS_ERR_FILE_CLOSED: + return -ENOENT; + case SPIFFS_ERR_FILE_DELETED: + return -ENOENT; + case SPIFFS_ERR_BAD_DESCRIPTOR: + return -EBADF; + case SPIFFS_ERR_IS_INDEX: + return -ENOENT; + case SPIFFS_ERR_IS_FREE: + return -ENOENT; + case SPIFFS_ERR_INDEX_SPAN_MISMATCH: + return -EIO; + case SPIFFS_ERR_DATA_SPAN_MISMATCH: + return -EIO; + case SPIFFS_ERR_INDEX_REF_FREE: + return -EIO; + case SPIFFS_ERR_INDEX_REF_LU: + return -EIO; + case SPIFFS_ERR_INDEX_REF_INVALID: + return -EIO; + case SPIFFS_ERR_INDEX_FREE: + return -EIO; + case SPIFFS_ERR_INDEX_LU: + return -EIO; + case SPIFFS_ERR_INDEX_INVALID: + return -EIO; + case SPIFFS_ERR_NOT_WRITABLE: + return -EACCES; + case SPIFFS_ERR_NOT_READABLE: + return -EACCES; + case SPIFFS_ERR_CONFLICTING_NAME: + return -EEXIST; + case SPIFFS_ERR_NOT_CONFIGURED: + return -ENODEV; + case SPIFFS_ERR_NOT_A_FS: + return -ENODEV; + } + + return (int) err; +} + +static const vfs_file_system_ops_t spiffs_fs_ops = { + .mount = _mount, + .umount = _umount, + .unlink = _unlink, + .rename = _rename, +}; + +static const vfs_file_ops_t spiffs_file_ops = { + .open = _open, + .close = _close, + .read = _read, + .write = _write, + .lseek = _lseek, + .fstat = _fstat, +}; + +static const vfs_dir_ops_t spiffs_dir_ops = { + .opendir = _opendir, + .readdir = _readdir, + .closedir = _closedir, +}; + +const vfs_file_system_t spiffs_file_system = { + .fs_op = &spiffs_fs_ops, + .f_op = &spiffs_file_ops, + .d_op = &spiffs_dir_ops, +}; diff --git a/pkg/spiffs/include/spiffs_config.h b/pkg/spiffs/include/spiffs_config.h new file mode 100644 index 0000000000..534d0fb487 --- /dev/null +++ b/pkg/spiffs/include/spiffs_config.h @@ -0,0 +1,301 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * spiffs_config.h + * + * Created on: Jul 3, 2013 + * Author: petera + */ + +#ifndef SPIFFS_CONFIG_H_ +#define SPIFFS_CONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "board.h" + +// ----------- 8< ------------ +// Following includes are for the linux test build of spiffs +// These may/should/must be removed/altered/replaced in your target +#include +#include +#include +#include +#include +#include + +// ----------- >8 ------------ + +// compile time switches + +// Set generic spiffs debug output call. +#ifndef SPIFFS_DBG +#define SPIFFS_DBG(...) //DEBUG(__VA_ARGS__) +#endif +// Set spiffs debug output call for garbage collecting. +#ifndef SPIFFS_GC_DBG +#define SPIFFS_GC_DBG(...) //DEBUG(__VA_ARGS__) +#endif +// Set spiffs debug output call for caching. +#ifndef SPIFFS_CACHE_DBG +#define SPIFFS_CACHE_DBG(...) //DEBUG(__VA_ARGS__) +#endif +// Set spiffs debug output call for system consistency checks. +#ifndef SPIFFS_CHECK_DBG +#define SPIFFS_CHECK_DBG(...) //DEBUG(__VA_ARGS__) +#endif + +// Enable/disable API functions to determine exact number of bytes +// for filedescriptor and cache buffers. Once decided for a configuration, +// this can be disabled to reduce flash. +#ifndef SPIFFS_BUFFER_HELP +#define SPIFFS_BUFFER_HELP 0 +#endif + +// Enables/disable memory read caching of nucleus file system operations. +// If enabled, memory area must be provided for cache in SPIFFS_mount. +#ifndef SPIFFS_CACHE +#define SPIFFS_CACHE 1 +#endif +#if SPIFFS_CACHE +// Enables memory write caching for file descriptors in hydrogen +#ifndef SPIFFS_CACHE_WR +#define SPIFFS_CACHE_WR 1 +#endif + +// Enable/disable statistics on caching. Debug/test purpose only. +#ifndef SPIFFS_CACHE_STATS +#define SPIFFS_CACHE_STATS 1 +#endif +#endif + +// Always check header of each accessed page to ensure consistent state. +// If enabled it will increase number of reads, will increase flash. +#ifndef SPIFFS_PAGE_CHECK +#define SPIFFS_PAGE_CHECK 1 +#endif + +// Define maximum number of gc runs to perform to reach desired free pages. +#ifndef SPIFFS_GC_MAX_RUNS +#define SPIFFS_GC_MAX_RUNS 5 +#endif + +// Enable/disable statistics on gc. Debug/test purpose only. +#ifndef SPIFFS_GC_STATS +#define SPIFFS_GC_STATS 1 +#endif + +// 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). +// To have a fair wear-leveling, the erase age is also included in score, +// whose factor normally is the most positive. +// 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. +#ifndef SPIFFS_GC_HEUR_W_DELET +#define SPIFFS_GC_HEUR_W_DELET (5) +#endif +// Garbage collecting heuristics - weight used for used pages. +#ifndef SPIFFS_GC_HEUR_W_USED +#define SPIFFS_GC_HEUR_W_USED (-1) +#endif +// Garbage collecting heuristics - weight used for time between +// last erased and erase of this block. +#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE +#define SPIFFS_GC_HEUR_W_ERASE_AGE (50) +#endif + +// Object name maximum length. Note that this length include the +// zero-termination character, meaning maximum string of characters +// can at most be SPIFFS_OBJ_NAME_LEN - 1. +#ifndef SPIFFS_OBJ_NAME_LEN +#define SPIFFS_OBJ_NAME_LEN (32) +#endif + +// Size of buffer allocated on stack used when copying data. +// Lower value generates more read/writes. No meaning having it bigger +// than logical page size. +#ifndef SPIFFS_COPY_BUFFER_STACK +#define SPIFFS_COPY_BUFFER_STACK (64) +#endif + +// Enable this to have an identifiable spiffs filesystem. This will look for +// a magic in all sectors to determine if this is a valid spiffs system or +// not on mount point. If not, SPIFFS_format must be called prior to mounting +// again. +#ifndef SPIFFS_USE_MAGIC +#define SPIFFS_USE_MAGIC (1) +#endif + +#if SPIFFS_USE_MAGIC +// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is +// enabled, the magic will also be dependent on the length of the filesystem. +// For example, a filesystem configured and formatted for 4 megabytes will not +// be accepted for mounting with a configuration defining the filesystem as 2 +// megabytes. +#ifndef SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_USE_MAGIC_LENGTH (0) +#endif +#endif + +// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level +// These should be defined on a multithreaded system + +struct spiffs_t; +void spiffs_lock(struct spiffs_t *fs); +void spiffs_unlock(struct spiffs_t *fs); + +// define this to enter a mutex if you're running on a multithreaded system +#ifndef SPIFFS_LOCK +#define SPIFFS_LOCK(fs) spiffs_lock(fs) +#endif +// define this to exit a mutex if you're running on a multithreaded system +#ifndef SPIFFS_UNLOCK +#define SPIFFS_UNLOCK(fs) spiffs_unlock(fs) +#endif + +// Enable if only one spiffs instance with constant configuration will exist +// on the target. This will reduce calculations, flash and memory accesses. +// Parts of configuration must be defined below instead of at time of mount. +#ifndef SPIFFS_SINGLETON +#define SPIFFS_SINGLETON 0 +#endif + +#if SPIFFS_SINGLETON +// Instead of giving parameters in config struct, singleton build must +// give parameters in defines below. +#ifndef SPIFFS_CFG_PHYS_SZ +#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2) +#endif +#ifndef SPIFFS_CFG_PHYS_ERASE_SZ +#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536) +#endif +#ifndef SPIFFS_CFG_PHYS_ADDR +#define SPIFFS_CFG_PHYS_ADDR(ignore) (0) +#endif +#ifndef SPIFFS_CFG_LOG_PAGE_SZ +#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256) +#endif +#ifndef SPIFFS_CFG_LOG_BLOCK_SZ +#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536) +#endif +#endif + +// Enable this if your target needs aligned data for index tables +#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES +#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0 +#endif + +// Enable this if you want the HAL callbacks to be called with the spiffs struct +#ifndef SPIFFS_HAL_CALLBACK_EXTRA +#define SPIFFS_HAL_CALLBACK_EXTRA 1 +#endif + +// Enable this if you want to add an integer offset to all file handles +// (spiffs_file). This is useful if running multiple instances of spiffs on +// same target, in order to recognise to what spiffs instance a file handle +// belongs. +// NB: This adds config field fh_ix_offset in the configuration struct when +// mounting, which must be defined. +#ifndef SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FILEHDL_OFFSET 0 +#endif + +// Enable this to compile a read only version of spiffs. +// This will reduce binary size of spiffs. All code comprising modification +// of the file system will not be compiled. Some config will be ignored. +// HAL functions for erasing and writing to spi-flash may be null. Cache +// can be disabled for even further binary size reduction (and ram savings). +// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL. +// If the file system cannot be mounted due to aborted erase operation and +// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be +// returned. +// Might be useful for e.g. bootloaders and such. +#ifndef SPIFFS_READ_ONLY +#define SPIFFS_READ_ONLY 0 +#endif + +// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function +// in the api. This function will visualize all filesystem using given printf +// function. +#ifndef SPIFFS_TEST_VISUALISATION +#define SPIFFS_TEST_VISUALISATION 0 +#endif +#if SPIFFS_TEST_VISUALISATION +#ifndef spiffs_printf +#define spiffs_printf(...) DEBUG(__VA_ARGS__) +#endif +// spiffs_printf argument for a free page +#ifndef SPIFFS_TEST_VIS_FREE_STR +#define SPIFFS_TEST_VIS_FREE_STR "_" +#endif +// spiffs_printf argument for a deleted page +#ifndef SPIFFS_TEST_VIS_DELE_STR +#define SPIFFS_TEST_VIS_DELE_STR "/" +#endif +// spiffs_printf argument for an index page for given object id +#ifndef SPIFFS_TEST_VIS_INDX_STR +#define SPIFFS_TEST_VIS_INDX_STR(id) "i" +#endif +// spiffs_printf argument for a data page for given object id +#ifndef SPIFFS_TEST_VIS_DATA_STR +#define SPIFFS_TEST_VIS_DATA_STR(id) "d" +#endif +#endif + +// Types depending on configuration such as the amount of flash bytes +// given to spiffs file system in total (spiffs_file_system_size), +// the logical block size (log_block_size), and the logical page size +// (log_page_size) + +// Block index type. Make sure the size of this type can hold +// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size +typedef uint16_t spiffs_block_ix; +// Page index type. Make sure the size of this type can hold +// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size +typedef uint16_t spiffs_page_ix; +// Object id type - most significant bit is reserved for index flag. Make sure the +// size of this type can hold the highest object id on a full system, +// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2 +typedef uint16_t spiffs_obj_id; +// Object span index type. Make sure the size of this type can +// hold the largest possible span index on the system - +// i.e. (spiffs_file_system_size / log_page_size) - 1 +typedef uint16_t spiffs_span_ix; + +typedef uint8_t u8_t; +typedef uint32_t u32_t; +typedef int32_t s32_t; +typedef uint16_t u16_t; +typedef int16_t s16_t; + +#ifdef __cplusplus +} +#endif + +#endif /* SPIFFS_CONFIG_H_ */ diff --git a/pkg/spiffs/patches/0001-Use-const-pointer-in-write-functions.patch b/pkg/spiffs/patches/0001-Use-const-pointer-in-write-functions.patch new file mode 100644 index 0000000000..565faf9d6f Binary files /dev/null and b/pkg/spiffs/patches/0001-Use-const-pointer-in-write-functions.patch differ diff --git a/pkg/spiffs/patches/0002-Use-const-pointer-through-all-write-functions.patch b/pkg/spiffs/patches/0002-Use-const-pointer-through-all-write-functions.patch new file mode 100644 index 0000000000..d5bc913e5e Binary files /dev/null and b/pkg/spiffs/patches/0002-Use-const-pointer-through-all-write-functions.patch differ diff --git a/sys/include/fs/spiffs_fs.h b/sys/include/fs/spiffs_fs.h new file mode 100644 index 0000000000..5316914068 --- /dev/null +++ b/sys/include/fs/spiffs_fs.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 OTA keys S.A. + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup fs + * @defgroup spiffs SPIFFS integration + * @{ + * + * @file + * @brief SPIFFS integration with vfs + * + * @author Vincent Dupont + */ + +#ifndef SPIFFS_FS_H +#define SPIFFS_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "spiffs.h" +#include "spiffs_config.h" +#include "vfs.h" +#include "mtd.h" +#include "mutex.h" + +/** Size of the buffer needed for directory */ +#define SPIFFS_DIR_SIZE (12) + +#if (VFS_DIR_BUFFER_SIZE < SPIFFS_DIR_SIZE) +#error "VFS_DIR_BUFFER_SIZE too small" +#endif + +/** + * @name SPIFFS config constants + * @{ + */ +#ifndef SPIFFS_FS_CACHE_SIZE +#if SPIFFS_CACHE +#define SPIFFS_FS_CACHE_SIZE (512) +#else +#define SPIFFS_FS_CACHE_SIZE (0) +#endif /* SPIFFS_CACHE */ +#endif /* SPIFFS_FS_CACHE_SIZE */ +#ifndef SPIFFS_FS_WORK_SIZE +#define SPIFFS_FS_WORK_SIZE (512) +#endif +#ifndef SPIFFS_FS_FD_SPACE_SIZE +#define SPIFFS_FS_FD_SPACE_SIZE (125) +#endif +/** @} */ + +/** + * This contains everything needed to run an instance of SPIFFS + */ +typedef struct spiffs_desc { + spiffs fs; /**< The SPIFFS struct */ + uint8_t work[SPIFFS_FS_WORK_SIZE]; /**< SPIFFS work buffer */ + uint8_t fd_space[SPIFFS_FS_FD_SPACE_SIZE]; /**< SPIFFS file descriptor cache */ +#if (SPIFFS_CACHE == 1) || defined(DOXYGEN) + uint8_t cache[SPIFFS_FS_CACHE_SIZE]; /**< SPIFFS cache */ +#endif + spiffs_config config; /**< SPIFFS config, filled at mount time depending + * on the underlying mtdi_dev_t @p dev */ + mutex_t lock; /**< A lock for SPIFFS internal use */ +#if (SPIFFS_HAL_CALLBACK_EXTRA == 1) || defined(DOXYGEN) + mtd_dev_t *dev; /**< The underlying mtd device, must be set by user */ +#endif +} spiffs_desc_t; + +/** The SPIFFS vfs driver, a pointer to a spiffs_desc_t must be provided as vfs_mountp::private_data */ +extern const vfs_file_system_t spiffs_file_system; + +#ifdef __cplusplus +} +#endif + +#endif /* SPIFFS_FS_H */ + +/** @} */