Try to use latest spiffs but not success.

This commit is contained in:
HuangRui 2015-05-21 10:39:02 +08:00
parent fc8fa2cc91
commit a1e67c5cf0
18 changed files with 647 additions and 119 deletions

View File

@ -13,8 +13,11 @@
#define LUA_USE_MODULES
#ifdef LUA_USE_MODULES
/*
#define LUA_USE_MODULES_NODE
*/
#define LUA_USE_MODULES_FILE
/*
#define LUA_USE_MODULES_GPIO
#define LUA_USE_MODULES_WIFI
#define LUA_USE_MODULES_NET
@ -31,6 +34,7 @@
#define LUA_USE_MODULES_U8G
#define LUA_USE_MODULES_WS2812
#define LUA_USE_MODULES_CJSON
*/
#endif /* LUA_USE_MODULES */
#endif /* __USER_MODULES_H__ */

View File

@ -303,4 +303,4 @@ Having these figures you can disable SPIFFS_BUFFER_HELP again to save flash.
* HOW TO CONFIG
TODO
TODO

View File

@ -1 +1,15 @@
* When mending lost pages, also see if they fit into length specified in object index header
* When mending lost pages, also see if they fit into length specified in object index header
SPIFFS2 thoughts
* Instead of exact object id:s in the object lookup tables, use a hash of span index and object id.
Eg. object id xor:ed with bit-reversed span index.
This should decrease number of actual pages that needs to be visited when looking thru the obj lut.
* Logical number of each block. When moving stuff in a garbage collected page, the free
page is assigned the same number as the garbage collected. Thus, object index pages do not have to
be rewritten.
* Steal one page, use as a bit parity page. When starting an fs modification operation, write one bit
as zero. When ending, write another bit as zero. On mount, if number of zeroes in page is uneven, a
check is automatically run.

View File

