Commit 4f21224d authored by TerryE's avatar TerryE
Browse files

LFS patch updates following review II and testing

parent 4f7af452
...@@ -162,7 +162,8 @@ end: ...@@ -162,7 +162,8 @@ end:
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
} }
extern lua_Load gLoad; extern int lua_put_line(const char *s, size_t l);
static const coap_endpoint_path_t path_command = {2, {"v1", "c"}}; static const coap_endpoint_path_t path_command = {2, {"v1", "c"}};
static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo) static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
{ {
...@@ -170,16 +171,9 @@ static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scra ...@@ -170,16 +171,9 @@ static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scra
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN); return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
if (inpkt->payload.len > 0) if (inpkt->payload.len > 0)
{ {
lua_Load *load = &gLoad; char line[LUA_MAXINPUT];
if(load->line_position == 0){ if (!coap_buffer_to_string(line, LUA_MAXINPUT, &inpkt->payload) &&
coap_buffer_to_string(load->line, load->len,&inpkt->payload); lua_put_line(line, c_strlen(line))) {
load->line_position = c_strlen(load->line)+1;
// load->line[load->line_position-1] = '\n';
// load->line[load->line_position] = 0;
// load->line_position++;
load->done = 1;
NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here
NODE_DBG("\nResult(if any):\n"); NODE_DBG("\nResult(if any):\n");
system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0); system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0);
} }
......
...@@ -23,7 +23,7 @@ endif ...@@ -23,7 +23,7 @@ endif
# makefile at its root level - these are then overridden # makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein # for a subtree within the makefile rooted therein
# #
#DEFINES += #DEFINES += -DGDBSTUB_REDIRECT_CONSOLE_OUTPUT
############################################################# #############################################################
# Recursion Magic - Don't touch this!! # Recursion Magic - Don't touch this!!
......
#ifndef __USER_CONFIG_H__ #ifndef __USER_CONFIG_H__
#define __USER_CONFIG_H__ #define __USER_CONFIG_H__
// The firmware supports a range of Flash sizes, though 4Mbyte seems to be // The firmware supports a range of Flash sizes, though 4 Mbyte seems to be
// currently the most common. Current builds include a discovery function // the most common currently. NodeMCU builds include a discovery function
// which is enabled by FLASH_AUTOSIZE, but you can override this by commenting // 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 // 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. // FLASH_512K, FLASH_1M, FLASH_2M, FLASH_4M, FLASH_8M, FLASH_16M.
#define FLASH_AUTOSIZE #define FLASH_AUTOSIZE
//#define FLASH_4M //#define FLASH_4M
// The firmware now selects a baudrate of 115,200 by default, but the driver also // The firmware now selects a baudrate of 115,200 by default, but the driver
// includes automatic baud rate detection at start-up by default. If you want to // also includes automatic baud rate detection at start-up. If you want to change
// change the default rate then vaild rates are 300, 600, 1200, 2400, 4800, 9600, // the default rate then vaild rates are 300, 600, 1200, 2400, 4800, 9600, 19200,
// 19200, 31250, 38400, 57600, 74880, 115200, 230400, 256000, 460800 [, 921600, // 31250, 38400, 57600, 74880, 115200, 230400, 256000, 460800 [, 921600, 1843200,
// 1843200, 368640]. Note that the last 3 rates are not recommended as these // 368640]. Note that the last 3 rates are not recommended as these might be
// might be unreliable. // unreliable, but 460800 seems to work well for most USB-serial devices.
#define BIT_RATE_DEFAULT BIT_RATE_115200 #define BIT_RATE_DEFAULT BIT_RATE_115200
#define BIT_RATE_AUTOBAUD //#define BIT_RATE_AUTOBAUD
// Three separate build variants are now supported. The main difference is in the // 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 // processing of numeric data types. If LUA_NUMBER_INTEGRAL is defined, then
// all numeric calculations are done in integer, with divide being an integer // all numeric calculations are done in integer, with divide being an integer
// operations, and decimal fraction constants are illegal. Otherwise all // operations, and decimal fraction constants are illegal. Otherwise all
// numeric operations use floating point, though they are exact for integer // numeric operations use floating point, though they are exact for integer
// expressions < 2^53. The main advantage of INTEGRAL builds is that the basic // expressions < 2^53.
// 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 // The main advantage of INTEGRAL builds is that the basic internal storage unit,
// experimental option LUA_PACK_TVALUES which reduces the floating point TValues // the TValue, is 8 bytes long. We have now reduced the size of FP TValues to
// to 12 bytes without any performance impact. // 12 bytes rather than the previous 16 as this gives a material RAM saving with
// no performance loss. However, you can define LUA_DWORD_ALIGNED_TVALUES and
// this will force 16 byte TValues on FP builds.
//#define LUA_NUMBER_INTEGRAL //#define LUA_NUMBER_INTEGRAL
//#define LUA_PACK_TVALUES //#define LUA_DWORD_ALIGNED_TVALUES
// The Lua Flash Store (LFS) allows you to store Lua code in Flash memory and // 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 // 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 // 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 // the size of the store that you need. This can be any multiple of 4kB up to
// a maximum 256Kb. // a maximum 256Kb.
//#define LUA_FLASH_STORE 0x10000 //#define LUA_FLASH_STORE 0x10000
...@@ -48,45 +50,45 @@ ...@@ -48,45 +50,45 @@
// By default Lua executes the file init.lua at start up. The following // By default Lua executes the file init.lua at start up. The following
// define allows you to replace this with an alternative startup. Warning: // define allows you to replace this with an alternative startup. Warning:
// you must protect this execution otherwise you will enter a panic loop. // you must protect this execution otherwise you will enter a panic loop;
// the simplest way is to wrap the action in a function invoked by a pcall.
// The example provided executes the LFS module "_init" at startup or fails // The example provided executes the LFS module "_init" at startup or fails
// through to the interactive prompt. // 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')" //#define LUA_INIT_STRING "pcall(function() node.flashindex'_init'() end)"
// ********* WARNING THIS OPTION ISN'T CURRENTLY WORKING
// NodeMCU supports two file systems: SPIFFS and FATFS, the first is available // 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. // 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 // If you use SPIFFS then there are a number of options which impact the
// RAM overhead and performance of the file system. // RAM overhead and performance of the file system.
//
// If you use the spiffsimg tool to create your own FS images on your dev PC // 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 // 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 // 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 // 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 // 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 // general, limiting the size of the FS only to what your application needs
// gives the fastest start-up and imaging times. // gives the fastest start-up and imaging times.
#define BUILD_SPIFFS #define BUILD_SPIFFS
//#define BUILD_FATFS
//#define SPIFFS_FIXED_LOCATION 0x100000 //#define SPIFFS_FIXED_LOCATION 0x100000
//#define SPIFFS_MAX_FILESYSTEM_SIZE 0x10000 //#define SPIFFS_MAX_FILESYSTEM_SIZE 0x20000
//#define SPIFFS_SIZE_1M_BOUNDARY //#define SPIFFS_SIZE_1M_BOUNDARY
#define SPIFFS_CACHE 1 // Enable if you use you SPIFFS in R/W mode #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 SPIFFS_MAX_OPEN_FILES 4 // maximum number of open files for SPIFFS
#define FS_OBJ_NAME_LEN 31 // maximum length of a filename #define FS_OBJ_NAME_LEN 31 // maximum length of a filename
//#define BUILD_FATFS
// The HTTPS stack requires client SSL to be enabled. The SSL buffer size is // 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. // used only for espconn-layer secure connections, and is ignored otherwise.
// Some HTTPS applications require a larger buffer size to work. See // Some HTTPS applications require a larger buffer size to work. See
// https://github.com/nodemcu/nodemcu-firmware/issues/1457 for details. // https://github.com/nodemcu/nodemcu-firmware/issues/1457 for details.
// The SHA2 and MD2 libraries are also used by the crypto functions. The // The SHA2 and MD2 libraries are also optionally used by the crypto functions.
// MD2 function are implemented in the ROM BIOS, and the SHA2 by NodeMCU // The SHA1 and MD5 function are implemented in the ROM BIOS. The MD2 and SHA2
// code, so only enable SHA2 if you need this functionality. // are by firmware code, and can be enabled if you need this functionality.
//#define CLIENT_SSL_ENABLE //#define CLIENT_SSL_ENABLE
//#define MD2_ENABLE //#define MD2_ENABLE
...@@ -97,15 +99,15 @@ ...@@ -97,15 +99,15 @@
// GPIO_INTERRUPT_ENABLE needs to be defined if your application uses the // GPIO_INTERRUPT_ENABLE needs to be defined if your application uses the
// gpio.trig() or related GPIO interrupt service routine code. Likewise 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 // 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 // don't require this functionality, then commenting out these options out
// options which removes any associated runtime overhead. // will remove any associated runtime overhead.
#define GPIO_INTERRUPT_ENABLE #define GPIO_INTERRUPT_ENABLE
#define GPIO_INTERRUPT_HOOK_ENABLE #define GPIO_INTERRUPT_HOOK_ENABLE
// If your application uses the light sleep functions and you wish the // If your application uses the light sleep functions and you wish the
// firmware to manage timer rescheduling over sleeps (the CPU clock is // firmware to manage timer rescheduling over sleeps (the CPU clock is
// suspended so timers get out of sync) then enable the following options // suspended so timers get out of sync) then enable the following options
//#define ENABLE_TIMER_SUSPEND //#define ENABLE_TIMER_SUSPEND
...@@ -115,24 +117,32 @@ ...@@ -115,24 +117,32 @@
// The WiFi module optionally offers an enhanced level of WiFi connection // The WiFi module optionally offers an enhanced level of WiFi connection
// management, using internal timer callbacks. Whilst many Lua developers // management, using internal timer callbacks. Whilst many Lua developers
// prefer to implement equivalent features in Lua, others will prefer the // prefer to implement equivalent features in Lua, others will prefer the
// Wifi module to do this for them. Uncomment the following to enable // Wifi module to do this for them. Uncomment the following to enable
// this functionality. The event sub-options are ignore if the SMART // this functionality. See the relevant WiFi module documentation for
// functionality is not enabled. // further details, as the scope of these changes is not obvious.
// Enable the wifi.startsmart() and wifi.stopsmart()
//#define WIFI_SMART_ENABLE //#define WIFI_SMART_ENABLE
// Enable wifi.sta.config() event callbacks
#define WIFI_SDK_EVENT_MONITOR_ENABLE #define WIFI_SDK_EVENT_MONITOR_ENABLE
// Enable creation on the wifi.eventmon.reason table
#define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE #define WIFI_EVENT_MONITOR_DISCONNECT_REASON_LIST_ENABLE
// Enable use of the WiFi.monitor sub-module
//#define LUA_USE_MODULES_WIFI_MONITOR
// Whilst the DNS client details can be configured through the WiFi API, // Whilst the DNS client details can be configured through the WiFi API,
// the defaults can be exposed temporarily during start-up. The following // 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 options allow you to configure this in the firmware. If the
// WIFI_STA_HOSTNAME is not defined then the hostname will default to // 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 // 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 // prefix "NODE-". If it is defined then the hostname must only contain
// alphanumeric characters. If you are imaging multiple modules with this // alphanumeric characters. If you are imaging multiple modules with this
// firmware then you must also define WIFI_STA_HOSTNAME_APPEND_MAC to // 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 // append the last 3 octets of the MAC address. Note that the total
// Hostname MUST be 32 chars or less. // Hostname MUST be 32 chars or less.
//#define WIFI_STA_HOSTNAME "NodeMCU" //#define WIFI_STA_HOSTNAME "NodeMCU"
...@@ -145,7 +155,7 @@ ...@@ -145,7 +155,7 @@
#define ENDUSER_SETUP_AP_SSID "SetupGadget" #define ENDUSER_SETUP_AP_SSID "SetupGadget"
// The following sections are only relevent for those developers who are // The following sections are only relevent for those developers who are
// developing modules or core Lua changes and configure how extra diagnostics // developing modules or core Lua changes and configure how extra diagnostics
// are enabled in the firmware. These should only be configured if you are // 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 // building your own custom firmware and have full access to the firmware
...@@ -153,18 +163,18 @@ ...@@ -153,18 +163,18 @@
// Enabling DEVELOPMENT_TOOLS adds the asserts in LUA and also some useful // 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 // 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 // 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 // slowdown). If you want to use the remote GDB to handle breaks and failed
// assertions then enable the DEVELOPMENT_USE GDB option. A supplimentary // assertions then enable the DEVELOPMENT_USE GDB option. A supplimentary
// define DEVELOPMENT_BREAK_ON_STARTUP_PIN allows you to define a GPIO pin, // 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. // 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 // The DEVELOP_VERSION option enables lots of debug output, and is normally
// only used by hardcore developers. // only used by hardcore developers.
// These options can be enabled globally here or you can alternatively use // 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 // 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 // directory basis. If you do this then you can also set the corresponding
// compile options (-O0 -ggdb) on a per directory as well. // compile options (-O0 -ggdb) on a per directory as well.
//#define DEVELOPMENT_TOOLS //#define DEVELOPMENT_TOOLS
...@@ -196,19 +206,24 @@ extern void luaL_dbgbreak(void); ...@@ -196,19 +206,24 @@ extern void luaL_dbgbreak(void);
#endif #endif
#endif #endif
#if !defined(LUA_NUMBER_INTEGRAL) && defined (LUA_DWORD_ALIGNED_TVALUES)
#define LUA_PACK_TVALUES
#else
#undef LUA_PACK_TVALUES
#endif
#ifdef DEVELOP_VERSION #ifdef DEVELOP_VERSION
#define NODE_DEBUG #define NODE_DEBUG
#define COAP_DEBUG #define COAP_DEBUG
#endif /* DEVELOP_VERSION */ #endif /* DEVELOP_VERSION */
#define NODE_ERROR
#ifdef NODE_DEBUG #ifdef NODE_DEBUG
#define NODE_DBG dbg_printf #define NODE_DBG dbg_printf
#else #else
#define NODE_DBG #define NODE_DBG
#endif /* NODE_DEBUG */ #endif /* NODE_DEBUG */
#define NODE_ERROR
#ifdef NODE_ERROR #ifdef NODE_ERROR
#define NODE_ERR dbg_printf #define NODE_ERR dbg_printf
#else #else
...@@ -218,9 +233,14 @@ extern void luaL_dbgbreak(void); ...@@ -218,9 +233,14 @@ extern void luaL_dbgbreak(void);
// #define GPIO_SAFE_NO_INTR_ENABLE // #define GPIO_SAFE_NO_INTR_ENABLE
#define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed)) #define ICACHE_STORE_TYPEDEF_ATTR __attribute__((aligned(4),packed))
#define ICACHE_STORE_ATTR __attribute__((aligned(4))) #define ICACHE_STORE_ATTR __attribute__((aligned(4)))
#define ICACHE_RAM_STRING(x) ICACHE_RAM_STRING2(x) #define ICACHE_STRING(x) ICACHE_STRING2(x)
#define ICACHE_RAM_STRING2(x) #x #define ICACHE_STRING2(x) #x
#define ICACHE_RAM_ATTR __attribute__((section(".iram0.text." __FILE__ "." ICACHE_RAM_STRING(__LINE__)))) #define ICACHE_RAM_ATTR \
__attribute__((section(".iram0.text." __FILE__ "." ICACHE_STRING(__LINE__))))
#define ICACHE_FLASH_RESERVED_ATTR \
__attribute__((section(".irom.reserved." __FILE__ "." ICACHE_STRING(__LINE__)),\
used,unused,aligned(INTERNAL_FLASH_SECTOR_SIZE)))
#ifdef GPIO_SAFE_NO_INTR_ENABLE #ifdef GPIO_SAFE_NO_INTR_ENABLE
#define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline)) #define NO_INTR_CODE ICACHE_RAM_ATTR __attribute__ ((noinline))
#else #else
...@@ -228,4 +248,3 @@ extern void luaL_dbgbreak(void); ...@@ -228,4 +248,3 @@ extern void luaL_dbgbreak(void);
#endif #endif
#endif /* __USER_CONFIG_H__ */ #endif /* __USER_CONFIG_H__ */
...@@ -15,18 +15,6 @@ ...@@ -15,18 +15,6 @@
#include "c_stdlib.h" #include "c_stdlib.h"
#include "c_types.h" #include "c_types.h"
#include "c_string.h" #include "c_string.h"
extern const char lua_init_value[];
const char *c_getenv(const char *__string)
{
if (c_strcmp(__string, "LUA_INIT") == 0)
{
return lua_init_value;
}
return NULL;
}
#include <_ansi.h> #include <_ansi.h>
//#include <reent.h> //#include <reent.h>
//#include "mprec.h" //#include "mprec.h"
......
...@@ -46,8 +46,7 @@ ...@@ -46,8 +46,7 @@
// void c_exit(int); // void c_exit(int);
// c_getenv() get env "LUA_INIT" string for lua initialization. //const char *c_getenv(const char *__string);
const char *c_getenv(const char *__string);
// void *c_malloc(size_t __size); // void *c_malloc(size_t __size);
// void *c_zalloc(size_t __size); // void *c_zalloc(size_t __size);
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
//#define DEBUG_ALLOCATOR //#define DEBUG_ALLOCATOR
#ifdef DEBUG_ALLOCATOR #ifdef DEBUG_ALLOCATOR
#ifdef LUA_CROSS_COMPILER #ifdef LUA_CROSS_COMPILER
static void break_hook(void) static void break_hook(void) {}
#define ASSERT(s) if (!(s)) {break_hook();} #define ASSERT(s) if (!(s)) {break_hook();}
#else #else
#define ASSERT(s) if (!(s)) {asm ("break 0,0" ::);} #define ASSERT(s) if (!(s)) {asm ("break 0,0" ::);}
...@@ -186,7 +186,7 @@ void *debug_realloc (void *b, size_t oldsize, size_t size) { ...@@ -186,7 +186,7 @@ void *debug_realloc (void *b, size_t oldsize, size_t size) {
/* }====================================================================== */ /* }====================================================================== */
#else #else
#define this_realloc(p,os,s) c_realloc(p,s) #define this_realloc(p,os,s) c_realloc(p,s)
#endif #endif /* DEBUG_ALLOCATOR */
/* /*
** {====================================================== ** {======================================================
......
...@@ -41,7 +41,7 @@ static uint32_t curOffset; ...@@ -41,7 +41,7 @@ static uint32_t curOffset;
#define FLASH_PAGE_SIZE INTERNAL_FLASH_SECTOR_SIZE #define FLASH_PAGE_SIZE INTERNAL_FLASH_SECTOR_SIZE
#define FLASH_PAGES (FLASH_SIZE/FLASH_PAGE_SIZE) #define FLASH_PAGES (FLASH_SIZE/FLASH_PAGE_SIZE)
#define BREAK_ON_STARTUP_PIN 1 // GPIO 5 or setting to 0 will disable pin startup char flash_region_base[FLASH_SIZE] ICACHE_FLASH_RESERVED_ATTR;
#ifdef NODE_DEBUG #ifdef NODE_DEBUG
extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
...@@ -94,6 +94,7 @@ static char *flashBlock(const void* b, size_t size) { ...@@ -94,6 +94,7 @@ static char *flashBlock(const void* b, size_t size) {
return cur; return cur;
} }
static void flashErase(uint32_t start, uint32_t end){ static void flashErase(uint32_t start, uint32_t end){
int i; int i;
if (start == -1) start = FLASH_PAGES - 1; if (start == -1) start = FLASH_PAGES - 1;
...@@ -104,38 +105,41 @@ static void flashErase(uint32_t start, uint32_t end){ ...@@ -104,38 +105,41 @@ 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
}
/* /*
* Hook in lstate.c:f_luaopen() to set up ROstrt and ROpvmain if needed * Hook in lstate.c:f_luaopen() to set up ROstrt and ROpvmain if needed
*/ */
LUAI_FUNC void luaN_init (lua_State *L) { LUAI_FUNC void luaN_init (lua_State *L) {
// luaL_dbgbreak();
curOffset = 0;
flashAddr = flash_region_base;
flashAddrPhys = platform_flash_mapped2phys((uint32_t)flashAddr);
flashSector = platform_flash_get_sector_of_address(flashAddrPhys);
FlashHeader *fh = cast(FlashHeader *, flashAddr); FlashHeader *fh = cast(FlashHeader *, flashAddr);
/* /*
* For the LFS to be valid, its signature has to be correct for this build variant, * 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 * 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 * 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. * direct imaging of an absolute LFS with the wrong base address.
*/ */
if ((fh->flash_sig & (~FLASH_SIG_ABSOLUTE)) == FLASH_SIG &&
fh->pROhash != ALL_SET && if ((fh->flash_sig & (~FLASH_SIG_ABSOLUTE)) != FLASH_SIG ) {
((fh->mainProto - cast(FlashAddr, fh)) < fh->flash_size)) { NODE_ERR("Flash sig not correct: %p vs %p\n",
G(L)->ROstrt.hash = cast(GCObject **, fh->pROhash); fh->flash_sig & (~FLASH_SIG_ABSOLUTE), FLASH_SIG);
G(L)->ROstrt.nuse = fh->nROuse ; return;
G(L)->ROstrt.size = fh->nROsize; }
G(L)->ROpvmain = cast(Proto *,fh->mainProto);
if (fh->pROhash == ALL_SET ||
((fh->mainProto - cast(FlashAddr, fh)) >= fh->flash_size)) {
NODE_ERR("Flash size check failed: %p vs 0xFFFFFFFF; %p >= %p\n",
fh->mainProto - cast(FlashAddr, fh), fh->flash_size);
return;
} }
G(L)->ROstrt.hash = cast(GCObject **, fh->pROhash);
G(L)->ROstrt.nuse = fh->nROuse ;
G(L)->ROstrt.size = fh->nROsize;
G(L)->ROpvmain = cast(Proto *,fh->mainProto);
} }
#define BYTE_OFFSET(t,f) cast(size_t, &(cast(t *, NULL)->f)) #define BYTE_OFFSET(t,f) cast(size_t, &(cast(t *, NULL)->f))
......
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
#include "lstate.h" #include "lstate.h"
#include "lzio.h" #include "lzio.h"
#ifdef LUA_NUNBER_INTEGRAL #ifdef LUA_NUMBER_INTEGRAL
# define FLASH_SIG_B1 0x02 # define FLASH_SIG_B1 0x02
#else #else
# define FLASH_SIG_B1 0x00 # define FLASH_SIG_B1 0x00
#endif #endif
#ifdef LUA_PACK_TVALUES #ifdef LUA_PACK_TVALUES
#ifdef LUA_NUNBER_INTEGRAL #ifdef LUA_NUMBER_INTEGRAL
#error "LUA_PACK_TVALUES is only valid for Floating point builds" #error "LUA_PACK_TVALUES is only valid for Floating point builds"
#endif #endif
# define FLASH_SIG_B2 0x04 # define FLASH_SIG_B2 0x04
...@@ -40,7 +40,6 @@ typedef struct { ...@@ -40,7 +40,6 @@ typedef struct {
lu_int32 fill2; /* reserved */ lu_int32 fill2; /* reserved */
} FlashHeader; } FlashHeader;
void luaN_user_init(void);
LUAI_FUNC void luaN_init (lua_State *L); LUAI_FUNC void luaN_init (lua_State *L);
LUAI_FUNC int luaN_flashSetup (lua_State *L); LUAI_FUNC int luaN_flashSetup (lua_State *L);
LUAI_FUNC int luaN_reload_reboot (lua_State *L); LUAI_FUNC int luaN_reload_reboot (lua_State *L);
......
...@@ -65,7 +65,8 @@ ...@@ -65,7 +65,8 @@
static void removeentry (Node *n) { static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n))); lua_assert(ttisnil(gval(n)));
if (ttype(gkey(n)) != LUA_TDEADKEY && iscollectable(gkey(n))) if (ttype(gkey(n)) != LUA_TDEADKEY && iscollectable(gkey(n)))
lua_assert(!isLFSobject(&((gkey(n))->value.gc->gch))); // The gkey is always in RAM so it can be marked as DEAD even though it
// refers to an LFS object.
setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */ setttype(gkey(n), LUA_TDEADKEY); /* dead key; remove it */
} }
......
...@@ -613,7 +613,7 @@ static int ll_seeall (lua_State *L) { ...@@ -613,7 +613,7 @@ static int ll_seeall (lua_State *L) {
static void setpath (lua_State *L, const char *fieldname, const char *envname, static void setpath (lua_State *L, const char *fieldname, const char *envname,
const char *def) { const char *def) {
const char *path = c_getenv(envname); const char *path = NULL; /* getenv(envname) not used in NodeMCU */;
if (path == NULL) /* no environment variable? */ if (path == NULL) /* no environment variable? */
lua_pushstring(L, def); /* use default */ lua_pushstring(L, def); /* use default */
else { else {
......
...@@ -29,11 +29,9 @@ ...@@ -29,11 +29,9 @@
lua_State *globalL = NULL; lua_State *globalL = NULL;
lua_Load gLoad; static lua_Load gLoad;
static const char *progname = LUA_PROGNAME; static const char *progname = LUA_PROGNAME;
static void l_message (const char *pname, const char *msg) { static void l_message (const char *pname, const char *msg) {
#if defined(LUA_USE_STDIO) #if defined(LUA_USE_STDIO)
if (pname) c_fprintf(c_stderr, "%s: ", pname); if (pname) c_fprintf(c_stderr, "%s: ", pname);
...@@ -237,19 +235,16 @@ static int runargs (lua_State *L, char **argv, int n) { ...@@ -237,19 +235,16 @@ static int runargs (lua_State *L, char **argv, int n) {
} }
#ifdef LUA_INIT_STRING #ifndef LUA_INIT_STRING
const char lua_init_value[] = LUA_INIT_STRING; #define LUA_INIT_STRING "@init.lua"
#else
const char lua_init_value[] = "@init.lua";
#endif #endif
static int handle_luainit (lua_State *L) { static int handle_luainit (lua_State *L) {
const char *init = c_getenv(LUA_INIT); const char *init = LUA_INIT_STRING;
if (init == NULL) return 0; /* status OK */ if (init[0] == '@')
else if (init[0] == '@')
return dofsfile(L, init+1); return dofsfile(L, init+1);
else else
return dostring(L, init, "=" LUA_INIT); return dostring(L, init, LUA_INIT);
} }
...@@ -284,7 +279,6 @@ static int pmain (lua_State *L) { ...@@ -284,7 +279,6 @@ static int pmain (lua_State *L) {
static void dojob(lua_Load *load); static void dojob(lua_Load *load);
static bool readline(lua_Load *load); static bool readline(lua_Load *load);
char line_buffer[LUA_MAXINPUT];
#ifdef LUA_RPC #ifdef LUA_RPC
int main (int argc, char **argv) { int main (int argc, char **argv) {
...@@ -315,24 +309,39 @@ int lua_main (int argc, char **argv) { ...@@ -315,24 +309,39 @@ int lua_main (int argc, char **argv) {
gLoad.L = L; gLoad.L = L;
gLoad.firstline = 1; gLoad.firstline = 1;
gLoad.done = 0; gLoad.done = 0;
gLoad.line = line_buffer; gLoad.line = c_malloc(LUA_MAXINPUT);
gLoad.len = LUA_MAXINPUT; gLoad.len = LUA_MAXINPUT;
gLoad.line_position = 0; gLoad.line_position = 0;
gLoad.prmt = get_prompt(L, 1); gLoad.prmt = get_prompt(L, 1);
dojob(&gLoad); dojob(&gLoad);
NODE_DBG("Heap size::%d.\n",system_get_free_heap_size()); NODE_DBG("Heap size:%d.\n",system_get_free_heap_size());
legc_set_mode( L, EGC_ALWAYS, 4096 ); legc_set_mode( L, EGC_ALWAYS, 4096 );
// legc_set_mode( L, EGC_ON_MEM_LIMIT, 4096 ); // legc_set_mode( L, EGC_ON_MEM_LIMIT, 4096 );
// lua_close(L); // lua_close(L);
return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS; return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
} }
int lua_put_line(const char *s, size_t l) {
if (s == NULL || ++l < LUA_MAXINPUT || gLoad.line_position > 0)
return 0;
c_memcpy(gLoad.line, s, l);
gLoad.line[l] = '\0';
gLoad.line_position = l;
gLoad.done = 1;
NODE_DBG("Get command: %s\n", gLoad.line);
return 1;
}
void lua_handle_input (bool force) void lua_handle_input (bool force)
{ {
while (gLoad.L && (force || readline (&gLoad))) while (gLoad.L && (force || readline (&gLoad))) {
NODE_DBG("Handle Input: first=%u, pos=%u, len=%u, actual=%u, line=%s\n", gLoad.firstline,
gLoad.line_position, gLoad.len, c_strlen(gLoad.line), gLoad.line);
dojob (&gLoad); dojob (&gLoad);
force = false;
}
} }
void donejob(lua_Load *load){ void donejob(lua_Load *load){
...@@ -462,11 +471,12 @@ static bool readline(lua_Load *load){ ...@@ -462,11 +471,12 @@ static bool readline(lua_Load *load){
{ {
/* Get a empty line, then go to get a new line */ /* Get a empty line, then go to get a new line */
c_puts(load->prmt); c_puts(load->prmt);
continue;
} else { } else {
load->done = 1; load->done = 1;
need_dojob = true; need_dojob = true;
break;
} }
continue;
} }
/* other control character or not an acsii character */ /* other control character or not an acsii character */
......
...@@ -155,7 +155,7 @@ static void *fromFashAddr(FlashAddr a) { ...@@ -155,7 +155,7 @@ static void *fromFashAddr(FlashAddr a) {
* Add a TS found in the Proto Load to the table at the ToS * Add a TS found in the Proto Load to the table at the ToS
*/ */
static void addTS(lua_State *L, TString *ts) { static void addTS(lua_State *L, TString *ts) {
lua_assert(ttisstring(&(ts->tsv))); lua_assert(ts->tsv.tt==LUA_TSTRING);
lua_pushnil(L); lua_pushnil(L);
setsvalue(L, L->top-1, ts); setsvalue(L, L->top-1, ts);
lua_pushinteger(L, 1); lua_pushinteger(L, 1);
......
...@@ -169,26 +169,16 @@ static int node_heap( lua_State* L ) ...@@ -169,26 +169,16 @@ static int node_heap( lua_State* L )
return 1; return 1;
} }
extern lua_Load gLoad; extern int lua_put_line(const char *s, size_t l);
extern bool user_process_input(bool force); extern bool user_process_input(bool force);
// Lua: input("string") // Lua: input("string")
static int node_input( lua_State* L ) static int node_input( lua_State* L ) {
{
size_t l = 0; size_t l = 0;
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
if (s != NULL && l > 0 && l < LUA_MAXINPUT - 1) if (lua_put_line(s, l)) {
{ NODE_DBG("Result (if any):\n");
lua_Load *load = &gLoad; user_process_input(true);
if (load->line_position == 0) {
c_memcpy(load->line, s, l);
load->line[l + 1] = '\0';
load->line_position = c_strlen(load->line) + 1;
load->done = 1;
NODE_DBG("Get command:\n");
NODE_DBG(load->line); // buggy here
NODE_DBG("\nResult(if any):\n");
user_process_input(true);
}
} }
return 0; return 0;
} }
......
...@@ -24,7 +24,7 @@ extern char _flash_used_end[]; ...@@ -24,7 +24,7 @@ extern char _flash_used_end[];
// Helper function: find the flash sector in which an address resides // Helper function: find the flash sector in which an address resides
// Return the sector number, as well as the start and end address of the sector // Return the sector number, as well as the start and end address of the sector
static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend ) static uint32_t flash_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend )
{ {
#ifdef INTERNAL_FLASH_SECTOR_SIZE #ifdef INTERNAL_FLASH_SECTOR_SIZE
// All the sectors in the flash have the same size, so just align the address // All the sectors in the flash have the same size, so just align the address
...@@ -53,7 +53,7 @@ static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t ...@@ -53,7 +53,7 @@ static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t
uint32_t platform_flash_get_sector_of_address( uint32_t addr ) uint32_t platform_flash_get_sector_of_address( uint32_t addr )
{ {
return flashh_find_sector( addr, NULL, NULL ); return flash_find_sector( addr, NULL, NULL );
} }
uint32_t platform_flash_get_num_sectors(void) uint32_t platform_flash_get_num_sectors(void)
...@@ -67,54 +67,22 @@ uint32_t platform_flash_get_num_sectors(void) ...@@ -67,54 +67,22 @@ uint32_t platform_flash_get_num_sectors(void)
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE #endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
} }
static uint32_t allocated = 0;
static uint32_t phys_flash_used_end = 0; //Phyiscal address of last byte in last flash used sector
uint32_t platform_flash_reserve_section( uint32_t regsize, uint32_t *start )
{
// Return Flash sector no (and optional flash mapped address of first allocated byte)
if(phys_flash_used_end == 0)
flashh_find_sector(platform_flash_mapped2phys( (uint32_t)_flash_used_end - 1), NULL, &phys_flash_used_end );
/* find sector and last byte address of previous allocation */
uint32_t end;
uint32_t sect = flashh_find_sector( phys_flash_used_end + allocated, NULL, &end );
if(start)
*start = end + 1;
/* allocated regions are always sector aligned */
flashh_find_sector( phys_flash_used_end + allocated + regsize, NULL, &end );
allocated = end - phys_flash_used_end;
NODE_DBG("Flash base: %08x %08x %08x\n", regsize, allocated, phys_flash_used_end);
return sect + 1;
}
uint32_t platform_flash_get_first_free_block_address( uint32_t *psect ) uint32_t platform_flash_get_first_free_block_address( uint32_t *psect )
{ {
// Round the total used flash size to the closest flash block address // Round the total used flash size to the closest flash block address
uint32_t start, end, sect; uint32_t start, end, sect;
NODE_DBG("_flash_used_end:%08x\n", (uint32_t)_flash_used_end); NODE_DBG("_flash_used_end:%08x\n", (uint32_t)_flash_used_end);
#if 0
if(_flash_used_end>0){ // find the used sector
sect = flashh_find_sector( platform_flash_mapped2phys ( (uint32_t)_flash_used_end - 1), NULL, &end );
sect++;
start = end + 1;
}else{
sect = flashh_find_sector( 0, &start, NULL ); // find the first free sector
}
if(_flash_used_end>0){ // find the used sector if(_flash_used_end>0){ // find the used sector
uint32_t sta1, sec1; sect = flash_find_sector( platform_flash_mapped2phys ( (uint32_t)_flash_used_end - 1), NULL, &end );
sec1 = platform_flash_reserve_section( 0, &sta1 ); if( psect )
NODE_DBG("Flash base: %p %p %p %p\n", sect, start, sec1, sta1); *psect = sect + 1;
return end + 1;
} else {
sect = flash_find_sector( 0, &start, NULL ); // find the first free sector
if( psect )
*psect = sect;
return start;
} }
#endif
sect = _flash_used_end ? platform_flash_reserve_section( 0, &start ) :
flashh_find_sector( 0, &start, NULL );
if( psect )
*psect = sect;
return start;
} }
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size ) uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size )
......
...@@ -116,10 +116,11 @@ bool flash_rom_set_size_type(uint8_t size) ...@@ -116,10 +116,11 @@ bool flash_rom_set_size_type(uint8_t size)
uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR; uint8_t data[SPI_FLASH_SEC_SIZE] ICACHE_STORE_ATTR;
if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE)) if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{ {
((SPIFlashInfo *)(&data[0]))->size = size; NODE_DBG("\nflash_rom_set_size_type(%u), was %u\n", size, ((SPIFlashInfo *)data)->size );
((SPIFlashInfo *)data)->size = size;
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE)) if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
{ {
NODE_DBG("\nERASE SUCCESS\n"); NODE_DBG("\nSECTOR 0 ERASE SUCCESS\n");
} }
if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE)) if (SPI_FLASH_RESULT_OK == spi_flash_write(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{ {
...@@ -266,6 +267,7 @@ bool flash_rom_set_speed(uint32_t speed) ...@@ -266,6 +267,7 @@ bool flash_rom_set_speed(uint32_t speed)
if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE)) if (SPI_FLASH_RESULT_OK == spi_flash_read(0, (uint32 *)data, SPI_FLASH_SEC_SIZE))
{ {
((SPIFlashInfo *)(&data[0]))->speed = speed_type; ((SPIFlashInfo *)(&data[0]))->speed = speed_type;
NODE_DBG("\nflash_rom_set_speed(%u), was %u\n", speed_type, ((SPIFlashInfo *)(&data[0]))->speed );
if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE)) if (SPI_FLASH_RESULT_OK == spi_flash_erase_sector(0 * SPI_FLASH_SEC_SIZE))
{ {
NODE_DBG("\nERASE SUCCESS\n"); NODE_DBG("\nERASE SUCCESS\n");
......
...@@ -879,7 +879,7 @@ uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t siz ...@@ -879,7 +879,7 @@ uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t siz
if(SPI_FLASH_RESULT_OK == r) if(SPI_FLASH_RESULT_OK == r)
return size; return size;
else{ else{
NODE_ERR( "ERROR in flash_write: r=%d at %p\n", ( int )r, ( unsigned )toaddr); NODE_ERR( "ERROR in flash_write: r=%d at %p\n", r, toaddr);
return 0; return 0;
} }
} }
...@@ -917,37 +917,35 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size ) ...@@ -917,37 +917,35 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size )
if(SPI_FLASH_RESULT_OK == r) if(SPI_FLASH_RESULT_OK == r)
return size; return size;
else{ else{
NODE_ERR( "ERROR in flash_read: r=%d at %p\n", ( int )r, ( unsigned )fromaddr); NODE_ERR( "ERROR in flash_read: r=%d at %p\n", r, fromaddr);
return 0; return 0;
} }
} }
int platform_flash_erase_sector( uint32_t sector_id ) int platform_flash_erase_sector( uint32_t sector_id )
{ {
NODE_DBG( "flash_erase_sector(%u)\n", sector_id);
system_soft_wdt_feed (); system_soft_wdt_feed ();
return flash_erase( sector_id ) == SPI_FLASH_RESULT_OK ? PLATFORM_OK : PLATFORM_ERR; return flash_erase( sector_id ) == SPI_FLASH_RESULT_OK ? PLATFORM_OK : PLATFORM_ERR;
} }
static uint32_t flash_map_meg_offset () static uint32_t flash_map_meg_offset (void) {
{
uint32_t cache_ctrl = READ_PERI_REG(CACHE_FLASH_CTRL_REG); uint32_t cache_ctrl = READ_PERI_REG(CACHE_FLASH_CTRL_REG);
if (!(cache_ctrl & CACHE_FLASH_ACTIVE)) if (!(cache_ctrl & CACHE_FLASH_ACTIVE))
return -1; return -1;
bool b0 = (cache_ctrl & CACHE_FLASH_MAPPED0) ? 1 : 0; uint32_t m0 = (cache_ctrl & CACHE_FLASH_MAPPED0) ? 0x100000 : 0;
bool b1 = (cache_ctrl & CACHE_FLASH_MAPPED1) ? 1 : 0; uint32_t m1 = (cache_ctrl & CACHE_FLASH_MAPPED1) ? 0x200000 : 0;
return ((b1 << 1) | b0) * 0x100000; return m0 + m1;
} }
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr) uint32_t platform_flash_mapped2phys (uint32_t mapped_addr) {
{ uint32_t meg = flash_map_meg_offset();
uint32_t meg = flash_map_meg_offset(); return (meg&1) ? -1 : mapped_addr - INTERNAL_FLASH_MAPPED_ADDRESS + meg ;
return (meg&1) ? -1 : mapped_addr - INTERNAL_FLASH_MAPPED_ADDRESS + meg ;
} }
uint32_t platform_flash_phys2mapped (uint32_t phys_addr) uint32_t platform_flash_phys2mapped (uint32_t phys_addr) {
{ uint32_t meg = flash_map_meg_offset();
uint32_t meg = flash_map_meg_offset(); return (meg&1) ? -1 : phys_addr + INTERNAL_FLASH_MAPPED_ADDRESS - meg;
return (meg&1) ? -1 : phys_addr + INTERNAL_FLASH_MAPPED_ADDRESS - meg;
} }
void* platform_print_deprecation_note( const char *msg, const char *time_frame) void* platform_print_deprecation_note( const char *msg, const char *time_frame)
......
...@@ -268,11 +268,8 @@ uint32_t platform_eth_get_elapsed_time(void); ...@@ -268,11 +268,8 @@ uint32_t platform_eth_get_elapsed_time(void);
// ***************************************************************************** // *****************************************************************************
// Internal flash erase/write functions // Internal flash erase/write functions
uint32_t platform_flash_reserve_section( uint32_t regsize, uint32_t *start );
uint32_t platform_flash_get_first_free_block_address( uint32_t *psect ); uint32_t platform_flash_get_first_free_block_address( uint32_t *psect );
uint32_t platform_flash_get_sector_of_address( uint32_t addr ); uint32_t platform_flash_get_sector_of_address( uint32_t addr );
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr);
uint32_t platform_flash_phys2mapped (uint32_t phys_addr);
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size ); uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size );
uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size ); uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size );
uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size ); uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size );
...@@ -282,13 +279,14 @@ int platform_flash_erase_sector( uint32_t sector_id ); ...@@ -282,13 +279,14 @@ int platform_flash_erase_sector( uint32_t sector_id );
/** /**
* Translated a mapped address to a physical flash address, based on the * Translated a mapped address to a physical flash address, based on the
* current flash cache mapping. * current flash cache mapping, and v.v.
* @param mapped_addr Address to translate (>= INTERNAL_FLASH_MAPPED_ADDRESS) * @param mapped_addr Address to translate (>= INTERNAL_FLASH_MAPPED_ADDRESS)
* @return the corresponding physical flash address, or -1 if flash cache is * @return the corresponding physical flash address, or -1 if flash cache is
* not currently active. * not currently active.
* @see Cache_Read_Enable. * @see Cache_Read_Enable.
*/ */
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr); uint32_t platform_flash_mapped2phys (uint32_t mapped_addr);
uint32_t platform_flash_phys2mapped (uint32_t phys_addr);
// ***************************************************************************** // *****************************************************************************
// Allocator support // Allocator support
......
...@@ -129,8 +129,7 @@ bool user_process_input(bool force) { ...@@ -129,8 +129,7 @@ bool user_process_input(bool force) {
return task_post_low(input_sig, force); return task_post_low(input_sig, force);
} }
void nodemcu_init(void) void nodemcu_init(void) {
{
NODE_ERR("\n"); NODE_ERR("\n");
// Initialize platform first for lua modules. // Initialize platform first for lua modules.
if( platform_init() != PLATFORM_OK ) if( platform_init() != PLATFORM_OK )
...@@ -139,11 +138,13 @@ void nodemcu_init(void) ...@@ -139,11 +138,13 @@ void nodemcu_init(void)
NODE_DBG("Can not init platform for modules.\n"); NODE_DBG("Can not init platform for modules.\n");
return; return;
} }
uint32_t size_detected = flash_detect_size_byte();
if( flash_detect_size_byte() != flash_rom_get_size_byte() ) { uint32_t size_from_rom = flash_rom_get_size_byte();
NODE_ERR("Self adjust flash size.\n"); if( size_detected != size_from_rom ) {
NODE_ERR("Self adjust flash size. 0x%x (ROM) -> 0x%x (Detected)\n",
size_from_rom, size_detected);
// Fit hardware real flash size. // Fit hardware real flash size.
flash_rom_set_size_byte(flash_detect_size_byte()); flash_rom_set_size_byte(size_detected);
system_restart (); system_restart ();
// Don't post the start_lua task, we're about to reboot... // Don't post the start_lua task, we're about to reboot...
...@@ -240,7 +241,6 @@ user_rf_cal_sector_set(void) ...@@ -240,7 +241,6 @@ user_rf_cal_sector_set(void)
return rf_cal_sec; return rf_cal_sec;
} }
extern void luaN_user_init(void);
/****************************************************************************** /******************************************************************************
* FunctionName : user_init * FunctionName : user_init
* Description : entry of user application, init user function here * Description : entry of user application, init user function here
...@@ -261,10 +261,5 @@ void user_init(void) ...@@ -261,10 +261,5 @@ void user_init(void)
#ifndef NODE_DEBUG #ifndef NODE_DEBUG
system_set_os_print(0); system_set_os_print(0);
#endif #endif
#ifdef LUA_FLASH_STORE
luaN_user_init();
#endif
system_init_done_cb(nodemcu_init); system_init_done_cb(nodemcu_init);
} }
## Lua Compact Debug (LCD)
LCD (Lua Compact Debug) was developed in Sept 2015 by Terry Ellison as a patch to the Lua system to decrease the RAM usage of Lua scripts. This makes it possible to run larger Lua scripts on systems with limited RAM. Its use is most typically for eLua-type applications, and in this version it targets the **NodeMCU** implementation for the ESP8266 chipsets.
This section gives a full description of LCD. If you are writing **NodeMCU** Lua modules, then this paper will be of interest to you, as it shows how to use LCD in an easy to configure way. *Note that the default `user_config.h` has enabled LCD at a level 2 stripdebug since mid-2016*.
### Motivation
The main issue that led me to write this patch is the relatively high Lua memory consumption of its embedded debug information, as this typically results in a 60% memory increase for most Lua code. This information is generated when any Lua source is complied because the Lua parser uses this as meta information during the compilation process. It is then retained by default for use in generating debug information. The only standard method of removing this information is to use the “strip” option when precompiling source using a standard eLua **luac.cross** on the host, or (in the case of NodeMCU) using the `node.compile()` function on the target environment.
Most application developers that are new to embedded development simply live with this overhead, because either they aren't familiar with these advanced techniques, or they want to keep the source line information in error messages for debugging.
The standard Lua compiler generates fixed 4 byte instructions which are interpreted by the Lua VM during execution. The debug information consists of a map from instruction count to source line number (4 bytes per instruction) and two tables keyed by the names of each local and upvalue. These tables contain metadata on these variables used in the function. This information can be accessed to enable symbolic debugging of Lua source (which isn't supported on **NodeMCU** platforms anyway), and the line number information is also used to generate error messages.
This overhead is sufficient large on limited RAM systems to replace this scheme by making two changes which optimize for space rather than time:
- The encoding scheme used in this patch typically uses 1 byte per source line instead of 4 bytes per instruction, and this represents a 10 to 20-fold reduction in the size of this vector. The access time during compile is still **O(1)**, and **O(N)** during runtime error handling, where **N** is number of non-blank lines in the function. In practice this might add a few microseconds to the time take to generate the error message for typical embedded functions.
- The line number, local and upvalue information is needed during the compilation of a given compilation unit (a source file or source string), but its only use after this is for debugging and so can be discarded. (This is what the `luac -s` option and `node.compile()` do). The line number information if available is used in error reporting. An extra API call has therefore been added to discarded this debug information on completion of the compilation.
To minimise the impact within the C source code for the Lua system, an extra system define **LUA_OPTIMIZE_DEBUG** can be set in the `user_config.h` file to configure a given firmware build. This define sets the default value for all compiles and can take one of four values:
1. (or not defined) use the default Lua scheme.
2. Use compact line encoding scheme and retain all debug information.
3. Use compact line encoding scheme and only retain line number debug information.
4. Discard all debug information on completion of compile.
Building the firmware with the 0 option compiles to the pre-patch version. Options 1-3 generate the `strip_debug()` function, which allows this default value to be set at runtime.
_Note that options 2 and 3 can also change the default behaviour of the `loadstring()` function in that any functions declared within the string cannot inherited any outer locals within the parent hierarchy as upvalues if these have been stripped of the locals and upvalues information._
### Details
There are various API calls which compile and load Lua source code. During compilation each variable name is parsed, and is then resolved in the following order:
- Against the list of local variables declared so far in the current scope is scanned for a match.
- Against the local variable lists for each of the lexically parent functions are then scanned for a match, and if found the variable is tagged as an _upvalue_.
- If unmatched against either of these local scopes then the variable defaults to being a global reference.
The parser and code generator must therefore access the line mapping, upvalues, and locals information tables maintained in each function Prototype header during source compilation. This scoping scheme works because function compilation is recursive: if function A contains the definition of function B which contains the definition of function C, then the compilation of A is paused to compile B and this is in turn paused to compile C; then B complete and then A completes.
The variable meta information is stored in standard Lua tables which are allocated using the standard Lua doubling algorithm and hence they can contain a lot of unused space. The parser therefore calls `close_func()` once compilation of a function has been completed to trim these vectors to the final sizes.
The patch makes the following if `LUA_OPTIMIZE_DEBUG` > 0. (The existing functionality is preserved if this define is zero or undefined.)
- It adds an extra API call: `stripdebug([level[, function]])` as discussed below.
- It extends the trim logic in `close_func()` to replace this trim action by deleting the information according to the current default debug optimization level.
- The `lineinfo` vector associated with each function is replaced by a `packedlineinfo` string using a run length encoding scheme that uses a repeat of an optional line number delta (this is omitted if the line offset is zero) and a count of the number of instruction generated for that source line. This scheme uses roughly an **M** byte vector where **M** is the number of non-blank source lines, as opposed to a **4N** byte vector where **N** is the number of VM instruction. This vector is built sequentially during code generation so it is this patch conditionally replaces the current map with an algorithm to generate the packed version on the fly.
The `stripdebug([level[, function]])` call is processed as follows:
- If both arguments are omitted then the function returns the current default strip level.
- If the function parameter is omitted, then the level is used as the default setting for future compiles. The level must be 1-3 corresponding to the above debug optimization settings. Hence if `stripdebug(3)` is included in **init.lua**, then all debug information will be stripped out of subsequently compiled functions.
- The function parameter if present is parsed in the same way as the function argument in `setfenv()` (except that the integer 0 level is not permitted, and this function tree corresponding to this scope is walked to implement this debug optimization level.
The `packedlineinfo` encoding scheme is as follows:
- It comprises a repeat of (optional) line delta + VM instruction count (IC) for that line starting from a base line number of zero. The line deltas are optional because line deltas of +1 are assumed as default and therefore not emitted.
- ICs are stored as a single byte with the high bit set to zero. Sequences longer than 126 instructions for a single sequence are rare, but can be are encoded using a multi byte sequence using 0 line deltas, e.g. 126 (0) 24 for a line generating 150 VM instructions. The high bit is always unset, and note that this scheme reserves the code 0x7F as discussed below.
- Line deltas are stored with the high bit set and are variable (little-endian) in length. Since deltas are always delimited by an IC which has the top bit unset, the length of each delta can be determined from these delimiters. Deltas are stored as signed ones-compliment with the sign bit in the second bit of low order byte, that is in the format (in binary) `1snnnnnnn [1nnnnnnn]*`, with `s` denoting the sign and `n…n` the value element using the following map. This means that a single byte is used encode line deltas in the range -63 … 65; two bytes used to encode line deltas in the range -8191 … 8193, etc..
```C
value = (sign == 1) ? -delta : delta - 2
```
- This approach has no arbitrary limits, in that it can accommodate any line delta or IC count. Though in practice, most deltas are omitted and multi-byte sequences are rarely generated.
- The codes 0x00 and 0x7F are reserved in this scheme. This is because Lua allocates such growing vectors on a size-doubling basis. The line info vector is always null terminated so that the standard **strlen()** function can be used to determine its length. Any unused bytes between the last IC and the terminating null are filled with 0x7F.
The current mapping scheme has **O(1)** access, but with a code-space overhead of some 140%. This alternative approach has been designed to be space optimized rather than time optimized. It requires the actual IC to line number map to be computed by linearly enumerating the string from the low instruction end during execution, resulting in an **O(N)** access cost, where **N** is the number of bytes in the encoded vector. However, code generation builds this information incrementally, and so only appends to it (or occasionally updates the last element's line number), and the patch adds a couple of fields to the parser `FuncState` record to enable efficient **O(1)** access during compilation.
### Testing
Essentially testing any eLua compiler or runtime changes are a total pain, because eLua is designed to be build against a **newlib**-based ELF. Newlib uses a stripped down set of headers and libraries that are intended for embedded use (rather than being ran over a standard operating system). Gdb support is effectively non-existent, so I found it just easier first to develop this code on a standard Lua build running under Linux (and therefore with full gdb support), and then port the patch to NodeMCU once tested and working.
I tested my patch in standard Lua built with "make generic" and against the [Lua 5.1 suite](http://lua-users.org/lists/lua-l/2006-03/msg00723.html). The test suite was an excellent testing tool, and it revealed a number of cases that exposed logic flaws in my approach, resulting from Lua's approach of not carrying out inline status testing by instead implementing a throw / catch strategy. In fact I realised that I had to redesign the vector generation algorithm to handle this robustly.
As with all eLua builds the patch assumes Lua will not be executing in a multithreaded environment with OS threads running different lua_States. (This is also the case for the NodeMCU firmware). It executes the full test suite cleanly as maximum test levels and I also added some specific tests to cover new **stripdebug** usecases.
Once this testing was completed, I then ported the patch to the NodeMCU build. This was pretty straight forward as this code is essentially independent of the NodeMCU functional changes. The only real issue as to ensure that the NodeMCU `c_strlen()` calls replaced the standard `strlen()`, etc.
I then built both `luac.cross` and firmware images with the patch disable to ensure binary compatibility with the non-patched version and then with the patch enabled at optimization level 3.
In use there is little noticeable difference other than the code size during development are pretty much the same as when running with `node.compile()` stripped code. The new option 2 (retaining packed line info only) has such a minimal size impact that its worth using this all the time. I've also added a separate patch to NodeMCU (which this assumes) so that errors now generate a full traceback.
### How to enable LCD
Enabling LCD is simple: all you need is a patched version and define `LUA_OPTIMIZE_DEBUG` at the default level that you want in `app/include/user_config.h` and do a normal make.
Without this define enabled, the unpatched version is generated.
Note that since `node.compile()` strips all debug information, old **.lc** files generated by this command will still run under the patched firmware, but binary files which retain debug information will not work across patched and non-patched versions.
Other than optionally including a `node.stripdebug(N)` or whatever in your **init.lua**, the patch is otherwise transparent at an application level.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment