From ca836f1944dde0949ebd1438b5c2850867aa9f93 Mon Sep 17 00:00:00 2001 From: Siggi <57836141+langausd@users.noreply.github.com> Date: Sat, 10 Apr 2021 22:03:41 +0200 Subject: [PATCH] Lfs fix (#131) * added - usage info for LFS targets - lfs.img build rule (requires luac.cross from nodemcu-firmware) - basic autodetection for USB serial device * updated LFS code for recent nodemcu versions * safe default (SOFTAP) * Revert "safe default (SOFTAP)" This reverts commit a76db2a153f421cc81e9c1caf0903d550043b1d6. * removed compatibility code * updated nodemcu-firmware requirement Co-authored-by: langausd --- Makefile | 12 ++++-- README.md | 2 +- init.lua | 5 ++- srv/_init.lua | 103 ++++++++++++++++++++++++-------------------------- 4 files changed, 62 insertions(+), 60 deletions(-) diff --git a/Makefile b/Makefile index f76d9a0..12472a3 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,11 @@ # Path to nodemcu-uploader (https://github.com/kmpm/nodemcu-uploader) NODEMCU-UPLOADER?=python ../nodemcu-uploader/nodemcu-uploader.py +# Path to LUA cross compiler (part of the nodemcu firmware; only needed to compile the LFS image yourself) +LUACC?=../nodemcu-firmware/luac.cross + # Serial port -PORT?=/dev/cu.SLAB_USBtoUART +PORT?=$(shell ls /dev/cu.SLAB_USBtoUART /dev/ttyUSB* 2>/dev/null|head -n1) SPEED?=115200 define _upload @@ -28,8 +31,10 @@ usage: @echo "make upload_http to upload files to be served" @echo "make upload_server to upload the server code and init.lua" @echo "make upload_all to upload all" + @echo "make upload_lfs to upload lfs based server code" + @echo "make upload_all_lfs to upload all (LFS based)" -# Upload one files only +# Upload one file only upload: $(FILE) $(_upload) @@ -49,9 +54,8 @@ upload_wifi_config: $(WIFI_CONFIG) upload_lfs: $(LFS_FILES) $(_upload) -# Throw error if lfs file not found $(LFS_IMAGE): - $(error File $(LFS_IMAGE) not found) + $(LUACC) -f -o $(LFS_IMAGE) srv/*.lua # Upload all non-lfs files upload_all: $(HTTP_FILES) $(SERVER_FILES) $(WIFI_CONFIG) diff --git a/README.md b/README.md index 7d0cdc3..794d88c 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ Let the abuse begin. * Other methods: HEAD, DELETE, TRACE, OPTIONS, CONNECT, PATCH * Encryption / SSL -* Old nodemcu-firmware versions prior to January 2017) because I don't bother to test them. +* Old nodemcu-firmware versions prior to January 2021) because I don't bother to test them. ## Contributing diff --git a/init.lua b/init.lua index 6058c96..8fc3559 100644 --- a/init.lua +++ b/init.lua @@ -1,4 +1,4 @@ --- Compile freshly uploaded nodemcu-httpserver lua files. +-- check/flash/use LFS support, if possible if node.getpartitiontable().lfs_size > 0 then if file.exists("lfs.img") then if file.exists("lfs_lock") then @@ -9,12 +9,13 @@ if node.getpartitiontable().lfs_size > 0 then f:flush() f:close() file.remove("httpserver-compile.lua") - node.flashreload("lfs.img") + node.LFS.reload("lfs.img") end end pcall(node.flashindex("_init")) end +-- Compile freshly uploaded nodemcu-httpserver lua files. if file.exists("httpserver-compile.lua") then dofile("httpserver-compile.lua") file.remove("httpserver-compile.lua") diff --git a/srv/_init.lua b/srv/_init.lua index 77896b0..2150681 100644 --- a/srv/_init.lua +++ b/srv/_init.lua @@ -8,10 +8,10 @@ module related initialisaion in this. This example uses standard Lua features to simplify the LFS API. - The first section adds a 'LFS' table to _G and uses the __index metamethod to - resolve functions in the LFS, so you can execute the main function of module - 'fred' by executing LFS.fred(params), etc. It also implements some standard - readonly properties: + For Lua 5.1, the first section adds a 'LFS' table to _G and uses the __index + metamethod to resolve functions in the LFS, so you can execute the main + function of module 'fred' by executing LFS.fred(params), etc. + It also implements some standard readonly properties: LFS._time The Unix Timestamp when the luac.cross was executed. This can be used as a version identifier. @@ -24,36 +24,44 @@ print(table.concat(LFS._list,'\n')) gives you a single column listing of all modules in the LFS. + For Lua 5.3 LFS table is populated by the LFS implementation in C so this part + of the code is skipped. ---------------------------------------------------------------------------------]] -local index = node.flashindex +local lfsindex = node.LFS and node.LFS.get or node.flashindex +local G=_ENV or getfenv() +local lfs_t +if _VERSION == 'Lua 5.1' then + lfs_t = { + __index = function(_, name) + local fn_ut, ba, ma, size, modules = lfsindex(name) + if not ba then + return fn_ut + elseif name == '_time' then + return fn_ut + elseif name == '_config' then + local fs_ma, fs_size = file.fscfg() + return {lfs_base = ba, lfs_mapped = ma, lfs_size = size, + fs_mapped = fs_ma, fs_size = fs_size} + elseif name == '_list' then + return modules + else + return nil + end + end, -local lfs_t = { - __index = function(_, name) - local fn_ut, ba, ma, size, modules = index(name) - if not ba then - return fn_ut - elseif name == '_time' then - return fn_ut - elseif name == '_config' then - local fs_ma, fs_size = file.fscfg() - return {lfs_base = ba, lfs_mapped = ma, lfs_size = size, - fs_mapped = fs_ma, fs_size = fs_size} - elseif name == '_list' then - return modules - else - return nil - end - end, + __newindex = function(_, name, value) -- luacheck: no unused + error("LFS is readonly. Invalid write to LFS." .. name, 2) + end, + } - __newindex = function(_, name, value) - error("LFS is readonly. Invalid write to LFS." .. name, 2) - end, - - } - -local G=getfenv() -G.LFS = setmetatable(lfs_t,lfs_t) + setmetatable(lfs_t,lfs_t) + G.module = nil -- disable Lua 5.0 style modules to save RAM + package.seeall = nil +else + lfs_t = node.LFS +end +G.LFS = lfs_t --[[------------------------------------------------------------------------------- The second section adds the LFS to the require searchlist, so that you can @@ -67,33 +75,22 @@ G.LFS = setmetatable(lfs_t,lfs_t) ---------------------------------------------------------------------------------]] package.loaders[3] = function(module) -- loader_flash - local fn, ba = index(module) - return ba and "Module not in LFS" or fn + return lfs_t[module] end ---[[------------------------------------------------------------------------------- - You can add any other initialisation here, for example a couple of the globals - are never used, so setting them to nil saves a couple of global entries ----------------------------------------------------------------------------------]] - -G.module = nil -- disable Lua 5.0 style modules to save RAM -package.seeall = nil - ---[[------------------------------------------------------------------------------- - These replaces the builtins loadfile & dofile with ones which preferentially - loads the corresponding module from LFS if present. Flipping the search order +--[[---------------------------------------------------------------------------- + These replace the builtins loadfile & dofile with ones which preferentially + load from the filesystem and fall back to LFS. Flipping the search order is an exercise left to the reader.- ----------------------------------------------------------------------------------]] +------------------------------------------------------------------------------]] -local lf, df = loadfile, dofile +local lf = loadfile G.loadfile = function(n) - local mod, ext = n:match("(.*)%.(l[uc]a?)"); - local fn, ba = index(mod) - if ba or (ext ~= 'lc' and ext ~= 'lua') then return lf(n) else return fn end + if file.exists(n) then return lf(n) end + local mod = n:match("(.*)%.l[uc]a?$") + local fn = mod and lfsindex(mod) + return (fn or error (("Cannot find '%s' in FS or LFS"):format(n))) and fn end -G.dofile = function(n) - local mod, ext = n:match("(.*)%.(l[uc]a?)"); - local fn, ba = index(mod) - if ba or (ext ~= 'lc' and ext ~= 'lua') then return df(n) else return fn() end -end +-- Lua's dofile (luaB_dofile) reaches directly for luaL_loadfile; shim instead +G.dofile = function(n) return assert(loadfile(n))() end