Browse Source

LFS patch updates following review

TerryE 6 years ago
parent
commit
88bd9e01d3

+ 6 - 130
.gdbinit

@@ -20,139 +20,15 @@ define br
   d
   hb $arg0
 end
-set pagination off
-
-define prTS
-  set $o = &(((TString *)($arg0))->tsv)
-  printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
-  printf "String: hash = 0x%08x, len = %u : %s\n", $o->hash, $o->len, (char *)(&$o[1])
-end
-define prTnodes
-  set $o = (Table *)($arg0)
-  set $n = 1<<($o->lsizenode)
-  set $i = 0
-  while $i < $n
-    set $nd = ($o->node) + $i
-    if $nd->i_key.nk.tt && $nd->i_val.tt
-      if $nd->i_key.nk.tt == 6
-        printf "%4u: %s  %2i\n", $i, $nd->i_key.nk.tt , $nd->i_val.tt      else
-        printf "%4u: %2i  %2i\n", $i, $nd->i_key.nk.tt , $nd->i_val.tt
-      end
-    end
-    set $i = $i +1
-  end
-end
-define prTV
-  if $arg0
-    set $type = ($arg0).tt
-    set $val  = ($arg0).value
-
-    if $type == 0
-      # NIL
-      printf "Nil\n"
-    end
-    if $type == 1
-       # Boolean
-       printf "Boolean: %u\n", $val.n
-    end
-    if $type == 2
-       # ROTable
-       printf "ROTable: %p\n", $val.p
-    end
-    if $type == 3
-        # Light Function
-       printf "Light Func: %p\n", $val.p
-    end
-    if $type == 4
-       # Light User Data
-       printf "Light Udata: %p\n", $val.p
-    end
-    if $type == 5
-       # Number
-       printf "Number: %u\n", $val.n
-    end
-    if $type == 6
-      prTS $arg0
-    end
-    if $type == 7
-      # Table
-      set $o = &($val->gc.h)
-      printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
-      printf "Nodes: %4i %p\n", 2<<($o->lsizenode), $o->nodes
-      printf "Arry:  %4i %p\n", $o->sizearray, $o->array
-    end
-    if $type == 8
-      # Function
-      set $o = &($val->gc.cl.c)
-      printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
-       if $o->isC == 0
-        set $o = &($val->gc.cl.l)
-        printf "LClosure: nupvalues = %u, gclist = %p, env = %p, p = %p\n", $o->nupvalues, $o->gclist, $o->env, $o->p
-      else
-        printf "CClosure: nupvalues = %u, gclist = %p, env = %p, f = %p\np", $o->nupvalues, $o->gclist, $o->env, $o->f
-      end
-    end
-    if $type == 9
-      # UserData
-    end
-    if $type == 10
-      # Thread
-    end
-  end
-end
-
-define prL
-  if L > 0
-    printf " stack:   %u\n", L->top-L->base
-    printf " hooking: %u, %u, %u, %u, %p\n",  L->hookmask, L->allowhook, L->basehookcount, L->hookcount, L->hook
-  end
-end
-
-define dumpstrt
-  set $st = $arg0
-  set $i = 0
-  while $i< $st->size
-    set $o = &(((TString *)($st->hash[$i]))->tsv)
-    while $o
-      if $o->next
-        printf "Slot: %5i   %p  %p  %08x  %02x  %4u", $i, $o, $o->next, $o->hash, $o->marked, $o->len
-      else
-        printf "Slot: %5i   %p              %08x  %02x  %4u", $i, $o, $o->hash, $o->marked, $o->len
-      end
-      if $o->marked & 0x80
-        printf "* %s\n", *(char **)($o+1)
-      else
-        printf "  %s\n", (char *)($o+1)
-      end
-      set $o = &(((TString *)($o->next))->tsv)
-    end
-    set $i = $i + 1
-  end
-end
 
-define dumpRAMstrt
-  dumpstrt &(L->l_G->strt)
-end
-
-define dumpROstrt
-  dumpstrt &(L->l_G->ROstrt)
-end
-
-define graylist
-  set $n = $arg0
-  while  $n
-    printf "%p %2u %02X\n",$n, $n->gch.tt, $n->gch.marked
-    set $n=$n->gch.next
-  end
-end
-
-define prPC
- printf "Excuting instruction %i: %08x\n", (pc - cl->p->code)+1-1, i
+define upto 
+  d
+  hb $arg0
+  c
 end
 
-define prT
- print *(Table*)($arg0)
-end
+set pagination off
+set history filename ~/.gdb_history
 set history save on
 set history size 1000
 

+ 182 - 0
.gdbinitlua

@@ -0,0 +1,182 @@
+
+set pagination off
+set print null-stop
+
+define prTS
+  set $o = &(((TString *)($arg0))->tsv)
+  printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
+  printf "String: hash = 0x%08x, len = %u : %s\n", $o->hash, $o->len, (char *)(&$o[1])
+end
+
+define prTnodes
+  set $o = (Table *)($arg0)
+  set $n = 1<<($o->lsizenode)
+  set $i = 0
+  while $i < $n
+    set $nd = ($o->node) + $i
+    if $nd->i_key.nk.tt && $nd->i_val.tt
+      if $nd->i_key.nk.tt == 6
+        printf "%4u: %s  %2i\n", $i, $nd->i_key.nk.tt , $nd->i_val.tt
+      else
+        printf "%4u: %2i  %2i\n", $i, $nd->i_key.nk.tt , $nd->i_val.tt
+      end
+    end
+    set $i = $i +1
+  end
+end
+define prTV
+  if $arg0
+    set $type = ($arg0).tt
+    set $val  = ($arg0).value
+
+    if $type == 0
+      # NIL
+      printf "Nil\n"
+    end
+    if $type == 1
+       # Boolean
+       printf "Boolean: %u\n", $val.n
+    end
+    if $type == 2
+       # ROTable
+       printf "ROTable: %p\n", $val.p
+    end
+    if $type == 3
+        # Light Function
+       printf "Light Func: %p\n", $val.p
+    end
+    if $type == 4
+       # Light User Data
+       printf "Light Udata: %p\n", $val.p
+    end
+    if $type == 5
+       # Number
+       printf "Number: %u\n", $val.n
+    end
+    if $type == 6
+      prTS $arg0
+    end
+    if $type == 7
+      # Table
+      set $o = &($val->gc.h)
+      printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
+      printf "Nodes: %4i  %p\n", 2<<($o->lsizenode), $o->node
+      printf "Arry:  %4i  %p\n", $o->sizearray, $o->array
+    end
+    if $type == 8
+      # Function
+      set $o = &($val->gc.cl.c)
+      printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
+       if $o->isC == 0
+        set $o = &($val->gc.cl.l)
+        printf "LClosure: nupvalues = %u, gclist = %p, env = %p, p = %p\n", \
+          $o->nupvalues, $o->gclist, $o->env, $o->p
+      else
+        printf "CClosure: nupvalues = %u, gclist = %p, env = %p, f = %p\np", \
+          $o->nupvalues, $o->gclist, $o->env, $o->f
+      end
+    end
+    if $type == 9
+      # UserData
+    end
+    if $type == 10
+      # Thread
+    end
+  end
+end
+
+define prT
+ print *(Table*)($arg0)
+end
+
+define prL
+  if L > 0
+    printf " stack:   %u\n", L->top-L->base
+    printf " hooking: %u, %u, %u, %u, %p\n",  L->hookmask, L->allowhook, L->basehookcount, L->hookcount, L->hook
+  end
+end
+
+define dumpstrt
+  set $st = $arg0
+  set $i = 0
+  while $i< $st->size
+    set $o = &(((TString *)($st->hash[$i]))->tsv)
+    while $o
+      if $o->next
+        printf "Slot: %5i   %p  %p  %08x  %02x  %4u", \
+           $i, $o, $o->next, $o->hash, $o->marked, $o->len
+      else
+        printf "Slot: %5i   %p              %08x  %02x  %4u", \
+           $i, $o, $o->hash, $o->marked, $o->len
+      end
+      if $o->marked & 0x80
+        printf "* %s\n", *(char **)($o+1)
+      else
+        printf "  %s\n", (char *)($o+1)
+      end
+      set $o = &(((TString *)($o->next))->tsv)
+    end
+    set $i = $i + 1
+  end
+end
+
+define dumpRAMstrt
+  dumpstrt &(L->l_G->strt)
+end
+
+define dumpROstrt
+  dumpstrt &(L->l_G->ROstrt)
+end
+
+define graylist
+  set $n = $arg0
+  while  $n
+    printf "%p %2u %02X\n",$n, $n->gch.tt, $n->gch.marked
+    set $n=$n->gch.next
+  end
+end
+
+define prPC
+ printf "Excuting instruction %i: %08x\n", (pc - cl->p->code)+1-1, i
+end
+
+
+define where
+  set  $f=cl->p
+  printf "<%s:%u,%u>,  opcode %u\n",\
+    (char *)$f->source+17, $f->linedefined, $f->lastlinedefined, pc - $f->code
+end
+
+define callinfo
+  printf "%p:  ", L->ci
+  print *L->ci
+end
+
+define luastack
+  set $i = 0
+  set $ci = L->base_ci
+  set $s = L->stack
+  set $last = L->stack_last - L->stack
+  printf "stack = %p, last: %i, size: %i, " , $s, $last, L->stacksize
+  if $last+6==L->stacksize
+    printf "(OK)\n"
+  else
+    printf "(MISMATCH)\n"
+  end
+   printf " Ndx   top     base   func\n"
+  while $ci <= L->ci
+    printf "%3u %6i %6i %6i\n", $i++, $ci->top-$s, $ci->base-$s, ($ci++)->func-$s
+  end
+end
+
+define stacklen
+  printf "%i  top: %p, base: %p\n", \
+    L->ci->top - L->base, L->ci->top, L->base
+end
+
+define stackcheck
+  set $ci = L->ci
+  printf "Used: %i, Headroom: %i, Total: %i\n", \
+    L->top-$ci->base-1, $ci->top-L->top+1, $ci->top-$ci->base
+end
+

