SPIFFS partition support, file module from dev.
Now uses the designated partition (type 0xC2, 0x00) unconditionally.
This commit is contained in:
parent
0fe0096c04
commit
60339b812b
|
@ -9,20 +9,6 @@ SECTIONS {
|
|||
lua_rotable = ABSOLUTE(.);
|
||||
KEEP(*(.lua_rotable))
|
||||
LONG(0) LONG(0) /* Null-terminate the array */
|
||||
|
||||
/* Due to the way the gen_appbin.py script packs the bundle that goes into
|
||||
* flash, we don't have a convenient _flash_used_end symbol on the ESP32.
|
||||
* Instead we sum up the sections we know goes into the
|
||||
* irom0_flash.bin, so we can use that as a starting point to scan for
|
||||
* the next free page. We could presumably be even more specific and
|
||||
* account for the block headers and trailing checksum. Maybe later.
|
||||
*/
|
||||
_irom0_bin_min_sz = ABSOLUTE(
|
||||
_rodata_end - _rodata_start +
|
||||
_lit4_end - _lit4_start +
|
||||
_text_end - _text_start +
|
||||
_data_end - _data_start);
|
||||
|
||||
}
|
||||
}
|
||||
INSERT AFTER .flash.text
|
||||
|
|
|
@ -79,7 +79,7 @@ void nodemcu_init(void)
|
|||
if (!vfs_mount("/FLASH", 0)) {
|
||||
// Failed to mount -- try reformat
|
||||
NODE_ERR("Formatting file system. Please wait...\n");
|
||||
if (1 || !vfs_format()) { // FIXME
|
||||
if (!vfs_format()) {
|
||||
NODE_ERR( "*** ERROR ***: unable to format. FS might be compromised.\n" );
|
||||
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
|
||||
}
|
||||
|
@ -115,5 +115,5 @@ void app_main (void)
|
|||
console_init (&cfg, input_task);
|
||||
|
||||
xTaskCreate (
|
||||
nodemcu_main, "nodemcu", 2560, 0, tskIDLE_PRIORITY +1, NULL);
|
||||
nodemcu_main, "nodemcu", 3072, 0, tskIDLE_PRIORITY +1, NULL);
|
||||
}
|
||||
|
|
|
@ -6,4 +6,10 @@ config LUA_MODULE_NODE
|
|||
help
|
||||
Includes the node module (recommended).
|
||||
|
||||
config LUA_MODULE_FILE
|
||||
bool "File module"
|
||||
default "y"
|
||||
help
|
||||
Includes the file module (recommended).
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -0,0 +1,467 @@
|
|||
// Module for interfacing with file system
|
||||
|
||||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
|
||||
#include "vfs.h"
|
||||
#include <string.h>
|
||||
|
||||
static int file_fd = 0;
|
||||
static int rtc_cb_ref = LUA_NOREF;
|
||||
|
||||
|
||||
static void table2tm( lua_State *L, vfs_time *tm )
|
||||
{
|
||||
int idx = lua_gettop( L );
|
||||
|
||||
// extract items from table
|
||||
lua_getfield( L, idx, "year" );
|
||||
lua_getfield( L, idx, "mon" );
|
||||
lua_getfield( L, idx, "day" );
|
||||
lua_getfield( L, idx, "hour" );
|
||||
lua_getfield( L, idx, "min" );
|
||||
lua_getfield( L, idx, "sec" );
|
||||
|
||||
tm->year = luaL_optint( L, ++idx, 2016 );
|
||||
tm->mon = luaL_optint( L, ++idx, 6 );
|
||||
tm->day = luaL_optint( L, ++idx, 21 );
|
||||
tm->hour = luaL_optint( L, ++idx, 0 );
|
||||
tm->min = luaL_optint( L, ++idx, 0 );
|
||||
tm->sec = luaL_optint( L, ++idx, 0 );
|
||||
|
||||
// remove items from stack
|
||||
lua_pop( L, 6 );
|
||||
}
|
||||
|
||||
static int32_t file_rtc_cb( vfs_time *tm )
|
||||
{
|
||||
int32_t res = VFS_RES_ERR;
|
||||
|
||||
if (rtc_cb_ref != LUA_NOREF) {
|
||||
lua_State *L = lua_getstate();
|
||||
|
||||
lua_rawgeti( L, LUA_REGISTRYINDEX, rtc_cb_ref );
|
||||
lua_call( L, 0, 1 );
|
||||
|
||||
if (lua_type( L, lua_gettop( L ) ) == LUA_TTABLE) {
|
||||
table2tm( L, tm );
|
||||
res = VFS_RES_OK;
|
||||
}
|
||||
|
||||
// pop item returned by callback
|
||||
lua_pop( L, 1 );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Lua: on()
|
||||
static int file_on(lua_State *L)
|
||||
{
|
||||
enum events{
|
||||
ON_RTC = 0
|
||||
};
|
||||
const char *const eventnames[] = {"rtc", NULL};
|
||||
|
||||
int event = luaL_checkoption(L, 1, "rtc", eventnames);
|
||||
|
||||
switch (event) {
|
||||
case ON_RTC:
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, rtc_cb_ref);
|
||||
|
||||
if ((lua_type(L, 2) == LUA_TFUNCTION) ||
|
||||
(lua_type(L, 2) == LUA_TLIGHTFUNCTION)) {
|
||||
lua_pushvalue(L, 2); // copy argument (func) to the top of stack
|
||||
rtc_cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
vfs_register_rtc_cb(file_rtc_cb);
|
||||
} else {
|
||||
rtc_cb_ref = LUA_NOREF;
|
||||
vfs_register_rtc_cb(NULL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: close()
|
||||
static int file_close( lua_State* L )
|
||||
{
|
||||
if(file_fd){
|
||||
vfs_close(file_fd);
|
||||
file_fd = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BUILD_SPIFFS
|
||||
// Lua: format()
|
||||
static int file_format( lua_State* L )
|
||||
{
|
||||
file_close(L);
|
||||
if( !vfs_format() )
|
||||
{
|
||||
NODE_ERR( "\n*** ERROR ***: unable to format. FS might be compromised.\n" );
|
||||
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
|
||||
luaL_error(L, "Failed to format file system");
|
||||
}
|
||||
else{
|
||||
NODE_ERR( "format done.\n" );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int file_fscfg (lua_State *L)
|
||||
{
|
||||
uint32_t phys_addr, phys_size;
|
||||
|
||||
vfs_fscfg("/FLASH", &phys_addr, &phys_size);
|
||||
|
||||
lua_pushinteger (L, phys_addr);
|
||||
lua_pushinteger (L, phys_size);
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Lua: open(filename, mode)
|
||||
static int file_open( lua_State* L )
|
||||
{
|
||||
size_t len;
|
||||
if(file_fd){
|
||||
vfs_close(file_fd);
|
||||
file_fd = 0;
|
||||
}
|
||||
|
||||
const char *fname = luaL_checklstring( L, 1, &len );
|
||||
const char *basename = vfs_basename( fname );
|
||||
luaL_argcheck(L, strlen(basename) <= CONFIG_FS_OBJ_NAME_LEN && strlen(fname) == len, 1, "filename invalid");
|
||||
|
||||
const char *mode = luaL_optstring(L, 2, "r");
|
||||
|
||||
file_fd = vfs_open(fname, mode);
|
||||
|
||||
if(!file_fd){
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
lua_pushboolean(L, 1);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: list()
|
||||
static int file_list( lua_State* L )
|
||||
{
|
||||
vfs_dir *dir;
|
||||
vfs_item *item;
|
||||
|
||||
if ((dir = vfs_opendir(""))) {
|
||||
lua_newtable( L );
|
||||
while ((item = vfs_readdir(dir))) {
|
||||
lua_pushinteger(L, vfs_item_size(item));
|
||||
lua_setfield(L, -2, vfs_item_name(item));
|
||||
vfs_closeitem(item);
|
||||
}
|
||||
vfs_closedir(dir);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int file_seek (lua_State *L)
|
||||
{
|
||||
static const int mode[] = {VFS_SEEK_SET, VFS_SEEK_CUR, VFS_SEEK_END};
|
||||
static const char *const modenames[] = {"set", "cur", "end", NULL};
|
||||
if(!file_fd)
|
||||
return luaL_error(L, "open a file first");
|
||||
int op = luaL_checkoption(L, 1, "cur", modenames);
|
||||
long offset = luaL_optlong(L, 2, 0);
|
||||
op = vfs_lseek(file_fd, offset, mode[op]);
|
||||
if (op < 0)
|
||||
lua_pushnil(L); /* error */
|
||||
else
|
||||
lua_pushinteger(L, vfs_tell(file_fd));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: exists(filename)
|
||||
static int file_exists( lua_State* L )
|
||||
{
|
||||
size_t len;
|
||||
const char *fname = luaL_checklstring( L, 1, &len );
|
||||
const char *basename = vfs_basename( fname );
|
||||
luaL_argcheck(L, strlen(basename) <= CONFIG_FS_OBJ_NAME_LEN && strlen(fname) == len, 1, "filename invalid");
|
||||
|
||||
vfs_item *stat = vfs_stat((char *)fname);
|
||||
|
||||
lua_pushboolean(L, stat ? 1 : 0);
|
||||
|
||||
if (stat) vfs_closeitem(stat);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: remove(filename)
|
||||
static int file_remove( lua_State* L )
|
||||
{
|
||||
size_t len;
|
||||
const char *fname = luaL_checklstring( L, 1, &len );
|
||||
const char *basename = vfs_basename( fname );
|
||||
luaL_argcheck(L, strlen(basename) <= CONFIG_FS_OBJ_NAME_LEN && strlen(fname) == len, 1, "filename invalid");
|
||||
file_close(L);
|
||||
vfs_remove((char *)fname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lua: flush()
|
||||
static int file_flush( lua_State* L )
|
||||
{
|
||||
if(!file_fd)
|
||||
return luaL_error(L, "open a file first");
|
||||
if(vfs_flush(file_fd) == 0)
|
||||
lua_pushboolean(L, 1);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: rename("oldname", "newname")
|
||||
static int file_rename( lua_State* L )
|
||||
{
|
||||
size_t len;
|
||||
if(file_fd){
|
||||
vfs_close(file_fd);
|
||||
file_fd = 0;
|
||||
}
|
||||
|
||||
const char *oldname = luaL_checklstring( L, 1, &len );
|
||||
const char *basename = vfs_basename( oldname );
|
||||
luaL_argcheck(L, strlen(basename) <= CONFIG_FS_OBJ_NAME_LEN && strlen(oldname) == len, 1, "filename invalid");
|
||||
|
||||
const char *newname = luaL_checklstring( L, 2, &len );
|
||||
basename = vfs_basename( newname );
|
||||
luaL_argcheck(L, strlen(basename) <= CONFIG_FS_OBJ_NAME_LEN && strlen(newname) == len, 2, "filename invalid");
|
||||
|
||||
if(0 <= vfs_rename( oldname, newname )){
|
||||
lua_pushboolean(L, 1);
|
||||
} else {
|
||||
lua_pushboolean(L, 0);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// g_read()
|
||||
static int file_g_read( lua_State* L, int n, int16_t end_char )
|
||||
{
|
||||
if(n <= 0 || n > LUAL_BUFFERSIZE)
|
||||
n = LUAL_BUFFERSIZE;
|
||||
if(end_char < 0 || end_char >255)
|
||||
end_char = EOF;
|
||||
|
||||
luaL_Buffer b;
|
||||
if(!file_fd)
|
||||
return luaL_error(L, "open a file first");
|
||||
|
||||
luaL_buffinit(L, &b);
|
||||
char *p = luaL_prepbuffer(&b);
|
||||
int i;
|
||||
|
||||
n = vfs_read(file_fd, p, n);
|
||||
for (i = 0; i < n; ++i)
|
||||
if (p[i] == end_char)
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(i==0){
|
||||
luaL_pushresult(&b); /* close buffer */
|
||||
return (lua_objlen(L, -1) > 0); /* check whether read something */
|
||||
}
|
||||
|
||||
vfs_lseek(file_fd, -(n - i), VFS_SEEK_CUR);
|
||||
luaL_addsize(&b, i);
|
||||
luaL_pushresult(&b); /* close buffer */
|
||||
return 1; /* read at least an `eol' */
|
||||
}
|
||||
|
||||
// Lua: read()
|
||||
// file.read() will read all byte in file
|
||||
// file.read(10) will read 10 byte from file, or EOF is reached.
|
||||
// file.read('q') will read until 'q' or EOF is reached.
|
||||
static int file_read( lua_State* L )
|
||||
{
|
||||
unsigned need_len = LUAL_BUFFERSIZE;
|
||||
int16_t end_char = EOF;
|
||||
size_t el;
|
||||
if( lua_type( L, 1 ) == LUA_TNUMBER )
|
||||
{
|
||||
need_len = ( unsigned )luaL_checkinteger( L, 1 );
|
||||
if( need_len > LUAL_BUFFERSIZE ){
|
||||
need_len = LUAL_BUFFERSIZE;
|
||||
}
|
||||
}
|
||||
else if(lua_isstring(L, 1))
|
||||
{
|
||||
const char *end = luaL_checklstring( L, 1, &el );
|
||||
if(el!=1){
|
||||
return luaL_error( L, "wrong arg range" );
|
||||
}
|
||||
end_char = (int16_t)end[0];
|
||||
}
|
||||
|
||||
return file_g_read(L, need_len, end_char);
|
||||
}
|
||||
|
||||
// Lua: readline()
|
||||
static int file_readline( lua_State* L )
|
||||
{
|
||||
return file_g_read(L, LUAL_BUFFERSIZE, '\n');
|
||||
}
|
||||
|
||||
// Lua: write("string")
|
||||
static int file_write( lua_State* L )
|
||||
{
|
||||
if(!file_fd)
|
||||
return luaL_error(L, "open a file first");
|
||||
size_t l, rl;
|
||||
const char *s = luaL_checklstring(L, 1, &l);
|
||||
rl = vfs_write(file_fd, s, l);
|
||||
if(rl==l)
|
||||
lua_pushboolean(L, 1);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: writeline("string")
|
||||
static int file_writeline( lua_State* L )
|
||||
{
|
||||
if(!file_fd)
|
||||
return luaL_error(L, "open a file first");
|
||||
size_t l, rl;
|
||||
const char *s = luaL_checklstring(L, 1, &l);
|
||||
rl = vfs_write(file_fd, s, l);
|
||||
if(rl==l){
|
||||
rl = vfs_write(file_fd, "\n", 1);
|
||||
if(rl==1)
|
||||
lua_pushboolean(L, 1);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
}
|
||||
else{
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Lua: fsinfo()
|
||||
static int file_fsinfo( lua_State* L )
|
||||
{
|
||||
u32_t total, used;
|
||||
if (vfs_fsinfo("", &total, &used)) {
|
||||
return luaL_error(L, "file system failed");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
vfs_vol *vol;
|
||||
} volume_type;
|
||||
|
||||
#ifdef CONFIG_BUILD_FATFS
|
||||
// Lua: vol = file.mount("/SD0")
|
||||
static int file_mount( lua_State *L )
|
||||
{
|
||||
const char *ldrv = luaL_checkstring( L, 1 );
|
||||
int num = luaL_optint( L, 2, -1 );
|
||||
volume_type *vol = (volume_type *)lua_newuserdata( L, sizeof( volume_type ) );
|
||||
|
||||
if ((vol->vol = vfs_mount( ldrv, num ))) {
|
||||
/* set its metatable */
|
||||
luaL_getmetatable(L, "vfs.vol");
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
} else {
|
||||
// remove created userdata
|
||||
lua_pop( L, 1 );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Lua: success = file.chdir("/SD0/")
|
||||
static int file_chdir( lua_State *L )
|
||||
{
|
||||
const char *path = luaL_checkstring( L, 1 );
|
||||
|
||||
lua_pushboolean( L, 0 <= vfs_chdir( path ) );
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int file_vol_umount( lua_State *L )
|
||||
{
|
||||
volume_type *vol = luaL_checkudata( L, 1, "file.vol" );
|
||||
luaL_argcheck( L, vol, 1, "volume expected" );
|
||||
|
||||
lua_pushboolean( L, 0 <= vfs_umount( vol->vol ) );
|
||||
|
||||
// invalidate vfs descriptor, it has been free'd anyway
|
||||
vol->vol = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static const LUA_REG_TYPE file_vol_map[] =
|
||||
{
|
||||
{ LSTRKEY( "umount" ), LFUNCVAL( file_vol_umount )},
|
||||
//{ LSTRKEY( "getfree" ), LFUNCVAL( file_vol_getfree )},
|
||||
//{ LSTRKEY( "getlabel" ), LFUNCVAL( file_vol_getlabel )},
|
||||
//{ LSTRKEY( "__gc" ), LFUNCVAL( file_vol_free ) },
|
||||
{ LSTRKEY( "__index" ), LROVAL( file_vol_map ) },
|
||||
{ LNILKEY, LNILVAL }
|
||||
};
|
||||
|
||||
// Module function map
|
||||
static const LUA_REG_TYPE file_map[] = {
|
||||
{ LSTRKEY( "list" ), LFUNCVAL( file_list ) },
|
||||
{ LSTRKEY( "open" ), LFUNCVAL( file_open ) },
|
||||
{ LSTRKEY( "close" ), LFUNCVAL( file_close ) },
|
||||
{ LSTRKEY( "write" ), LFUNCVAL( file_write ) },
|
||||
{ LSTRKEY( "writeline" ), LFUNCVAL( file_writeline ) },
|
||||
{ LSTRKEY( "read" ), LFUNCVAL( file_read ) },
|
||||
{ LSTRKEY( "readline" ), LFUNCVAL( file_readline ) },
|
||||
#ifdef CONFIG_BUILD_SPIFFS
|
||||
{ LSTRKEY( "format" ), LFUNCVAL( file_format ) },
|
||||
{ LSTRKEY( "fscfg" ), LFUNCVAL( file_fscfg ) },
|
||||
#endif
|
||||
{ LSTRKEY( "remove" ), LFUNCVAL( file_remove ) },
|
||||
{ LSTRKEY( "seek" ), LFUNCVAL( file_seek ) },
|
||||
{ LSTRKEY( "flush" ), LFUNCVAL( file_flush ) },
|
||||
{ LSTRKEY( "rename" ), LFUNCVAL( file_rename ) },
|
||||
{ LSTRKEY( "exists" ), LFUNCVAL( file_exists ) },
|
||||
{ LSTRKEY( "fsinfo" ), LFUNCVAL( file_fsinfo ) },
|
||||
{ LSTRKEY( "on" ), LFUNCVAL( file_on ) },
|
||||
#ifdef CONFIG_BUILD_FATFS
|
||||
{ LSTRKEY( "mount" ), LFUNCVAL( file_mount ) },
|
||||
{ LSTRKEY( "chdir" ), LFUNCVAL( file_chdir ) },
|
||||
#endif
|
||||
{ LNILKEY, LNILVAL }
|
||||
};
|
||||
|
||||
int luaopen_file( lua_State *L ) {
|
||||
luaL_rometatable( L, "file.vol", (void *)file_vol_map );
|
||||
return 0;
|
||||
}
|
||||
|
||||
NODEMCU_MODULE(FILE, "file", file_map, luaopen_file);
|
|
@ -1,29 +1,5 @@
|
|||
menu "Platform config"
|
||||
|
||||
choice FLASH_SIZE
|
||||
bool "Platform SPI flash size"
|
||||
default FLASH_SIZE_AUTO
|
||||
help
|
||||
Configure the size of the SPI flash on the platform.
|
||||
|
||||
This is used to determine various things such as file system size,
|
||||
the location of SDK configuration data, and initial RF data.
|
||||
config FLASH_SIZE_AUTO
|
||||
bool "Auto-detect"
|
||||
config FLASH_SIZE_512K
|
||||
bool "512KB (4Mbit)"
|
||||
config FLASH_SIZE_1M
|
||||
bool "1MB (8Mbit)"
|
||||
config FLASH_SIZE_2M
|
||||
bool "2MB (16Mbit)"
|
||||
config FLASH_SIZE_4M
|
||||
bool "4MB (32Mbit)"
|
||||
config FLASH_SIZE_8M
|
||||
bool "8MB (64Mbit)"
|
||||
config FLASH_SIZE_16M
|
||||
bool "16MB (128Mbit)"
|
||||
endchoice
|
||||
|
||||
choice CONSOLE_BIT_RATE
|
||||
prompt "UART console default bit rate"
|
||||
default CONSOLE_BIT_RATE_115200
|
||||
|
|
|
@ -2,58 +2,19 @@
|
|||
#define _CPU_ESP32_H_
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_spi_flash.h"
|
||||
|
||||
#define NUM_UART 3
|
||||
|
||||
#if defined(CONFIG_FLASH_SIZE_512K)
|
||||
# define FLASH_SEC_NUM 0x80 // 4MByte: 0x400, 2MByte: 0x200, 1MByte: 0x100, 512KByte: 0x80
|
||||
#elif defined(CONFIG_FLASH_SIZE_1M)
|
||||
# define FLASH_SEC_NUM 0x100
|
||||
#elif defined(CONFIG_FLASH_SIZE_2M)
|
||||
# define FLASH_SEC_NUM 0x200
|
||||
#elif defined(CONFIG_FLASH_SIZE_4M)
|
||||
# define FLASH_SEC_NUM 0x400
|
||||
#elif defined(CONFIG_FLASH_SIZE_8M)
|
||||
# define FLASH_SEC_NUM 0x800
|
||||
#elif defined(CONFIG_FLASH_SIZE_16M)
|
||||
# define FLASH_SEC_NUM 0x1000
|
||||
#elif defined(CONFIG_FLASH_SIZE_AUTO)
|
||||
# if defined(FLASH_SAFE_API)
|
||||
# define FLASH_SEC_NUM (flash_safe_get_sec_num())
|
||||
# else
|
||||
# define FLASH_SEC_NUM (flash_rom_get_sec_num())
|
||||
# endif // defined(FLASH_SAFE_API)
|
||||
#else
|
||||
# define FLASH_SEC_NUM 0x80
|
||||
#endif
|
||||
|
||||
|
||||
#define SYS_PARAM_SEC_NUM 4
|
||||
#define SYS_PARAM_SEC_START (FLASH_SEC_NUM - SYS_PARAM_SEC_NUM)
|
||||
|
||||
|
||||
#define INTERNAL_FLASH_SECTOR_SIZE SPI_FLASH_SEC_SIZE
|
||||
#define INTERNAL_FLASH_WRITE_UNIT_SIZE 4
|
||||
#define INTERNAL_FLASH_READ_UNIT_SIZE 4
|
||||
|
||||
#define INTERNAL_FLASH_SIZE ( (SYS_PARAM_SEC_START) * INTERNAL_FLASH_SECTOR_SIZE )
|
||||
#define FLASH_SEC_NUM (flash_safe_get_sec_num())
|
||||
|
||||
#define IROM0_START_MAPPED_ADDR 0x3F400000
|
||||
// TODO: tie this in with the partition table!
|
||||
#define IROM0_START_FLASH_ADDR 0x40000
|
||||
// TODO: might need to revamp all this once cache windows fully understood
|
||||
#define INTERNAL_FLASH_MAPPED_ADDRESS IROM0_START_MAPPED_ADDR
|
||||
|
||||
|
||||
#if defined(FLASH_SAFE_API)
|
||||
#define flash_write flash_safe_write
|
||||
#define flash_erase flash_safe_erase_sector
|
||||
#define flash_read flash_safe_read
|
||||
#else
|
||||
#define flash_write spi_flash_write
|
||||
#define flash_erase spi_flash_erase_sector
|
||||
#define flash_read spi_flash_read
|
||||
#endif // defined(FLASH_SAFE_API)
|
||||
// Determine whether an address is in the flash-cache range
|
||||
static inline bool is_cache_flash_addr (uint32_t addr)
|
||||
{
|
||||
return addr >= 0x3F400000 && addr < 0x3FC00000;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
#ifndef __FLASH_API_H__
|
||||
#define __FLASH_API_H__
|
||||
#include "platform.h"
|
||||
|
||||
#define FLASH_SIZE_1MBYTE ( 1 * 1024 * 1024)
|
||||
#define FLASH_SIZE_2MBYTE ( 2 * 1024 * 1024)
|
||||
#define FLASH_SIZE_4MBYTE ( 4 * 1024 * 1024)
|
||||
#define FLASH_SIZE_8MBYTE ( 8 * 1024 * 1024)
|
||||
#define FLASH_SIZE_16MBYTE (16 * 1024 * 1024)
|
||||
#include "esp_spi_flash.h"
|
||||
|
||||
uint32_t flash_safe_get_size_byte(void);
|
||||
uint16_t flash_safe_get_sec_num(void);
|
||||
|
@ -17,4 +12,14 @@ uint16_t flash_rom_get_sec_num(void);
|
|||
uint8_t flash_rom_get_mode(void);
|
||||
uint32_t flash_rom_get_speed(void);
|
||||
|
||||
#define FLASH_SIZE_1MBYTE ( 1 * 1024 * 1024)
|
||||
#define FLASH_SIZE_2MBYTE ( 2 * 1024 * 1024)
|
||||
#define FLASH_SIZE_4MBYTE ( 4 * 1024 * 1024)
|
||||
#define FLASH_SIZE_8MBYTE ( 8 * 1024 * 1024)
|
||||
#define FLASH_SIZE_16MBYTE (16 * 1024 * 1024)
|
||||
|
||||
#define flash_write spi_flash_write
|
||||
#define flash_erase spi_flash_erase_sector
|
||||
#define flash_read spi_flash_read
|
||||
|
||||
#endif // __FLASH_API_H__
|
||||
|
|
|
@ -70,7 +70,6 @@ int platform_uart_set_flow_control( unsigned id, int type );
|
|||
|
||||
// Internal flash erase/write functions
|
||||
|
||||
uint32_t platform_flash_get_first_free_block_address( uint32_t *psect );
|
||||
uint32_t platform_flash_get_sector_of_address( uint32_t addr );
|
||||
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size );
|
||||
uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size );
|
||||
|
@ -79,18 +78,22 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size );
|
|||
uint32_t platform_flash_get_num_sectors(void);
|
||||
int platform_flash_erase_sector( uint32_t sector_id );
|
||||
|
||||
/**
|
||||
* Translated a mapped address to a physical flash address, based on the
|
||||
* current flash cache mapping.
|
||||
* @param mapped_addr Address to translate (>= INTERNAL_FLASH_MAPPED_ADDRESS)
|
||||
* @return the corresponding physical flash address, or -1 if flash cache is
|
||||
* not currently active.
|
||||
* @see Cache_Read_Enable.
|
||||
*/
|
||||
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr);
|
||||
|
||||
|
||||
// Internal flash partitions
|
||||
#define PLATFORM_PARTITION_TYPE_APP 0x00
|
||||
#define PLATFORM_PARTITION_TYPE_DATA 0x01
|
||||
#define PLATFORM_PARTITION_TYPE_NODEMCU 0xC2
|
||||
|
||||
#define PLATFORM_PARTITION_SUBTYPE_APP_FACTORY 0x00
|
||||
#define PLATFORM_PARTITION_SUBTYPE_APP_OTA(n) (0x10+n)
|
||||
#define PLATFORM_PARTITION_SUBTYPE_APP_TEST 0x20
|
||||
|
||||
#define PLATFORM_PARTITION_SUBTYPE_DATA_OTA 0x00
|
||||
#define PLATFORM_PARTITION_SUBTYPE_DATA_RF 0x01
|
||||
#define PLATFORM_PARTITION_SUBTYPE_DATA_WIFI 0x02
|
||||
|
||||
#define PLATFORM_PARTITION_SUBTYPE_NODEMCU_SPIFFS 0x00
|
||||
|
||||
typedef struct {
|
||||
uint8_t label[16];
|
||||
uint32_t offs;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Espressif ESP32 Partition Table
|
||||
# Name, Type, SubType, Offset, Size
|
||||
factory, app, factory, 0x10000, 1M
|
||||
rfdata, data, rf, 0x110000, 256K
|
||||
wifidata,data, wifi, 0x150000, 256K
|
||||
# 0xC2 => NodeMCU, 0x0 => Spiffs
|
||||
spiffs, 0xC2, 0x0, , 448K
|
|
|
@ -7,17 +7,10 @@
|
|||
// ****************************************************************************
|
||||
// Internal flash support functions
|
||||
|
||||
/* This symbol must be exported by the linker command file and contain the
|
||||
* size of all the sections packed into the irom0_flash.bin file, in order
|
||||
* for us to find the end of used flash.
|
||||
*/
|
||||
extern char _irom0_bin_min_sz[];
|
||||
|
||||
// Helper function: find the flash sector in which an address resides
|
||||
// Return the sector number, as well as the start and end address of the sector
|
||||
static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend )
|
||||
{
|
||||
#ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
// All the sectors in the flash have the same size, so just align the address
|
||||
uint32_t sect_id = address / INTERNAL_FLASH_SECTOR_SIZE;
|
||||
|
||||
|
@ -26,20 +19,6 @@ static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t
|
|||
if( pend )
|
||||
*pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE - 1;
|
||||
return sect_id;
|
||||
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
// The flash has blocks of different size
|
||||
// Their size is decribed in the INTERNAL_FLASH_SECTOR_ARRAY macro
|
||||
const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
|
||||
uint32_t total = 0, i = 0;
|
||||
|
||||
while( ( total <= address ) && ( i < sizeof( flash_sect_size ) / sizeof( uint32_t ) ) )
|
||||
total += flash_sect_size[ i ++ ];
|
||||
if( pstart )
|
||||
*pstart = ( total - flash_sect_size[ i - 1 ] );
|
||||
if( pend )
|
||||
*pend = total - 1;
|
||||
return i - 1;
|
||||
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
}
|
||||
|
||||
uint32_t platform_flash_get_sector_of_address( uint32_t addr )
|
||||
|
@ -49,26 +28,7 @@ uint32_t platform_flash_get_sector_of_address( uint32_t addr )
|
|||
|
||||
uint32_t platform_flash_get_num_sectors(void)
|
||||
{
|
||||
#ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
return INTERNAL_FLASH_SIZE / INTERNAL_FLASH_SECTOR_SIZE;
|
||||
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
|
||||
|
||||
return sizeof( flash_sect_size ) / sizeof( uint32_t );
|
||||
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
|
||||
}
|
||||
|
||||
uint32_t platform_flash_get_first_free_block_address( uint32_t *psect )
|
||||
{
|
||||
uint32_t flash_offs = IROM0_START_FLASH_ADDR + (uint32_t)_irom0_bin_min_sz;
|
||||
uint32_t sect =
|
||||
(flash_offs + INTERNAL_FLASH_SECTOR_SIZE-1)/INTERNAL_FLASH_SECTOR_SIZE;
|
||||
++sect; /* compensate for various headers not counted in _irom0_bin_min_sz */
|
||||
|
||||
if (psect)
|
||||
*psect = sect;
|
||||
|
||||
return sect * INTERNAL_FLASH_SECTOR_SIZE;
|
||||
return flash_safe_get_sec_num ();
|
||||
}
|
||||
|
||||
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size )
|
||||
|
@ -168,6 +128,7 @@ uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size )
|
|||
#endif // #ifndef INTERNAL_FLASH_READ_UNIT_SIZE
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Assumptions:
|
||||
* > toaddr is INTERNAL_FLASH_WRITE_UNIT_SIZE aligned
|
||||
|
@ -179,7 +140,7 @@ uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t siz
|
|||
const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;
|
||||
uint32_t *apbuf = NULL;
|
||||
uint32_t fromaddr = (uint32_t)from;
|
||||
if( (fromaddr & blkmask ) || (fromaddr >= INTERNAL_FLASH_MAPPED_ADDRESS)) {
|
||||
if( (fromaddr & blkmask ) || is_cache_flash_addr(fromaddr)) {
|
||||
apbuf = (uint32_t *)malloc(size);
|
||||
if(!apbuf)
|
||||
return 0;
|
||||
|
@ -240,9 +201,3 @@ int platform_flash_erase_sector( uint32_t sector_id )
|
|||
return flash_erase( sector_id ) == ESP_OK ? PLATFORM_OK : PLATFORM_ERR;
|
||||
}
|
||||
|
||||
|
||||
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr)
|
||||
{
|
||||
// FIXME: need to take actual memory maps into account!
|
||||
return mapped_addr - IROM0_START_MAPPED_ADDR + IROM0_START_FLASH_ADDR;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,9 @@ int32_t vfs_get_rtc( vfs_time *tm )
|
|||
}
|
||||
|
||||
|
||||
#if LDRV_TRAVERSAL
|
||||
static int dir_level = 1;
|
||||
#endif
|
||||
|
||||
static const char *normalize_path( const char *path )
|
||||
{
|
||||
|
@ -216,14 +218,14 @@ int32_t vfs_rename( const char *oldname, const char *newname )
|
|||
int32_t vfs_mkdir( const char *name )
|
||||
{
|
||||
vfs_fs_fns *fs_fns;
|
||||
const char *normname = normalize_path( name );
|
||||
char *outname;
|
||||
|
||||
#ifdef CONFIG_BUILD_SPIFFS
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BUILD_FATFS
|
||||
const char *normname = normalize_path( name );
|
||||
char *outname;
|
||||
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
|
||||
int32_t r = fs_fns->mkdir( outname );
|
||||
free( outname );
|
||||
|
@ -301,11 +303,11 @@ int32_t vfs_chdir( const char *path )
|
|||
{
|
||||
vfs_fs_fns *fs_fns;
|
||||
const char *normpath = normalize_path( path );
|
||||
const char *level;
|
||||
char *outname;
|
||||
int ok = VFS_RES_ERR;
|
||||
|
||||
#if LDRV_TRAVERSAL
|
||||
const char *level;
|
||||
// track dir level
|
||||
if (normpath[0] == '/') {
|
||||
dir_level = 0;
|
||||
|
@ -450,8 +452,6 @@ const char *vfs_basename( const char *path )
|
|||
int vfs_getc( int fd )
|
||||
{
|
||||
unsigned char c = 0xFF;
|
||||
int32_t res;
|
||||
|
||||
if(!vfs_eof( fd )) {
|
||||
if (1 != vfs_read( fd, &c, 1 )) {
|
||||
NODE_DBG("getc errno %i\n", vfs_ferrno( fd ));
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "flash_api.h"
|
||||
#include "spiffs.h"
|
||||
|
||||
spiffs fs;
|
||||
static spiffs fs;
|
||||
|
||||
#define LOG_PAGE_SIZE 256
|
||||
#define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2)
|
||||
|
@ -49,118 +49,43 @@ The small 4KB sectors allow for greater flexibility in applications th
|
|||
|
||||
********************/
|
||||
|
||||
static bool myspiffs_set_location(spiffs_config *cfg, int align, int offset, int block_size) {
|
||||
#ifdef SPIFFS_FIXED_LOCATION
|
||||
cfg->phys_addr = (SPIFFS_FIXED_LOCATION + block_size - 1) & ~(block_size-1);
|
||||
#else
|
||||
cfg->phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL ) + offset;
|
||||
cfg->phys_addr = (cfg->phys_addr + align - 1) & ~(align - 1);
|
||||
#endif
|
||||
#ifdef SPIFFS_SIZE_1M_BOUNDARY
|
||||
cfg->phys_size = ((0x100000 - (SYS_PARAM_SEC_NUM * INTERNAL_FLASH_SECTOR_SIZE) - ( ( u32_t )cfg->phys_addr )) & ~(block_size - 1)) & 0xfffff;
|
||||
#else
|
||||
cfg->phys_size = (INTERNAL_FLASH_SIZE - ( ( u32_t )cfg->phys_addr )) & ~(block_size - 1);
|
||||
#endif
|
||||
if ((int) cfg->phys_size < 0) {
|
||||
return false;
|
||||
}
|
||||
cfg->log_block_size = block_size;
|
||||
|
||||
return (cfg->phys_size / block_size) >= MIN_BLOCKS_FS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if FS was found
|
||||
* align must be a power of two
|
||||
*/
|
||||
static bool myspiffs_set_cfg(spiffs_config *cfg, int align, int offset, bool force_create) {
|
||||
cfg->phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
|
||||
cfg->log_page_size = LOG_PAGE_SIZE; // as we said
|
||||
|
||||
cfg->hal_read_f = my_spiffs_read;
|
||||
cfg->hal_write_f = my_spiffs_write;
|
||||
cfg->hal_erase_f = my_spiffs_erase;
|
||||
|
||||
if (!myspiffs_set_location(cfg, align, offset, LOG_BLOCK_SIZE)) {
|
||||
if (!myspiffs_set_location(cfg, align, offset, LOG_BLOCK_SIZE_SMALL_FS)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
NODE_DBG("fs.start:%x,max:%x\n",cfg->phys_addr,cfg->phys_size);
|
||||
|
||||
#ifdef SPIFFS_USE_MAGIC_LENGTH
|
||||
if (force_create) {
|
||||
static bool get_spiffs_partition (spiffs_config *cfg)
|
||||
{
|
||||
platform_partition_t info;
|
||||
uint8_t i = 0;
|
||||
while (platform_partition_info (i, &info))
|
||||
{
|
||||
if (info.type == PLATFORM_PARTITION_TYPE_NODEMCU &&
|
||||
info.subtype == PLATFORM_PARTITION_SUBTYPE_NODEMCU_SPIFFS)
|
||||
{
|
||||
cfg->phys_addr = info.offs;
|
||||
cfg->phys_size = info.size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int size = SPIFFS_probe_fs(cfg);
|
||||
|
||||
if (size > 0 && size < cfg->phys_size) {
|
||||
NODE_DBG("Overriding size:%x\n",size);
|
||||
cfg->phys_size = size;
|
||||
else
|
||||
++i;
|
||||
}
|
||||
if (size > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool myspiffs_find_cfg(spiffs_config *cfg, bool force_create) {
|
||||
int i;
|
||||
|
||||
if (!force_create) {
|
||||
#ifdef SPIFFS_FIXED_LOCATION
|
||||
if (myspiffs_set_cfg(cfg, 0, 0, false)) {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
if (INTERNAL_FLASH_SIZE >= 700000) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (myspiffs_set_cfg(cfg, 0x10000, 0x10000 * i, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, LOG_BLOCK_SIZE * i, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// No existing file system -- set up for a format
|
||||
if (INTERNAL_FLASH_SIZE >= 700000) {
|
||||
myspiffs_set_cfg(cfg, 0x10000, 0x10000, true);
|
||||
#ifndef SPIFFS_MAX_FILESYSTEM_SIZE
|
||||
if (cfg->phys_size < 400000) {
|
||||
// Don't waste so much in alignment
|
||||
myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, LOG_BLOCK_SIZE * 4, true);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, 0, true);
|
||||
}
|
||||
|
||||
#ifdef SPIFFS_MAX_FILESYSTEM_SIZE
|
||||
if (cfg->phys_size > SPIFFS_MAX_FILESYSTEM_SIZE) {
|
||||
cfg->phys_size = (SPIFFS_MAX_FILESYSTEM_SIZE) & ~(cfg->log_block_size - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: try to automatically append a spiffs partition; needs support
|
||||
// over in platform_partition.c for that too
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool myspiffs_mount_internal(bool force_mount) {
|
||||
|
||||
static bool myspiffs_mount_internal(bool force_mount)
|
||||
{
|
||||
spiffs_config cfg;
|
||||
if (!myspiffs_find_cfg(&cfg, force_mount) && !force_mount) {
|
||||
cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
|
||||
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
|
||||
cfg.log_block_size = LOG_BLOCK_SIZE;
|
||||
cfg.hal_read_f = my_spiffs_read;
|
||||
cfg.hal_write_f = my_spiffs_write;
|
||||
cfg.hal_erase_f = my_spiffs_erase;
|
||||
if (!get_spiffs_partition (&cfg))
|
||||
return false;
|
||||
|
||||
if (!force_mount && SPIFFS_probe_fs (&cfg) != cfg.phys_size)
|
||||
return false;
|
||||
}
|
||||
|
||||
fs.err_code = 0;
|
||||
|
||||
|
@ -169,12 +94,8 @@ static bool myspiffs_mount_internal(bool force_mount) {
|
|||
spiffs_work_buf,
|
||||
spiffs_fds,
|
||||
sizeof(spiffs_fds),
|
||||
#if SPIFFS_CACHE
|
||||
spiffs_cache,
|
||||
sizeof(spiffs_cache),
|
||||
#else
|
||||
0, 0,
|
||||
#endif
|
||||
// myspiffs_check_callback);
|
||||
0);
|
||||
NODE_DBG("mount res: %d, %d\n", res, fs.err_code);
|
||||
|
@ -199,7 +120,8 @@ int myspiffs_format( void )
|
|||
|
||||
NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr);
|
||||
|
||||
if (SPIFFS_format(&fs) < 0) {
|
||||
s32_t res = SPIFFS_format (&fs);
|
||||
if (res < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue