From 60339b812b9f31eeb4ce516bbbdf6551271cbd41 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Thu, 22 Sep 2016 17:18:22 +1000 Subject: [PATCH] SPIFFS partition support, file module from dev. Now uses the designated partition (type 0xC2, 0x00) unconditionally. --- components/base_nodemcu/ld/nodemcu_core.ld | 14 - components/base_nodemcu/user_main.c | 4 +- components/modules/Kconfig | 6 + components/modules/file.c | 467 +++++++++++++++++++++ components/platform/Kconfig | 24 -- components/platform/include/cpu_esp32.h | 51 +-- components/platform/include/flash_api.h | 17 +- components/platform/include/platform.h | 25 +- components/platform/partitions-2MB.csv | 7 + components/platform/platform_flash.c | 51 +-- components/platform/vfs.c | 10 +- components/spiffs/spiffs.c | 140 ++---- 12 files changed, 552 insertions(+), 264 deletions(-) create mode 100644 components/modules/file.c create mode 100644 components/platform/partitions-2MB.csv diff --git a/components/base_nodemcu/ld/nodemcu_core.ld b/components/base_nodemcu/ld/nodemcu_core.ld index 36463461..e0c936b9 100644 --- a/components/base_nodemcu/ld/nodemcu_core.ld +++ b/components/base_nodemcu/ld/nodemcu_core.ld @@ -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 diff --git a/components/base_nodemcu/user_main.c b/components/base_nodemcu/user_main.c index 796e0c7a..14df47a9 100644 --- a/components/base_nodemcu/user_main.c +++ b/components/base_nodemcu/user_main.c @@ -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); } diff --git a/components/modules/Kconfig b/components/modules/Kconfig index 8e651a8d..47530dc4 100644 --- a/components/modules/Kconfig +++ b/components/modules/Kconfig @@ -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 diff --git a/components/modules/file.c b/components/modules/file.c new file mode 100644 index 00000000..f5c751c9 --- /dev/null +++ b/components/modules/file.c @@ -0,0 +1,467 @@ +// Module for interfacing with file system + +#include "module.h" +#include "lauxlib.h" +#include "platform.h" + +#include "vfs.h" +#include + +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); diff --git a/components/platform/Kconfig b/components/platform/Kconfig index 6b0be234..57a53bf0 100644 --- a/components/platform/Kconfig +++ b/components/platform/Kconfig @@ -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 diff --git a/components/platform/include/cpu_esp32.h b/components/platform/include/cpu_esp32.h index 187e26c6..8df54a07 100644 --- a/components/platform/include/cpu_esp32.h +++ b/components/platform/include/cpu_esp32.h @@ -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 diff --git a/components/platform/include/flash_api.h b/components/platform/include/flash_api.h index 1ca8710c..7966b8bf 100644 --- a/components/platform/include/flash_api.h +++ b/components/platform/include/flash_api.h @@ -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__ diff --git a/components/platform/include/platform.h b/components/platform/include/platform.h index 8852b4e2..3b5ee9c2 100644 --- a/components/platform/include/platform.h +++ b/components/platform/include/platform.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; diff --git a/components/platform/partitions-2MB.csv b/components/platform/partitions-2MB.csv new file mode 100644 index 00000000..69e651a6 --- /dev/null +++ b/components/platform/partitions-2MB.csv @@ -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 diff --git a/components/platform/platform_flash.c b/components/platform/platform_flash.c index 7de683ea..dee664d7 100644 --- a/components/platform/platform_flash.c +++ b/components/platform/platform_flash.c @@ -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; -} diff --git a/components/platform/vfs.c b/components/platform/vfs.c index f4b7a09d..969802af 100644 --- a/components/platform/vfs.c +++ b/components/platform/vfs.c @@ -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 )); diff --git a/components/spiffs/spiffs.c b/components/spiffs/spiffs.c index ead8e42e..03f7c596 100644 --- a/components/spiffs/spiffs.c +++ b/components/spiffs/spiffs.c @@ -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) { - 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; - } - 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)) { +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; } -#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 + else + ++i; } - - // 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; }