+ 2 - 0
.gitignore

@@ -1,6 +1,8 @@
 sdk/
 cache/
 .ccache/
+local/
+luac.cross
 user_config.h
 server-ca.crt
 

+ 8 - 5
app/Makefile

@@ -20,11 +20,14 @@ FLAVOR = debug
 ifndef PDIR # {
 GEN_IMAGES= eagle.app.v6.out
 GEN_BINS= eagle.app.v6.bin
-OPT_MKTARGETS      := coap crypto dht http mqtt pcm sjson sqlite3 tsl2561 u8glib ucglib websocket
-SEL_MKTARGETS      := $(shell $(CC) -E -dM include/user_modules.h | sed -n '/^\#define LUA_USE_MODULES_/{s/.\{24\}\(.*\)/\L\1/; p}')
-OPT_SEL_MKTARGETS  := $(foreach tgt,$(OPT_MKTARGETS),$(findstring $(tgt), $(SEL_MKTARGETS)))
-OPT_SEL_COMPONENTS := $(foreach tgt,$(OPT_SEL_MKTARGETS),$(tgt)/lib$(tgt).a)
-SPECIAL_MKTARGETS  :=$(APP_MKTARGETS)
+OPT_MKTARGETS        := coap crypto dht http mqtt pcm sjson sqlite3 tsl2561 websocket
+OPT_MKLIBTARGETS     := u8g ucg
+SEL_MKTARGETS        := $(shell $(CC) -E -dM include/user_modules.h | sed -n '/^\#define LUA_USE_MODULES_/{s/.\{24\}\(.*\)/\L\1/; p}')
+OPT_SEL_MKLIBTARGETS := $(foreach tgt,$(OPT_MKLIBTARGETS),$(findstring $(tgt), $(SEL_MKTARGETS)))
+OPT_SEL_MKTARGETS    := $(foreach tgt,$(OPT_MKTARGETS),$(findstring $(tgt), $(SEL_MKTARGETS))) \
+                        $(foreach tgt,$(OPT_SEL_MKLIBTARGETS),$(tgt)lib)
+OPT_SEL_COMPONENTS   := $(foreach tgt,$(OPT_SEL_MKTARGETS),$(tgt)/lib$(tgt).a)
+SPECIAL_MKTARGETS    :=$(APP_MKTARGETS)
 
 SUBDIRS= 					\
 	user 					\

+ 182 - 91
app/include/user_config.h

@@ -1,23 +1,191 @@
 #ifndef __USER_CONFIG_H__
 #define __USER_CONFIG_H__
 
-// #define FLASH_512K
-// #define FLASH_1M
-// #define FLASH_2M
-// #define FLASH_4M
-// #define FLASH_8M
-// #define FLASH_16M
+// The firmware supports a range of Flash sizes, though 4Mbyte seems to be 
+// currently the most common.  Current builds include a discovery function
+// which is enabled by FLASH_AUTOSIZE, but you can override this by commenting
+// this out and enabling the explicitly size, e.g. FLASH_4M.  Valid sizes are
+// FLASH_512K, FLASH_1M, FLASH_2M, FLASH_4M, FLASH_8M, FLASH_16M.
+  
 #define FLASH_AUTOSIZE
+//#define FLASH_4M
+
+
+// The firmware now selects a baudrate of 115,200 by default, but the driver also 
+// includes automatic baud rate detection at start-up by default.  If you want to
+// change the default rate then vaild rates are  300, 600, 1200, 2400, 4800, 9600, 
+// 19200, 31250, 38400, 57600, 74880, 115200, 230400, 256000, 460800 [, 921600, 
+// 1843200, 368640].  Note that the last 3 rates are not recommended as these 
+// might be unreliable.
+ 
+#define BIT_RATE_DEFAULT BIT_RATE_115200
+#define BIT_RATE_AUTOBAUD
+
+
+// Three separate build variants are now supported. The main difference is in the
+// processing of numeric data types.  If LUA_NUMBER_INTEGRAL is defined, then
+// all numeric calculations are done in integer, with divide being an integer 
+// operations, and decimal fraction constants are illegal.  Otherwise all
+// numeric operations use floating point, though they are exact for integer
+// expressions < 2^53.  The main advantage of INTEGRAL builds is that the basic
+// internal storage unit, the TValue, is 8 bytes long, rather than the default 
+// on floating point builds of 16 bytes.  We have now also introduced an 
+// experimental option LUA_PACK_TVALUES which reduces the floating point TValues
+// to 12 bytes without any performance impact.
+
+//#define LUA_NUMBER_INTEGRAL
+//#define LUA_PACK_TVALUES
+
+
+// The Lua Flash Store (LFS) allows you to store Lua code in Flash memory and
+// the Lua VMS will execute this code directly from flash without needing any 
+// RAM overhead.  If you want to enable LFS then set the following define to
+// the size of the store that you need.  This can be any multiple of 4kB up to 
+// a maximum 256Kb.
+
+//#define LUA_FLASH_STORE 0x10000
+
+
+// By default Lua executes the file init.lua at start up.  The following
+// define allows you to replace this with an alternative startup.  Warning:
+// you must protect this execution otherwise you will enter a panic loop.
+// The example provided executes the LFS module "_init" at startup or fails
+// through to the interactive prompt.
+// ********* WARNING THIS OPTION ISN'T CURRENTLY WORKING
+//#define LUA_INIT_STRING "local fi=node.flashindex; return pcall(fi and fi'_init')"
+// ********* WARNING THIS OPTION ISN'T CURRENTLY WORKING
+
+
+// NodeMCU supports two file systems: SPIFFS and FATFS, the first is available
+// on all ESP8266 modules.  The latter requires extra H/W so is less common.
+// If you use SPIFFS then there are a number of options which impact the 
+// RAM overhead and performance of the file system.  
+//
+// If you use the spiffsimg tool to create your own FS images on your dev PC
+// then we recommend that you fix the location and size of the FS, allowing
+// some headroom for rebuilding flash images and LFS.  As an alternative to
+// fixing the size of the FS, you can force the SPIFFS file system to end on 
+// the next 1Mb boundary.  This is useful for certain OTA scenarios.  In
+// general, limiting the size of the FS only to what your application needs 
+// gives the fastest start-up and imaging times.
+
+#define BUILD_SPIFFS
+//#define BUILD_FATFS
+
+//#define SPIFFS_FIXED_LOCATION        0x100000
+//#define SPIFFS_MAX_FILESYSTEM_SIZE    0x10000	
+//#define SPIFFS_SIZE_1M_BOUNDARY
+#define SPIFFS_CACHE 1          // Enable if you use you SPIFFS in R/W mode 
+#define SPIFFS_MAX_OPEN_FILES 4 // maximum number of open files for SPIFFS
+#define FS_OBJ_NAME_LEN 31      // maximum length of a filename
+
+
+// The HTTPS stack requires client SSL to be enabled.  The SSL buffer size is
+// used only for espconn-layer secure connections, and is ignored otherwise.  
+// Some HTTPS  applications require a larger buffer size to work.  See
+// https://github.com/nodemcu/nodemcu-firmware/issues/1457 for details.
+// The SHA2 and MD2 libraries are also used by the crypto functions.  The 
+// MD2 function are implemented in the ROM BIOS, and the SHA2 by NodeMCU
+// code, so only enable SHA2 if you need this functionality.
+
+//#define CLIENT_SSL_ENABLE
+//#define MD2_ENABLE
+#define SHA2_ENABLE
+#define SSL_BUFFER_SIZE 5120
+
+
+// GPIO_INTERRUPT_ENABLE needs to be defined if your application uses the
+// gpio.trig() or related GPIO interrupt service routine code.  Likewise the
+// GPIO interrupt hook is requited for a few modules such as rotary.  If you
+// don't require this functionality, then we recommend commenting out these 
+// options which removes any associated runtime overhead. 
+
+#define GPIO_INTERRUPT_ENABLE
+#define GPIO_INTERRUPT_HOOK_ENABLE
+
+
+// If your application uses the light sleep functions and you wish the 
+// firmware to manage timer rescheduling over sleeps (the CPU clock is 
+// suspended so timers get out of sync) then enable the following options
+
+//#define ENABLE_TIMER_SUSPEND
+//#define PMSLEEP_ENABLE
+
+
+// The WiFi module optionally offers an enhanced level of WiFi connection
+// management, using internal timer callbacks.  Whilst many Lua developers
+// prefer to implement equivalent features in Lua, others will prefer the
+// Wifi module to do this for them.  Uncomment the following to enable 
+// this functionality. The event sub-options are ignore if the SMART 
+// functionality is not enabled.
+
+//#define WIFI_SMART_ENABLE
+#define WIFI_SDK_EVENT_MONITOR_ENABLE
+#define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
+
+
+// Whilst the DNS client details can be configured through the WiFi API,
+// the defaults can be exposed temporarily during start-up.  The following
+// WIFI_STA options allow you to configure this in the firmware.  If the
+// WIFI_STA_HOSTNAME is not defined then the hostname will default to 
+// to the last 3 octets (6 hexadecimal digits) of MAC address with the 
+// prefix "NODE-".  If it is defined then the hostname must only contain
+// alphanumeric characters. If you are imaging multiple modules with this
+// firmware then you must also define WIFI_STA_HOSTNAME_APPEND_MAC to 
+// append the last 3 octets of the MAC address.  Note that the total 
+// Hostname MUST be 32 chars or less.
+
+//#define WIFI_STA_HOSTNAME "NodeMCU"
+//#define WIFI_STA_HOSTNAME_APPEND_MAC
+
+
+// If you use the enduser_setup module, then you can also set the default
+// SSID when this module is running in AP mode.
+
+#define ENDUSER_SETUP_AP_SSID "SetupGadget"
+
+
+// The following sections are only relevent for those developers who are 
+// developing modules or core Lua changes and configure how extra diagnostics
+// are enabled in the firmware. These should only be configured if you are
+// building your own custom firmware and have full access to the firmware
+// source code.
+
+// Enabling DEVELOPMENT_TOOLS adds the asserts in LUA and also some useful
+// extras to the node module. These are silent in normal operation and so can
+// be enabled without any harm (except for the code size increase and slight 
+// slowdown). If you want to use the remote GDB to handle breaks and failed 
+// assertions then enable the DEVELOPMENT_USE GDB option.  A supplimentary
+// define DEVELOPMENT_BREAK_ON_STARTUP_PIN allows you to define a GPIO pin, 
+// which if pulled low at start-up will immediately initiate a GDB session.
+
+// The DEVELOP_VERSION option enables lots of debug output, and is normally 
+// only used by hardcore developers.
+
+// These options can be enabled globally here or you can alternatively use 
+// the DEFINES variable in the relevant Makefile to set these on a per
+// directory basis. If you do this then you can also set the corresponding 
+// compile options (-O0 -ggdb) on a per directory as well.
 