@ -1,6 +1,8 @@
#include "c_stdio.h"
#include "platform.h"
#include "spiffs.h"
#undef NODE_DBG
#define NODE_DBG c_printf
spiffs fs;
@ -78,6 +80,15 @@ void myspiffs_unmount() {
int myspiffs_format( void )
{
SPIFFS_unmount(&fs);
if(0 == SPIFFS_format(&fs))
{
return 1;
}
else
{
return 0;
}
#if 0
u32_t sect_first, sect_last;
sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL );
sect_first += 0x3000;
@ -90,7 +101,9 @@ int myspiffs_format( void )
if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )
return 0;
myspiffs_mount();
return 1;
#endif
}
int myspiffs_check( void )
@ -116,7 +129,7 @@ size_t myspiffs_write( int fd, const void* ptr, size_t len ){
return len;
}
#endif
int res = SPIFFS_write(&fs, (spiffs_file)fd, (void *)ptr, len);
int res = SPIFFS_write(&fs, (spiffs_file)fd, (void *)ptr, (size_t)len);
if (res < 0) {
NODE_DBG("write errno %i\n", SPIFFS_errno(&fs));
return 0;
@ -124,7 +137,7 @@ size_t myspiffs_write( int fd, const void* ptr, size_t len ){
return res;
}
size_t myspiffs_read( int fd, void* ptr, size_t len){
int res = SPIFFS_read(&fs, (spiffs_file)fd, ptr, len);
int res = SPIFFS_read(&fs, (spiffs_file)fd, ptr, (size_t)len);
if (res < 0) {
NODE_DBG("read errno %i\n", SPIFFS_errno(&fs));
return 0;

View File

@ -41,6 +41,13 @@ extern "C" {
#define SPIFFS_ERR_NOT_WRITABLE -10021
#define SPIFFS_ERR_NOT_READABLE -10022
#define SPIFFS_ERR_CONFLICTING_NAME -10023
#define SPIFFS_ERR_NOT_CONFIGURED -10024
#define SPIFFS_ERR_NOT_A_FS -10025
#define SPIFFS_ERR_MOUNTED -10026
#define SPIFFS_ERR_ERASE_FAIL -10027
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
#define SPIFFS_ERR_INTERNAL -10050
@ -215,6 +222,11 @@ typedef struct {
// check callback function
spiffs_check_callback check_cb_f;
// mounted flag
u8_t mounted;
// config magic
u32_t config_magic;
} spiffs;
/* spiffs file status struct */
@ -242,7 +254,10 @@ typedef struct {
// functions
/**
* Initializes the file system dynamic parameters and mounts the filesystem
* Initializes the file system dynamic parameters and mounts the filesystem.
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
* if the flash does not contain a recognizable file system.
* In this case, SPIFFS_format must be called prior to remounting.
* @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
@ -441,6 +456,24 @@ s32_t SPIFFS_check(spiffs *fs);
*/
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
/**
* Formats the entire file system. All data will be lost.
* The filesystem must not be mounted when calling this.
*
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
* MUST be called prior to formatting in order to configure the filesystem.
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
* SPIFFS_format.
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
* SPIFFS_unmount first.
*/
s32_t SPIFFS_format(spiffs *fs);
/**
* Returns nonzero if spiffs is mounted, or zero if unmounted.
*/
u8_t SPIFFS_mounted(spiffs *fs);
/**
* Check if EOF reached.
* @param fs the file system struct

View File

@ -195,7 +195,7 @@ s32_t spiffs_phys_wr(
cache->last_access++;
cp->last_access = cache->last_access;
if (cp->flags && SPIFFS_CACHE_FLAG_WRTHRU) {
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 {

View File

@ -30,19 +30,19 @@ typedef uint8_t u8_t;
// Set generic spiffs debug output call.
#ifndef SPIFFS_DGB
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_DBG(...) c_printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for garbage collecting.
#ifndef SPIFFS_GC_DGB
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_GC_DBG(...) //c_printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for caching.
#ifndef SPIFFS_CACHE_DGB
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_CACHE_DBG(...) //c_printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for system consistency checks.
#ifndef SPIFFS_CHECK_DGB
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_CHECK_DBG(...) //c_printf(__VA_ARGS__)
#endif
// Enable/disable API functions to determine exact number of bytes
@ -119,14 +119,22 @@ typedef uint8_t u8_t;
#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 (0)
#endif
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
// These should be defined on a multithreaded system
// define this to entering a mutex if you're running on a multithreaded system
// define this to enter a mutex if you're running on a multithreaded system
#ifndef SPIFFS_LOCK
#define SPIFFS_LOCK(fs)
#endif
// define this to exiting a mutex if you're running on a multithreaded system
// define this to exit a mutex if you're running on a multithreaded system
#ifndef SPIFFS_UNLOCK
#define SPIFFS_UNLOCK(fs)
#endif
@ -159,7 +167,12 @@ typedef uint8_t u8_t;
#endif
#endif
// Set SPFIFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
// 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
// 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

View File

@ -8,31 +8,11 @@ static s32_t spiffs_gc_erase_block(
spiffs *fs,
spiffs_block_ix bix) {
s32_t res;
u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);
s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);
SPIFFS_GC_DBG("gc: erase block %i\n", bix);
// here we ignore res, just try erasing the block
while (size > 0) {
SPIFFS_GC_DBG("gc: erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
(void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
}
fs->free_blocks++;
// register erase count for this block
res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
SPIFFS_ERASE_COUNT_PADDR(fs, bix),
sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count);
res = spiffs_erase_block(fs, bix);
SPIFFS_CHECK_RES(res);
fs->max_erase_count++;
if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {
fs->max_erase_count = 0;
}
#if SPIFFS_CACHE
{
u32_t i;
@ -130,12 +110,15 @@ s32_t spiffs_gc_check(
}
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
// SPIFFS_GC_DBG("gc: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
// return SPIFFS_ERR_FULL;
// }
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
SPIFFS_GC_DBG("gc_check: full freeblk:%i needed:%i free:%i dele:%i\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
return SPIFFS_ERR_FULL;
}
//printf("gcing started %i dirty, blocks %i free, want %i bytes\n", fs->stats_p_allocated + fs->stats_p_deleted, fs->free_blocks, len);
do {
SPIFFS_GC_DBG("\ngc_check #%i: run gc free_blocks:%i pfree:%i pallo:%i pdele:%i [%i] len:%i of %i\n",
tries,
@ -145,11 +128,13 @@ s32_t spiffs_gc_check(
spiffs_block_ix *cands;
int count;
spiffs_block_ix cand;
res = spiffs_gc_find_candidate(fs, &cands, &count);
s32_t prev_free_pages = free_pages;
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
SPIFFS_CHECK_RES(res);
if (count == 0) {
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
return res;
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
}
#if SPIFFS_GC_STATS
fs->stats_gc_runs++;
@ -176,6 +161,12 @@ s32_t spiffs_gc_check(
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
- fs->stats_p_allocated - fs->stats_p_deleted;
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
// abort early to reduce wear, at least tried once
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
break;
}
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
@ -234,7 +225,8 @@ s32_t spiffs_gc_erase_page_stats(
s32_t spiffs_gc_find_candidate(
spiffs *fs,
spiffs_block_ix **block_candidates,
int *candidate_count) {
int *candidate_count,
char fs_crammed) {
s32_t res = SPIFFS_OK;
u32_t blocks = fs->block_count;
spiffs_block_ix cur_block = 0;
@ -307,7 +299,7 @@ s32_t spiffs_gc_find_candidate(
s32_t score =
deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
erase_age * SPIFFS_GC_HEUR_W_ERASE_AGE;
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
int cand_ix = 0;
SPIFFS_GC_DBG("gc_check: bix:%i del:%i use:%i score:%i\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
while (cand_ix < max_candidates) {

View File

@ -21,6 +21,36 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) {
#endif
#endif
u8_t SPIFFS_mounted(spiffs *fs) {
return SPIFFS_CHECK_MOUNT(fs);
}
s32_t SPIFFS_format(spiffs *fs) {
SPIFFS_API_CHECK_CFG(fs);
if (SPIFFS_CHECK_MOUNT(fs)) {
fs->err_code = SPIFFS_ERR_MOUNTED;
return -1;
}
s32_t res;
SPIFFS_LOCK(fs);
spiffs_block_ix bix = 0;
while (bix < fs->block_count) {
fs->max_erase_count = 0;
res = spiffs_erase_block(fs, bix);
if (res != SPIFFS_OK) {
res = SPIFFS_ERR_ERASE_FAIL;
}
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
bix++;
}
SPIFFS_UNLOCK(fs);
return 0;
}
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
u8_t *fd_space, u32_t fd_space_size,
void *cache, u32_t cache_size,
@ -65,7 +95,16 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
spiffs_cache_init(fs);
#endif
s32_t res = spiffs_obj_lu_scan(fs);
s32_t res;
#if SPIFFS_USE_MAGIC
res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE;
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
#endif
fs->config_magic = SPIFFS_CONFIG_MAGIC;
res = spiffs_obj_lu_scan(fs);
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_DBG("page index byte len: %i\n", SPIFFS_CFG_LOG_PAGE_SZ(fs));
@ -79,13 +118,15 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
fs->check_cb_f = check_cb_f;
fs->mounted = 1;
SPIFFS_UNLOCK(fs);
return 0;
}
void SPIFFS_unmount(spiffs *fs) {
if (!SPIFFS_CHECK_MOUNT(fs)) return;
if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;
SPIFFS_LOCK(fs);
u32_t i;
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
@ -98,7 +139,8 @@ void SPIFFS_unmount(spiffs *fs) {
spiffs_fd_return(fs, cur_fd->file_nbr);
}
}
fs->block_count = 0;
fs->mounted = 0;
SPIFFS_UNLOCK(fs);
}
@ -112,6 +154,7 @@ void SPIFFS_clearerr(spiffs *fs) {
s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) {
(void)mode;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_obj_id obj_id;
@ -127,6 +170,7 @@ s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) {
spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode) {
(void)mode;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -185,6 +229,7 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode
}
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -214,6 +259,7 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl
}
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -282,6 +328,7 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs
}
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -400,6 +447,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
}
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -444,6 +492,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
}
s32_t SPIFFS_remove(spiffs *fs, char *path) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -477,6 +526,7 @@ s32_t SPIFFS_remove(spiffs *fs, char *path) {
}
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -525,6 +575,7 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi
}
s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -542,6 +593,7 @@ s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) {
}
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -595,6 +647,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
s32_t res = SPIFFS_OK;
#if SPIFFS_CACHE_WR
@ -608,6 +661,11 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
}
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
if (!SPIFFS_CHECK_CFG((fs))) {
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
return;
}
if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return;
@ -623,6 +681,7 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -664,10 +723,17 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) {
(void)name;
if (!SPIFFS_CHECK_CFG((fs))) {
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
return 0;
}
if (!SPIFFS_CHECK_MOUNT(fs)) {
fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
return 0;
}
d->fs = fs;
d->block = 0;
d->entry = 0;
@ -743,12 +809,14 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
}
s32_t SPIFFS_closedir(spiffs_DIR *d) {
SPIFFS_API_CHECK_CFG(d->fs);
SPIFFS_API_CHECK_MOUNT(d->fs);
return 0;
}
s32_t SPIFFS_check(spiffs *fs) {
s32_t res;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -766,6 +834,7 @@ s32_t SPIFFS_check(spiffs *fs) {
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
s32_t res = SPIFFS_OK;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -788,11 +857,13 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
}
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
s32_t res = SPIFFS_OK;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
s32_t res;
res = spiffs_fd_get(fs, fh, &fd);
SPIFFS_API_CHECK_RES(fs, res);
@ -807,11 +878,13 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
s32_t res = SPIFFS_OK;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
s32_t res;
res = spiffs_fd_get(fs, fh, &fd);
SPIFFS_API_CHECK_RES(fs, res);
@ -826,11 +899,13 @@ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_size(spiffs *fs, spiffs_file fh) {
s32_t res = SPIFFS_OK;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
spiffs_fd *fd;
s32_t res;
res = spiffs_fd_get(fs, fh, &fd);
SPIFFS_API_CHECK_RES(fs, res);
@ -847,6 +922,7 @@ s32_t SPIFFS_size(spiffs *fs, spiffs_file fh) {
#if SPIFFS_TEST_VISUALISATION
s32_t SPIFFS_vis(spiffs *fs) {
s32_t res = SPIFFS_OK;
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);

View File

@ -142,9 +142,13 @@ s32_t spiffs_obj_lu_find_entry_visitor(
cur_block++;
cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);
if (cur_block >= fs->block_count) {
// block wrap
cur_block = 0;
cur_block_addr = 0;
if (flags & SPIFFS_VIS_NO_WRAP) {
return SPIFFS_VIS_END;
} else {
// block wrap
cur_block = 0;
cur_block_addr = 0;
}
}
}
@ -213,6 +217,45 @@ s32_t spiffs_obj_lu_find_entry_visitor(
return SPIFFS_VIS_END;
}
s32_t spiffs_erase_block(
spiffs *fs,
spiffs_block_ix bix) {
s32_t res;
u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);
s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);
// here we ignore res, just try erasing the block
while (size > 0) {
SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
(void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
}
fs->free_blocks++;
// register erase count for this block
res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
SPIFFS_ERASE_COUNT_PADDR(fs, bix),
sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count);
SPIFFS_CHECK_RES(res);
#if SPIFFS_USE_MAGIC
// finally, write magic
spiffs_obj_id magic = SPIFFS_MAGIC(fs);
res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
SPIFFS_MAGIC_PADDR(fs, bix),
sizeof(spiffs_obj_id), (u8_t *)&magic);
SPIFFS_CHECK_RES(res);
#endif
fs->max_erase_count++;
if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {
fs->max_erase_count = 0;
}
return res;
}
static s32_t spiffs_obj_lu_scan_v(
spiffs *fs,
@ -238,40 +281,44 @@ static s32_t spiffs_obj_lu_scan_v(
return SPIFFS_VIS_COUNTINUE;
}
// Scans thru all obj lu and counts free, deleted and used pages
// Find the maximum block erase count
// Checks magic if enabled
s32_t spiffs_obj_lu_scan(
spiffs *fs) {
s32_t res;
spiffs_block_ix bix;
int entry;
#if SPIFFS_USE_MAGIC
spiffs_block_ix unerased_bix = (spiffs_block_ix)-1;
#endif
fs->free_blocks = 0;
fs->stats_p_allocated = 0;
fs->stats_p_deleted = 0;
res = spiffs_obj_lu_find_entry_visitor(fs,
0,
0,
0,
0,
spiffs_obj_lu_scan_v,
0,
0,
&bix,
&entry);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
SPIFFS_CHECK_RES(res);
// find out erase count
// if enabled, check magic
bix = 0;
spiffs_obj_id erase_count_final;
spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE;
spiffs_obj_id erase_count_max = 0;
while (bix < fs->block_count) {
#if SPIFFS_USE_MAGIC
spiffs_obj_id magic;
res = _spiffs_rd(fs,
SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
0, SPIFFS_MAGIC_PADDR(fs, bix) ,
sizeof(spiffs_obj_id), (u8_t *)&magic);
SPIFFS_CHECK_RES(res);
if (magic != SPIFFS_MAGIC(fs)) {
if (unerased_bix == (spiffs_block_ix)-1) {
// allow one unerased block as it might be powered down during an erase
unerased_bix = bix;
} else {
// more than one unerased block, bail out
SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS);
}
}
#endif
spiffs_obj_id erase_count;
res = _spiffs_rd(fs,
SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
@ -297,6 +344,38 @@ s32_t spiffs_obj_lu_scan(
fs->max_erase_count = erase_count_final;
#if SPIFFS_USE_MAGIC
if (unerased_bix != (spiffs_block_ix)-1) {
// found one unerased block, remedy
SPIFFS_DBG("mount: erase block %i\n", bix);
res = spiffs_erase_block(fs, unerased_bix);
SPIFFS_CHECK_RES(res);
}
#endif
// count blocks
fs->free_blocks = 0;
fs->stats_p_allocated = 0;
fs->stats_p_deleted = 0;
res = spiffs_obj_lu_find_entry_visitor(fs,
0,
0,
0,
0,
spiffs_obj_lu_scan_v,
0,
0,
&bix,
&entry);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
SPIFFS_CHECK_RES(res);
return res;
}

View File

@ -131,6 +131,10 @@
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
#define SPIFFS_MAGIC(fs) ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
#define SPIFFS_CONFIG_MAGIC (0x20090315)
#if SPIFFS_SINGLETON == 0
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
((fs)->cfg.log_page_size)
@ -189,9 +193,18 @@
// returns data size in a data page
#define SPIFFS_DATA_PAGE_SIZE(fs) \
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
// returns physical address for block's erase count
// returns physical address for block's erase count,
// always in the physical last entry of the last object lookup page
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
// returns physical address for block's magic,
// always in the physical second last entry of the last object lookup page
#define SPIFFS_MAGIC_PADDR(fs, bix) \
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
// checks if there is any room for magic in the object luts
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
// define helpers object
@ -238,7 +251,10 @@
#define SPIFFS_CHECK_MOUNT(fs) \
((fs)->block_count > 0)
((fs)->mounted != 0)
#define SPIFFS_CHECK_CFG(fs) \
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
#define SPIFFS_CHECK_RES(res) \
do { \
@ -251,6 +267,12 @@
return -1; \
}
#define SPIFFS_API_CHECK_CFG(fs) \
if (!SPIFFS_CHECK_CFG((fs))) { \
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
return -1; \
}
#define SPIFFS_API_CHECK_RES(fs, res) \
if ((res) < SPIFFS_OK) { \
(fs)->err_code = (res); \
@ -381,6 +403,8 @@ typedef struct {
// object structs
// page header, part of each page except object lookup pages
// NB: this is always aligned when the data page is an object index,
// as in this case struct spiffs_page_object_ix is used
typedef struct __attribute(( packed )) {
// object id
spiffs_obj_id obj_id;
@ -391,11 +415,15 @@ typedef struct __attribute(( packed )) {
} spiffs_page_header;
// object index header page header
typedef struct __attribute(( packed )) {
typedef struct __attribute(( packed ))
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
#endif
{
// common page header
spiffs_page_header p_hdr;
// alignment
u8_t _align[4 - ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)==0 ? 4 : ((sizeof(spiffs_page_header)+sizeof(spiffs_obj_type)+SPIFFS_OBJ_NAME_LEN)&3)];
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
@ -478,6 +506,10 @@ s32_t spiffs_obj_lu_find_entry_visitor(
spiffs_block_ix *block_ix,
int *lu_entry);
s32_t spiffs_erase_block(
spiffs *fs,
spiffs_block_ix bix);
// ---------------
s32_t spiffs_obj_lu_scan(
@ -625,7 +657,8 @@ s32_t spiffs_gc_erase_page_stats(
s32_t spiffs_gc_find_candidate(
spiffs *fs,
spiffs_block_ix **block_candidate,
int *candidate_count);
int *candidate_count,
char fs_crammed);
s32_t spiffs_gc_clean(
spiffs *fs,

View File

@ -15,6 +15,9 @@
// spiffs file system offset in emulated spi flash
#define SPIFFS_PHYS_ADDR (4*1024*1024)
// test using filesystem magic
//#define SPIFFS_USE_MAGIC 1
#define SECTOR_SIZE 65536
#define LOG_BLOCK (SECTOR_SIZE*2)
#define LOG_PAGE (SECTOR_SIZE/256)

View File

@ -17,7 +17,6 @@
#include <dirent.h>
#include <unistd.h>
SUITE(bug_tests)
void setup() {
_setup_test_only();
@ -27,7 +26,7 @@ void teardown() {
}
TEST(nodemcu_full_fs_1) {
fs_reset_specific(0, 4096*20, 4096, 4096, 256);
fs_reset_specific(0, 0, 4096*20, 4096, 4096, 256);
int res;
spiffs_file fd;
@ -86,7 +85,7 @@ TEST(nodemcu_full_fs_1) {
} TEST_END(nodemcu_full_fs_1)
TEST(nodemcu_full_fs_2) {
fs_reset_specific(0, 4096*22, 4096, 4096, 256);
fs_reset_specific(0, 0, 4096*22, 4096, 4096, 256);
int res;
spiffs_file fd;
@ -116,6 +115,8 @@ TEST(nodemcu_full_fs_2) {
SPIFFS_clearerr(FS);
printf(" create small file\n");
fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
#if 0
// before gc in v3.1
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
TEST_CHECK(fd > 0);
@ -130,12 +131,17 @@ TEST(nodemcu_full_fs_2) {
printf(" >>> file %s size: %i\n", s.name, s.size);
TEST_CHECK(s.size == 0);
SPIFFS_clearerr(FS);
#else
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL);
SPIFFS_clearerr(FS);
#endif
printf(" remove files\n");
res = SPIFFS_remove(FS, "test1.txt");
TEST_CHECK(res == SPIFFS_OK);
#if 0
res = SPIFFS_remove(FS, "test2.txt");
TEST_CHECK(res == SPIFFS_OK);
#endif
printf(" create medium file\n");
fd = SPIFFS_open(FS, "test3.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
@ -157,4 +163,169 @@ TEST(nodemcu_full_fs_2) {
} TEST_END(nodemcu_full_fs_2)
TEST(magic_test) {
// one obj lu page, not full
fs_reset_specific(0, 0, 4096*16, 4096, 4096*1, 128);
TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS));
// one obj lu page, full
fs_reset_specific(0, 0, 4096*16, 4096, 4096*2, 128);
TEST_CHECK(!SPIFFS_CHECK_MAGIC_POSSIBLE(FS));
// two obj lu pages, not full
fs_reset_specific(0, 0, 4096*16, 4096, 4096*4, 128);
TEST_CHECK(SPIFFS_CHECK_MAGIC_POSSIBLE(FS));
return TEST_RES_OK;
} TEST_END(magic_test)
TEST(nodemcu_309) {
fs_reset_specific(0, 0, 4096*20, 4096, 4096, 256);
int res;
spiffs_file fd;
int j;
for (j = 1; j <= 3; j++) {
char fname[32];
sprintf(fname, "20K%i.txt", j);
fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0);
TEST_CHECK(fd > 0);
int i;
spiffs_stat s;
res = SPIFFS_OK;
u8_t err = 0;
for (i = 1; i <= 1280; i++) {
char *buf = "0123456789ABCDE\n";
res = SPIFFS_write(FS, fd, buf, strlen(buf));
if (!err && res < 0) {
printf("err @ %i,%i\n", i, j);
err = 1;
}
}
}
int errno = SPIFFS_errno(FS);
TEST_CHECK(errno == SPIFFS_ERR_FULL);
u32_t total;
u32_t used;
SPIFFS_info(FS, &total, &used);
printf("total:%i\nused:%i\nremain:%i\nerrno:%i\n", total, used, total-used, errno);
TEST_CHECK(total-used < 11000);
spiffs_DIR d;
struct spiffs_dirent e;
struct spiffs_dirent *pe = &e;
SPIFFS_opendir(FS, "/", &d);
int spoon_guard = 0;
while ((pe = SPIFFS_readdir(&d, pe))) {
printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size);
TEST_CHECK(spoon_guard++ < 3);
}
TEST_CHECK(spoon_guard == 3);
SPIFFS_closedir(&d);
return TEST_RES_OK;
} TEST_END(nodemcu_309)
TEST(robert) {
// create a clean file system starting at address 0, 2 megabytes big,
// sector size 65536, block size 65536, page size 256
fs_reset_specific(0, 0, 1024*1024*2, 65536, 65536, 256);
int res;
spiffs_file fd;
char fname[32];
sprintf(fname, "test.txt");
fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
TEST_CHECK(fd > 0);
int i;
res = SPIFFS_OK;
char buf[500];
memset(buf, 0xaa, 500);
res = SPIFFS_write(FS, fd, buf, 500);
TEST_CHECK(res >= SPIFFS_OK);
SPIFFS_close(FS, fd);
int errno = SPIFFS_errno(FS);
TEST_CHECK(errno == SPIFFS_OK);
//SPIFFS_vis(FS);
// unmount
SPIFFS_unmount(FS);
// remount
res = fs_mount_specific(0, 1024*1024*2, 65536, 65536, 256);
TEST_CHECK(res== SPIFFS_OK);
//SPIFFS_vis(FS);
spiffs_stat s;
TEST_CHECK(SPIFFS_stat(FS, fname, &s) == SPIFFS_OK);
printf("file %s stat size %i\n", s.name, s.size);
TEST_CHECK(s.size == 500);
return TEST_RES_OK;
} TEST_END(robert)
TEST(spiffs_12) {
fs_reset_specific(0x4024c000, 0x4024c000 + 0, 192*1024, 4096, 4096*2, 256);
int res;
spiffs_file fd;
int j = 1;
while (1) {
char fname[32];
sprintf(fname, "file%i.txt", j);
fd = SPIFFS_open(FS, fname, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_DIRECT, 0);
if (fd <=0) break;
int i;
res = SPIFFS_OK;
for (i = 1; i <= 100; i++) {
char *buf = "0123456789ABCDE\n";
res = SPIFFS_write(FS, fd, buf, strlen(buf));
if (res < 0) break;
}
SPIFFS_close(FS, fd);
j++;
}
int errno = SPIFFS_errno(FS);
TEST_CHECK(errno == SPIFFS_ERR_FULL);
u32_t total;
u32_t used;
SPIFFS_info(FS, &total, &used);
printf("total:%i (%iK)\nused:%i (%iK)\nremain:%i (%iK)\nerrno:%i\n", total, total/1024, used, used/1024, total-used, (total-used)/1024, errno);
spiffs_DIR d;
struct spiffs_dirent e;
struct spiffs_dirent *pe = &e;
SPIFFS_opendir(FS, "/", &d);
while ((pe = SPIFFS_readdir(&d, pe))) {
printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size);
}
SPIFFS_closedir(&d);
//SPIFFS_vis(FS);
//dump_page(FS, 0);
//dump_page(FS, 1);
return TEST_RES_OK;
} TEST_END(spiffs_12)
SUITE_END(bug_tests)

View File

@ -592,7 +592,6 @@ TEST(simultaneous_write_append) {
}
TEST_END(simultaneous_write_append)
TEST(file_uniqueness)
{
int res;

View File

@ -24,9 +24,12 @@
#include <dirent.h>
#include <unistd.h>
static unsigned char area[PHYS_FLASH_SIZE];
#define AREA(x) area[(x) - addr_offset]
static int erases[256];
static unsigned char area[PHYS_FLASH_SIZE];
static u32_t addr_offset = 0;
static int erases[PHYS_FLASH_SIZE/SECTOR_SIZE];
static char _path[256];
static u32_t bytes_rd = 0;
static u32_t bytes_wr = 0;
@ -88,7 +91,7 @@ static s32_t _read(u32_t addr, u32_t size, u8_t *dst) {
printf("FATAL read addr too high %08x + %08x > %08x\n", addr, size, SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE);
exit(0);
}
memcpy(dst, &area[addr], size);
memcpy(dst, &AREA(addr), size);
return 0;
}
@ -117,14 +120,14 @@ static s32_t _write(u32_t addr, u32_t size, u8_t *src) {
for (i = 0; i < size; i++) {
if (((addr + i) & (__fs.cfg.log_page_size-1)) != offsetof(spiffs_page_header, flags)) {
if (check_valid_flash && ((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);
if (check_valid_flash && ((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) / LOG_PAGE;
dump_page(&__fs, pix);
return -1;
}
}
area[addr + i] &= src[i];
AREA(addr + i) &= src[i];
}
return 0;
}
@ -139,7 +142,7 @@ static s32_t _erase(u32_t addr, u32_t size) {
return -1;
}
erases[(addr-__fs.cfg.phys_addr)/__fs.cfg.phys_erase_block]++;
memset(&area[addr], 0xff, size);
memset(&AREA(addr), 0xff, size);
return 0;
}
@ -165,7 +168,7 @@ void hexdump(u32_t addr, u32_t len) {
if (a-32+j < addr)
printf(" ");
else {
printf("%c", (area[a-32+j] < 32 || area[a-32+j] >= 0x7f) ? '.' : area[a-32+j]);
printf("%c", (AREA(a-32+j) < 32 || AREA(a-32+j) >= 0x7f) ? '.' : AREA(a-32+j));
}
}
}
@ -174,7 +177,7 @@ void hexdump(u32_t addr, u32_t len) {
if (a < addr) {
printf(" ");
} else {
printf("%02x", area[a]);
printf("%02x", AREA(a));
}
}
int j;
@ -183,7 +186,7 @@ void hexdump(u32_t addr, u32_t len) {
if (a-32+j < addr)
printf(" ");
else {
printf("%c", (area[a-32+j] < 32 || area[a-32+j] >= 0x7f) ? '.' : area[a-32+j]);
printf("%c", (AREA(a-32+j) < 32 || AREA(a-32+j) >= 0x7f) ? '.' : AREA(a-32+j));
}
}
printf("\n");
@ -198,9 +201,9 @@ void dump_page(spiffs *fs, spiffs_page_ix p) {
} else {
u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs , p)) +
SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, p) * sizeof(spiffs_obj_id);
spiffs_obj_id obj_id = *((spiffs_obj_id *)&area[obj_id_addr]);
spiffs_obj_id obj_id = *((spiffs_obj_id *)&AREA(obj_id_addr));
// data page
spiffs_page_header *ph = (spiffs_page_header *)&area[addr];
spiffs_page_header *ph = (spiffs_page_header *)&AREA(addr);
printf("DATA %04x:%04x ", obj_id, ph->span_ix);
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_FINAL) == 0) ? "FIN " : "fin ");
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_DELET) == 0) ? "DEL " : "del ");
@ -212,7 +215,7 @@ void dump_page(spiffs *fs, spiffs_page_ix p) {
printf("OBJ_IX");
if (ph->span_ix == 0) {
printf("_HDR ");
spiffs_page_object_ix_header *oix_hdr = (spiffs_page_object_ix_header *)&area[addr];
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 {
@ -228,14 +231,14 @@ void dump_page(spiffs *fs, spiffs_page_ix p) {
void area_write(u32_t addr, u8_t *buf, u32_t size) {
int i;
for (i = 0; i < size; i++) {
area[addr + i] = *buf++;
AREA(addr + i) = *buf++;
}
}
void area_read(u32_t addr, u8_t *buf, u32_t size) {
int i;
for (i = 0; i < size; i++) {
*buf++ = area[addr + i];
*buf++ = AREA(addr + i);
}
}
@ -313,12 +316,13 @@ static void spiffs_check_cb_f(spiffs_check_type type, spiffs_check_report report
}
}
void fs_reset_specific(u32_t phys_addr, u32_t phys_size,
void fs_set_addr_offset(u32_t offset) {
addr_offset = offset;
}
s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size,
u32_t phys_sector_size,
u32_t log_block_size, u32_t log_page_size) {
memset(area, 0xcc, sizeof(area));
memset(&area[phys_addr], 0xff, phys_size);
spiffs_config c;
c.hal_erase_f = _erase;
c.hal_read_f = _read;
@ -329,10 +333,35 @@ void fs_reset_specific(u32_t phys_addr, u32_t phys_size,
c.phys_erase_block = phys_sector_size;
c.phys_size = phys_size;
return SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f);
}
void fs_reset_specific(u32_t addr_offset, u32_t phys_addr, u32_t phys_size,
u32_t phys_sector_size,
u32_t log_block_size, u32_t log_page_size) {
fs_set_addr_offset(addr_offset);
memset(area, 0xcc, sizeof(area));
memset(&AREA(phys_addr), 0xff, phys_size);
memset(&__fs, 0, sizeof(__fs));
memset(erases,0,sizeof(erases));
memset(_cache,0,sizeof(_cache));
SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f);
s32_t res = fs_mount_specific(phys_addr, phys_size, phys_sector_size, log_block_size, log_page_size);
#if SPIFFS_USE_MAGIC
if (res == SPIFFS_OK) {
SPIFFS_unmount(&__fs);
}
res = SPIFFS_format(&__fs);
if (res != SPIFFS_OK) {
printf("format failed, %i\n", SPIFFS_errno(&__fs));
}
res = SPIFFS_mount(&__fs, &c, _work, _fds, sizeof(_fds), _cache, sizeof(_cache), spiffs_check_cb_f);
if (res != SPIFFS_OK) {
printf("mount failed, %i\n", SPIFFS_errno(&__fs));
}
#endif
clear_flash_ops_log();
log_flash_ops = 1;
@ -340,7 +369,7 @@ void fs_reset_specific(u32_t phys_addr, u32_t phys_size,
}
void fs_reset() {
fs_reset_specific(SPIFFS_PHYS_ADDR, SPIFFS_FLASH_SIZE, SECTOR_SIZE, LOG_BLOCK, LOG_PAGE);
fs_reset_specific(0, SPIFFS_PHYS_ADDR, SPIFFS_FLASH_SIZE, SECTOR_SIZE, LOG_BLOCK, LOG_PAGE);
}
void set_flash_ops_log(int enable) {
@ -574,6 +603,8 @@ void _teardown() {
printf(" cache hits : %i (sum %i)\n", (FS)->cache_hits, chits_tot);
printf(" cache misses : %i (sum %i)\n", (FS)->cache_misses, cmiss_tot);
printf(" cache utiliz : %f\n", ((float)chits_tot/(float)(chits_tot + cmiss_tot)));
chits_tot = 0;
cmiss_tot = 0;
#endif
#endif
dump_flash_access_stats();
@ -586,8 +617,8 @@ void _teardown() {
SPIFFS_check(FS);
clear_test_path();
//hexdump_mem(&area[SPIFFS_PHYS_ADDR - 16], 32);
//hexdump_mem(&area[SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE - 16], 32);
//hexdump_mem(&AREA(SPIFFS_PHYS_ADDR - 16), 32);
//hexdump_mem(&AREA(SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE - 16), 32);
}
u32_t tfile_get_size(tfile_size s) {

View File

@ -57,9 +57,13 @@ typedef struct {
void fs_reset();
void fs_reset_specific(u32_t phys_addr, u32_t phys_size,
void fs_reset_specific(u32_t addr_offset, u32_t phys_addr, u32_t phys_size,
u32_t phys_sector_size,
u32_t log_block_size, u32_t log_page_size);
s32_t fs_mount_specific(u32_t phys_addr, u32_t phys_size,
u32_t phys_sector_size,
u32_t log_block_size, u32_t log_page_size);
void fs_set_addr_offset(u32_t offset);
int read_and_verify(char *name);
int read_and_verify_fd(spiffs_file fd, char *name);
void dump_page(spiffs *fs, spiffs_page_ix p);

View File

@ -28,6 +28,8 @@ static struct {
test_res *stopped;
test_res *stopped_last;
FILE *spec;
char incl_filter[256];
char excl_filter[256];
} test_main;
void test_init(void (*on_stop)(test *t)) {
@ -41,7 +43,7 @@ static char check_spec(char *name) {
size_t sz;
ssize_t read;
while ((read = getline(&line, &sz, test_main.spec)) != -1) {
if (strncmp(line, name, strlen(name)) == 0) {
if (strncmp(line, name, strlen(line)-1) == 0) {
free(line);
return 1;
}
@ -53,9 +55,21 @@ static char check_spec(char *name) {
}
}
static char check_incl_filter(char *name) {
if (strlen(test_main.incl_filter)== 0) return 1;
return strstr(name, test_main.incl_filter) == 0 ? 0 : 1;
}
static char check_excl_filter(char *name) {
if (strlen(test_main.excl_filter)== 0) return 1;
return strstr(name, test_main.excl_filter) == 0 ? 1 : 0;
}
void add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)) {
if (f == 0) return;
if (!check_spec(name)) return;
if (!check_incl_filter(name)) return;
if (!check_excl_filter(name)) return;
DBGT("adding test %s\n", name);
test *t = malloc(sizeof(test));
memset(t, 0, sizeof(test));
@ -94,16 +108,36 @@ static void dump_res(test_res **head) {
}
}
void run_tests(int argc, char **args) {
int run_tests(int argc, char **args) {
memset(&test_main, 0, sizeof(test_main));
if (argc > 1) {
printf("running tests from %s\n", args[1]);
FILE *fd = fopen(args[1], "r");
if (fd == NULL) {
printf("%s not found\n", args[1]);
exit(EXIT_FAILURE);
int arg;
int incl_filter = 0;
int excl_filter = 0;
for (arg = 1; arg < argc; arg++) {
if (strlen(args[arg]) == 0) continue;
if (0 == strcmp("-f", args[arg])) {
incl_filter = 1;
continue;
}
if (0 == strcmp("-e", args[arg])) {
excl_filter = 1;
continue;
}
if (incl_filter) {
strcpy(test_main.incl_filter, args[arg]);
incl_filter = 0;
} else if (excl_filter) {
strcpy(test_main.excl_filter, args[arg]);
excl_filter = 0;
} else {
printf("running tests from %s\n", args[arg]);
FILE *fd = fopen(args[1], "r");
if (fd == NULL) {
printf("%s not found\n", args[arg]);
return -2;
}
test_main.spec = fd;
}
test_main.spec = fd;
}
DBGT("adding suites...\n");
@ -115,7 +149,7 @@ void run_tests(int argc, char **args) {
if (test_main.test_count == 0) {
printf("No tests to run\n");
return;
return 0;
}
int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
@ -133,6 +167,7 @@ void run_tests(int argc, char **args) {
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->test_result = res;
cur_t->teardown(cur_t);
int fd = res == TEST_RES_OK ? fd_success : fd_bad;
write(fd, cur_t->name, strlen(cur_t->name));
@ -169,7 +204,9 @@ void run_tests(int argc, char **args) {
dump_res(&test_main.stopped);
if (ok < test_main.test_count) {
printf("\nFAILED\n");
return -1;
} else {
printf("\nALL TESTS OK\n");
return 0;
}
}

View File

@ -48,8 +48,8 @@ void add_suites() {
}
*/
#ifndef TESTS_H_
#define TESTS_H_
#ifndef TESTRUNNER_H_
#define TESTRUNNER_H_
#define TEST_RES_OK 0
#define TEST_RES_FAIL -1
@ -66,6 +66,7 @@ typedef struct test_s {
void (*setup)(struct test_s *t);
void (*teardown)(struct test_s *t);
struct test_s *_next;
unsigned char test_result;
} test;
typedef struct test_res_s {
@ -77,6 +78,30 @@ typedef struct test_res_s {
printf(" TEST FAIL %s:%i\n", __FILE__, __LINE__); \
goto __fail_stop; \
}
#define TEST_CHECK_EQ(x, y) if ((x) != (y)) { \
printf(" TEST FAIL %s:%i, %i != %i\n", __FILE__, __LINE__, (x), (y)); \
goto __fail_stop; \
}
#define TEST_CHECK_NEQ(x, y) if ((x) == (y)) { \
printf(" TEST FAIL %s:%i, %i == %i\n", __FILE__, __LINE__, (x), (y)); \
goto __fail_stop; \
}
#define TEST_CHECK_GT(x, y) if ((x) <= (y)) { \
printf(" TEST FAIL %s:%i, %i <= %i\n", __FILE__, __LINE__, (x), (y)); \
goto __fail_stop; \
}
#define TEST_CHECK_LT(x, y) if ((x) >= (y)) { \
printf(" TEST FAIL %s:%i, %i >= %i\n", __FILE__, __LINE__, (x), (y)); \
goto __fail_stop; \
}
#define TEST_CHECK_GE(x, y) if ((x) < (y)) { \
printf(" TEST FAIL %s:%i, %i < %i\n", __FILE__, __LINE__, (x), (y)); \
goto __fail_stop; \
}
#define TEST_CHECK_LE(x, y) if ((x) > (y)) { \
printf(" TEST FAIL %s:%i, %i > %i\n", __FILE__, __LINE__, (x), (y)); \
goto __fail_stop; \
}
#define TEST_ASSERT(x) if (!(x)) { \
printf(" TEST ASSERT %s:%i\n", __FILE__, __LINE__); \
goto __fail_assert; \
@ -105,6 +130,7 @@ typedef struct test_res_s {
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(int argc, char **args);
// returns 0 if all tests ok, -1 if any test failed, -2 on badness
int run_tests(int argc, char **args);
#endif /* TESTS_H_ */
#endif /* TESTRUNNER_H_ */