Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
7b160da1a3
14
.travis.yml
14
.travis.yml
|
@ -8,13 +8,21 @@ install:
|
||||||
script:
|
script:
|
||||||
- make all
|
- make all
|
||||||
- cd bin/
|
- cd bin/
|
||||||
- file_name="nodemcu-firmware_v${TRAVIS_TAG}.${TRAVIS_BUILD_NUMBER}.bin"
|
- file_name_float="nodemcu_float_${TRAVIS_TAG}.bin"
|
||||||
- srec_cat -output ${file_name} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
|
- srec_cat -output ${file_name_float} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
|
||||||
|
- cd ../
|
||||||
|
- make clean
|
||||||
|
- make EXTRA_CCFLAGS="-DLUA_NUMBER_INTEGRAL"
|
||||||
|
- cd bin/
|
||||||
|
- file_name_integer="nodemcu_integer_${TRAVIS_TAG}.bin"
|
||||||
|
- srec_cat -output ${file_name_integer} -binary 0x00000.bin -binary -fill 0xff 0x00000 0x10000 0x10000.bin -binary -offset 0x10000
|
||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
provider: releases
|
||||||
api_key:
|
api_key:
|
||||||
secure: Swecz5lWvsuSbchSbVQ1rmCPN9nQIN5p/HlZNIEdEgAgnoLcJxRV4P8poVTB37jiA8Pck+8x2nWXpg74Rqik0i3KlPNvDfg5o4rIazWLNs4bc1Tbcpt44XAzFKKLYnDnWQUGcqjk7BcAXuNAF2X/fPBCVhFbHVg3Z7cDb32RsNw=
|
secure: Swecz5lWvsuSbchSbVQ1rmCPN9nQIN5p/HlZNIEdEgAgnoLcJxRV4P8poVTB37jiA8Pck+8x2nWXpg74Rqik0i3KlPNvDfg5o4rIazWLNs4bc1Tbcpt44XAzFKKLYnDnWQUGcqjk7BcAXuNAF2X/fPBCVhFbHVg3Z7cDb32RsNw=
|
||||||
file: "$TRAVIS_BUILD_DIR/bin/${file_name}"
|
file:
|
||||||
|
- "$TRAVIS_BUILD_DIR/bin/${file_name_float}"
|
||||||
|
- "$TRAVIS_BUILD_DIR/bin/${file_name_integer}"
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
on:
|
on:
|
||||||
tags: true
|
tags: true
|
||||||
|
|
15
README.md
15
README.md
|
@ -1,7 +1,7 @@
|
||||||
# **NodeMCU** #
|
# **NodeMCU** #
|
||||||
version 0.9.5
|
version 0.9.5
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware)
|
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware) [![Download](https://img.shields.io/badge/download-~400k-orange.svg)](https://github.com/nodemcu/nodemcu-firmware/releases/latest)
|
||||||
|
|
||||||
###A lua based firmware for wifi-soc esp8266
|
###A lua based firmware for wifi-soc esp8266
|
||||||
Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br />
|
Build on [ESP8266 sdk 0.9.5](http://bbs.espressif.com/viewtopic.php?f=5&t=154)<br />
|
||||||
|
@ -33,6 +33,19 @@ Tencent QQ group: 309957875<br />
|
||||||
- cross compiler (done)
|
- cross compiler (done)
|
||||||
|
|
||||||
# Change log
|
# Change log
|
||||||
|
2015-03-11<br />
|
||||||
|
fix bugs of spiffs.<br />
|
||||||
|
build both float and integer version [latest releases](https://github.com/nodemcu/nodemcu-firmware/releases/latest).<br />
|
||||||
|
fix tmr.time().<br />
|
||||||
|
fix memory leak when DNS fail.
|
||||||
|
|
||||||
|
2015-03-10<br />
|
||||||
|
update to the recent spiffs.<br />
|
||||||
|
add file.fsinfo() api, usage: remain, used, total = file.fsinfo().<br />
|
||||||
|
add Travis CI. please download the latest firmware from [releases](https://github.com/nodemcu/nodemcu-firmware/releases).<br />
|
||||||
|
add math lib, partial api work.<br />
|
||||||
|
u8g module, ws2812 module default enabled in dev-branch build.
|
||||||
|
|
||||||
2015-02-13<br />
|
2015-02-13<br />
|
||||||
add node.compile() api to compile lua text file into lua bytecode file.<br />
|
add node.compile() api to compile lua text file into lua bytecode file.<br />
|
||||||
this will reduce memory usage noticeably when require modules into NodeMCU.<br />
|
this will reduce memory usage noticeably when require modules into NodeMCU.<br />
|
||||||
|
|
|
@ -7,6 +7,6 @@
|
||||||
#define NODE_VERSION_INTERNAL 0U
|
#define NODE_VERSION_INTERNAL 0U
|
||||||
|
|
||||||
#define NODE_VERSION "NodeMCU 0.9.5"
|
#define NODE_VERSION "NodeMCU 0.9.5"
|
||||||
#define BUILD_DATE "build 20150306"
|
#define BUILD_DATE "build 20150311"
|
||||||
|
|
||||||
#endif /* __USER_VERSION_H__ */
|
#endif /* __USER_VERSION_H__ */
|
||||||
|
|
|
@ -175,6 +175,22 @@ static int file_rename( lua_State* L )
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lua: fsinfo()
|
||||||
|
static int file_fsinfo( lua_State* L )
|
||||||
|
{
|
||||||
|
uint32_t total, used;
|
||||||
|
SPIFFS_info(&fs, &total, &used);
|
||||||
|
NODE_DBG("total: %d, used:%d\n", total, used);
|
||||||
|
if(total>0x7FFFFFFF || used>0x7FFFFFFF || used > total)
|
||||||
|
{
|
||||||
|
return luaL_error(L, "file system error");;
|
||||||
|
}
|
||||||
|
lua_pushinteger(L, total-used);
|
||||||
|
lua_pushinteger(L, used);
|
||||||
|
lua_pushinteger(L, total);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// g_read()
|
// g_read()
|
||||||
|
@ -308,6 +324,7 @@ const LUA_REG_TYPE file_map[] =
|
||||||
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
|
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
|
||||||
// { LSTRKEY( "check" ), LFUNCVAL( file_check ) },
|
// { LSTRKEY( "check" ), LFUNCVAL( file_check ) },
|
||||||
{ LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
|
{ LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
|
||||||
|
{ LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LUA_OPTIMIZE_MEMORY > 0
|
#if LUA_OPTIMIZE_MEMORY > 0
|
||||||
|
|
|
@ -200,10 +200,15 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(nud->self_ref == LUA_NOREF){
|
||||||
|
NODE_DBG("self_ref null.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(ipaddr == NULL)
|
if(ipaddr == NULL)
|
||||||
{
|
{
|
||||||
NODE_ERR( "DNS Fail!\n" );
|
NODE_ERR( "DNS Fail!\n" );
|
||||||
return;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ipaddr->addr is a uint32_t ip
|
// ipaddr->addr is a uint32_t ip
|
||||||
|
@ -214,16 +219,12 @@ static void net_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
|
||||||
c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr)));
|
c_sprintf(ip_str, IPSTR, IP2STR(&(ipaddr->addr)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nud->self_ref == LUA_NOREF){
|
|
||||||
NODE_DBG("self_ref null.\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function
|
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->cb_dns_found_ref); // the callback function
|
||||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua
|
lua_rawgeti(gL, LUA_REGISTRYINDEX, nud->self_ref); // pass the userdata(conn) to callback func in lua
|
||||||
lua_pushstring(gL, ip_str); // the ip para
|
lua_pushstring(gL, ip_str); // the ip para
|
||||||
lua_call(gL, 2, 0);
|
lua_call(gL, 2, 0);
|
||||||
|
|
||||||
|
end:
|
||||||
if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0)
|
if((pesp_conn->type == ESPCONN_TCP && pesp_conn->proto.tcp->remote_port == 0)
|
||||||
|| (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){
|
|| (pesp_conn->type == ESPCONN_UDP && pesp_conn->proto.udp->remote_port == 0) ){
|
||||||
lua_gc(gL, LUA_GCSTOP, 0);
|
lua_gc(gL, LUA_GCSTOP, 0);
|
||||||
|
@ -597,12 +598,22 @@ static void socket_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
|
||||||
NODE_DBG("pesp_conn null.\n");
|
NODE_DBG("pesp_conn null.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
lnet_userdata *nud = (lnet_userdata *)pesp_conn->reverse;
|
||||||
|
if(nud == NULL)
|
||||||
|
return;
|
||||||
|
if(gL == NULL)
|
||||||
|
return;
|
||||||
if(ipaddr == NULL)
|
if(ipaddr == NULL)
|
||||||
{
|
{
|
||||||
dns_reconn_count++;
|
dns_reconn_count++;
|
||||||
if( dns_reconn_count >= 5 ){
|
if( dns_reconn_count >= 5 ){
|
||||||
NODE_ERR( "DNS Fail!\n" );
|
NODE_ERR( "DNS Fail!\n" );
|
||||||
|
lua_gc(gL, LUA_GCSTOP, 0);
|
||||||
|
if(nud->self_ref != LUA_NOREF){
|
||||||
|
luaL_unref(gL, LUA_REGISTRYINDEX, nud->self_ref);
|
||||||
|
nud->self_ref = LUA_NOREF; // unref this, and the net.socket userdata will delete it self
|
||||||
|
}
|
||||||
|
lua_gc(gL, LUA_GCRESTART, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NODE_ERR( "DNS retry %d!\n", dns_reconn_count );
|
NODE_ERR( "DNS retry %d!\n", dns_reconn_count );
|
||||||
|
|
|
@ -148,24 +148,30 @@ static int tmr_wdclr( lua_State* L )
|
||||||
}
|
}
|
||||||
|
|
||||||
static os_timer_t rtc_timer_updator;
|
static os_timer_t rtc_timer_updator;
|
||||||
static uint64_t cur_count = 0;
|
static uint32_t cur_count = 0;
|
||||||
static uint64_t rtc_us = 0;
|
static uint32_t rtc_10ms = 0;
|
||||||
void rtc_timer_update_cb(void *arg){
|
void rtc_timer_update_cb(void *arg){
|
||||||
uint64_t t = (uint64_t)system_get_rtc_time();
|
uint32_t t = (uint32_t)system_get_rtc_time();
|
||||||
uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count);
|
uint32_t delta = 0;
|
||||||
|
if(t>=cur_count){
|
||||||
|
delta = t-cur_count;
|
||||||
|
}else{
|
||||||
|
delta = 0xFFFFFFF - cur_count + t + 1;
|
||||||
|
}
|
||||||
|
// uint64_t delta = (t>=cur_count)?(t - cur_count):(0x100000000 + t - cur_count);
|
||||||
// NODE_ERR("%x\n",t);
|
// NODE_ERR("%x\n",t);
|
||||||
cur_count = t;
|
cur_count = t;
|
||||||
unsigned c = system_rtc_clock_cali_proc();
|
uint32_t c = system_rtc_clock_cali_proc();
|
||||||
uint64_t itg = c >> 12;
|
uint32_t itg = c >> 12; // ~=5
|
||||||
uint64_t dec = c & 0xFFF;
|
uint32_t dec = c & 0xFFF; // ~=2ff
|
||||||
rtc_us += (delta*itg + ((delta*dec)>>12));
|
rtc_10ms += (delta*itg + ((delta*dec)>>12)) / 10000;
|
||||||
// TODO: store rtc_us to rtc memory.
|
// TODO: store rtc_10ms to rtc memory.
|
||||||
}
|
}
|
||||||
// Lua: time() , return rtc time in second
|
// Lua: time() , return rtc time in second
|
||||||
static int tmr_time( lua_State* L )
|
static int tmr_time( lua_State* L )
|
||||||
{
|
{
|
||||||
uint64_t local = rtc_us;
|
uint32_t local = rtc_10ms;
|
||||||
lua_pushinteger( L, ((uint32_t)(local/1000000)) & 0x7FFFFFFF );
|
lua_pushinteger( L, ((uint32_t)(local/100)) & 0x7FFFFFFF );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,7 @@ int myspiffs_error( int fd ){
|
||||||
return SPIFFS_errno(&fs);
|
return SPIFFS_errno(&fs);
|
||||||
}
|
}
|
||||||
void myspiffs_clearerr( int fd ){
|
void myspiffs_clearerr( int fd ){
|
||||||
fs.errno = SPIFFS_OK;
|
SPIFFS_clearerr(&fs);
|
||||||
}
|
}
|
||||||
int myspiffs_rename( const char *old, const char *newname ){
|
int myspiffs_rename( const char *old, const char *newname ){
|
||||||
return SPIFFS_rename(&fs, (char *)old, (char *)newname);
|
return SPIFFS_rename(&fs, (char *)old, (char *)newname);
|
||||||
|
|
|
@ -9,6 +9,10 @@
|
||||||
|
|
||||||
#ifndef SPIFFS_H_
|
#ifndef SPIFFS_H_
|
||||||
#define SPIFFS_H_
|
#define SPIFFS_H_
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "c_stdio.h"
|
#include "c_stdio.h"
|
||||||
#include "spiffs_config.h"
|
#include "spiffs_config.h"
|
||||||
|
|
||||||
|
@ -181,7 +185,7 @@ typedef struct {
|
||||||
u32_t fd_count;
|
u32_t fd_count;
|
||||||
|
|
||||||
// last error
|
// last error
|
||||||
s32_t errno;
|
s32_t err_code;
|
||||||
|
|
||||||
// current number of free blocks
|
// current number of free blocks
|
||||||
u32_t free_blocks;
|
u32_t free_blocks;
|
||||||
|
@ -375,9 +379,9 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||||
* Renames a file
|
* Renames a file
|
||||||
* @param fs the file system struct
|
* @param fs the file system struct
|
||||||
* @param old path of file to rename
|
* @param old path of file to rename
|
||||||
* @param new new path of file
|
* @param newPath new path of file
|
||||||
*/
|
*/
|
||||||
s32_t SPIFFS_rename(spiffs *fs, char *old, char *new);
|
s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns last error of last file operation.
|
* Returns last error of last file operation.
|
||||||
|
@ -385,6 +389,12 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new);
|
||||||
*/
|
*/
|
||||||
s32_t SPIFFS_errno(spiffs *fs);
|
s32_t SPIFFS_errno(spiffs *fs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears last error.
|
||||||
|
* @param fs the file system struct
|
||||||
|
*/
|
||||||
|
void SPIFFS_clearerr(spiffs *fs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a directory stream corresponding to the given name.
|
* Opens a directory stream corresponding to the given name.
|
||||||
* The stream is positioned at the first entry in the directory.
|
* The stream is positioned at the first entry in the directory.
|
||||||
|
@ -416,6 +426,21 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||||
*/
|
*/
|
||||||
s32_t SPIFFS_check(spiffs *fs);
|
s32_t SPIFFS_check(spiffs *fs);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns number of total bytes available and number of used bytes.
|
||||||
|
* This is an estimation, and depends on if there a many files with little
|
||||||
|
* data or few files with much data.
|
||||||
|
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||||
|
* run. This indicates a power loss in midst of things. In worst case
|
||||||
|
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
||||||
|
*
|
||||||
|
* @param fs the file system struct
|
||||||
|
* @param total total number of bytes in filesystem
|
||||||
|
* @param used used number of bytes in filesystem
|
||||||
|
*/
|
||||||
|
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if EOF reached.
|
* Check if EOF reached.
|
||||||
* @param fs the file system struct
|
* @param fs the file system struct
|
||||||
|
@ -468,4 +493,8 @@ int myspiffs_check( void );
|
||||||
int myspiffs_rename( const char *old, const char *newname );
|
int myspiffs_rename( const char *old, const char *newname );
|
||||||
size_t myspiffs_size( int fd );
|
size_t myspiffs_size( int fd );
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* SPIFFS_H_ */
|
#endif /* SPIFFS_H_ */
|
||||||
|
|
|
@ -30,19 +30,19 @@ typedef uint8_t u8_t;
|
||||||
|
|
||||||
// Set generic spiffs debug output call.
|
// Set generic spiffs debug output call.
|
||||||
#ifndef SPIFFS_DGB
|
#ifndef SPIFFS_DGB
|
||||||
#define SPIFFS_DBG(...)
|
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
// Set spiffs debug output call for garbage collecting.
|
// Set spiffs debug output call for garbage collecting.
|
||||||
#ifndef SPIFFS_GC_DGB
|
#ifndef SPIFFS_GC_DGB
|
||||||
#define SPIFFS_GC_DBG(...)
|
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
// Set spiffs debug output call for caching.
|
// Set spiffs debug output call for caching.
|
||||||
#ifndef SPIFFS_CACHE_DGB
|
#ifndef SPIFFS_CACHE_DGB
|
||||||
#define SPIFFS_CACHE_DBG(...)
|
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
// Set spiffs debug output call for system consistency checks.
|
// Set spiffs debug output call for system consistency checks.
|
||||||
#ifndef SPIFFS_CHECK_DGB
|
#ifndef SPIFFS_CHECK_DGB
|
||||||
#define SPIFFS_CHECK_DBG(...)
|
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable/disable API functions to determine exact number of bytes
|
// Enable/disable API functions to determine exact number of bytes
|
||||||
|
@ -77,7 +77,7 @@ typedef uint8_t u8_t;
|
||||||
|
|
||||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
// Define maximum number of gc runs to perform to reach desired free pages.
|
||||||
#ifndef SPIFFS_GC_MAX_RUNS
|
#ifndef SPIFFS_GC_MAX_RUNS
|
||||||
#define SPIFFS_GC_MAX_RUNS 3
|
#define SPIFFS_GC_MAX_RUNS 5
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
// Enable/disable statistics on gc. Debug/test purpose only.
|
||||||
|
|
|
@ -119,16 +119,21 @@ s32_t spiffs_gc_check(
|
||||||
spiffs *fs,
|
spiffs *fs,
|
||||||
u32_t len) {
|
u32_t len) {
|
||||||
s32_t res;
|
s32_t res;
|
||||||
u32_t free_pages =
|
s32_t free_pages =
|
||||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count
|
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
||||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
|
|
||||||
if (fs->free_blocks > 3 &&
|
if (fs->free_blocks > 3 &&
|
||||||
len < free_pages * SPIFFS_DATA_PAGE_SIZE(fs)) {
|
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||||
return SPIFFS_OK;
|
return SPIFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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);
|
//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 {
|
do {
|
||||||
|
@ -168,16 +173,22 @@ s32_t spiffs_gc_check(
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
free_pages =
|
free_pages =
|
||||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * fs->block_count
|
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||||
|
|
||||||
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
||||||
len > free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
|
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||||
SPIFFS_GC_DBG("gc_check: finished\n");
|
|
||||||
|
|
||||||
//printf("gcing finished %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
|
free_pages =
|
||||||
// fs->stats_p_allocated + fs->stats_p_deleted,
|
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||||
// fs->free_blocks, free_pages, tries, res);
|
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||||
|
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||||
|
res = SPIFFS_ERR_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIFFS_GC_DBG("gc_check: finished, %i dirty, blocks %i free, %i pages free, %i tries, res %i\n",
|
||||||
|
fs->stats_p_allocated + fs->stats_p_deleted,
|
||||||
|
fs->free_blocks, free_pages, tries, res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,11 @@ void SPIFFS_unmount(spiffs *fs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_errno(spiffs *fs) {
|
s32_t SPIFFS_errno(spiffs *fs) {
|
||||||
return fs->errno;
|
return fs->err_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPIFFS_clearerr(spiffs *fs) {
|
||||||
|
fs->err_code = SPIFFS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) {
|
s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) {
|
||||||
|
@ -314,8 +318,6 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
SPIFFS_DBG("SPIFFS_write %i %04x offs:%i len %i\n", fh, fd->obj_id, offset, len);
|
|
||||||
|
|
||||||
#if SPIFFS_CACHE_WR
|
#if SPIFFS_CACHE_WR
|
||||||
if ((fd->flags & SPIFFS_DIRECT) == 0) {
|
if ((fd->flags & SPIFFS_DIRECT) == 0) {
|
||||||
if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
|
if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
|
||||||
|
@ -328,12 +330,13 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
|
||||||
offset + len > fd->cache_page->offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) // writing beyond cache page
|
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
|
// 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",
|
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);
|
fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->offset, fd->cache_page->size);
|
||||||
res = spiffs_hydro_write(fs, fd,
|
res = spiffs_hydro_write(fs, fd,
|
||||||
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
||||||
fd->cache_page->offset, fd->cache_page->size);
|
fd->cache_page->offset, fd->cache_page->size);
|
||||||
spiffs_cache_fd_release(fs, fd->cache_page);
|
spiffs_cache_fd_release(fs, fd->cache_page);
|
||||||
|
SPIFFS_API_CHECK_RES(fs, res);
|
||||||
} else {
|
} else {
|
||||||
// writing within cache
|
// writing within cache
|
||||||
alloc_cpage = 0;
|
alloc_cpage = 0;
|
||||||
|
@ -379,6 +382,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, u32_t len) {
|
||||||
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
||||||
fd->cache_page->offset, fd->cache_page->size);
|
fd->cache_page->offset, fd->cache_page->size);
|
||||||
spiffs_cache_fd_release(fs, fd->cache_page);
|
spiffs_cache_fd_release(fs, fd->cache_page);
|
||||||
|
SPIFFS_API_CHECK_RES(fs, res);
|
||||||
res = spiffs_hydro_write(fs, fd, buf, offset, len);
|
res = spiffs_hydro_write(fs, fd, buf, offset, len);
|
||||||
SPIFFS_API_CHECK_RES(fs, res);
|
SPIFFS_API_CHECK_RES(fs, res);
|
||||||
}
|
}
|
||||||
|
@ -580,7 +584,7 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
|
||||||
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
|
||||||
fd->cache_page->offset, fd->cache_page->size);
|
fd->cache_page->offset, fd->cache_page->size);
|
||||||
if (res < SPIFFS_OK) {
|
if (res < SPIFFS_OK) {
|
||||||
fs->errno = res;
|
fs->err_code = res;
|
||||||
}
|
}
|
||||||
spiffs_cache_fd_release(fs, fd->cache_page);
|
spiffs_cache_fd_release(fs, fd->cache_page);
|
||||||
}
|
}
|
||||||
|
@ -605,7 +609,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
|
||||||
|
|
||||||
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
|
void SPIFFS_close(spiffs *fs, spiffs_file fh) {
|
||||||
if (!SPIFFS_CHECK_MOUNT(fs)) {
|
if (!SPIFFS_CHECK_MOUNT(fs)) {
|
||||||
fs->errno = SPIFFS_ERR_NOT_MOUNTED;
|
fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
|
@ -661,7 +665,7 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) {
|
||||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) {
|
spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) {
|
||||||
(void)name;
|
(void)name;
|
||||||
if (!SPIFFS_CHECK_MOUNT(fs)) {
|
if (!SPIFFS_CHECK_MOUNT(fs)) {
|
||||||
fs->errno = SPIFFS_ERR_NOT_MOUNTED;
|
fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
d->fs = fs;
|
d->fs = fs;
|
||||||
|
@ -707,7 +711,7 @@ static s32_t spiffs_read_dir_v(
|
||||||
|
|
||||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
|
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
|
||||||
if (!SPIFFS_CHECK_MOUNT(d->fs)) {
|
if (!SPIFFS_CHECK_MOUNT(d->fs)) {
|
||||||
d->fs->errno = SPIFFS_ERR_NOT_MOUNTED;
|
d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
|
@ -732,7 +736,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
|
||||||
d->entry = entry + 1;
|
d->entry = entry + 1;
|
||||||
ret = e;
|
ret = e;
|
||||||
} else {
|
} else {
|
||||||
d->fs->errno = res;
|
d->fs->err_code = res;
|
||||||
}
|
}
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -760,6 +764,29 @@ s32_t SPIFFS_check(spiffs *fs) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
|
||||||
|
s32_t res = SPIFFS_OK;
|
||||||
|
SPIFFS_API_CHECK_MOUNT(fs);
|
||||||
|
SPIFFS_LOCK(fs);
|
||||||
|
|
||||||
|
u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);
|
||||||
|
u32_t blocks = fs->block_count;
|
||||||
|
u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||||
|
u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);
|
||||||
|
u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page
|
||||||
|
|
||||||
|
if (total) {
|
||||||
|
*total = total_data_pages * data_page_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (used) {
|
||||||
|
*used = fs->stats_p_allocated * data_page_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPIFFS_UNLOCK(fs);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
|
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
|
||||||
SPIFFS_API_CHECK_MOUNT(fs);
|
SPIFFS_API_CHECK_MOUNT(fs);
|
||||||
SPIFFS_LOCK(fs);
|
SPIFFS_LOCK(fs);
|
||||||
|
@ -878,11 +905,14 @@ s32_t SPIFFS_vis(spiffs *fs) {
|
||||||
} // per block
|
} // per block
|
||||||
|
|
||||||
spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count);
|
spiffs_printf("era_cnt_max: %i\n", fs->max_erase_count);
|
||||||
spiffs_printf("last_errno: %i\n", fs->errno);
|
spiffs_printf("last_errno: %i\n", fs->err_code);
|
||||||
spiffs_printf("blocks: %i\n", fs->block_count);
|
spiffs_printf("blocks: %i\n", fs->block_count);
|
||||||
spiffs_printf("free_blocks: %i\n", fs->free_blocks);
|
spiffs_printf("free_blocks: %i\n", fs->free_blocks);
|
||||||
spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated);
|
spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated);
|
||||||
spiffs_printf("page_delet: %i\n", fs->stats_p_deleted);
|
spiffs_printf("page_delet: %i\n", fs->stats_p_deleted);
|
||||||
|
u32_t total, used;
|
||||||
|
SPIFFS_info(fs, &total, &used);
|
||||||
|
spiffs_printf("used: %i of %i\n", used, total);
|
||||||
|
|
||||||
SPIFFS_UNLOCK(fs);
|
SPIFFS_UNLOCK(fs);
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -614,7 +614,7 @@ s32_t spiffs_object_create(
|
||||||
spiffs_page_object_ix_header oix_hdr;
|
spiffs_page_object_ix_header oix_hdr;
|
||||||
int entry;
|
int entry;
|
||||||
|
|
||||||
res = spiffs_gc_check(fs, 0);
|
res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
|
obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
|
||||||
|
@ -811,7 +811,17 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
u32_t written = 0;
|
u32_t written = 0;
|
||||||
|
|
||||||
res = spiffs_gc_check(fs, len);
|
SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size);
|
||||||
|
|
||||||
|
if (offset > fd->size) {
|
||||||
|
SPIFFS_DBG("append: offset reversed to size\n");
|
||||||
|
offset = fd->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
|
||||||
|
if (res != SPIFFS_OK) {
|
||||||
|
SPIFFS_DBG("append: gc check fail %i\n", res);
|
||||||
|
}
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||||
|
@ -912,7 +922,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
||||||
res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
|
res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
}
|
}
|
||||||
SPIFFS_DBG("append: %04x found object index at page %04x\n", fd->obj_id, pix);
|
SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size);
|
||||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
|
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
|
||||||
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
@ -1003,8 +1013,8 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
||||||
// update size in object header index page
|
// update size in object header index page
|
||||||
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
|
||||||
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
|
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
|
||||||
SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id
|
SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id
|
||||||
, offset+written, new_objix_hdr_page, 0, written);
|
, offset+written, new_objix_hdr_page, 0, written, res2);
|
||||||
SPIFFS_CHECK_RES(res2);
|
SPIFFS_CHECK_RES(res2);
|
||||||
} else {
|
} else {
|
||||||
// wrote within object index header page
|
// wrote within object index header page
|
||||||
|
@ -1042,7 +1052,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
u32_t written = 0;
|
u32_t written = 0;
|
||||||
|
|
||||||
res = spiffs_gc_check(fs, len);
|
res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||||
|
@ -1308,7 +1318,7 @@ s32_t spiffs_object_truncate(
|
||||||
s32_t res = SPIFFS_OK;
|
s32_t res = SPIFFS_OK;
|
||||||
spiffs *fs = fd->fs;
|
spiffs *fs = fd->fs;
|
||||||
|
|
||||||
res = spiffs_gc_check(fs, 0);
|
res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs));
|
||||||
SPIFFS_CHECK_RES(res);
|
SPIFFS_CHECK_RES(res);
|
||||||
|
|
||||||
spiffs_page_ix objix_pix = fd->objix_hdr_pix;
|
spiffs_page_ix objix_pix = fd->objix_hdr_pix;
|
||||||
|
@ -1386,13 +1396,26 @@ s32_t spiffs_object_truncate(
|
||||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;
|
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPIFFS_DBG("truncate: got data pix %04x\n", data_pix);
|
||||||
|
|
||||||
if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) {
|
if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) {
|
||||||
// delete full data page
|
// delete full data page
|
||||||
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
|
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
|
||||||
if (res != SPIFFS_OK) break;
|
if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
|
||||||
|
SPIFFS_DBG("truncate: err validating data pix %i\n", res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res == SPIFFS_OK) {
|
||||||
|
res = spiffs_page_delete(fs, data_pix);
|
||||||
|
if (res != SPIFFS_OK) {
|
||||||
|
SPIFFS_DBG("truncate: err deleting data pix %i\n", res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
|
||||||
|
res = SPIFFS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
res = spiffs_page_delete(fs, data_pix);
|
|
||||||
if (res != SPIFFS_OK) break;
|
|
||||||
// update current size
|
// update current size
|
||||||
if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {
|
if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {
|
||||||
cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);
|
cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);
|
||||||
|
|
|
@ -247,19 +247,19 @@
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
||||||
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
||||||
(fs)->errno = SPIFFS_ERR_NOT_MOUNTED; \
|
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
||||||
return -1; \
|
return -1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||||||
if ((res) < SPIFFS_OK) { \
|
if ((res) < SPIFFS_OK) { \
|
||||||
(fs)->errno = (res); \
|
(fs)->err_code = (res); \
|
||||||
return -1; \
|
return -1; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||||||
if ((res) < SPIFFS_OK) { \
|
if ((res) < SPIFFS_OK) { \
|
||||||
(fs)->errno = (res); \
|
(fs)->err_code = (res); \
|
||||||
SPIFFS_UNLOCK(fs); \
|
SPIFFS_UNLOCK(fs); \
|
||||||
return -1; \
|
return -1; \
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "testrunner.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main(int argc, char **args) {
|
||||||
|
run_tests(argc, args);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* params_test.h
|
||||||
|
*
|
||||||
|
* Created on: May 26, 2013
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PARAMS_TEST_H_
|
||||||
|
#define PARAMS_TEST_H_
|
||||||
|
|
||||||
|
// total emulated spi flash size
|
||||||
|
#define PHYS_FLASH_SIZE (16*1024*1024)
|
||||||
|
// spiffs file system size
|
||||||
|
#define SPIFFS_FLASH_SIZE (2*1024*1024)
|
||||||
|
// spiffs file system offset in emulated spi flash
|
||||||
|
#define SPIFFS_PHYS_ADDR (4*1024*1024)
|
||||||
|
|
||||||
|
#define SECTOR_SIZE 65536
|
||||||
|
#define LOG_BLOCK (SECTOR_SIZE*2)
|
||||||
|
#define LOG_PAGE (SECTOR_SIZE/256)
|
||||||
|
|
||||||
|
#define FD_BUF_SIZE 64*6
|
||||||
|
#define CACHE_BUF_SIZE (LOG_PAGE + 32)*8
|
||||||
|
|
||||||
|
#define ASSERT(c, m) real_assert((c),(m), __FILE__, __LINE__);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
void real_assert(int c, const char *n, const char *file, int l);
|
||||||
|
|
||||||
|
#endif /* PARAMS_TEST_H_ */
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* test_bugreports.c
|
||||||
|
*
|
||||||
|
* Created on: Mar 8, 2015
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "testrunner.h"
|
||||||
|
#include "test_spiffs.h"
|
||||||
|
#include "spiffs_nucleus.h"
|
||||||
|
#include "spiffs.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
SUITE(bug_tests)
|
||||||
|
void setup() {
|
||||||
|
_setup_test_only();
|
||||||
|
}
|
||||||
|
void teardown() {
|
||||||
|
_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(nodemcu_full_fs_1) {
|
||||||
|
fs_reset_specific(0, 4096*20, 4096, 4096, 256);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
spiffs_file fd;
|
||||||
|
|
||||||
|
printf(" fill up system by writing one byte a lot\n");
|
||||||
|
fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
int i;
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_OK;
|
||||||
|
for (i = 0; i < 100*1000; i++) {
|
||||||
|
u8_t buf = 'x';
|
||||||
|
res = SPIFFS_write(FS, fd, &buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int errno = SPIFFS_errno(FS);
|
||||||
|
int res2 = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res2 == SPIFFS_OK);
|
||||||
|
printf(" >>> file %s size: %i\n", s.name, s.size);
|
||||||
|
|
||||||
|
TEST_CHECK(errno == SPIFFS_ERR_FULL);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
printf(" remove big file\n");
|
||||||
|
res = SPIFFS_remove(FS, "test1.txt");
|
||||||
|
|
||||||
|
printf("res:%i errno:%i\n",res, SPIFFS_errno(FS));
|
||||||
|
|
||||||
|
TEST_CHECK(res == SPIFFS_OK);
|
||||||
|
res2 = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res2 == -1);
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FILE_CLOSED);
|
||||||
|
res2 = SPIFFS_stat(FS, "test1.txt", &s);
|
||||||
|
TEST_CHECK(res2 == -1);
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_NOT_FOUND);
|
||||||
|
|
||||||
|
printf(" create small file\n");
|
||||||
|
fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
res = SPIFFS_OK;
|
||||||
|
for (i = 0; res >= 0 && i < 1000; i++) {
|
||||||
|
u8_t buf = 'x';
|
||||||
|
res = SPIFFS_write(FS, fd, &buf, 1);
|
||||||
|
}
|
||||||
|
TEST_CHECK(res >= SPIFFS_OK);
|
||||||
|
|
||||||
|
res2 = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res2 == SPIFFS_OK);
|
||||||
|
printf(" >>> file %s size: %i\n", s.name, s.size);
|
||||||
|
|
||||||
|
TEST_CHECK(s.size == 1000);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
|
||||||
|
} TEST_END(nodemcu_full_fs_1)
|
||||||
|
|
||||||
|
TEST(nodemcu_full_fs_2) {
|
||||||
|
fs_reset_specific(0, 4096*22, 4096, 4096, 256);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
spiffs_file fd;
|
||||||
|
|
||||||
|
printf(" fill up system by writing one byte a lot\n");
|
||||||
|
fd = SPIFFS_open(FS, "test1.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
int i;
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_OK;
|
||||||
|
for (i = 0; i < 100*1000; i++) {
|
||||||
|
u8_t buf = 'x';
|
||||||
|
res = SPIFFS_write(FS, fd, &buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int errno = SPIFFS_errno(FS);
|
||||||
|
int res2 = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res2 == SPIFFS_OK);
|
||||||
|
printf(" >>> file %s size: %i\n", s.name, s.size);
|
||||||
|
|
||||||
|
TEST_CHECK(errno == SPIFFS_ERR_FULL);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
res2 = SPIFFS_stat(FS, "test1.txt", &s);
|
||||||
|
TEST_CHECK(res2 == SPIFFS_OK);
|
||||||
|
|
||||||
|
SPIFFS_clearerr(FS);
|
||||||
|
printf(" create small file\n");
|
||||||
|
fd = SPIFFS_open(FS, "test2.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
u8_t buf = 'x';
|
||||||
|
res = SPIFFS_write(FS, fd, &buf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_FULL);
|
||||||
|
res2 = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res2 == SPIFFS_OK);
|
||||||
|
printf(" >>> file %s size: %i\n", s.name, s.size);
|
||||||
|
TEST_CHECK(s.size == 0);
|
||||||
|
SPIFFS_clearerr(FS);
|
||||||
|
|
||||||
|
printf(" remove files\n");
|
||||||
|
res = SPIFFS_remove(FS, "test1.txt");
|
||||||
|
TEST_CHECK(res == SPIFFS_OK);
|
||||||
|
res = SPIFFS_remove(FS, "test2.txt");
|
||||||
|
TEST_CHECK(res == SPIFFS_OK);
|
||||||
|
|
||||||
|
printf(" create medium file\n");
|
||||||
|
fd = SPIFFS_open(FS, "test3.txt", SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
|
||||||
|
for (i = 0; i < 20*1000; i++) {
|
||||||
|
u8_t buf = 'x';
|
||||||
|
res = SPIFFS_write(FS, fd, &buf, 1);
|
||||||
|
}
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_OK);
|
||||||
|
|
||||||
|
res2 = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res2 == SPIFFS_OK);
|
||||||
|
printf(" >>> file %s size: %i\n", s.name, s.size);
|
||||||
|
TEST_CHECK(s.size == 20*1000);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
|
||||||
|
} TEST_END(nodemcu_full_fs_2)
|
||||||
|
|
||||||
|
SUITE_END(bug_tests)
|
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* test_dev.c
|
||||||
|
*
|
||||||
|
* Created on: Jul 14, 2013
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "testrunner.h"
|
||||||
|
#include "test_spiffs.h"
|
||||||
|
#include "spiffs_nucleus.h"
|
||||||
|
#include "spiffs.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
SUITE(check_tests)
|
||||||
|
void setup() {
|
||||||
|
_setup();
|
||||||
|
}
|
||||||
|
void teardown() {
|
||||||
|
_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(evil_write) {
|
||||||
|
fs_set_validate_flashing(0);
|
||||||
|
printf("writing corruption to block 1 data range (leaving lu intact)\n");
|
||||||
|
u32_t data_range = SPIFFS_CFG_LOG_BLOCK_SZ(FS) -
|
||||||
|
SPIFFS_CFG_LOG_PAGE_SZ(FS) * (SPIFFS_OBJ_LOOKUP_PAGES(FS));
|
||||||
|
u8_t *corruption = malloc(data_range);
|
||||||
|
memrand(corruption, data_range);
|
||||||
|
u32_t addr = 0 * SPIFFS_CFG_LOG_PAGE_SZ(FS) * SPIFFS_OBJ_LOOKUP_PAGES(FS);
|
||||||
|
area_write(addr, corruption, data_range);
|
||||||
|
free(corruption);
|
||||||
|
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
|
||||||
|
printf("CHECK1-----------------\n");
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
printf("CHECK2-----------------\n");
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
printf("CHECK3-----------------\n");
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = test_create_and_write_file("file2", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(evil_write)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(lu_check1) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify lu entry data page index 1
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
// reset lu entry to being erased, but keep page data
|
||||||
|
spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED;
|
||||||
|
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
|
||||||
|
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
|
||||||
|
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry*sizeof(spiffs_obj_id);
|
||||||
|
|
||||||
|
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(lu_check1)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(page_cons1) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify object index, find object index header
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
// set object index entry 2 to a bad page
|
||||||
|
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 0 * sizeof(spiffs_page_ix);
|
||||||
|
spiffs_page_ix bad_pix_ref = 0x55;
|
||||||
|
area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
|
||||||
|
area_write(addr+2, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
|
||||||
|
|
||||||
|
// delete all cache
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(page_cons1)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(page_cons2) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify object index, find object index header
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
// find data page span index 0
|
||||||
|
spiffs_page_ix dpix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &dpix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
// set object index entry 1+2 to a data page 0
|
||||||
|
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix);
|
||||||
|
spiffs_page_ix bad_pix_ref = dpix;
|
||||||
|
area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
|
||||||
|
area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
|
||||||
|
|
||||||
|
// delete all cache
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(page_cons2)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST(page_cons3) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify object index, find object index header
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
// set object index entry 1+2 lookup page
|
||||||
|
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + sizeof(spiffs_page_object_ix_header) + 1 * sizeof(spiffs_page_ix);
|
||||||
|
spiffs_page_ix bad_pix_ref = SPIFFS_PAGES_PER_BLOCK(FS) * (*FS.block_count - 2);
|
||||||
|
area_write(addr, (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
|
||||||
|
area_write(addr+sizeof(spiffs_page_ix), (u8_t*)&bad_pix_ref, sizeof(spiffs_page_ix));
|
||||||
|
|
||||||
|
// delete all cache
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(page_cons3)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(page_cons_final) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify page header, make unfinalized
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 1, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
// set page span ix 1 as unfinalized
|
||||||
|
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags);
|
||||||
|
u8_t flags;
|
||||||
|
area_read(addr, (u8_t*)&flags, 1);
|
||||||
|
flags |= SPIFFS_PH_FLAG_FINAL;
|
||||||
|
area_write(addr, (u8_t*)&flags, 1);
|
||||||
|
|
||||||
|
// delete all cache
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(page_cons_final)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(index_cons1) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify lu entry data page index header
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
printf(" deleting lu entry pix %04x\n", pix);
|
||||||
|
// reset lu entry to being erased, but keep page data
|
||||||
|
spiffs_obj_id obj_id = SPIFFS_OBJ_ID_DELETED;
|
||||||
|
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
|
||||||
|
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
|
||||||
|
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id);
|
||||||
|
|
||||||
|
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(index_cons1)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(index_cons2) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify lu entry data page index header
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
printf(" writing lu entry for index page, ix %04x, as data page\n", pix);
|
||||||
|
spiffs_obj_id obj_id = 0x1234;
|
||||||
|
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
|
||||||
|
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
|
||||||
|
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id);
|
||||||
|
|
||||||
|
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(index_cons2)
|
||||||
|
|
||||||
|
|
||||||
|
TEST(index_cons3) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify lu entry data page index header
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
printf(" setting lu entry pix %04x to another index page\n", pix);
|
||||||
|
// reset lu entry to being erased, but keep page data
|
||||||
|
spiffs_obj_id obj_id = 1234 | SPIFFS_OBJ_ID_IX_FLAG;
|
||||||
|
spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(FS, pix);
|
||||||
|
int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(FS, pix);
|
||||||
|
u32_t addr = SPIFFS_BLOCK_TO_PADDR(FS, bix) + entry * sizeof(spiffs_obj_id);
|
||||||
|
|
||||||
|
area_write(addr, (u8_t*)&obj_id, sizeof(spiffs_obj_id));
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(index_cons3)
|
||||||
|
|
||||||
|
TEST(index_cons4) {
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*SPIFFS_PAGES_PER_BLOCK(FS);
|
||||||
|
int res = test_create_and_write_file("file", size, size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
res = read_and_verify("file");
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, "file", SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
// modify lu entry data page index header, flags
|
||||||
|
spiffs_page_ix pix;
|
||||||
|
res = spiffs_obj_lu_find_id_and_span(FS, s.obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
printf(" cue objix hdr deletion in page %04x\n", pix);
|
||||||
|
// set flags as deleting ix header
|
||||||
|
u32_t addr = SPIFFS_PAGE_TO_PADDR(FS, pix) + offsetof(spiffs_page_header, flags);
|
||||||
|
u8_t flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE);
|
||||||
|
|
||||||
|
area_write(addr, (u8_t*)&flags, 1);
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
} TEST_END(index_cons4)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SUITE_END(check_tests)
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* test_dev.c
|
||||||
|
*
|
||||||
|
* Created on: Jul 14, 2013
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "testrunner.h"
|
||||||
|
#include "test_spiffs.h"
|
||||||
|
#include "spiffs_nucleus.h"
|
||||||
|
#include "spiffs.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
SUITE(dev_tests)
|
||||||
|
void setup() {
|
||||||
|
_setup();
|
||||||
|
}
|
||||||
|
void teardown() {
|
||||||
|
_teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(interrupted_write) {
|
||||||
|
char *name = "interrupt";
|
||||||
|
char *name2 = "interrupt2";
|
||||||
|
int res;
|
||||||
|
spiffs_file fd;
|
||||||
|
|
||||||
|
const u32_t sz = SPIFFS_CFG_LOG_PAGE_SZ(FS)*8;
|
||||||
|
u8_t *buf = malloc(sz);
|
||||||
|
memrand(buf, sz);
|
||||||
|
|
||||||
|
printf(" create reference file\n");
|
||||||
|
fd = SPIFFS_open(FS, name, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
clear_flash_ops_log();
|
||||||
|
res = SPIFFS_write(FS, fd, buf, sz);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
u32_t written = get_flash_ops_log_write_bytes();
|
||||||
|
printf(" written bytes: %i\n", written);
|
||||||
|
|
||||||
|
|
||||||
|
printf(" create error file\n");
|
||||||
|
fd = SPIFFS_open(FS, name2, SPIFFS_RDWR | SPIFFS_CREAT | SPIFFS_TRUNC, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
clear_flash_ops_log();
|
||||||
|
invoke_error_after_write_bytes(written/2, 0);
|
||||||
|
res = SPIFFS_write(FS, fd, buf, sz);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
TEST_CHECK(SPIFFS_errno(FS) == SPIFFS_ERR_TEST);
|
||||||
|
|
||||||
|
clear_flash_ops_log();
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
// delete all cache
|
||||||
|
spiffs_cache *cache = spiffs_get_cache(FS);
|
||||||
|
cache->cpage_use_map = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
printf(" read error file\n");
|
||||||
|
fd = SPIFFS_open(FS, name2, SPIFFS_RDONLY, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
|
||||||
|
spiffs_stat s;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
printf(" file size: %i\n", s.size);
|
||||||
|
|
||||||
|
if (s.size > 0) {
|
||||||
|
u8_t *buf2 = malloc(s.size);
|
||||||
|
res = SPIFFS_read(FS, fd, buf2, s.size);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
|
||||||
|
u32_t ix = 0;
|
||||||
|
for (ix = 0; ix < s.size; ix += 16) {
|
||||||
|
int i;
|
||||||
|
printf(" ");
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
printf("%02x", buf[ix+i]);
|
||||||
|
}
|
||||||
|
printf(" ");
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
printf("%02x", buf2[ix+i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
free(buf2);
|
||||||
|
}
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
|
||||||
|
printf(" FS check\n");
|
||||||
|
SPIFFS_check(FS);
|
||||||
|
|
||||||
|
printf(" read error file again\n");
|
||||||
|
fd = SPIFFS_open(FS, name2, SPIFFS_APPEND | SPIFFS_RDWR, 0);
|
||||||
|
TEST_CHECK(fd > 0);
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
printf(" file size: %i\n", s.size);
|
||||||
|
printf(" write file\n");
|
||||||
|
res = SPIFFS_write(FS, fd, buf, sz);
|
||||||
|
TEST_CHECK(res >= 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return TEST_RES_OK;
|
||||||
|
|
||||||
|
} TEST_END(interrupted_write)
|
||||||
|
|
||||||
|
SUITE_END(dev_tests)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,746 @@
|
||||||
|
/*
|
||||||
|
* test_spiffs.c
|
||||||
|
*
|
||||||
|
* Created on: Jun 19, 2013
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "params_test.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>
|
||||||
|
|
||||||
|
static unsigned char area[PHYS_FLASH_SIZE];
|
||||||
|
|
||||||
|
static int erases[256];
|
||||||
|
static char _path[256];
|
||||||
|
static u32_t bytes_rd = 0;
|
||||||
|
static u32_t bytes_wr = 0;
|
||||||
|
static u32_t reads = 0;
|
||||||
|
static u32_t writes = 0;
|
||||||
|
static u32_t error_after_bytes_written = 0;
|
||||||
|
static u32_t error_after_bytes_read = 0;
|
||||||
|
static char error_after_bytes_written_once_only = 0;
|
||||||
|
static char error_after_bytes_read_once_only = 0;
|
||||||
|
static char log_flash_ops = 1;
|
||||||
|
static u32_t fs_check_fixes = 0;
|
||||||
|
|
||||||
|
spiffs __fs;
|
||||||
|
static u8_t _work[LOG_PAGE*2];
|
||||||
|
static u8_t _fds[FD_BUF_SIZE];
|
||||||
|
static u8_t _cache[CACHE_BUF_SIZE];
|
||||||
|
|
||||||
|
static int check_valid_flash = 1;
|
||||||
|
|
||||||
|
#define TEST_PATH "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) {
|
||||||
|
if (log_flash_ops) {
|
||||||
|
bytes_rd += size;
|
||||||
|
reads++;
|
||||||
|
if (error_after_bytes_read > 0 && bytes_rd >= error_after_bytes_read) {
|
||||||
|
if (error_after_bytes_read_once_only) {
|
||||||
|
error_after_bytes_read = 0;
|
||||||
|
}
|
||||||
|
return SPIFFS_ERR_TEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (addr < __fs.cfg.phys_addr) {
|
||||||
|
printf("FATAL read addr too low %08x < %08x\n", addr, SPIFFS_PHYS_ADDR);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (addr + size > __fs.cfg.phys_addr + __fs.cfg.phys_size) {
|
||||||
|
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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s32_t _write(u32_t addr, u32_t size, u8_t *src) {
|
||||||
|
int i;
|
||||||
|
//printf("wr %08x %i\n", addr, size);
|
||||||
|
if (log_flash_ops) {
|
||||||
|
bytes_wr += size;
|
||||||
|
writes++;
|
||||||
|
if (error_after_bytes_written > 0 && bytes_wr >= error_after_bytes_written) {
|
||||||
|
if (error_after_bytes_written_once_only) {
|
||||||
|
error_after_bytes_written = 0;
|
||||||
|
}
|
||||||
|
return SPIFFS_ERR_TEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr < __fs.cfg.phys_addr) {
|
||||||
|
printf("FATAL write addr too low %08x < %08x\n", addr, SPIFFS_PHYS_ADDR);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (addr + size > __fs.cfg.phys_addr + __fs.cfg.phys_size) {
|
||||||
|
printf("FATAL write addr too high %08x + %08x > %08x\n", addr, size, SPIFFS_PHYS_ADDR + SPIFFS_FLASH_SIZE);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
spiffs_page_ix pix = (addr + i) / LOG_PAGE;
|
||||||
|
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 & (__fs.cfg.phys_erase_block-1)) {
|
||||||
|
printf("trying to erase at addr %08x, out of boundary\n", addr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (size & (__fs.cfg.phys_erase_block-1)) {
|
||||||
|
printf("trying to erase at with size %08x, out of boundary\n", size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
erases[(addr-__fs.cfg.phys_addr)/__fs.cfg.phys_erase_block]++;
|
||||||
|
memset(&area[addr], 0xff, size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hexdump_mem(u8_t *b, u32_t len) {
|
||||||
|
while (len--) {
|
||||||
|
if ((((intptr_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 {
|
||||||
|
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]);
|
||||||
|
// data page
|
||||||
|
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 ");
|
||||||
|
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_INDEX) == 0) ? "IDX " : "idx ");
|
||||||
|
printf("%s", ((ph->flags & SPIFFS_PH_FLAG_USED) == 0) ? "USD " : "usd ");
|
||||||
|
printf("%s ", ((ph->flags & SPIFFS_PH_FLAG_IXDELE) == 0) ? "IDL " : "idl ");
|
||||||
|
if (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void area_write(u32_t addr, u8_t *buf, u32_t size) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_erase_counts(spiffs *fs) {
|
||||||
|
spiffs_block_ix bix;
|
||||||
|
printf(" BLOCK |\n");
|
||||||
|
printf(" AGE COUNT|\n");
|
||||||
|
for (bix = 0; bix < fs->block_count; bix++) {
|
||||||
|
printf("----%3i ----|", bix);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
for (bix = 0; bix < fs->block_count; bix++) {
|
||||||
|
spiffs_obj_id erase_mark;
|
||||||
|
_spiffs_rd(fs, 0, 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&erase_mark);
|
||||||
|
if (erases[bix] == 0) {
|
||||||
|
printf(" |");
|
||||||
|
} else {
|
||||||
|
printf("%7i %4i|", (fs->max_erase_count - erase_mark), erases[bix]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_flash_access_stats() {
|
||||||
|
printf(" RD: %10i reads %10i bytes %10i avg bytes/read\n", reads, bytes_rd, reads == 0 ? 0 : (bytes_rd / reads));
|
||||||
|
printf(" WR: %10i writes %10i bytes %10i avg bytes/write\n", writes, bytes_wr, writes == 0 ? 0 : (bytes_wr / writes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u32_t old_perc = 999;
|
||||||
|
static void spiffs_check_cb_f(spiffs_check_type type, spiffs_check_report report,
|
||||||
|
u32_t arg1, u32_t arg2) {
|
||||||
|
/* if (report == SPIFFS_CHECK_PROGRESS && old_perc != arg1) {
|
||||||
|
old_perc = arg1;
|
||||||
|
printf("CHECK REPORT: ");
|
||||||
|
switch(type) {
|
||||||
|
case SPIFFS_CHECK_LOOKUP:
|
||||||
|
printf("LU "); break;
|
||||||
|
case SPIFFS_CHECK_INDEX:
|
||||||
|
printf("IX "); break;
|
||||||
|
case SPIFFS_CHECK_PAGE:
|
||||||
|
printf("PA "); break;
|
||||||
|
}
|
||||||
|
printf("%i%%\n", arg1 * 100 / 256);
|
||||||
|
}*/
|
||||||
|
if (report != SPIFFS_CHECK_PROGRESS) {
|
||||||
|
if (report != SPIFFS_CHECK_ERROR) fs_check_fixes++;
|
||||||
|
printf(" check: ");
|
||||||
|
switch (type) {
|
||||||
|
case SPIFFS_CHECK_INDEX:
|
||||||
|
printf("INDEX "); break;
|
||||||
|
case SPIFFS_CHECK_LOOKUP:
|
||||||
|
printf("LOOKUP "); break;
|
||||||
|
case SPIFFS_CHECK_PAGE:
|
||||||
|
printf("PAGE "); break;
|
||||||
|
default:
|
||||||
|
printf("???? "); break;
|
||||||
|
}
|
||||||
|
if (report == SPIFFS_CHECK_ERROR) {
|
||||||
|
printf("ERROR %i", arg1);
|
||||||
|
} else if (report == SPIFFS_CHECK_DELETE_BAD_FILE) {
|
||||||
|
printf("DELETE BAD FILE %04x", arg1);
|
||||||
|
} else if (report == SPIFFS_CHECK_DELETE_ORPHANED_INDEX) {
|
||||||
|
printf("DELETE ORPHANED INDEX %04x", arg1);
|
||||||
|
} else if (report == SPIFFS_CHECK_DELETE_PAGE) {
|
||||||
|
printf("DELETE PAGE %04x", arg1);
|
||||||
|
} else if (report == SPIFFS_CHECK_FIX_INDEX) {
|
||||||
|
printf("FIX INDEX %04x:%04x", arg1, arg2);
|
||||||
|
} else if (report == SPIFFS_CHECK_FIX_LOOKUP) {
|
||||||
|
printf("FIX INDEX %04x:%04x", arg1, arg2);
|
||||||
|
} else {
|
||||||
|
printf("??");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_reset_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;
|
||||||
|
c.hal_write_f = _write;
|
||||||
|
c.log_block_size = log_block_size;
|
||||||
|
c.log_page_size = log_page_size;
|
||||||
|
c.phys_addr = phys_addr;
|
||||||
|
c.phys_erase_block = phys_sector_size;
|
||||||
|
c.phys_size = phys_size;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
clear_flash_ops_log();
|
||||||
|
log_flash_ops = 1;
|
||||||
|
fs_check_fixes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_reset() {
|
||||||
|
fs_reset_specific(SPIFFS_PHYS_ADDR, SPIFFS_FLASH_SIZE, SECTOR_SIZE, LOG_BLOCK, LOG_PAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_flash_ops_log(int enable) {
|
||||||
|
log_flash_ops = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_flash_ops_log() {
|
||||||
|
bytes_rd = 0;
|
||||||
|
bytes_wr = 0;
|
||||||
|
reads = 0;
|
||||||
|
writes = 0;
|
||||||
|
error_after_bytes_read = 0;
|
||||||
|
error_after_bytes_written = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t get_flash_ops_log_read_bytes() {
|
||||||
|
return bytes_rd;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t get_flash_ops_log_write_bytes() {
|
||||||
|
return bytes_wr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void invoke_error_after_read_bytes(u32_t b, char once_only) {
|
||||||
|
error_after_bytes_read = b;
|
||||||
|
error_after_bytes_read_once_only = once_only;
|
||||||
|
}
|
||||||
|
void invoke_error_after_write_bytes(u32_t b, char once_only) {
|
||||||
|
error_after_bytes_written = b;
|
||||||
|
error_after_bytes_written_once_only = once_only;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_set_validate_flashing(int i) {
|
||||||
|
check_valid_flash = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.err_code);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_and_verify(char *name) {
|
||||||
|
s32_t res;
|
||||||
|
int fd = SPIFFS_open(&__fs, name, SPIFFS_RDONLY, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
printf(" read_and_verify: could not open file %s\n", name);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
return read_and_verify_fd(fd, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_and_verify_fd(spiffs_file fd, char *name) {
|
||||||
|
s32_t res;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_on_stop(test *t) {
|
||||||
|
printf(" spiffs errno:%i\n", SPIFFS_errno(&__fs));
|
||||||
|
#if SPIFFS_TEST_VISUALISATION
|
||||||
|
SPIFFS_vis(FS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void memrand(u8_t *b, int len) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
b[i] = rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_create_file(char *name) {
|
||||||
|
spiffs_stat s;
|
||||||
|
spiffs_file fd;
|
||||||
|
int res = SPIFFS_creat(FS, name, 0);
|
||||||
|
CHECK_RES(res);
|
||||||
|
fd = SPIFFS_open(FS, name, SPIFFS_RDONLY, 0);
|
||||||
|
CHECK(fd >= 0);
|
||||||
|
res = SPIFFS_fstat(FS, fd, &s);
|
||||||
|
CHECK_RES(res);
|
||||||
|
CHECK(strcmp((char*)s.name, name) == 0);
|
||||||
|
CHECK(s.size == 0);
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_create_and_write_file(char *name, int size, int chunk_size) {
|
||||||
|
int res;
|
||||||
|
spiffs_file fd;
|
||||||
|
printf(" create and write %s", name);
|
||||||
|
res = test_create_file(name);
|
||||||
|
if (res < 0) {
|
||||||
|
printf(" failed creation, %i\n",res);
|
||||||
|
}
|
||||||
|
CHECK(res >= 0);
|
||||||
|
fd = SPIFFS_open(FS, name, SPIFFS_APPEND | SPIFFS_RDWR, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
printf(" failed open, %i\n",res);
|
||||||
|
}
|
||||||
|
CHECK(fd >= 0);
|
||||||
|
int pfd = open(make_test_fname(name), O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||||
|
int offset = 0;
|
||||||
|
int mark = 0;
|
||||||
|
while (offset < size) {
|
||||||
|
int len = MIN(size-offset, chunk_size);
|
||||||
|
if (offset > mark) {
|
||||||
|
mark += size/16;
|
||||||
|
printf(".");
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
u8_t *buf = malloc(len);
|
||||||
|
memrand(buf, len);
|
||||||
|
res = SPIFFS_write(FS, fd, buf, len);
|
||||||
|
write(pfd, buf, len);
|
||||||
|
free(buf);
|
||||||
|
if (res < 0) {
|
||||||
|
printf("\n error @ offset %i, res %i\n", offset, res);
|
||||||
|
}
|
||||||
|
offset += len;
|
||||||
|
CHECK(res >= 0);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
close(pfd);
|
||||||
|
|
||||||
|
spiffs_stat stat;
|
||||||
|
res = SPIFFS_fstat(FS, fd, &stat);
|
||||||
|
if (res < 0) {
|
||||||
|
printf(" failed fstat, %i\n",res);
|
||||||
|
}
|
||||||
|
CHECK(res >= 0);
|
||||||
|
if (stat.size != size) {
|
||||||
|
printf(" failed size, %i != %i\n", stat.size, size);
|
||||||
|
}
|
||||||
|
CHECK(stat.size == size);
|
||||||
|
|
||||||
|
SPIFFS_close(FS, fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
#if SPIFFS_CACHE_STATS
|
||||||
|
static u32_t chits_tot = 0;
|
||||||
|
static u32_t cmiss_tot = 0;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void _setup_test_only() {
|
||||||
|
fs_set_validate_flashing(1);
|
||||||
|
test_init(test_on_stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _setup() {
|
||||||
|
fs_reset();
|
||||||
|
_setup_test_only();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _teardown() {
|
||||||
|
printf(" free blocks : %i of %i\n", (FS)->free_blocks, (FS)->block_count);
|
||||||
|
printf(" pages allocated : %i\n", (FS)->stats_p_allocated);
|
||||||
|
printf(" pages deleted : %i\n", (FS)->stats_p_deleted);
|
||||||
|
#if SPIFFS_GC_STATS
|
||||||
|
printf(" gc runs : %i\n", (FS)->stats_gc_runs);
|
||||||
|
#endif
|
||||||
|
#if SPIFFS_CACHE
|
||||||
|
#if SPIFFS_CACHE_STATS
|
||||||
|
chits_tot += (FS)->cache_hits;
|
||||||
|
cmiss_tot += (FS)->cache_misses;
|
||||||
|
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)));
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
dump_flash_access_stats();
|
||||||
|
clear_flash_ops_log();
|
||||||
|
#if SPIFFS_GC_STATS
|
||||||
|
if ((FS)->stats_gc_runs > 0)
|
||||||
|
#endif
|
||||||
|
dump_erase_counts(FS);
|
||||||
|
printf(" fs consistency check:\n");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tfile_get_size(tfile_size s) {
|
||||||
|
switch (s) {
|
||||||
|
case EMPTY:
|
||||||
|
return 0;
|
||||||
|
case SMALL:
|
||||||
|
return SPIFFS_DATA_PAGE_SIZE(FS)/2;
|
||||||
|
case MEDIUM:
|
||||||
|
return SPIFFS_DATA_PAGE_SIZE(FS) * (SPIFFS_PAGES_PER_BLOCK(FS) - SPIFFS_OBJ_LOOKUP_PAGES(FS));
|
||||||
|
case LARGE:
|
||||||
|
return (FS)->cfg.phys_size/3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concurrent_files, int dbg) {
|
||||||
|
int res;
|
||||||
|
tfile *tfiles = malloc(sizeof(tfile) * max_concurrent_files);
|
||||||
|
memset(tfiles, 0, sizeof(tfile) * max_concurrent_files);
|
||||||
|
int run = 0;
|
||||||
|
int cur_config_ix = 0;
|
||||||
|
char name[32];
|
||||||
|
while (run < max_runs) {
|
||||||
|
if (dbg) printf(" run %i/%i\n", run, max_runs);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < max_concurrent_files; i++) {
|
||||||
|
sprintf(name, "file%i_%i", (1+run), i);
|
||||||
|
tfile *tf = &tfiles[i];
|
||||||
|
if (tf->state == 0 && cur_config_ix < cfg_count) {
|
||||||
|
// create a new file
|
||||||
|
strcpy(tf->name, name);
|
||||||
|
tf->state = 1;
|
||||||
|
tf->cfg = cfgs[cur_config_ix];
|
||||||
|
int size = tfile_get_size(tf->cfg.tsize);
|
||||||
|
if (dbg) printf(" create new %s with cfg %i/%i, size %i\n", name, (1+cur_config_ix), cfg_count, size);
|
||||||
|
|
||||||
|
if (tf->cfg.tsize == EMPTY) {
|
||||||
|
res = SPIFFS_creat(FS, name, 0);
|
||||||
|
CHECK_RES(res);
|
||||||
|
int pfd = open(make_test_fname(name), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||||
|
close(pfd);
|
||||||
|
int extra_flags = tf->cfg.ttype == APPENDED ? SPIFFS_APPEND : 0;
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, name, extra_flags | SPIFFS_RDWR, 0);
|
||||||
|
CHECK(fd > 0);
|
||||||
|
tf->fd = fd;
|
||||||
|
} else {
|
||||||
|
int extra_flags = tf->cfg.ttype == APPENDED ? SPIFFS_APPEND : 0;
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, name, extra_flags | SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0);
|
||||||
|
CHECK(fd > 0);
|
||||||
|
extra_flags = tf->cfg.ttype == APPENDED ? O_APPEND : 0;
|
||||||
|
int pfd = open(make_test_fname(name), extra_flags | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||||
|
tf->fd = fd;
|
||||||
|
u8_t *buf = malloc(size);
|
||||||
|
memrand(buf, size);
|
||||||
|
res = SPIFFS_write(FS, fd, buf, size);
|
||||||
|
CHECK_RES(res);
|
||||||
|
write(pfd, buf, size);
|
||||||
|
close(pfd);
|
||||||
|
free(buf);
|
||||||
|
res = read_and_verify(name);
|
||||||
|
CHECK_RES(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_config_ix++;
|
||||||
|
} else if (tf->state > 0) {
|
||||||
|
// hande file lifecycle
|
||||||
|
switch (tf->cfg.ttype) {
|
||||||
|
case UNTAMPERED: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case APPENDED: {
|
||||||
|
if (dbg) printf(" appending %s\n", tf->name);
|
||||||
|
int size = SPIFFS_DATA_PAGE_SIZE(FS)*3;
|
||||||
|
u8_t *buf = malloc(size);
|
||||||
|
memrand(buf, size);
|
||||||
|
res = SPIFFS_write(FS, tf->fd, buf, size);
|
||||||
|
CHECK_RES(res);
|
||||||
|
int pfd = open(make_test_fname(tf->name), O_APPEND | O_RDWR);
|
||||||
|
write(pfd, buf, size);
|
||||||
|
close(pfd);
|
||||||
|
free(buf);
|
||||||
|
res = read_and_verify(tf->name);
|
||||||
|
CHECK_RES(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MODIFIED: {
|
||||||
|
if (dbg) printf(" modify %s\n", tf->name);
|
||||||
|
spiffs_stat stat;
|
||||||
|
res = SPIFFS_fstat(FS, tf->fd, &stat);
|
||||||
|
CHECK_RES(res);
|
||||||
|
int size = stat.size / tf->cfg.tlife + SPIFFS_DATA_PAGE_SIZE(FS)/3;
|
||||||
|
int offs = (stat.size / tf->cfg.tlife) * tf->state;
|
||||||
|
res = SPIFFS_lseek(FS, tf->fd, offs, SPIFFS_SEEK_SET);
|
||||||
|
CHECK_RES(res);
|
||||||
|
u8_t *buf = malloc(size);
|
||||||
|
memrand(buf, size);
|
||||||
|
res = SPIFFS_write(FS, tf->fd, buf, size);
|
||||||
|
CHECK_RES(res);
|
||||||
|
int pfd = open(make_test_fname(tf->name), O_RDWR);
|
||||||
|
lseek(pfd, offs, SEEK_SET);
|
||||||
|
write(pfd, buf, size);
|
||||||
|
close(pfd);
|
||||||
|
free(buf);
|
||||||
|
res = read_and_verify(tf->name);
|
||||||
|
CHECK_RES(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case REWRITTEN: {
|
||||||
|
if (tf->fd > 0) {
|
||||||
|
SPIFFS_close(FS, tf->fd);
|
||||||
|
}
|
||||||
|
if (dbg) printf(" rewriting %s\n", tf->name);
|
||||||
|
spiffs_file fd = SPIFFS_open(FS, tf->name, SPIFFS_TRUNC | SPIFFS_CREAT | SPIFFS_RDWR, 0);
|
||||||
|
CHECK(fd > 0);
|
||||||
|
int pfd = open(make_test_fname(tf->name), O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||||
|
tf->fd = fd;
|
||||||
|
int size = tfile_get_size(tf->cfg.tsize);
|
||||||
|
u8_t *buf = malloc(size);
|
||||||
|
memrand(buf, size);
|
||||||
|
res = SPIFFS_write(FS, fd, buf, size);
|
||||||
|
CHECK_RES(res);
|
||||||
|
write(pfd, buf, size);
|
||||||
|
close(pfd);
|
||||||
|
free(buf);
|
||||||
|
res = read_and_verify(tf->name);
|
||||||
|
CHECK_RES(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tf->state++;
|
||||||
|
if (tf->state > tf->cfg.tlife) {
|
||||||
|
// file outlived its time, kill it
|
||||||
|
if (tf->fd > 0) {
|
||||||
|
SPIFFS_close(FS, tf->fd);
|
||||||
|
}
|
||||||
|
if (dbg) printf(" removing %s\n", tf->name);
|
||||||
|
res = read_and_verify(tf->name);
|
||||||
|
CHECK_RES(res);
|
||||||
|
res = SPIFFS_remove(FS, tf->name);
|
||||||
|
CHECK_RES(res);
|
||||||
|
remove(make_test_fname(tf->name));
|
||||||
|
memset(tf, 0, sizeof(tf));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run++;
|
||||||
|
}
|
||||||
|
free(tfiles);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
|
||||||
|
#define CHECK(r) if (!(r)) return -1;
|
||||||
|
#define CHECK_RES(r) if (r < 0) return -1;
|
||||||
|
#define FS_PURE_DATA_PAGES(fs) \
|
||||||
|
((fs)->cfg.phys_size / (fs)->cfg.log_page_size - (fs)->block_count * SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||||
|
#define FS_PURE_DATA_SIZE(fs) \
|
||||||
|
FS_PURE_DATA_PAGES(fs) * SPIFFS_DATA_PAGE_SIZE(fs)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMPTY,
|
||||||
|
SMALL,
|
||||||
|
MEDIUM,
|
||||||
|
LARGE,
|
||||||
|
} tfile_size;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UNTAMPERED,
|
||||||
|
APPENDED,
|
||||||
|
MODIFIED,
|
||||||
|
REWRITTEN,
|
||||||
|
} tfile_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SHORT = 4,
|
||||||
|
NORMAL = 20,
|
||||||
|
LONG = 100,
|
||||||
|
} tfile_life;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
tfile_size tsize;
|
||||||
|
tfile_type ttype;
|
||||||
|
tfile_life tlife;
|
||||||
|
} tfile_conf;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int state;
|
||||||
|
spiffs_file fd;
|
||||||
|
tfile_conf cfg;
|
||||||
|
char name[32];
|
||||||
|
} tfile;
|
||||||
|
|
||||||
|
|
||||||
|
void fs_reset();
|
||||||
|
void fs_reset_specific(u32_t phys_addr, u32_t phys_size,
|
||||||
|
u32_t phys_sector_size,
|
||||||
|
u32_t log_block_size, u32_t log_page_size);
|
||||||
|
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);
|
||||||
|
void hexdump(u32_t addr, u32_t len);
|
||||||
|
char *make_test_fname(const char *name);
|
||||||
|
void clear_test_path();
|
||||||
|
void area_write(u32_t addr, u8_t *buf, u32_t size);
|
||||||
|
void area_read(u32_t addr, u8_t *buf, u32_t size);
|
||||||
|
void dump_erase_counts(spiffs *fs);
|
||||||
|
void dump_flash_access_stats();
|
||||||
|
void set_flash_ops_log(int enable);
|
||||||
|
void clear_flash_ops_log();
|
||||||
|
u32_t get_flash_ops_log_read_bytes();
|
||||||
|
u32_t get_flash_ops_log_write_bytes();
|
||||||
|
void invoke_error_after_read_bytes(u32_t b, char once_only);
|
||||||
|
void invoke_error_after_write_bytes(u32_t b, char once_only);
|
||||||
|
|
||||||
|
void memrand(u8_t *b, int len);
|
||||||
|
int test_create_file(char *name);
|
||||||
|
int test_create_and_write_file(char *name, int size, int chunk_size);
|
||||||
|
void _setup();
|
||||||
|
void _setup_test_only();
|
||||||
|
void _teardown();
|
||||||
|
u32_t tfile_get_size(tfile_size s);
|
||||||
|
int run_file_config(int cfg_count, tfile_conf* cfgs, int max_runs, int max_concurrent_files, int dbg);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* TEST_SPIFFS_H_ */
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* testrunner.c
|
||||||
|
*
|
||||||
|
* Created on: Jun 18, 2013
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.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;
|
||||||
|
FILE *spec;
|
||||||
|
} test_main;
|
||||||
|
|
||||||
|
void test_init(void (*on_stop)(test *t)) {
|
||||||
|
test_main.on_stop = on_stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char check_spec(char *name) {
|
||||||
|
if (test_main.spec) {
|
||||||
|
fseek(test_main.spec, 0, SEEK_SET);
|
||||||
|
char *line = NULL;
|
||||||
|
size_t sz;
|
||||||
|
ssize_t read;
|
||||||
|
while ((read = getline(&line, &sz, test_main.spec)) != -1) {
|
||||||
|
if (strncmp(line, name, strlen(name)) == 0) {
|
||||||
|
free(line);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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(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);
|
||||||
|
}
|
||||||
|
test_main.spec = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBGT("adding suites...\n");
|
||||||
|
add_suites();
|
||||||
|
DBGT("%i tests added\n", test_main.test_count);
|
||||||
|
if (test_main.spec) {
|
||||||
|
fclose(test_main.spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_main.test_count == 0) {
|
||||||
|
printf("No tests to run\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||||
|
int fd_bad = open("_tests_fail", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
|
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);
|
||||||
|
int fd = res == TEST_RES_OK ? fd_success : fd_bad;
|
||||||
|
write(fd, cur_t->name, strlen(cur_t->name));
|
||||||
|
write(fd, "\n", 1);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
close(fd_success);
|
||||||
|
close(fd_bad);
|
||||||
|
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(int argc, char **args);
|
||||||
|
|
||||||
|
#endif /* TESTS_H_ */
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* testsuites.c
|
||||||
|
*
|
||||||
|
* Created on: Jun 19, 2013
|
||||||
|
* Author: petera
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testrunner.h"
|
||||||
|
|
||||||
|
void add_suites() {
|
||||||
|
//ADD_SUITE(dev_tests);
|
||||||
|
ADD_SUITE(check_tests);
|
||||||
|
ADD_SUITE(hydrogen_tests)
|
||||||
|
ADD_SUITE(bug_tests)
|
||||||
|
}
|
|
@ -363,3 +363,18 @@ cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun
|
||||||
cc = coap.Client()
|
cc = coap.Client()
|
||||||
cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
|
cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
|
||||||
cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")
|
cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")
|
||||||
|
|
||||||
|
|
||||||
|
file.open("test1.txt", "a+") for i = 1, 100*1000 do file.write("x") end file.close() print("Done.")
|
||||||
|
for n,s in pairs(file.list()) do print(n.." size: "..s) end
|
||||||
|
file.remove("test1.txt")
|
||||||
|
for n,s in pairs(file.list()) do print(n.." size: "..s) end
|
||||||
|
file.open("test2.txt", "a+") for i = 1, 1*1000 do file.write("x") end file.close() print("Done.")
|
||||||
|
|
||||||
|
|
||||||
|
function TestDNSLeak()
|
||||||
|
c=net.createConnection(net.TCP, 0)
|
||||||
|
c:connect(80, "bad-name.tlddfdf")
|
||||||
|
tmr.alarm(1, 3000, 0, function() print("hack socket close, MEM: "..node.heap()) c:close() end) -- socket timeout hack
|
||||||
|
print("MEM: "..node.heap())
|
||||||
|
end
|
||||||
|
|
|
@ -2,8 +2,9 @@ HDC1000 = require("HDC1000")
|
||||||
|
|
||||||
sda = 1
|
sda = 1
|
||||||
scl = 2
|
scl = 2
|
||||||
|
drdyn = false
|
||||||
|
|
||||||
HDC1000.init(sda, scl)
|
HDC1000.init(sda, scl, drdyn)
|
||||||
HDC1000.config() -- default values are used if called with no arguments. prototype is config(address, resolution, heater)
|
HDC1000.config() -- default values are used if called with no arguments. prototype is config(address, resolution, heater)
|
||||||
|
|
||||||
print(string.format("Temperature: %.2f °C\nHumidity: %.2f %%", HDC1000.getTemp(), HDC1000.getHumi()))
|
print(string.format("Temperature: %.2f °C\nHumidity: %.2f %%", HDC1000.getTemp(), HDC1000.getHumi()))
|
||||||
|
|
|
@ -25,6 +25,7 @@ _G[modname] = M
|
||||||
local id = 0
|
local id = 0
|
||||||
local i2c = i2c
|
local i2c = i2c
|
||||||
local delay = 20000
|
local delay = 20000
|
||||||
|
local _drdyn_pin
|
||||||
|
|
||||||
local HDC1000_ADDR = 0x40
|
local HDC1000_ADDR = 0x40
|
||||||
|
|
||||||
|
@ -69,7 +70,8 @@ function M.batteryDead()
|
||||||
end
|
end
|
||||||
|
|
||||||
-- initalize i2c
|
-- initalize i2c
|
||||||
function M.init(sda, scl)
|
function M.init(sda, scl, drdyn_pin)
|
||||||
|
_drdyn_pin = drdyn_pin
|
||||||
i2c.setup(id, sda, scl, i2c.SLOW)
|
i2c.setup(id, sda, scl, i2c.SLOW)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -84,14 +86,22 @@ end
|
||||||
-- outputs temperature in Celsius degrees
|
-- outputs temperature in Celsius degrees
|
||||||
function M.getHumi()
|
function M.getHumi()
|
||||||
setReadRegister(HDC1000_HUMI)
|
setReadRegister(HDC1000_HUMI)
|
||||||
tmr.delay(delay)
|
if(_drdyn_pin ~= false) then
|
||||||
|
gpio.mode(_drdyn_pin, gpio.INPUT)
|
||||||
|
while(gpio.read(_drdyn_pin)==1) do
|
||||||
|
end
|
||||||
|
else tmr.delay(delay) end
|
||||||
return(read16()/65535.0*100)
|
return(read16()/65535.0*100)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- outputs humidity in %RH
|
-- outputs humidity in %RH
|
||||||
function M.getTemp()
|
function M.getTemp()
|
||||||
setReadRegister(HDC1000_TEMP)
|
setReadRegister(HDC1000_TEMP)
|
||||||
tmr.delay(delay)
|
if(_drdyn_pin ~= false) then
|
||||||
|
gpio.mode(_drdyn_pin, gpio.INPUT)
|
||||||
|
while(gpio.read(_drdyn_pin)==1) do
|
||||||
|
end
|
||||||
|
else tmr.delay(delay) end
|
||||||
return(read16()/65535.0*165-40)
|
return(read16()/65535.0*165-40)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,11 @@ First, require it:
|
||||||
|
|
||||||
Then, initialize it:
|
Then, initialize it:
|
||||||
|
|
||||||
`HDC1000.init(sda, scl)`
|
`HDC1000.init(sda, scl, drdyn)`
|
||||||
|
|
||||||
|
If you don't want to use the DRDYn pin, set it to false: a 20ms delay will be automatically set after each read request.
|
||||||
|
|
||||||
|
`HDC1000.init(sda, scl, false)`
|
||||||
|
|
||||||
Configure it:
|
Configure it:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
[Downloads](https://github.com/nodemcu/nodemcu-firmware/releases/latest)
|
Loading…
Reference in New Issue