SPIFFS partition support, file module from dev.

Now uses the designated partition (type 0xC2, 0x00) unconditionally.
This commit is contained in:
Johny Mattsson 2016-09-22 17:18:22 +10:00
parent 0fe0096c04
commit 60339b812b
12 changed files with 552 additions and 264 deletions

View File

@ -9,20 +9,6 @@ SECTIONS {
lua_rotable = ABSOLUTE(.); lua_rotable = ABSOLUTE(.);
KEEP(*(.lua_rotable)) KEEP(*(.lua_rotable))
LONG(0) LONG(0) /* Null-terminate the array */ 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 INSERT AFTER .flash.text

View File

@ -79,7 +79,7 @@ void nodemcu_init(void)
if (!vfs_mount("/FLASH", 0)) { if (!vfs_mount("/FLASH", 0)) {
// Failed to mount -- try reformat // Failed to mount -- try reformat
NODE_ERR("Formatting file system. Please wait...\n"); 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( "*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\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); console_init (&cfg, input_task);
xTaskCreate ( xTaskCreate (
nodemcu_main, "nodemcu", 2560, 0, tskIDLE_PRIORITY +1, NULL); nodemcu_main, "nodemcu", 3072, 0, tskIDLE_PRIORITY +1, NULL);
} }

View File

@ -6,4 +6,10 @@ config LUA_MODULE_NODE
help help
Includes the node module (recommended). Includes the node module (recommended).
config LUA_MODULE_FILE
bool "File module"
default "y"
help
Includes the file module (recommended).
endmenu endmenu

467
components/modules/file.c Normal file
View File

@ -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);

View File

@ -1,29 +1,5 @@
menu "Platform config" 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 choice CONSOLE_BIT_RATE
prompt "UART console default bit rate" prompt "UART console default bit rate"
default CONSOLE_BIT_RATE_115200 default CONSOLE_BIT_RATE_115200

View File

@ -2,58 +2,19 @@
#define _CPU_ESP32_H_ #define _CPU_ESP32_H_
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_spi_flash.h"
#define NUM_UART 3 #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_SECTOR_SIZE SPI_FLASH_SEC_SIZE
#define INTERNAL_FLASH_WRITE_UNIT_SIZE 4 #define INTERNAL_FLASH_WRITE_UNIT_SIZE 4
#define INTERNAL_FLASH_READ_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 // Determine whether an address is in the flash-cache range
// TODO: tie this in with the partition table! static inline bool is_cache_flash_addr (uint32_t addr)
#define IROM0_START_FLASH_ADDR 0x40000 {
// TODO: might need to revamp all this once cache windows fully understood return addr >= 0x3F400000 && addr < 0x3FC00000;
#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)
#endif #endif

View File

@ -1,12 +1,7 @@
#ifndef __FLASH_API_H__ #ifndef __FLASH_API_H__
#define __FLASH_API_H__ #define __FLASH_API_H__
#include "platform.h" #include "platform.h"
#include "esp_spi_flash.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)
uint32_t flash_safe_get_size_byte(void); uint32_t flash_safe_get_size_byte(void);
uint16_t flash_safe_get_sec_num(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); uint8_t flash_rom_get_mode(void);
uint32_t flash_rom_get_speed(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__ #endif // __FLASH_API_H__

View File

@ -70,7 +70,6 @@ int platform_uart_set_flow_control( unsigned id, int type );
// Internal flash erase/write functions // 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_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_write( const void *from, uint32_t toaddr, uint32_t size );
uint32_t platform_flash_read( void *to, uint32_t fromaddr, 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); uint32_t platform_flash_get_num_sectors(void);
int platform_flash_erase_sector( uint32_t sector_id ); 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 // 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 { typedef struct {
uint8_t label[16]; uint8_t label[16];
uint32_t offs; uint32_t offs;

View File

@ -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
1 # Espressif ESP32 Partition Table
2 # Name, Type, SubType, Offset, Size
3 factory, app, factory, 0x10000, 1M
4 rfdata, data, rf, 0x110000, 256K
5 wifidata,data, wifi, 0x150000, 256K
6 # 0xC2 => NodeMCU, 0x0 => Spiffs
7 spiffs, 0xC2, 0x0, , 448K

View File

@ -7,17 +7,10 @@
// **************************************************************************** // ****************************************************************************
// Internal flash support functions // 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 // 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 // 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 ) 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 // All the sectors in the flash have the same size, so just align the address
uint32_t sect_id = address / INTERNAL_FLASH_SECTOR_SIZE; 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 ) if( pend )
*pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE - 1; *pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE - 1;
return sect_id; 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 ) 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) uint32_t platform_flash_get_num_sectors(void)
{ {
#ifdef INTERNAL_FLASH_SECTOR_SIZE return flash_safe_get_sec_num ();
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;
} }
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size ) 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 #endif // #ifndef INTERNAL_FLASH_READ_UNIT_SIZE
} }
/* /*
* Assumptions: * Assumptions:
* > toaddr is INTERNAL_FLASH_WRITE_UNIT_SIZE aligned * > 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; const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;
uint32_t *apbuf = NULL; uint32_t *apbuf = NULL;
uint32_t fromaddr = (uint32_t)from; 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); apbuf = (uint32_t *)malloc(size);
if(!apbuf) if(!apbuf)
return 0; 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; 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;
}

View File

@ -29,7 +29,9 @@ int32_t vfs_get_rtc( vfs_time *tm )
} }
#if LDRV_TRAVERSAL
static int dir_level = 1; static int dir_level = 1;
#endif
static const char *normalize_path( const char *path ) 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 ) int32_t vfs_mkdir( const char *name )
{ {
vfs_fs_fns *fs_fns; vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS #ifdef CONFIG_BUILD_SPIFFS
// not supported // not supported
#endif #endif
#ifdef CONFIG_BUILD_FATFS #ifdef CONFIG_BUILD_FATFS
const char *normname = normalize_path( name );
char *outname;
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) { if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->mkdir( outname ); int32_t r = fs_fns->mkdir( outname );
free( outname ); free( outname );
@ -301,11 +303,11 @@ int32_t vfs_chdir( const char *path )
{ {
vfs_fs_fns *fs_fns; vfs_fs_fns *fs_fns;
const char *normpath = normalize_path( path ); const char *normpath = normalize_path( path );
const char *level;
char *outname; char *outname;
int ok = VFS_RES_ERR; int ok = VFS_RES_ERR;
#if LDRV_TRAVERSAL #if LDRV_TRAVERSAL
const char *level;
// track dir level // track dir level
if (normpath[0] == '/') { if (normpath[0] == '/') {
dir_level = 0; dir_level = 0;
@ -450,8 +452,6 @@ const char *vfs_basename( const char *path )
int vfs_getc( int fd ) int vfs_getc( int fd )
{ {
unsigned char c = 0xFF; unsigned char c = 0xFF;
int32_t res;
if(!vfs_eof( fd )) { if(!vfs_eof( fd )) {
if (1 != vfs_read( fd, &c, 1 )) { if (1 != vfs_read( fd, &c, 1 )) {
NODE_DBG("getc errno %i\n", vfs_ferrno( fd )); NODE_DBG("getc errno %i\n", vfs_ferrno( fd ));

View File

@ -4,7 +4,7 @@
#include "flash_api.h" #include "flash_api.h"
#include "spiffs.h" #include "spiffs.h"
spiffs fs; static spiffs fs;
#define LOG_PAGE_SIZE 256 #define LOG_PAGE_SIZE 256
#define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2) #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; static bool get_spiffs_partition (spiffs_config *cfg)
} {
platform_partition_t info;
/* uint8_t i = 0;
* Returns true if FS was found while (platform_partition_info (i, &info))
* align must be a power of two {
*/ if (info.type == PLATFORM_PARTITION_TYPE_NODEMCU &&
static bool myspiffs_set_cfg(spiffs_config *cfg, int align, int offset, bool force_create) { info.subtype == PLATFORM_PARTITION_SUBTYPE_NODEMCU_SPIFFS)
cfg->phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet {
cfg->log_page_size = LOG_PAGE_SIZE; // as we said cfg->phys_addr = info.offs;
cfg->phys_size = info.size;
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) {
return true; return true;
} }
else
int size = SPIFFS_probe_fs(cfg); ++i;
if (size > 0 && size < cfg->phys_size) {
NODE_DBG("Overriding size:%x\n",size);
cfg->phys_size = size;
} }
if (size > 0) { // TODO: try to automatically append a spiffs partition; needs support
return true; // over in platform_partition.c for that too
}
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
return false; return false;
} }
static bool myspiffs_mount_internal(bool force_mount) {
static bool myspiffs_mount_internal(bool force_mount)
{
spiffs_config cfg; 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; return false;
}
fs.err_code = 0; fs.err_code = 0;
@ -169,12 +94,8 @@ static bool myspiffs_mount_internal(bool force_mount) {
spiffs_work_buf, spiffs_work_buf,
spiffs_fds, spiffs_fds,
sizeof(spiffs_fds), sizeof(spiffs_fds),
#if SPIFFS_CACHE
spiffs_cache, spiffs_cache,
sizeof(spiffs_cache), sizeof(spiffs_cache),
#else
0, 0,
#endif
// myspiffs_check_callback); // myspiffs_check_callback);
0); 0);
NODE_DBG("mount res: %d, %d\n", res, fs.err_code); 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); 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; return 0;
} }