-// This adds the asserts in LUA. It also adds some useful extras to the
-// node module. This is all silent in normal operation and so can be enabled
-// without any harm (except for the code size increase and slight slowdown)
-// You can either set these defines here to operate globally or you edit the
-// relevant Makefile setting them in the DEFINES variable is you only want to
-// enable extra debug for specific subdirs.  If you want to use the remote GDB to 
-// handle breaks and failed assetions then enable DEVELOPMENT_USE GDB 
 //#define DEVELOPMENT_TOOLS
 //#define DEVELOPMENT_USE_GDB
+//#define DEVELOPMENT_BREAK_ON_STARTUP_PIN 1
+//#define DEVELOP_VERSION
+
+
+// *** Heareafter, there be demons ***
+
+// The remaining options are advanced configuration options and you should only
+// change this if you have tracked the implications through the Firmware sources
+// and understand the these.
+
+#define LUA_TASK_PRIO             USER_TASK_PRIO_0
+#define LUA_PROCESS_LINE_SIG      2
+#define LUA_OPTIMIZE_DEBUG        2
+#define READLINE_INTERVAL        80
+#define STRBUF_DEFAULT_INCREMENT  3
+#define LUA_USE_BUILTIN_DEBUG_MINIMAL // for debug.getregistry() and debug.traceback()
+
 #ifdef DEVELOPMENT_TOOLS
 #if defined(LUA_CROSS_COMPILER) || !defined(DEVELOPMENT_USE_GDB)
 extern void luaL_assertfail(const char *file, int line, const char *message);
@@ -28,19 +196,11 @@ extern void luaL_dbgbreak(void);
 #endif
 #endif
 
-// This enables lots of debug output and changes the serial bit rate. This
-// is normally only used by hardcore developers
-// #define DEVELOP_VERSION
 #ifdef DEVELOP_VERSION
 #define NODE_DEBUG
 #define COAP_DEBUG
 #endif /* DEVELOP_VERSION */
 
-#define BIT_RATE_DEFAULT BIT_RATE_115200
-
-// This enables automatic baud rate detection at startup
-#define BIT_RATE_AUTOBAUD
-
 #define NODE_ERROR
 
 #ifdef NODE_DEBUG
@@ -55,12 +215,7 @@ extern void luaL_dbgbreak(void);
 #define NODE_ERR
 #endif	/* NODE_ERROR */
 
-#define LUA_USE_BUILTIN_DEBUG_MINIMAL // for debug.getregistry() and debug.traceback()
-
-#define GPIO_INTERRUPT_ENABLE
-#define GPIO_INTERRUPT_HOOK_ENABLE
 // #define GPIO_SAFE_NO_INTR_ENABLE
-
 #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed))
 #define ICACHE_STORE_ATTR __attribute__((aligned(4)))
 #define ICACHE_RAM_ATTR __attribute__((section(".iram0.text")))
@@ -70,69 +225,5 @@ extern void luaL_dbgbreak(void);
 #define NO_INTR_CODE inline
 #endif
 
-// SSL buffer size used only for espconn-layer secure connections.
-// See https://github.com/nodemcu/nodemcu-firmware/issues/1457 for conversation details.
-#define SSL_BUFFER_SIZE 5120
-
-//#define CLIENT_SSL_ENABLE
-//#define MD2_ENABLE
-#define SHA2_ENABLE
-
-#define BUILD_SPIFFS
-#define SPIFFS_CACHE 1
-
-//#define BUILD_FATFS
-
-// maximum length of a filename
-#define FS_OBJ_NAME_LEN 31
-
-// maximum number of open files for SPIFFS
-#define SPIFFS_MAX_OPEN_FILES 4
-
-// Uncomment this next line for fastest startup and set the FS only to what
-// your application needs.  This reduces the format time dramatically
-//#define SPIFFS_MAX_FILESYSTEM_SIZE       0x10000	
-//
-// You can force the spiffs file system to be at a fixed location
-//#define SPIFFS_FIXED_LOCATION   	0x100000
-//
-// You can force the SPIFFS file system to end on the next !M boundary
-// (minus the 16k parameter space). THis is useful for certain OTA scenarios
-// #define SPIFFS_SIZE_1M_BOUNDARY
-
-//#define LUA_NUMBER_INTEGRAL
-
-// If you want to enable Lua Flash Store (LFS) then set the following define to
-// the size of the store.  This can be any multiple of 4kB up to a maximum 256Kb.
-//#define LUA_FLASH_STORE 0x10000
-
-#define READLINE_INTERVAL 80
-#define LUA_TASK_PRIO USER_TASK_PRIO_0
-#define LUA_PROCESS_LINE_SIG 2
-#define LUA_OPTIMIZE_DEBUG      2
-
-#define ENDUSER_SETUP_AP_SSID "SetupGadget"
-
-/*
- * A valid hostname only contains alphanumeric and hyphen(-) characters, with no hyphens at first or last char
- * if WIFI_STA_HOSTNAME not defined: hostname will default to NODE-xxxxxx (xxxxxx being last 3 octets of MAC address)
- * if WIFI_STA_HOSTNAME defined: hostname must only contain alphanumeric characters
- * if WIFI_STA_HOSTNAME_APPEND_MAC not defined: Hostname MUST be 32 chars or less
- * if WIFI_STA_HOSTNAME_APPEND_MAC defined: Hostname MUST be 26 chars or less, since last 3 octets of MAC address will be appended
- * if defined hostname is invalid: hostname will default to NODE-xxxxxx (xxxxxx being last 3 octets of MAC address)
-*/
-//#define WIFI_STA_HOSTNAME "NodeMCU"
-//#define WIFI_STA_HOSTNAME_APPEND_MAC
-
-//#define WIFI_SMART_ENABLE
-
-#define WIFI_SDK_EVENT_MONITOR_ENABLE
-#define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
-
-////#define ENABLE_TIMER_SUSPEND
-//#define PMSLEEP_ENABLE
-
-
-#define STRBUF_DEFAULT_INCREMENT 32
-
 #endif	/* __USER_CONFIG_H__ */
+

+ 1 - 3
app/include/user_modules.h

@@ -1,8 +1,6 @@
 #ifndef __USER_MODULES_H__
 #define __USER_MODULES_H__
 
-
-
 #ifndef LUA_CROSS_COMPILER
 
 // The default configuration is designed to run on all ESP modules including the 512 KB modules like ESP-01 and only
@@ -57,7 +55,7 @@
 //#define LUA_USE_MODULES_SJSON
 //#define LUA_USE_MODULES_SNTP
 //#define LUA_USE_MODULES_SOMFY
-//#define LUA_USE_MODULES_SPI
+#define LUA_USE_MODULES_SPI
 //#define LUA_USE_MODULES_SQLITE3
 //#define LUA_USE_MODULES_STRUCT
 //#define LUA_USE_MODULES_SWITEC

+ 1 - 38
app/libc/c_stdlib.c

@@ -16,14 +16,8 @@
 #include "c_types.h"
 #include "c_string.h"
 
-// const char *lua_init_value = "print(\"Hello world\")";
-const char *lua_init_value = "@init.lua";
+extern const char lua_init_value[];
 
-// int c_abs(int x){
-//  return x>0?x:0-x;
-// }
-// void c_exit(int e){
-// }
 const char *c_getenv(const char *__string)
 {
     if (c_strcmp(__string, "LUA_INIT") == 0)
@@ -32,38 +26,7 @@ const char *c_getenv(const char *__string)
     }
     return NULL;
 }
-// make sure there is enough memory before real malloc, otherwise malloc will panic and reset
-// void *c_malloc(size_t __size){
-//  if(__size>system_get_free_heap_size()){
-//      NODE_ERR("malloc: not enough memory\n");
-//      return NULL;
-//  }
-//  return (void *)os_malloc(__size);
-// }
-
-// void *c_zalloc(size_t __size){
-//  if(__size>system_get_free_heap_size()){
-//      NODE_ERR("zalloc: not enough memory\n");
-//      return NULL;
-//  }
-//  return (void *)os_zalloc(__size);
-// }
-
-// void c_free(void *p){
-//  // NODE_ERR("free1: %d\n", system_get_free_heap_size());
-//  os_free(p);
-//  // NODE_ERR("-free1: %d\n", system_get_free_heap_size());
-// }c_stdlib.s
 
-
-
-// int  c_rand(void){
-// }
-// void c_srand(unsigned int __seed){
-// }
-
-// int  c_atoi(const char *__nptr){
-// }
 #include <_ansi.h>
 //#include <reent.h>
 //#include "mprec.h"

