Commit 17df207a authored by Johny Mattsson's avatar Johny Mattsson
Browse files

Port Terry's Lua 5.1 + 5.3 work from the esp8266 branch.

Changes have been kept to a minimum, but a serious chunk of work was
needed to move from 8266isms to IDFisms.

Some things got refactored into components/lua/common, in particular
the LFS location awareness.

As part of this work I also evicted our partition table manipulation
code, as with the current IDF it kept breaking checksums and rendering
things unbootable, which is the opposite of helpful (which was the
original intent behind it).

The uart module got relocated from base_nodemcu to the modules component
properly, after I worked out how to force its inclusion using Kconfig alone.
parent f123d462
......@@ -7,9 +7,9 @@ jobs:
build:
strategy:
matrix:
lua_ver: ['5.1']
numbers: ['float','integral']
target: ['esp32','esp32c3']
lua_ver: ['5.1', '5.3']
numbers: ['default', 'alternate']
target: ['esp32', 'esp32c3']
runs-on: ubuntu-latest
......@@ -28,19 +28,27 @@ jobs:
- name: Install dependencies
run: ./install.sh
shell: bash
- name: Build firmware (Lua 5.1)
if: ${{ matrix.lua_ver == '5.1' && matrix.numbers == 'float' }}
- name: Build firmware (default configuration)
if: ${{ matrix.numbers == 'default' }}
run: |
cp sdkconfig.defaults sdkconfig
make IDF_TARGET=${{ matrix.target }}
shell: bash
- name: Build firmware (Lua 5.1, integer-only)
if: ${{ matrix.lua_ver == '5.1' && matrix.numbers == 'integral' }}
if: ${{ matrix.lua_ver == '5.1' && matrix.numbers == 'alternate' }}
run: |
cp sdkconfig.defaults sdkconfig
echo CONFIG_LUA_NUMBER_INTEGRAL=y >> sdkconfig
make IDF_TARGET=${{ matrix.target }}
shell: bash
- name: Build firmware (Lua 5.3, 64bit int/double)
if: ${{ matrix.lua_ver == '5.3' && matrix.numbers == 'alternate' }}
run: |
cp sdkconfig.defaults sdkconfig
echo CONFIG_LUA_NUMBER_INT64=y >> sdkconfig
echo CONFIG_LUA_NUMBER_DOUBLE=y >> sdkconfig
make IDF_TARGET=${{ matrix.target }}
shell: bash
- name: Upload luac.cross
uses: actions/upload-artifact@v2
if: ${{ success() }}
......
idf_component_register(
SRCS "ip_fmt.c" "lextra.c" "linit.c" "lnodeaux.c" "uart.c" "user_main.c"
SRCS "ip_fmt.c" "user_main.c"
INCLUDE_DIRS "include"
REQUIRES "lua"
PRIV_REQUIRES "nvs_flash"
LDFRAGMENTS "nodemcu.lf"
)
target_compile_options(${COMPONENT_LIB} PRIVATE -DCONFIG_NODEMCU_CMODULE_UART)
target_link_libraries(${COMPONENT_LIB}
"-u UART_module_selected1"
"-u lua_rotables_part_map"
"-Wl,-defsym=lua_rotables_map=_lua_rotables_map_start"
"-Wl,-defsym=lua_libs_map=_lua_libs_map_start"
)
#ifndef __MODULE_H__
#define __MODULE_H__
#include "sdkconfig.h"
#include "lrotable.h"
#include "lnodemcu.h"
/* Registering a module within NodeMCU is really easy these days!
*
......@@ -18,11 +17,11 @@
*
* Then simply put a line like this at the bottom of your module file:
*
* NODEMCU_MODULE(MYNAME, "myname", myname_map, luaopen_myname);
* NODEMCU_MODULE(MYNAME, "myname", myname, luaopen_myname);
*
* or perhaps
*
* NODEMCU_MODULE(MYNAME, "myname", myname_map, NULL);
* NODEMCU_MODULE(MYNAME, "myname", myname, NULL);
*
* if you don't need an init function.
*
......@@ -36,23 +35,6 @@
#define MODULE_PASTE_(x,y) x##y
#define MODULE_EXPAND_PASTE_(x,y) MODULE_PASTE_(x,y)
#ifdef LUA_CROSS_COMPILER
#ifdef _MSC_VER
//on msvc it is necessary to go through more pre-processor hoops to get the
//section name built; string merging does not happen in the _declspecs.
//NOTE: linker magic is invoked via the magical '$' character. Caveat editor.
#define __TOKIFY(s) .rodata1$##s
#define __TOTOK(s) __TOKIFY(s)
#define __STRINGIFY(x) #x
#define __TOSTRING(x) __STRINGIFY(x)
#define __ROSECNAME(s) __TOSTRING(__TOTOK(s))
#define LOCK_IN_SECTION(s) __declspec ( allocate( __ROSECNAME(s) ) )
#else
#define LOCK_IN_SECTION(s) __attribute__((used,unused,section(".rodata1." #s)))
#endif
#else
#define LOCK_IN_SECTION(s) __attribute__((used,unused,section(".lua_" #s)))
#endif
/* For the ROM table, we name the variable according to ( | denotes concat):
* cfgname | _module_selected | CONFIG_NODEMCU_CMODULE_##cfgname
* where the CONFIG_NODEMCU_CMODULE_XYZ macro is first expanded to yield either
......@@ -65,10 +47,10 @@
*/
#define NODEMCU_MODULE(cfgname, luaname, map, initfunc) \
const LOCK_IN_SECTION(libs) \
luaR_entry MODULE_PASTE_(lua_lib_,cfgname) = { luaname, LRO_FUNCVAL(initfunc) }; \
ROTable_entry MODULE_PASTE_(lua_lib_,cfgname) = { luaname, LRO_FUNCVAL(initfunc) }; \
const LOCK_IN_SECTION(rotable) \
luaR_entry MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(CONFIG_NODEMCU_CMODULE_,cfgname))) \
= {luaname, LRO_ROVAL(map ## _map)}
ROTable_entry MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(CONFIG_NODEMCU_CMODULE_,cfgname))) \
= {luaname, LRO_ROVAL(map)}
#endif
......@@ -89,6 +71,6 @@
// NODEMCU_MODULE_STD() defines the entry points for an external module:
#define NODEMCU_MODULE_STD() \
static const LOCK_IN_SECTION(libs) \
luaR_entry lua_lib_module = {MODNAME, LRO_FUNCVAL(module_init)}; \
const LOCK_IN_SECTION(rotable) \
luaR_entry MODULE_EXPAND_PASTE_(EXTMODNAME, _entry) = {MODNAME, LRO_ROVAL(module_map)};
ROTable_entry lua_lib_module = {MODNAME, LRO_FUNCVAL(module_init)}; \
const const LOCK_IN_SECTION(rotable) \
ROTable_entry MODULE_EXPAND_PASTE_(EXTMODNAME, _entry) = {MODNAME, LRO_ROVAL(module_map)};
/*
** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $
** Initialization of libraries for lua.c
** See Copyright Notice in lua.h
*/
#define linit_c
#define LUA_LIB
#define LUAC_CROSS_FILE
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luaconf.h"
#include "module.h"
#include "lstate.h"
#include "lrotable.h"
#include <assert.h>
#include <stdalign.h>
LROT_EXTERN(strlib);
LROT_EXTERN(tab_funcs);
LROT_EXTERN(dblib);
LROT_EXTERN(co_funcs);
LROT_EXTERN(math);
#if defined(LUA_CROSS_COMPILER)
LROT_EXTERN(oslib);
//LROT_EXTERN(iolib);
#endif
/*
* The NodeMCU Lua initalisation has been adapted to use linker-based module
* registration. This uses a PSECT naming convention to allow the ROTable and
* initialisation function entries to be collected by the linker into two
* consoliated ROTables. This significantly simplifies adding new modules and
* configuring builds with a small subset of the total modules.
*
* This linker-based approach is not practical for cross compiler builds which
* must link on a range of platforms, and where we don't have control of PSECT
* placement. However unlike the target builds, the luac.cross builds only
* used a small and fixed list of libraries and so in this case the table can
* be defined in this source file, so in this case all library ROTables are
* defined here, avoiding the need for linker magic is avoided on host builds.
*
* Note that a separate ROTable is defined in lbaselib.c for the base functions
* and there is a metatable index cascade from _G to this base function table to
* the master rotables table. In the target build, the linker marshals the
* table, hence the LROT_BREAK() macros which don't 0 terminate the lists.
*/
#ifdef _MSC_VER
//MSVC requires us to declare these sections before we refer to them
#pragma section(__ROSECNAME(A), read)
#pragma section(__ROSECNAME(zzzzzzzz), read)
#pragma section(__ROSECNAME(libs), read)
#pragma section(__ROSECNAME(rotable), read)
//These help us to find the beginning and ending of the RO data. NOTE: linker
//magic is used; the section names are lexically sorted, so 'a' and 'z' are
//important to keep the other sections lexically between these two dummy
//variables. Check your mapfile output if you need to fiddle with this stuff.
const LOCK_IN_SECTION(A) char _ro_start[1] = {0};
const LOCK_IN_SECTION(zzzzzzzz) char _ro_end[1] = {0};
#endif
#if defined(LUA_CROSS_COMPILER)
LROT_PUBLIC_BEGIN(LOCK_IN_SECTION(rotable) lua_rotables)
LROT_TABENTRY( string, strlib )
LROT_TABENTRY( table, tab_funcs )
LROT_TABENTRY( coroutine, co_funcs )
LROT_TABENTRY( debug, dblib)
LROT_TABENTRY( math, math )
LROT_TABENTRY( ROM, lua_rotables )
LROT_TABENTRY( os, oslib )
//LROT_TABENTRY( io, iolib )
LROT_END(lua_rotables, NULL, 0)
#else
// Due to limitations in the IDF linker fragment generation, we have to
// play with link-time symbol generation/aliasing to set up the rotables
// properly. As part of that, we need to use a different name for the
// table here.
LROT_PUBLIC_BEGIN(LOCK_IN_SECTION(rotable) lua_rotables_part)
#ifdef CONFIG_LUA_BUILTIN_STRING
LROT_TABENTRY( string, strlib )
#endif
#ifdef CONFIG_LUA_BUILTIN_TABLE
LROT_TABENTRY( table, tab_funcs )
#endif
#ifdef CONFIG_LUA_BUILTIN_COROUTINE
LROT_TABENTRY( coroutine, co_funcs )
#endif
#ifdef CONFIG_LUA_BUILTIN_DEBUG
LROT_TABENTRY( debug, dblib)
#endif
#ifdef CONFIG_LUA_BUILTIN_MATH
LROT_TABENTRY( math, math )
#endif
LROT_TABENTRY( ROM, lua_rotables_part )
LROT_BREAK(lua_rotables_part)
#endif
LROT_PUBLIC_BEGIN(LOCK_IN_SECTION(libs) lua_libs)
LROT_FUNCENTRY( _, luaopen_base )
LROT_FUNCENTRY( package, luaopen_package )
#ifdef CONFIG_LUA_BUILTIN_STRING
LROT_FUNCENTRY( string, luaopen_string )
#endif
#ifdef CONFIG_LUA_BUILTIN_TABLE
LROT_FUNCENTRY( table, luaopen_table )
#endif
#ifdef CONFIG_LUA_BUILTIN_DEBUG
LROT_FUNCENTRY( debug, luaopen_debug )
#endif
#ifndef LUA_CROSS_COMPILER
LROT_BREAK(lua_libs)
#else
LROT_FUNCENTRY( io, luaopen_io )
LROT_END( lua_libs, NULL, 0)
#endif
#ifndef LUA_CROSS_COMPILER
extern void luaL_dbgbreak(void);
#endif
/* Historically the linker script took care of zero terminating both the
* lua_libs and lua_rotable arrays, but the IDF currently does not
* support injecting LONG(0) entries. To compensate, we have explicit
* end markers here which the linker fragment then place appropriately
* to terminate aforementioned arrays.
*/
const luaR_entry LOCK_IN_SECTION(libs_end_marker) libs_end_marker= { 0, };
const luaR_entry LOCK_IN_SECTION(rotable_end_marker) rotable_end_marker = { 0, };
void luaL_openlibs (lua_State *L) {
lua_pushrotable(L, LROT_TABLEREF(lua_libs));
lua_pushnil(L); /* first key */
/* loop round and open libraries */
#ifndef LUA_CROSS_COMPILER
// luaL_dbgbreak(); // This is a test point for debugging library start ups
#endif
while (lua_next(L, -2) != 0) {
if (lua_islightfunction(L,-1) &&
fvalue(L->top-1)) { // only process function entries
lua_pushvalue(L, -2);
lua_call(L, 1, 0); // call luaopen_XXX(libname)
} else {
lua_pop(L, 1);
}
}
lua_pop(L, 1); //cleanup stack
}
#ifndef LUA_CROSS_COMPILER
# ifdef LUA_NUMBER_INTEGRAL
# define COMPARE <=
# else
# define COMPARE ==
# endif
_Static_assert(_Alignof(luaR_entry) COMPARE 8, "Unexpected alignment of module registration - update the linker script snippets to match!");
_Static_assert(sizeof(luaR_entry) COMPARE 24, "Unexpect size of array member - update the linker script snippets to match!");
#endif
[sections:lua_libs]
entries:
.lua_libs
[sections:lua_libs_end_marker]
entries:
.lua_libs_end_marker
[sections:lua_rotable]
entries:
.lua_rotable
[sections:lua_rotable_end_marker]
entries:
.lua_rotable_end_marker
[sections:lua_esp_event_cb_table]
entries:
.lua_esp_event_cb_table
[scheme:nodemcu_arrays]
entries:
lua_libs -> flash_rodata
lua_libs_end_marker -> flash_rodata
lua_rotable -> flash_rodata
lua_rotable_end_marker -> flash_rodata
lua_esp_event_cb_table -> flash_rodata
# Important: don't change the alignments below without also updating the
# _Static_assert over in linit.c and/or nodemcu_esp_event.h!
# _Static_assert over in nodemcu_esp_event.h!
[mapping:nodemcu]
archive: *
entries:
* (nodemcu_arrays);
lua_libs -> flash_rodata KEEP() ALIGN(8) SURROUND(lua_libs_map),
lua_libs_end_marker -> flash_rodata KEEP(),
lua_rotable -> flash_rodata ALIGN(8) SURROUND(lua_rotables_map),
lua_rotable_end_marker -> flash_rodata KEEP(),
lua_esp_event_cb_table -> flash_rodata KEEP() ALIGN(4) SURROUND(esp_event_cb_table)
......@@ -9,6 +9,7 @@
* 2014/1/1, v1.0 create this file.
*******************************************************************************/
#include "lua.h"
#include "linput.h"
#include "platform.h"
#include <string.h>
#include <stdlib.h>
......@@ -93,14 +94,13 @@ static void handle_default_loop_event(task_param_t param, task_prio_t prio)
// +================== New task interface ==================+
static void start_lua ()
{
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
NODE_DBG("Task task_lua started.\n");
lua_main( 2, lua_argv );
lua_main();
}
static void handle_input(task_param_t flag, task_prio_t priority) {
(void)priority;
lua_handle_input (flag);
(void)flag; (void)priority;
lua_handle_input();
}
static task_handle_t input_task;
......
if(CONFIG_LUA_VERSION_51)
set(srcs
"lua-5.1/lapi.c"
"lua-5.1/lauxlib.c"
"lua-5.1/lbaselib.c"
"lua-5.1/lcode.c"
"lua-5.1/ldblib.c"
"lua-5.1/ldebug.c"
"lua-5.1/ldo.c"
"lua-5.1/ldump.c"
"lua-5.1/lflash.c"
"lua-5.1/lfunc.c"
"lua-5.1/lgc.c"
"lua-5.1/llex.c"
"lua-5.1/lmathlib.c"
"lua-5.1/lmem.c"
"lua-5.1/lnodemcu.c"
"lua-5.1/loadlib.c"
"lua-5.1/lobject.c"
"lua-5.1/lopcodes.c"
"lua-5.1/lparser.c"
"lua-5.1/lstate.c"
"lua-5.1/lstring.c"
"lua-5.1/lstrlib.c"
"lua-5.1/ltable.c"
"lua-5.1/ltablib.c"
"lua-5.1/ltm.c"
"lua-5.1/lua.c"
"lua-5.1/lundump.c"
"lua-5.1/lvm.c"
"lua-5.1/lzio.c"
)
set(luadir "lua-5.1")
elseif(CONFIG_LUA_VERSION_53)
set(srcs
"lua-5.3/lapi.c"
"lua-5.3/lauxlib.c"
"lua-5.3/lbaselib.c"
"lua-5.3/lbitlib.c"
"lua-5.3/lcode.c"
"lua-5.3/lcorolib.c"
"lua-5.3/lctype.c"
"lua-5.3/ldblib.c"
"lua-5.3/ldebug.c"
"lua-5.3/ldo.c"
"lua-5.3/ldump.c"
"lua-5.3/lfunc.c"
"lua-5.3/lgc.c"
"lua-5.3/llex.c"
"lua-5.3/lmathlib.c"
"lua-5.3/lmem.c"
"lua-5.3/lnodemcu.c"
"lua-5.3/loadlib.c"
"lua-5.3/lobject.c"
"lua-5.3/lopcodes.c"
"lua-5.3/lparser.c"
"lua-5.3/lstate.c"
"lua-5.3/lstring.c"
"lua-5.3/lstrlib.c"
"lua-5.3/ltable.c"
"lua-5.3/ltablib.c"
"lua-5.3/ltm.c"
"lua-5.3/lua.c"
"lua-5.3/lundump.c"
"lua-5.3/lutf8lib.c"
"lua-5.3/lvm.c"
"lua-5.3/lzio.c"
)
set(luadir "lua-5.3")
endif()
set(common_srcs
"common/lextra.c"
"common/lfs.c"
"common/linput.c"
"common/linit.c"
"common/lnodeaux.c"
"common/lpanic.c"
)
idf_component_register(
SRCS "lapi.c" "lauxlib.c" "lbaselib.c" "lcode.c" "ldblib.c" "ldebug.c"
"ldo.c" "ldump.c" "legc.c" "lflash.c" "lfunc.c" "lgc.c" "llex.c" "lmathlib.c"
"lmem.c" "loadlib.c" "lobject.c" "lopcodes.c" "lparser.c" "lrotable.c"
"lstate.c" "lstring.c" "lstrlib.c" "ltable.c" "ltablib.c" "ltm.c"
"lua.c" "lundump.c" "lvm.c" "lzio.c"
INCLUDE_DIRS "."
REQUIRES "platform" "uzlib" "driver_console"
SRCS ${srcs} ${common_srcs}
INCLUDE_DIRS ${luadir} "common"
REQUIRES "platform" "nvs_flash" "uzlib" "driver_console"
PRIV_REQUIRES "base_nodemcu" "embedded_lfs"
LDFRAGMENTS "link_lua.lf"
)
#
# Cross compiler targets
#
# Not sure why we can't directly depend on ${SDKCONFIG_HEADER} in our
# externalproject_add(), but them's the brakes...
set(luac_build_dir "${BUILD_DIR}/luac_cross")
add_custom_command(
OUTPUT sdkconfig.h
COMMAND mkdir -p "${luac_build_dir}" && cp ${SDKCONFIG_HEADER} ${luac_build_dir}/sdkconfig.h
DEPENDS ${SDKCONFIG_HEADER}
VERBATIM
)
add_custom_target(sdkconfig_h DEPENDS sdkconfig.h)
externalproject_add(luac_cross_build
PREFIX ${luac_build_dir}
SOURCE_DIR ${COMPONENT_DIR}/${luadir}/host
CONFIGURE_COMMAND ""
BUILD_COMMAND make -f ${COMPONENT_DIR}/${luadir}/host/idf.mk LUAC_BUILD_DIR=${luac_build_dir} LUA_PATH=${COMPONENT_DIR}/${luadir} PYTHON=${PYTHON}
INSTALL_COMMAND ""
BUILD_ALWAYS 1
DEPENDS sdkconfig_h
)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
"${BUILD_DIR}/luac_cross/luac.cross;${BUILD_DIR}/luac_cross/${luadir}" )
menu "Lua configuration"
choice LUA_VERSION
prompt "Lua version"
default LUA_VERSION_51
help
The version of Lua interpreter to use.
config LUA_VERSION_51
bool "Lua 5.1"
config LUA_VERSION_53
bool "Lua 5.3"
endchoice
config LUA_NUMBER_INTEGRAL
depends on LUA_VERSION_51
bool "Integer-only build"
default "n"
help
Build Lua without support for floating point numbers.
Not generally recommended, but can save on code size.
config LUA_NUMBER_INT64
depends on LUA_VERSION_53
bool "Use 64bit integers"
default "n"
help
Build Lua with 64bit integers. This provides a greater value
range, but at the expense of extra memory usage and somewhat
reduced performance over the default 32bit integers.
config LUA_NUMBER_DOUBLE
depends on LUA_VERSION_53
bool "Use double precision floating point"
default "n"
help
Build Lua with double floating point precision. This provides
a greater value range, but at the expense of extra memory
usage and somewhat reduced performance over the default
single precision floating point.
menu "Core Lua modules"
config LUA_BUILTIN_STRING
......@@ -33,6 +67,13 @@ menu "Lua configuration"
help
Includes the math module (recommended).
config LUA_BUILTIN_UTF8
depends on !LUA_VERSION_51
bool "UTF8 module"
default "y"
help
Includes the debug module.
config LUA_BUILTIN_DEBUG
bool "Debug module"
default "n"
......@@ -78,4 +119,10 @@ menu "Lua configuration"
endmenu
config LUA_REQUIRED_MODULES
bool
default y
select NODEMCU_CMODULE_PIPE
select NODEMCU_CMODULE_UART
endmenu
#include "lfs.h"
#include "esp_partition.h"
#include "nvs_flash.h"
#include "platform.h"
#if defined(CONFIG_NODEMCU_EMBEDDED_LFS_SIZE)
// Symbol provided by embedded_lfs component
extern const char lua_flash_store_reserved[0];
#endif
bool lfs_get_location(lfs_location_info_t *out)
{
#if defined(CONFIG_NODEMCU_EMBEDDED_LFS_SIZE)
out->size = CONFIG_NODEMCU_EMBEDDED_LFS_SIZE;
out->addr_mem = lua_flash_store_reserved;
out->addr_phys = spi_flash_cache2phys(lua_flash_store_reserved);
if (out->addr_phys == SPI_FLASH_CACHE2PHYS_FAIL) {
NODE_ERR("spi_flash_cache2phys failed\n");
return false;
}
else
return true;
#else
const esp_partition_t *part = esp_partition_find_first(
PLATFORM_PARTITION_TYPE_NODEMCU,
PLATFORM_PARTITION_SUBTYPE_NODEMCU_LFS,
NULL);
if (!part)
return false; // Nothing to do if no LFS partition available
out->size = part->size; // in bytes
out->addr_mem = spi_flash_phys2cache(out->addr_phys, SPI_FLASH_MMAP_DATA);
out->addr_phys = part->address;
if (!out->addr_mem) { // not already mmap'd, have to do it ourselves
spi_flash_mmap_handle_t ignored;
esp_err_t err = spi_flash_mmap(
out->addr_phys, out->size, SPI_FLASH_MMAP_DATA, &out->addr_mem, &ignored);
if (err != ESP_OK) {
NODE_ERR("Unable to access LFS partition - is it 64kB aligned as it needs to be?\n");
return false;
}
}
return true;
#endif
}
#define LFS_LOAD_NS "lfsload"
#define LFS_LOAD_FILE_KEY "filename"
bool lfs_get_load_filename(char *buf, size_t bufsiz)
{
bool res = false;
nvs_handle_t handle;
esp_err_t err = nvs_open(LFS_LOAD_NS, NVS_READONLY, &handle);
if (err != ESP_OK)
goto out;
err = nvs_get_str(handle, LFS_LOAD_FILE_KEY, buf, &bufsiz);
if (err != ESP_OK)
goto close_out;
res = true;
close_out:
nvs_close(handle);
out:
return res;
}
bool lfs_set_load_filename(const char *fname)
{
bool res = false;
nvs_handle_t handle;
esp_err_t err = nvs_open(LFS_LOAD_NS, NVS_READWRITE, &handle);
if (err != ESP_OK)
goto out;
err = nvs_set_str(handle, LFS_LOAD_FILE_KEY, fname);
if (err != ESP_OK)
goto close_out;
res = true;
close_out:
nvs_close(handle);
out:
return res;
}
bool lfs_clear_load_filename(void)
{
bool res = false;
nvs_handle_t handle;
esp_err_t err = nvs_open(LFS_LOAD_NS, NVS_READWRITE, &handle);
if (err != ESP_OK)
goto out;
err = nvs_erase_key(handle, LFS_LOAD_FILE_KEY);
if (err != ESP_OK)
goto close_out;
res = true;
close_out:
nvs_close(handle);
out:
return res;
}
#ifndef _LFS_H_
#define _LFS_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
typedef struct {
uint32_t size;
uint32_t addr_phys; // physical address in flash
const void *addr_mem; // memory mapped address
} lfs_location_info_t;
bool lfs_get_location(lfs_location_info_t *out);
// Setting & getting of filename during reboot/load cycle
bool lfs_get_load_filename(char *buf, size_t bufsiz);
bool lfs_set_load_filename(const char *fname);
bool lfs_clear_load_filename(void);
#endif
/*
** $Id: linit.c,v 1.14.1.1 2007/12/27 13:02:25 roberto Exp $
** Initialization of libraries for lua.c
** See Copyright Notice in lua.h
*/
#define linit_c
#define LUA_LIB
#define LUA_CORE
/*
** NodeMCU uses RO segment based static ROTable declarations for all library
** tables, including the index of library tables itself (the ROM table). These
** tables can be moved from RAM to flash ROM on the ESPs.
**
** On the ESPs targets, we can marshal the table entries through linker-based
** PSECTs to enable the library initiation tables to be bound during the link
** process rather than being statically declared here. This simplifies the
** addition of new modules and configuring builds with a subset of the total
** modules available.
**
** Such a linker-based approach is not practical for cross compiler builds that
** must link on a range of platforms, and where we don't have control of PSECT
** placement. However unlike the target builds, the luac.cross builds only
** use a small and fixed list of libraries and so in this case all of libraries
** are defined here, avoiding the need for linker magic on host builds.
**
** Note that a separate ROTable is defined in lbaselib.c on luac.cross builds
** for the base functions. (These use linker based entries on target builds)
** and there is a metatable index cascade from _G to this base function table
** to the master rotables table. In the target build, the linker marshals the
** table, hence the LROT_BREAK() macros which don't 0 terminate the lists and
** skip generating the ROtable header.
*/
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "lstate.h"
#include "lnodemcu.h"
#if LUA_VERSION_NUM == 501
#include "lflash.h"
#endif
extern LROT_TABLE(strlib);
extern LROT_TABLE(tab_funcs);
extern LROT_TABLE(dblib);
extern LROT_TABLE(co_funcs);
extern LROT_TABLE(mathlib);
extern LROT_TABLE(utf8);
#if defined(LUA_CROSS_COMPILER)
/* _G __index -> rotables __index -> base_func */
extern LROT_TABLE(rotables_meta);
extern LROT_TABLE(base_func);
#if LUA_VERSION_NUM == 501
extern LROT_TABLE(oslib);
extern LROT_TABLE(iolib);
#endif
LROT_BEGIN(rotables_meta, NULL, LROT_MASK_INDEX)
LROT_TABENTRY( __index, base_func)
LROT_END(rotables_meta, NULL, LROT_MASK_INDEX)
LROT_BEGIN(rotables, LROT_TABLEREF(rotables_meta), 0)
LROT_TABENTRY( string, strlib )
LROT_TABENTRY( table, tab_funcs )
LROT_TABENTRY( coroutine, co_funcs )
LROT_TABENTRY( debug, dblib)
LROT_TABENTRY( math, mathlib )
#if LUA_VERSION_NUM >= 503
LROT_TABENTRY( utf8, utf8 )
#endif
LROT_TABENTRY( ROM, rotables )
#if LUA_VERSION_NUM == 501
LROT_TABENTRY( os, oslib )
LROT_TABENTRY( io, iolib )
#endif
LROT_END(rotables, LROT_TABLEREF(rotables_meta), 0)
LROT_BEGIN(lua_libs, NULL, 0)
LROT_FUNCENTRY( _G, luaopen_base )
LROT_FUNCENTRY( package, luaopen_package )
LROT_FUNCENTRY( string, luaopen_string )
#if LUA_VERSION_NUM >= 503
LROT_FUNCENTRY( nodemcu, luaN_init )
#endif
LROT_FUNCENTRY( io, luaopen_io )
LROT_FUNCENTRY( is, luaopen_os )
LROT_END(lua_libs, NULL, 0)
#else
/* These symbols get created by the linker fragment mapping:nodemcu
* at the head of the lua libs init table and the rotables, respectively.
*/
extern const ROTable_entry _lua_libs_map_start[];
extern const ROTable_entry _lua_rotables_map_start[];
ROTable rotables_ROTable; /* NOT const in this case */
LROT_ENTRIES_IN_SECTION(rotables, rotable)
#ifdef CONFIG_LUA_BUILTIN_STRING
LROT_TABENTRY( string, strlib )
#endif
#ifdef CONFIG_LUA_BUILTIN_TABLE
LROT_TABENTRY( table, tab_funcs )
#endif
#ifdef CONFIG_LUA_BUILTIN_COROUTINE
LROT_TABENTRY( coroutine, co_funcs )
#endif
#ifdef CONFIG_LUA_BUILTIN_DEBUG
LROT_TABENTRY( debug, dblib)
#endif
#ifdef CONFIG_LUA_BUILTIN_MATH
LROT_TABENTRY( math, mathlib )
#endif
#ifdef CONFIG_LUA_BUILTIN_UTF8
LROT_TABENTRY( utf8, utf8 )
#endif
LROT_TABENTRY( ROM, rotables )
LROT_BREAK(lua_rotables_part)
LROT_ENTRIES_IN_SECTION(lua_libs, libs)
LROT_FUNCENTRY( _G, luaopen_base )
LROT_FUNCENTRY( package, luaopen_package )
#ifdef CONFIG_LUA_BUILTIN_STRING
LROT_FUNCENTRY( string, luaopen_string )
#endif
LROT_FUNCENTRY( nodemcu, luaN_init )
LROT_BREAK(lua_libs)
#endif
/* Historically the linker script took care of zero terminating both the
* lua_libs and lua_rotable arrays, but the IDF currently does not
* support injecting LONG(0) entries. To compensate, we have explicit
* end markers here which the linker fragment then place appropriately
* to terminate aforementioned arrays.
*/
const ROTable_entry LOCK_IN_SECTION(libs_end_marker) libs_end_marker= { 0, };
const ROTable_entry LOCK_IN_SECTION(rotable_end_marker) rotable_end_marker = { 0, };
void luaL_openlibs (lua_State *L) {
#ifdef LUA_CROSS_COMPILER
const ROTable_entry *p = LROT_TABLEREF(lua_libs)->entry;
#else
const ROTable_entry *p = _lua_libs_map_start;
lua_createrotable(L, LROT_TABLEREF(rotables), _lua_rotables_map_start, NULL);
#endif
for ( ; p->key; p++) {
#if LUA_VERSION_NUM == 501
if (ttislightfunction(&p->value) && fvalue(&p->value)) {
lua_pushcfunction(L, fvalue(&p->value));
lua_pushstring(L, p->key);
lua_call(L, 1, 0); // call luaopen_XXX(libname)
}
#else
if (ttislcf(&p->value) && fvalue(&p->value))
luaL_requiref(L, p->key, fvalue(&p->value), 1);
#endif
}
}
#ifndef LUA_CROSS_COMPILER
_Static_assert(_Alignof(ROTable_entry) <= 8, "Unexpected alignment of module registration - update the linker script snippets to match!");
#endif
#include "driver/console.h"
#include "platform.h"
#include "linput.h"
#include "lua.h"
#include "lauxlib.h"
#include <stdio.h>
static struct input_state {
char *data;
int line_pos;
size_t len;
const char *prompt;
char last_nl_char;
} ins = {0};
#define NUL '\0'
#define BS '\010'
#define CR '\r'
#define LF '\n'
#define DEL 0x7f
#define BS_OVER "\010 \010"
static bool input_readline(void);
extern bool uart_on_data_cb(unsigned id, const char *buf, size_t len);
extern bool uart0_echo;
extern bool run_input;
extern uart_status_t uart_status[];
void lua_handle_input(void)
{
while(input_readline()) {}
}
/*
** The input state (ins) is private, so input_setup() exposes the necessary
** access to public properties and is called in user_init() before the Lua
** enviroment is initialised.
*/
void input_setup(int bufsize, const char *prompt) {
// Initialise non-zero elements
ins.data = malloc(bufsize);
ins.len = bufsize;
ins.prompt = prompt;
}
void input_setprompt (const char *prompt) {
ins.prompt = prompt;
}
/*
** input_readline() is called from the lua_handle_input() event routine which
** is called when input data is available. This works in one of two modes
** depending on the bool ins.run_input.
** - TRUE: it clears the input buf up to EOL, doing any callback and sending
** the line to Lua.
** - FALSE: it clears the input buf doing callbacks according to the data_len
** or end_char break.
*/
static bool input_readline(void) {
char ch = NUL;
while (console_getc(&ch)) {
if (run_input) {
/* handle CR & LF characters and aggregate \n\r and \r\n pairs */
char tmp_last_nl_char = ins.last_nl_char;
/* handle CR & LF characters
filters second char of LF&CR (\n\r) or CR&LF (\r\n) sequences */
if ((ch == CR && tmp_last_nl_char == LF) || // \n\r sequence -> skip \r
(ch == LF && tmp_last_nl_char == CR)) // \r\n sequence -> skip \n
{
continue;
}
/* backspace key */
if (ch == DEL || ch == BS) {
if (ins.line_pos > 0) {
if(uart0_echo) printf(BS_OVER);
ins.line_pos--;
}
ins.data[ins.line_pos] = 0;
continue;
}
/* end of data */
if (ch == CR || ch == LF) {
ins.last_nl_char = ch;
if (uart0_echo) putchar(LF);
if (ins.line_pos == 0) {
/* Get a empty line, then go to get a new line */
printf(ins.prompt);
fflush(stdout);
continue;
} else {
ins.data[ins.line_pos++] = LF;
lua_input_string(ins.data, ins.line_pos);
ins.line_pos = 0;
return true;
}
}
else
ins.last_nl_char = NUL;
if(uart0_echo) putchar(ch);
/* it's a large line, discard it */
if ( ins.line_pos + 1 >= ins.len ){
ins.line_pos = 0;
}
}
ins.data[ins.line_pos++] = ch;
if (!run_input)
{
uart_status_t *us = & uart_status[CONSOLE_UART];
if(((us->need_len!=0) && (ins.line_pos>= us->need_len)) || \
(ins.line_pos >= ins.len) || \
((us->end_char>=0) && ((unsigned char)ch==(unsigned char)us->end_char)))
{
uart_on_data_cb(CONSOLE_UART, ins.data, ins.line_pos);
ins.line_pos = 0;
}
}
}
return false;
}
void output_redirect(const char *str, size_t l) {
lua_State *L = lua_getstate();
int n = lua_gettop(L);
lua_pushliteral(L, "stdout");
lua_rawget(L, LUA_REGISTRYINDEX); /* fetch reg.stdout */
if (lua_istable(L, -1)) { /* reg.stdout is pipe */
lua_rawgeti(L, -1, 1); /* get the pipe_write func from stdout[1] */
lua_insert(L, -2); /* and move above the pipe ref */
lua_pushlstring(L, str, l);
if (lua_pcall(L, 2, 0, 0) != LUA_OK) { /* Reg.stdout:write(str) */
lua_writestringerror("error calling stdout:write(%s)\n", lua_tostring(L, -1));
esp_restart();
}
} else { /* reg.stdout == nil */
printf(str, l);
}
lua_settop(L, n); /* Make sure all code paths leave stack unchanged */
}
#ifndef READLINE_APP_H
#define READLINE_APP_H
extern void input_setup(int bufsize, const char *prompt);
extern void input_setprompt (const char *prompt);
void lua_handle_input(void);
#endif /* READLINE_APP_H */
......@@ -99,7 +99,7 @@ char* luaX_alloc_string(lua_State* L, int idx, int max_length) {
// luaX_free_string deallocates memory of a string allocated with luaX_alloc_string
void luaX_free_string(lua_State* L, char* st) {
if (st)
luaM_freearray(L, st, strlen(st) + 1, char);
luaN_freearray(L, st, strlen(st) + 1);
}
// luaX_unset_ref unpins a reference to a lua object in the registry
......
......@@ -36,6 +36,7 @@
#define _NODEMCU_LNODEAUX_H_
#include "lua.h"
#include <stdbool.h>
// lua_ref_t represents a reference to a lua object in the registry
typedef int lua_ref_t;
......
#include "lpanic.h"
#include "lauxlib.h"
#include <stdint.h>
#include <stdlib.h>
#ifndef LUA_CROSS_COMPILER
#include "esp_system.h"
/* defined in esp_system_internal.h */
void esp_reset_reason_set_hint(esp_reset_reason_t hint);
#endif
#ifndef LUA_CROSS_COMPILER
/*
* upper 28 bit have magic value 0xD1EC0DE0
* if paniclevel is valid (i.e. matches magic value)
* lower 4 bits have paniclevel:
* 0 = no panic occurred
* 1..15 = one..fifteen subsequent panic(s) occurred
*/
static __NOINIT_ATTR uint32_t l_rtc_panic_val;
void panic_clear_nvval() {
l_rtc_panic_val = 0xD1EC0DE0;
}
int panic_get_nvval() {
if ((l_rtc_panic_val & 0xfffffff0) == 0xD1EC0DE0) {
return (l_rtc_panic_val & 0xf);
}
panic_clear_nvval();
return 0;
}
#endif
int panic (lua_State *L) {
(void)L; /* to avoid warnings */
#ifndef LUA_CROSS_COMPILER
uint8_t paniclevel = panic_get_nvval();
if (paniclevel < 15) paniclevel++;
l_rtc_panic_val = 0xD1EC0DE0 | paniclevel;
#endif
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
lua_tostring(L, -1));
#ifndef LUA_CROSS_COMPILER
/* call abort() directly - we don't want another reset cause to intervene */
esp_reset_reason_set_hint(ESP_RST_PANIC);
#endif
abort();
while (1) {}
return 0;
}
#ifndef _LUA_PANIC_H_
#define _LUA_PANIC_H_
#include "lua.h"
void panic_clear_nvval (void);
int panic_get_nvval (void);
int panic (lua_State *L);
#endif
// Lua EGC (Emergeny Garbage Collector) interface
#include "legc.h"
#include "lstate.h"
void legc_set_mode(lua_State *L, int mode, int limit) {
global_State *g = G(L);
g->egcmode = mode;
g->memlimit = limit;
}
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