+ 2 - 2
app/lua/Makefile

@@ -25,8 +25,8 @@ STD_CFLAGS=-std=gnu11 -Wimplicit
 #   makefile at its root level - these are then overridden
 #   for a subtree within the makefile rooted therein
 #
-#DEFINES += -DDEVELOPMENT_TOOLS -DDEVELOPMENT_USE_GDB -DNODE_DEBUG -DBREAK_ON_STARTUP_PIN=1
-#EXTRA_CCFLAGS += -ggdb -O0
+DEFINES += -DDEVELOPMENT_TOOLS -DDEVELOPMENT_USE_GDB -DNODE_DEBUG -DDEVELOPMENT_BREAK_ON_STARTUP_PIN=1
+EXTRA_CCFLAGS += -ggdb -O0
 
 #############################################################
 # Recursion Magic - Don't touch this!!

+ 3 - 2
app/lua/lauxlib.c

@@ -775,8 +775,9 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
     lf.f = c_freopen(filename, "rb", lf.f);  /* reopen in binary mode */
     if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
     /* skip eventual `#!...' */
-   while ((c = c_getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
-    lf.extraline = 0;
+   while ((c = c_getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) {}
+
+   lf.extraline = 0;
   }
   c_ungetc(c, lf.f);
   status = lua_load(L, getF, &lf, lua_tostring(L, -1));

+ 3 - 0
app/lua/ldo.c

@@ -144,8 +144,11 @@ static void correctstack (lua_State *L, TValue *oldstack) {
 void luaD_reallocstack (lua_State *L, int newsize) {
   TValue *oldstack = L->stack;
   int realsize = newsize + 1 + EXTRA_STACK;
+  int block_status = is_block_gc(L);
   lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1);
+  set_block_gc(L);       /* The GC MUST be blocked during stack reallocaiton */
   luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue);
+  if (!block_status) unset_block_gc(L);  /* Honour the previous block status */
   L->stacksize = realsize;
   L->stack_last = L->stack+newsize;
   correctstack(L, oldstack);

+ 68 - 22
app/lua/lflash.c

@@ -107,11 +107,13 @@ static void flashErase(uint32_t start, uint32_t end){
 /* =====================================================================================
  * Hook in user_main.c to allocate flash memory for the lua flash store
  */
+extern void luaL_dbgbreak(void);   //<<<<<<<<<<<<< Temp
 void luaN_user_init(void) {
   curOffset    = 0;
   flashSector = platform_flash_reserve_section( FLASH_SIZE, &flashAddrPhys );
   flashAddr   = cast(char *,platform_flash_phys2mapped(flashAddrPhys));
   NODE_DBG("Flash initialised: %x %08x\n", flashSector, flashAddr); 
+//  luaL_dbgbreak();      //<<<<<<<<<<<<< Temp
 }
 
 
@@ -120,9 +122,15 @@ void luaN_user_init(void) {
  */  
 LUAI_FUNC void luaN_init (lua_State *L) {
   FlashHeader *fh = cast(FlashHeader *, flashAddr);
-  if (fh->flash_sig == FLASH_SIG && 
+  /*
+   * For the LFS to be valid, its signature has to be correct for this build variant,
+   * thr ROhash and main proto fields must be defined and the main proto address 
+   * be within the LFS address bounds. (This last check is primarily to detect the
+   * direct imaging of an absolute LFS with the wrong base address. 
+   */
+  if ((fh->flash_sig & (~FLASH_SIG_ABSOLUTE)) == FLASH_SIG && 
       fh->pROhash   != ALL_SET &&
-      fh->mainProto != ALL_SET) {
+      ((fh->mainProto - cast(FlashAddr, fh)) < fh->flash_size)) {
     G(L)->ROstrt.hash = cast(GCObject **, fh->pROhash);
     G(L)->ROstrt.nuse = fh->nROuse ;
     G(L)->ROstrt.size = fh->nROsize;
@@ -138,7 +146,7 @@ LUAI_FUNC void luaN_init (lua_State *L) {
  *  -  the lu_int16 offset of the next address pointer. 
  */
 
-static int rebuild_core (int fd, uint32_t size, lu_int32 *buf) {
+static int rebuild_core (int fd, uint32_t size, lu_int32 *buf, int is_absolute) {
   int bi;  /* byte offset into memory mapped LFS of current buffer */ 
   int wNextOffset = BYTE_OFFSET(FlashHeader,mainProto)/sizeof(lu_int32);
   int wj;  /* word offset into current input buffer */
@@ -149,14 +157,17 @@ static int rebuild_core (int fd, uint32_t size, lu_int32 *buf) {
     if (vfs_read(fd, buf , blen) != blen)
       return 0;
 
-    for (wj = 0; wj < wlen; wj++) {
-      if ((wi + wj) == wNextOffset) {  /* this word is the next linked address */
-        int wTargetOffset = buf[wj]&0xFFFF;
-        wNextOffset = buf[wj]>>16;
-        lua_assert(!wNextOffset || (wNextOffset>(wi+wj) && wNextOffset<size/sizeof(lu_int32)));
-        buf[wj] = cast(lu_int32, flashAddr + wTargetOffset*sizeof(lu_int32));
+    if (!is_absolute) {
+      for (wj = 0; wj < wlen; wj++) {
+        if ((wi + wj) == wNextOffset) {  /* this word is the next linked address */
+          int wTargetOffset = buf[wj]&0xFFFF;
+          wNextOffset = buf[wj]>>16;
+          lua_assert(!wNextOffset || (wNextOffset>(wi+wj) && wNextOffset<size/sizeof(lu_int32)));
+          buf[wj] = cast(lu_int32, flashAddr + wTargetOffset*sizeof(lu_int32));
+        }
       }
     }
+
     flashBlock(buf, blen);
   }
   return size;
@@ -167,7 +178,7 @@ static int rebuild_core (int fd, uint32_t size, lu_int32 *buf) {
  * Library function called by node.flash.load(filename).
  */
 LUALIB_API int luaN_reload_reboot (lua_State *L) {
-  int fd, status;
+  int fd, status, is_absolute;
   FlashHeader fh;
 
   const char *fn = lua_tostring(L, 1);
@@ -175,13 +186,14 @@ LUALIB_API int luaN_reload_reboot (lua_State *L) {
     return 0;
    
   if (vfs_read(fd, &fh, sizeof(fh)) != sizeof(fh) ||
-      fh.flash_sig != FLASH_SIG)
+      (fh.flash_sig & (~FLASH_SIG_ABSOLUTE)) != FLASH_SIG)
     return 0;
 
   if (vfs_lseek(fd, -1, VFS_SEEK_END) != fh.flash_size-1 ||
       vfs_lseek(fd, 0, VFS_SEEK_SET) != 0)
     return 0;
 
+  is_absolute = fh.flash_sig & FLASH_SIG_ABSOLUTE;
   lu_int32 *buffer = luaM_newvector(L, FLASH_PAGE_SIZE / sizeof(lu_int32), lu_int32);
 
   /*
@@ -194,12 +206,14 @@ LUALIB_API int luaN_reload_reboot (lua_State *L) {
    * point on, we make no calls on the Lua RTS.
    */
   flashErase(0,-1); 
-  if (rebuild_core(fd, fh.flash_size, buffer) != fh.flash_size)
+  if (rebuild_core(fd, fh.flash_size, buffer, is_absolute) != fh.flash_size)
     flashErase(0,-1);  
   /*
-   * Forcing a H/W timeout is the only robust way to insure that other interrupts
-   * and callbacks don't fire and attempt to reference to old LFS context.
+   * Issue a break 0,0.  This will either enter the debugger or force a restart if
+   * not installed.  Follow this by a H/W timeout is a robust way to insure that
+   * other interrupts / callbacks don't fire and reference THE old LFS context.
    */
+  asm("break 0,0" ::);
   while (1) {}
 
   return 0;
@@ -207,18 +221,50 @@ LUALIB_API int luaN_reload_reboot (lua_State *L) {
 
 
 /*
- * Return a C closure pointing to the Flash Index function
+ * In the arg is a valid LFS module name then return the LClosure pointing to it.
+ * Otherwise return:
+ *  -  The Unix time that the LFS was built
+ *  -  The base address and length of the LFS
+ *  -  An array of the module names in the the LFS
  */
 LUAI_FUNC int luaN_index (lua_State *L) {
   int i;
-  if(G(L)->ROpvmain) {
-    Closure *cl = luaF_newLclosure(L, 0, hvalue(gt(L)));
-    cl->l.p = G(L)->ROpvmain;
-    lua_settop(L, 1);
-    setclvalue(L, L->top-1, cl);
-    return 1;
+  int n = lua_gettop(L);
+
+  /* Return nil + the LFS base address if the LFS isn't loaded */ 
+  if(!(G(L)->ROpvmain)) {
+    lua_settop(L, 0);
+    lua_pushnil(L);
+    lua_pushinteger(L, (lua_Integer) flashAddr);
+    lua_pushinteger(L, flashAddrPhys);
+    return 3;
   }
-  return 0;
+
+  /* Push the LClosure of the LFS index function */
+  Closure *cl = luaF_newLclosure(L, 0, hvalue(gt(L)));
+  cl->l.p = G(L)->ROpvmain;
+  lua_settop(L, n+1);
+  setclvalue(L, L->top-1, cl);
+
+  /* Move it infront of the arguments and call the index function */
+  lua_insert(L, 1);
+  lua_call(L, n, LUA_MULTRET);
+
+  /* Return it if the response if a single value (the function) */
+  if (lua_gettop(L) == 1)
+    return 1;
+
+  lua_assert(lua_gettop(L) == 2);
+
+  /* Otherwise add the base address of the LFS, and its size bewteen the */
+  /* Unix time and the module list, then return all 4 params. */
+  lua_pushinteger(L, (lua_Integer) flashAddr);
+  lua_insert(L, 2);
+  lua_pushinteger(L, flashAddrPhys);
+  lua_insert(L, 3);
+  lua_pushinteger(L, cast(FlashHeader *, flashAddr)->flash_size);
+  lua_insert(L, 4);
+  return 5;
 }
 
 #endif

+ 17 - 1
app/lua/lflash.h

@@ -10,7 +10,23 @@
 #include "lstate.h"
 #include "lzio.h"
 
-#define FLASH_SIG          0xfafaaf00
+#ifdef LUA_NUNBER_INTEGRAL
+# define FLASH_SIG_B1 0x02
+#else
+# define FLASH_SIG_B1 0x00
+#endif
+
+#ifdef LUA_PACK_TVALUES
+#ifdef LUA_NUNBER_INTEGRAL
+#error "LUA_PACK_TVALUES is only valid for Floating point builds" 
+#endif
+# define FLASH_SIG_B2 0x04
+#else
+# define FLASH_SIG_B2 0x00
+#endif
+#define FLASH_SIG_ABSOLUTE    0x01
+#define FLASH_SIG_IN_PROGRESS 0x08
+#define FLASH_SIG  (0xfafaaf50 | FLASH_SIG_B2 | FLASH_SIG_B1)
 
 typedef lu_int32 FlashAddr;
 typedef struct {

+ 1 - 1
app/lua/lobject.c

@@ -71,7 +71,7 @@ int luaO_log2 (unsigned int x) {
  /* Use Normalization Shift Amount Unsigned:  0x1=>31 up to 0xffffffff =>0
   * See Xtensa Instruction Set Architecture (ISA) Refman  P 462 */
   asm volatile ("nsau %0, %1;" :"=r"(x) : "r"(x)); 
-  return 32 - x;
+  return 31 - x;
 #endif
 }
 

+ 6 - 0
app/lua/lobject.h

@@ -77,9 +77,15 @@ typedef union {
 #define TValuefields	Value value; int tt
 #define LUA_TVALUE_NIL {NULL}, LUA_TNIL
 
+#if defined(LUA_PACK_TVALUES) && !defined(LUA_CROSS_COMPILER)
+#pragma pack(4)
+#endif
 typedef struct lua_TValue {
   TValuefields;
 } TValue;
+#if defined(LUA_PACK_TVALUES) && !defined(LUA_CROSS_COMPILER)
+#pragma pack()
+#endif
 
 /* Macros to test type */
 #define ttisnil(o)	(ttype(o) == LUA_TNIL)

+ 5 - 7
app/lua/lparser.c

@@ -916,12 +916,11 @@ static int block_follow (int token) {
 static void block (LexState *ls) {
   /* block -> chunk */
   FuncState *fs = ls->fs;
-  BlockCnt *pbl = (BlockCnt*)luaM_malloc(ls->L,sizeof(BlockCnt));
-  enterblock(fs, pbl, 0);
+  BlockCnt bl;
+  enterblock(fs, &bl, 0);
   chunk(ls);
-  lua_assert(pbl->breaklist == NO_JUMP);
+  lua_assert(bl.breaklist == NO_JUMP);
   leaveblock(fs);
-  luaM_free(ls->L,pbl);
 }
 
 
@@ -1081,13 +1080,13 @@ static int exp1 (LexState *ls) {
 
 static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
   /* forbody -> DO block */
-  BlockCnt *pbl = (BlockCnt*)luaM_malloc(ls->L,sizeof(BlockCnt));
+  BlockCnt bl;
   FuncState *fs = ls->fs;
   int prep, endfor;
   adjustlocalvars(ls, 3);  /* control variables */
   checknext(ls, TK_DO);
   prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs);
-  enterblock(fs, pbl, 0);  /* scope for declared variables */
+  enterblock(fs, &bl, 0);  /* scope for declared variables */
   adjustlocalvars(ls, nvars);
   luaK_reserveregs(fs, nvars);
   block(ls);
@@ -1097,7 +1096,6 @@ static void forbody (LexState *ls, int base, int line, int nvars, int isnum) {
                      luaK_codeABC(fs, OP_TFORLOOP, base, 0, nvars);
   luaK_fixline(fs, line);  /* pretend that `OP_FOR' starts the loop */
   luaK_patchlist(fs, (isnum ? endfor : luaK_jump(fs)), prep + 1);
-  luaM_free(ls->L,pbl);
 }
 
 

+ 2 - 1
app/lua/ltable.c

@@ -445,7 +445,8 @@ static void resize (lua_State *L, Table *t, int nasize, int nhsize) {
   int oldasize = t->sizearray;
   if (nasize > oldasize)  /* array part must grow? */
     setarrayvector(L, t, nasize);
-  resize_hashpart(L, t, nhsize);
+  if (t->node != dummynode || nhsize>0)
+    resize_hashpart(L, t, nhsize);
   if (nasize < oldasize) {  /* array part must shrink? */
     t->sizearray = nasize;
     /* re-insert elements from vanishing slice */

+ 1 - 1
app/lua/ltablib.c

@@ -137,7 +137,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, int i) {
   if (!lua_isstring(L, -1))
     luaL_error(L, "invalid value (%s) at index %d in table for "
                   LUA_QL("concat"), luaL_typename(L, -1), i);
-    luaL_addvalue(b);
+  luaL_addvalue(b);
 }
 
 

+ 11 - 4
app/lua/lua.c

@@ -237,6 +237,12 @@ static int runargs (lua_State *L, char **argv, int n) {
 }
 
 
+#ifdef LUA_INIT_STRING
+const char lua_init_value[] = LUA_INIT_STRING;
+#else
+const char lua_init_value[] = "@init.lua";
+#endif
+
 static int handle_luainit (lua_State *L) {
   const char *init = c_getenv(LUA_INIT);
   if (init == NULL) return 0;  /* status OK */
@@ -288,9 +294,10 @@ int lua_main (int argc, char **argv) {
   int status;
   struct Smain s;
 
-#if defined(NODE_DEBUG) && defined(DEVELOPMENT_USE_GDB) && BREAK_ON_STARTUP_PIN > 0
-  platform_gpio_mode( BREAK_ON_STARTUP_PIN, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP );
-  lua_assert(platform_gpio_read(BREAK_ON_STARTUP_PIN));  // Break if pin pulled low
+#if defined(NODE_DEBUG) && defined(DEVELOPMENT_USE_GDB) && \
+    defined(DEVELOPMENT_BREAK_ON_STARTUP_PIN) && DEVELOPMENT_BREAK_ON_STARTUP_PIN > 0
+  platform_gpio_mode( DEVELOPMENT_BREAK_ON_STARTUP_PIN, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP );
+  lua_assert(platform_gpio_read(DEVELOPMENT_BREAK_ON_STARTUP_PIN));  // Break if pin pulled low
 #endif
 
   lua_State *L = lua_open();  /* create state */
@@ -324,7 +331,7 @@ int lua_main (int argc, char **argv) {
 
 void lua_handle_input (bool force)
 {
-  if (gLoad.L && (force || readline (&gLoad)))
+  while (gLoad.L && (force || readline (&gLoad)))
     dojob (&gLoad);
 }
 

+ 3 - 1
app/lua/luac_cross/Makefile

@@ -7,7 +7,7 @@
 .NOTPARALLEL:
 
 CCFLAGS:= -I.. -I../../include -I../../../include -I ../../libc
-LDFLAGS:= -L$(SDK_DIR)/lib -L$(SDK_DIR)/ld -lm -Wl,-Map=mapfile
+LDFLAGS:= -L$(SDK_DIR)/lib -L$(SDK_DIR)/ld -lm -ldl -Wl,-Map=mapfile
 
 CCFLAGS += -Wall
 
@@ -69,7 +69,9 @@ test :
 clean :
 	$(RM) -r $(ODIR)
 
+ifneq ($(MAKECMDGOALS),clean)
 -include $(DEPS)
+endif
 
 $(ODIR)/%.o: %.c
 	@mkdir -p $(ODIR);

+ 50 - 31
app/lua/luac_cross/lflashimg.c

@@ -33,37 +33,42 @@ typedef unsigned int uint;
 /*
  *
  * This dumper is a variant of the standard ldump, in that instead of producing a
- * binary loader format that lundump can load, it produced an image file that can be
+ * binary loader format that lundump can load, it produces an image file that can be
  * directly mapped or copied into addressable memory. The typical application is on
  * small memory IoT devices which support programmable flash storage such as the
  * ESP8266. A 64 Kb LFS image has 16Kb words and will enable all program-related
- * storage to be accessed directly from flash, leaving the RAM for true R/W application
- * data.
+ * storage to be accessed directly from flash, leaving the RAM for true R/W
+ * application data.
  *
- * The start address of the Lua Flash Store (LFS) is build-dependent,. However, by
- * adopting a position independent image format, cross compilation can leave this
- * detail to the on-device image loader. As all objects in the LFS can be treated as
- * multiples of 4-byte words. Although some record field are byte-size and can be byte
- * packed, all other fields are word aligned, and in particular any address references
- * within the LFS are word-aligned and also refer to word-aligned addresses within the
- * LFS.
- *
- * In order to make the LFS position independent, such addresses are stored in a
- * special format, where each PIC address is two 16-bit unsigned offsets:
+ * The start address of the Lua Flash Store (LFS) is build-dependent, and the cross
+ * compiler '-a' option allows the developer to fix the LFS at a defined flash memory
+ * address.  Alternatively and by default the cross compilation adopts a position 
+ * independent image format, which permits the  on-device image loader to load the LFS
+ * image at an appropriate base within the flash address space. As all objects in the
+ * LFS can be treated as multiples of 4-byte words, also all address fields are both 
+ * word aligned, and any address references within the LFS are also word-aligned, 
+ * such addresses are stored in a special format, where each PI address is two 
+ * 16-bit unsigned offsets:
  *
  *   Bits 0-15 is the offset into the LFS that this address refers to
  *   Bits 16-31 is the offset linking to the PIC next address.
  *
  * Hence the LFS can be up to 256Kb in length and the flash loader can use the forward
- * links to chain down from the mainProto address at offet 3 to all image addresses
- * during load and convert them to the corresponding correct absolute memory addresses.
+ * links to chain down PI address from the mainProto address at offet 3 to all image 
+ * addresses during load and convert them to the corresponding correct absolute memory
+ * addresses.  This reloation process is skipped for absolute addressed images (which
+ * are identified by the FLASH_SIG_ABSOLUTE bit setting in the flash signature.
  *
  * The flash image has a standard header detailed in lflash.h
  *
  * Note that luac.cross may be compiled on any little-endian machine with 32 or 64 bit
- * word length so Flash addresses cant be handled as standard C pointers as size_t and
- * int may not have the same size. Hence addresses with the must be declared as the
- * FlashAddr type rather than typed C pointers and must be accessed through macros.
+ * word length so Flash addresses can't be handled as standard C pointers as size_t
+ * and int may not have the same size. Hence addresses with the must be declared as
+ * the FlashAddr type rather than typed C pointers and must be accessed through macros.
+ *
+ * ALso note that image built with a given LUA_PACK_TVALUES / LUA_NUNBER_INTEGRAL
+ * combination must be loaded into a corresponding firmware build.  Hence these
+ * configuration options are also included in the FLash Signature.
  *
  * The Flash image is assembled up by first building the RO stringtable containing
  * all strings used in the compiled proto hierarchy.  This is followed by the Protos.
@@ -103,7 +108,6 @@ extern void __attribute__((noreturn)) luac_fatal(const char* message);
 #define DBG_PRINT(...) ((void)0)
 #endif
 
-#define FLASH_SIG 0xfafaaf00
 /*
  *  Serial allocator.  Throw a luac-style out of memory error is allocaiton fails.
  */
@@ -258,11 +262,16 @@ static void *resolveTString(lua_State* L, TString *s) {
  * In order to simplify repacking of structures from the host format to that target
  * format, this simple copy routine is data-driven by a simple format specifier.
  *   n       Number of consecutive records to be processed
- *   fmt     A string of A,I, S, V specifiers spanning the record.
+ *   fmt     A string of A, I, S, V specifiers spanning the record.
  *   src     Source of record
  *   returns Address of destination record
  */
+#if defined(LUA_PACK_TVALUES)
+#define TARGET_TV_SIZE (sizeof(lua_Number)+sizeof(lu_int32))
+#else
 #define TARGET_TV_SIZE (2*sizeof(lua_Number))
+#endif
+
 static void *flashCopy(lua_State* L, int n, const char *fmt, void *src) {
   /* ToS is the string address mapping table */
   if (n == 0)
@@ -270,7 +279,8 @@ static void *flashCopy(lua_State* L, int n, const char *fmt, void *src) {
   int i, recsize;
   void *newts;
   /* A bit of a botch because fmt is either "V" or a string of WORDSIZE specifiers */
-  /* The size 8 for integer builds and 16 for float ones on both architectures */
+  /* The size 8 / 12 / 16 bytes for integer builds, packed TV and default TVs resp */
+
   if (fmt[0]=='V') {
     lua_assert(fmt[1] == 0);   /* V formats must be singetons */
     recsize = TARGET_TV_SIZE;
@@ -288,6 +298,7 @@ static void *flashCopy(lua_State* L, int n, const char *fmt, void *src) {
       /* All input address types (A,S,V) are aligned to size_t boundaries */
       if (*p != 'I' && ((size_t)s)&(sizeof(size_t)-1))
         s++;
+
       switch (*p++) {
         case 'A':
           toFlashAddr(L, *d, *cast(void**, s));
@@ -368,33 +379,41 @@ static void *functionToFlash(lua_State* L, const Proto* orig) {
 }
 
 /*
- * Scan through the tagged address to form linked chain.  Do the scan backwards
- * from at last octaword including curOffset, as this makes the 'last' address
- * forward reference for the on-chip LFS loader.
+ * Scan through the tagged addresses.  This operates in one of two modes.
+ *  -  If address is non-zero then the offset is converted back into an absolute
+ *     mapped flash address using the specified address base.
+ *
+ *  -  If the address is zero then form a form linked chain with the upper 16 bits
+ *     the link to the last offset. As the scan is backwards, this 'last' address
+ *     becomes forward reference for the on-chip LFS loader.
  */
-void  linkPICaddresses(void){
+void  linkAddresses(lu_int32 address){
   int i, last = 0;
   for (i = curOffset-1 ; i >= 0; i--) {
     if (flashAddrTag[i]) {
       lua_assert(flashImage[i]<curOffset);
-      flashImage[i] |= last<<16;
-      last = i;
+      if (address) {
+        flashImage[i] = 4*flashImage[i] + address;
+      } else {
+        flashImage[i] |= last<<16;
+        last = i;
+      }
     }
   }
 }
 
 
-uint dumpToFlashImage (lua_State* L, const Proto *main, lua_Writer w, void* data, int strip)
-{
+uint dumpToFlashImage (lua_State* L, const Proto *main, lua_Writer w, 
+                       void* data, int strip, lu_int32 address) {
 // parameter strip is ignored for now
   lua_newtable(L);
   FlashHeader *fh = cast(FlashHeader *, flashAlloc(L, sizeof(FlashHeader)));
   scanProtoStrings(L, main);
   createROstrt(L,  fh);
   toFlashAddr(L, fh->mainProto, functionToFlash(L, main));
-  fh->flash_sig = FLASH_SIG;
+  fh->flash_sig = FLASH_SIG + (address ? FLASH_SIG_ABSOLUTE : 0);
   fh->flash_size = curOffset*WORDSIZE;
-  linkPICaddresses();
+  linkAddresses(address);
   lua_unlock(L);
   int status = w(L, flashImage, curOffset * sizeof(uint), data);
   lua_lock(L);

+ 67 - 43
app/lua/luac_cross/luac.c

@@ -34,7 +34,8 @@ static int listing=0;			/* list bytecodes? */
 static int dumping=1;			/* dump bytecodes? */
 static int stripping=0;	  /* strip debug information? */
 static int flash=0;	  		/* output flash image */
-static int lookup=0;	  		/* output lookup-style master combination header */
+static lu_int32 address=0;  /* output flash image at absolute location */
+static int lookup=0;			/* output lookup-style master combination header */
 static char Output[]={ OUTPUT };	/* default output file name */
 static const char* output=Output;	/* actual output file name */
 static const char* execute;       /* executed a Lua file */
@@ -69,6 +70,7 @@ static void usage(const char* message)
  "  -o name  output to file " LUA_QL("name") " (default is \"%s\")\n"
  "  -e name  execute a lua source file\n"
  "  -f       output a flash image file\n"
+ "  -a addr  generate an absolute, rather than position independent flash image file\n"
  "  -i       generate lookup combination master (default with option -f)\n" 
  "  -p       parse only\n"
  "  -s       strip debug information\n"
@@ -79,6 +81,8 @@ static void usage(const char* message)
 }
 
 #define	IS(s)	(strcmp(argv[i],s)==0)
+#define IROM0_SEG    0x40210000ul
+#define IROM0_SEGMAX 0x00100000ul
 
 static int doargs(int argc, char* argv[])
 {
@@ -105,8 +109,15 @@ static int doargs(int argc, char* argv[])
   }
   else if (IS("-f"))			/* Flash image file */
   {
-   flash=1;
-   lookup=1;
+   flash=lookup=1;
+  }
+  else if (IS("-a"))			/* Absolue flash image file */
+  {
+   flash=lookup=1;
+   address=strtol(argv[++i],NULL,0);
+   size_t offset = (unsigned) (address -IROM0_SEG);
+   if (offset > IROM0_SEGMAX)
+     usage(LUA_QL("-e") " absolute address must be valid flash address");
   }
   else if (IS("-i"))			/* lookup */
    lookup = 1;
@@ -159,7 +170,7 @@ static TString *corename(lua_State *L, const TString *filename)
  * then luac generates a main function to reference all sub-main prototypes.
  * This is one of two types:
  *   Type 0   The standard luac combination main
- *   Type 1   A lookup wrapper that facilitates indexing into the gernated protos 
+ *   Type 1   A lookup wrapper that facilitates indexing into the generated protos 
  */
 static const Proto* combine(lua_State* L, int n, int type)
 {
@@ -167,64 +178,76 @@ static const Proto* combine(lua_State* L, int n, int type)
   return toproto(L,-1);
  else
  {
-  int i,pc,stacksize;
-  Instruction *code;
+  int i;
+  Instruction *pc;
   Proto* f=luaF_newproto(L);
   setptvalue2s(L,L->top,f); incr_top(L);
   f->source=luaS_newliteral(L,"=(" PROGNAME ")");
   f->p=luaM_newvector(L,n,Proto*);
   f->sizep=n;
-  for (i=0; i<n; i++) f->p[i]=toproto(L,i-n-1);
+  for (i=0; i<n; i++) 
+    f->p[i]=toproto(L,i-n-1);
   pc=0;
 
-  if (type == 0)
-  {
+  if (type == 0) {
   /*
    * Type 0 is as per the standard luac, which is just a main routine which 
    * invokes all of the compiled functions sequentially.  This is fine if 
    * they are self registering modules, but useless otherwise.
    */
-   stacksize = 1;
-   code=luaM_newvector(L,2*n+1,Instruction);
-   for (i=0; i<n; i++)
-   {
-    code[pc++]=CREATE_ABx(OP_CLOSURE,0,i);
-    code[pc++]=CREATE_ABC(OP_CALL,0,1,1);
+   f->numparams    = 0;
+   f->maxstacksize = 1;
+   f->sizecode     = 2*n + 1 ;
+   f->sizek        = 0;
+   f->code         = luaM_newvector(L, f->sizecode , Instruction);
+   f->k            = luaM_newvector(L,f->sizek,TValue);
+
+   for (i=0, pc = f->code; i<n; i++) {
+    *pc++ = CREATE_ABx(OP_CLOSURE,0,i);
+    *pc++ = CREATE_ABC(OP_CALL,0,1,1);
    }
-   code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
-  }
-  else
-  {
+   *pc++ = CREATE_ABC(OP_RETURN,0,1,0);
+  } else {
   /*
    * The Type 1 main() is a lookup which takes a single argument, the name to  
    * be resolved. If this matches root name of one of the compiled files then
-   * a closure to this file main is returned.  If the name is "list": then the
-   * list of root names is returned, else a nil return.
+   * a closure to this file main is returned.  Otherwise the Unixtime of the
+   * compile and the list of root names is returned.
    */
-   lua_assert(n<LFIELDS_PER_FLUSH);
-   stacksize = n+2;
-   code=luaM_newvector(L,5*n+3  ,Instruction);
-   f->k=luaM_newvector(L,n+1,TValue);
-   f->sizek=n+1;
-   setnvalue(f->k, (lua_Number) time(NULL));
-   for (i=0; i<n; i++)  
+   if (n > LFIELDS_PER_FLUSH) {
+#define NO_MOD_ERR_(n) ": Number of modules > " #n
+#define NO_MOD_ERR(n) NO_MOD_ERR_(n)
+    usage(LUA_QL("-f")  NO_MOD_ERR(LFIELDS_PER_FLUSH));
+   }
+   f->numparams    = 1;
+   f->maxstacksize = n + 3;
+   f->sizecode     = 5*n + 5 ;
+   f->sizek        = n + 1;
+   f->sizelocvars  = 0;
+   f->code         = luaM_newvector(L, f->sizecode , Instruction);
+   f->k            = luaM_newvector(L,f->sizek,TValue);
+   for (i=0, pc = f->code; i<n; i++)  
    {
     /* if arg1 == FnameA then return function (...) -- funcA -- end end */
-    setsvalue2n(L,f->k+i+1,corename(L, f->p[i]->source));
-    code[pc++]=CREATE_ABC(OP_EQ,0,0,RKASK(i+1)); 
-    code[pc++]=CREATE_ABx(OP_JMP,0,MAXARG_sBx+2);
-    code[pc++]=CREATE_ABx(OP_CLOSURE,1,i);
-    code[pc++]=CREATE_ABC(OP_RETURN,1,2,0);
+    setsvalue2n(L,f->k+i,corename(L, f->p[i]->source));
+    *pc++ = CREATE_ABC(OP_EQ,0,0,RKASK(i)); 
+    *pc++ = CREATE_ABx(OP_JMP,0,MAXARG_sBx+2);
+    *pc++ = CREATE_ABx(OP_CLOSURE,1,i);
+    *pc++ = CREATE_ABC(OP_RETURN,1,2,0);
    }
-   for (i=0; i<=n; i++) code[pc++]=CREATE_ABx(OP_LOADK,i+1,i);
-   /* should be a block loop */
-   code[pc++]=CREATE_ABC(OP_RETURN,1,2+n,0);
-   code[pc++]=CREATE_ABC(OP_RETURN,0,1,0);
+
+   setnvalue(f->k+n, (lua_Number) time(NULL));
+
+   *pc++ = CREATE_ABx(OP_LOADK,1,n);
+   *pc++ = CREATE_ABC(OP_NEWTABLE,2,luaO_int2fb(i),0);   
+   for (i=0; i<n; i++) 
+     *pc++ = CREATE_ABx(OP_LOADK,i+3,i);
+   *pc++ = CREATE_ABC(OP_SETLIST,2,i,1);   
+   *pc++ = CREATE_ABC(OP_RETURN,1,3,0);
+   *pc++ = CREATE_ABC(OP_RETURN,0,1,0);
   }
-  f->numparams=1;
-  f->maxstacksize=stacksize;
-  f->code=code;
-  f->sizecode=pc;
+  lua_assert((pc-f->code) == f->sizecode);
+
   return f;
  }
 }
@@ -240,7 +263,8 @@ struct Smain {
  char** argv;
 };
 
-extern uint dumpToFlashImage (lua_State* L,const Proto *main, lua_Writer w, void* data, int strip);
+extern uint dumpToFlashImage (lua_State* L,const Proto *main, lua_Writer w, 
+                              void* data, int strip, lu_int32 address);
 
 static int pmain(lua_State* L)
 {
@@ -278,7 +302,7 @@ static int pmain(lua_State* L)
   lua_lock(L);
   if (flash) 
   {
-    result=dumpToFlashImage(L,f,writer, D, stripping);
+    result=dumpToFlashImage(L,f,writer, D, stripping, address);
   } else
   {
     result=luaU_dump_crosscompile(L,f,writer,D,stripping,target);

+ 6 - 1
app/lua/luaconf.h

@@ -38,6 +38,11 @@
 #define LUA_WIN
 #endif
 
+
+#if defined(LUA_CROSS_COMPILER)
+#define LUA_USE_LINUX
+#endif
+
 #if defined(LUA_USE_LINUX)
 #define LUA_USE_POSIX
 #define LUA_USE_DLOPEN		/* needs an extra library: -ldl */
@@ -59,7 +64,7 @@
 #if defined(LUA_USE_POSIX)
 #define LUA_USE_MKSTEMP
 #define LUA_USE_ISATTY
-#define LUA_USE_POPEN
+//#define LUA_USE_POPEN
 #define LUA_USE_ULONGJMP
 #endif
 

+ 7 - 13
app/modules/node.c

@@ -575,27 +575,25 @@ static const LUA_REG_TYPE node_task_map[] = {
   { LSTRKEY( "HIGH_PRIORITY" ),   LNUMVAL( TASK_PRIORITY_HIGH ) },
   { LNILKEY, LNILVAL }
 };
-#ifdef LUA_FLASH_STORE
-static const LUA_REG_TYPE node_flash_map[] = {
-  { LSTRKEY( "reload" ),          LFUNCVAL( luaN_reload_reboot ) },
-  { LSTRKEY( "index" ),           LFUNCVAL( luaN_index ) },
-  { LNILKEY, LNILVAL }
-};
-#endif
 
 static const LUA_REG_TYPE node_map[] =
 {
+  { LSTRKEY( "heap" ), LFUNCVAL( node_heap ) },
+  { LSTRKEY( "info" ), LFUNCVAL( node_info ) },
+  { LSTRKEY( "task" ), LROVAL( node_task_map ) },
+#ifdef LUA_FLASH_STORE
+  { LSTRKEY( "flashreload" ), LFUNCVAL( luaN_reload_reboot ) },
+  { LSTRKEY( "flashindex" ), LFUNCVAL( luaN_index ) },
+#endif
   { LSTRKEY( "restart" ), LFUNCVAL( node_restart ) },
   { LSTRKEY( "dsleep" ), LFUNCVAL( node_deepsleep ) },
 #ifdef PMSLEEP_ENABLE
   { LSTRKEY( "sleep" ), LFUNCVAL( node_sleep ) },
   PMSLEEP_INT_MAP,
 #endif
-  { LSTRKEY( "info" ), LFUNCVAL( node_info ) },
   { LSTRKEY( "chipid" ), LFUNCVAL( node_chipid ) },
   { LSTRKEY( "flashid" ), LFUNCVAL( node_flashid ) },
   { LSTRKEY( "flashsize" ), LFUNCVAL( node_flashsize) },
-  { LSTRKEY( "heap" ), LFUNCVAL( node_heap ) },
   { LSTRKEY( "input" ), LFUNCVAL( node_input ) },
   { LSTRKEY( "output" ), LFUNCVAL( node_output ) },
 // Moved to adc module, use adc.readvdd33()
@@ -609,12 +607,8 @@ static const LUA_REG_TYPE node_map[] =
   { LSTRKEY( "random" ), LFUNCVAL( node_random) },
 #ifdef LUA_OPTIMIZE_DEBUG
   { LSTRKEY( "stripdebug" ), LFUNCVAL( node_stripdebug ) },
-#endif
-#ifdef LUA_FLASH_STORE
-  { LSTRKEY( "flash") , LROVAL( node_flash_map ) },
 #endif
   { LSTRKEY( "egc" ),  LROVAL( node_egc_map ) },
-  { LSTRKEY( "task" ), LROVAL( node_task_map ) },
 #ifdef DEVELOPMENT_TOOLS
   { LSTRKEY( "osprint" ), LFUNCVAL( node_osprint ) },
 #endif

+ 30 - 31
docs/en/modules/node.md

@@ -145,6 +145,36 @@ none
 #### Returns
 flash ID (number)
 
+## node.flashindex()
+
+Returns the function reference for a function in the LFS (Lua Flash Store).
+
+#### Syntax
+`node.flashindex()`
+
+#### Parameters
+`modulename`  The name of the module to be loaded.  If this is `nil` or invalid then an info list is returned
+
+#### Returns
+-  In the case where the LFS in not loaded, `node.flashindex` evaluates to `nil`, followed by the flash and mapped base addresss of the LFS  
+-  If the LFS is loaded and the function is called with the name of a valid module in the LFS, then the function is returned in the same way the `load()` and the other Lua load functions do.
+-  Otherwise an extended info list is returned: the Unix time of the LFS build, the flash and mapped base addresses of the LFS and its current length, and an array of the valid module names in the LFS. 
+
+## node.flashreload()
+
+Reload the LFS (Lua Flash Store) with the flash image provided. Flash images are generated on the host machine using the `luac.cross`commnad.
+
+#### Syntax
+`node.flashreload(imageName)`
+
+#### Parameters
+`imageName` The of name of a image file in the filesystem to be loaded into the LFS.
+
+#### Returns
+If the LFS image has the incorrect signature or size, then `false` is returned.
+In the case of the `imagename` being a valid LFS image, this is then loaded into flash.  The ESP is then immediately rebooted so control is not returned to the calling application. 
+
+
 ## node.flashsize()
 
 Returns the flash chip size in bytes. On 4MB modules like ESP-12 the return value is 4194304 = 4096KB.
@@ -496,37 +526,6 @@ provides more detailed information on the EGC.
 `node.egc.setmode(node.egc.ALWAYS, 4096)  -- This is the default setting at startup.`
 `node.egc.setmode(node.egc.ON_ALLOC_FAILURE) -- This is the fastest activeEGC mode.`
 
-# node.flash module
-
-## node.flash.index()
-
-Returns the function reference for a function in the LFS (Lua Flash Store).
-
-#### Syntax
-`node.flash.index()`
-
-#### Parameters
-None
-
-#### Returns
--  In the case where the LFS in not loaded, `node.flash.index` evaluates to `nil`
--  If the LFS is loaded, this returns the index function within the LFS which indexes its contents. This index function can itself to called to interrogate or access the LFS contents:
-   -  In that case where the function is called with the name of a valid module in the LFS, the function is returned in the same way the `load()` and the other Lua load functions do.
-   -  Otherwise the function returns a list of module names in the LFS. Note that the first entry in the list is the Unix datetime of he build.
-
-## node.flash.reload()
-
-Reload the LFS (Lua Flash Store) with the flash image provided. Flash images are generated on the host machine using the `luac.cross`commnad.
-
-#### Syntax
-`node.flash.rebuild(imageName)`
-
-#### Parameters
-`imageName` The of name of a image file in the filesystem to be loaded into the LFS.
-
-#### Returns
-_Not applicable_.  The ESP will load the LFS image and immediately reboot.  Control is not returned to the calling application.
-
 # node.task module
 
 ## node.task.post()

+ 124 - 0
lua_examples/lfs/lfs_fragments.lua

@@ -0,0 +1,124 @@
+-- First time image boot to discover the confuration
+--
+-- If you want to use absolute address LFS load or SPIFFS imaging, then boot the
+-- image for the first time bare, that is without either LFS or SPIFFS preloaded
+-- then enter the following commands interactively through the UART:
+--
+local _,mapa,fa=node.flashindex(); return ('0x%x, 0x%x, 0x%x'):format(
+  mapa,fa,file.fscfg())
+--
+-- This will print out 3 hex constants: the absolute address used in the 
+-- 'luac.cross -a' options and the flash adresses of the LFS and SPIFFS.
+--
+--[[  So you would need these commands to image your ESP module:
+USB=/dev/ttyUSB0         # or whatever the device of your USB is
+NODEMCU=~/nodemcu        # The root of your NodeMCU file hierarchy
+SRC=$NODEMCU/local/lua   # your source directory for your LFS Lua files.
+BIN=$NODEMCU/bin
+ESPTOOL=$NODEMCU/tools/esptool.py
+
+$ESPTOOL --port $USB erase_flash   # Do this is you are having load funnies
+$ESPTOOL --port $USB --baud 460800  write_flash -fm dio 0x00000 \
+  $BIN/0x00000.bin 0x10000 $BIN/0x10000.bin
+#
+# Now restart your module and use whatever your intective tool is to do the above 
+# cmds, so if this outputs 0x4027b000, -0x7b000, 0x100000 then you can do
+#
+$NODEMCU/luac.cross -a 0x4027b000 -o $BIN/0x7b000-flash.img $SRC/*.lua
+$ESPTOOL --port $USB --baud 460800  write_flash -fm dio 0x7b000 \
+                                                   $BIN/0x7b000-flash.img
+# and if you've setup a SPIFFS then
+$ESPTOOL --port $USB --baud 460800  write_flash -fm dio 0x100000 \
+                                                   $BIN/0x100000-0x10000.img
+# and now you are good to go
+]]
+
+-----------------------------------------------------------------------------------
+--
+-- It is a good idea to add an _init.lua module to your LFS and do most of the 
+-- LFS module related initialisaion in this.  This example uses standard Lua
+-- features to simplify the LFS API.  
+--
+-- The first 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 doing LFS.fred(params)
+--
+-- The second adds the LFS to the require searchlist so that you can require a
+-- Lua module 'jean' in the LFS by simply doing require "jean".  However not that
+-- this is at the search entry following the FS searcher, so if you also have
+-- jean.lc or jean.lua in SPIFFS, then this will get preferentially loaded,
+-- albeit into RAM.  (Useful, for development).
+--
+do
+  local index = node.flashindex 
+  local lfs_t = { __index = function(_, name)
+      local fn, ba = index(name)
+      if not ba then return fn end -- or return nil implied
+    end}
+  getfenv().LFS = setmetatable(lfs_t,lfs_t)
+
+  local function loader_flash(module)
+    local fn, ba = index(module)
+    return ba and "Module not in LFS" or fn 
+  end
+  package.loaders[3] = loader_flash
+
+end
+
+-----------------------------------------------------------------------------------
+--
+-- File: init.lua
+--
+-- With the previous example you still need an init.lua to bootstrap the _init 
+-- module in LFS.  Here is an example.  It's a good idea either to use a timer 
+-- delay or a GPIO pin during development, so that you as developer can break into 
+-- the boot sequence if there is a problem with the _init bootstrap that is causing
+-- a panic loop.  Here is one example of how you might do this.  You have a second to
+-- inject tmr.stop(0) into UART0.  Extend if your reactions can't meet this.
+--
+-- You also want to do autoload the LFS, for example by adding the following:
+--
+if node.flashindex() == nil then 
+  node.flashreload('flash.img') 
+end
+
+tmr.alarm(0, 1000, tmr.ALARM_SINGLE, 
+  function()
+    local fi=node.flashindex; return pcall(fi and fi'_init')
+  end)
+
+-----------------------------------------------------------------------------------
+--
+-- The debug.getstrings function can be used to get a listing of the RAM (or ROM
+-- if LFS is loaded), as per the following example, so you can do this at the 
+-- interactive prompt or call it as a debug function during a running application. 
+--
+do
+  local a=debug.getstrings'RAM'
+  for i =1, #a do a[i] = ('%q'):format(a[i]) end
+  print ('local preload='..table.concat(a,','))
+end
+
+-----------------------------------------------------------------------------------
+--
+-- File: LFS_dummy_strings.lua
+--
+-- luac.cross -f will generate a ROM string table that includes all strings 
+-- referenced in the loaded modules.  If you want to preload other string constants
+-- hen the trick is to include a dummy module in the LFS.  You never need to call
+-- this.  It's inclusion is enough to add the strings to the ROM table.  Once in
+-- the ROM table, then you can use them in your application without incuring any 
+-- RAM or Lua Garbage Collector (LGC) overhead.  Here is a useful starting point,
+-- but you can add to this for your application.  
+--
+-- The trick is to build the LFS as normal then run the previous example from your
+-- running application and append these lines to this file.
+--
+local preload = "?.lc;?.lua", "@init.lua", "_G", "_LOADED", "_LOADLIB", "__add", 
+"__call", "__concat", "__div", "__eq", "__gc", "__index", "__le", "__len", "__lt", 
+"__mod", "__mode", "__mul", "__newindex", "__pow", "__sub", "__tostring", "__unm", 
+"collectgarbage", "cpath", "debug", "file", "file.obj", "file.vol", "flash", 
+"getstrings", "index", "ipairs", "list", "loaded", "loader", "loaders", "loadlib", 
+"module", "net.tcpserver", "net.tcpsocket", "net.udpsocket", "newproxy", "package", 
+"pairs", "path", "preload", "reload", "require", "seeall", "wdclr"
+

+ 9 - 3
tools/Makefile

@@ -34,6 +34,7 @@ else
 FLASH_FS_LOC := $(shell printf "0x%x" $(FLASH_FS_LOC))
 endif 
 
+LFSSOURCES := $(wildcard $(LUASOURCE)/*.lua)
 
 #############################################################
 # Rules base
@@ -68,9 +69,14 @@ spiffsscript: remove-image LFSimage spiffsimg/spiffsimg
 	@$(foreach f, $(SPIFFSFILES), echo "import $(FSSOURCE)$(f) $(f)" >> ./spiffsimg/spiffs.lst ;)
 	$(foreach sz, $(FLASHSIZE), spiffsimg/spiffsimg -f ../bin/0x%x-$(sz).img  $(FLASH_SW) $(sz) -U $(FLASH_FS_LOC) -r ./spiffsimg/spiffs.lst -d; )
 	@$(foreach sz, $(FLASHSIZE), if [ -r ../bin/spiffs-$(sz).dat ]; then echo Built $$(cat ../bin/spiffs-$(sz).dat)-$(sz).bin; fi; )
-	
-LFSimage: $(LUASOURCE)*.lua
-	../luac.cross -f -o $(FSSOURCE)flash.img $(LUASOURCE)*.lua
+
+ifneq ($(LFSSOURCES),)
+LFSimage: $(LFSSOURCES)
+       ../luac.cross -f -o $(FSSOURCE)flash.img $(LFSSOURCES)
+else
+LFSimage: 
+	rm -f $(FSSOURCE)flash.img
+endif
 
 remove-image:
 	$(foreach sz, $(FLASHSIZE), if [ -r ../bin/spiffs-$(sz).dat ]; then rm -f ../bin/$$(cat ../bin/spiffs-$(sz).dat)-$(sz).bin; fi; )