Commit dba57fa0 authored by Johny Mattsson's avatar Johny Mattsson
Browse files

Merge branch 'dev-esp32-idf4-lua53' into dev-esp32-idf4

parents 3a6961cc 8e5ce49d
...@@ -6,10 +6,11 @@ jobs: ...@@ -6,10 +6,11 @@ jobs:
build: build:
strategy: strategy:
fail-fast: false
matrix: matrix:
lua_ver: ['5.1'] lua_ver: ['5.1', '5.3']
numbers: ['float','integral'] numbers: ['default', 'alternate']
target: ['esp32','esp32c3'] target: ['esp32', 'esp32s2', 'esp32s3', 'esp32c3']
runs-on: ubuntu-latest runs-on: ubuntu-latest
...@@ -28,19 +29,27 @@ jobs: ...@@ -28,19 +29,27 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: ./install.sh run: ./install.sh
shell: bash shell: bash
- name: Build firmware (Lua 5.1) - name: Build firmware (default configuration)
if: ${{ matrix.lua_ver == '5.1' && matrix.numbers == 'float' }} if: ${{ matrix.numbers == 'default' }}
run: | run: |
cp sdkconfig.defaults sdkconfig cp sdkconfig.defaults sdkconfig
make IDF_TARGET=${{ matrix.target }} make IDF_TARGET=${{ matrix.target }}
shell: bash shell: bash
- name: Build firmware (Lua 5.1, integer-only) - 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: | run: |
cp sdkconfig.defaults sdkconfig cp sdkconfig.defaults sdkconfig
echo CONFIG_LUA_NUMBER_INTEGRAL=y >> sdkconfig echo CONFIG_LUA_NUMBER_INTEGRAL=y >> sdkconfig
make IDF_TARGET=${{ matrix.target }} make IDF_TARGET=${{ matrix.target }}
shell: bash 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 - name: Upload luac.cross
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
if: ${{ success() }} if: ${{ success() }}
......
idf_component_register( 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" INCLUDE_DIRS "include"
REQUIRES "lua" REQUIRES "lua"
PRIV_REQUIRES "nvs_flash" PRIV_REQUIRES "nvs_flash"
LDFRAGMENTS "nodemcu.lf" 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__ #ifndef __MODULE_H__
#define __MODULE_H__ #define __MODULE_H__
#include "sdkconfig.h" #include "lnodemcu.h"
#include "lrotable.h"
/* Registering a module within NodeMCU is really easy these days! /* Registering a module within NodeMCU is really easy these days!
* *
...@@ -18,11 +17,11 @@ ...@@ -18,11 +17,11 @@
* *
* Then simply put a line like this at the bottom of your module file: * 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 * or perhaps
* *
* NODEMCU_MODULE(MYNAME, "myname", myname_map, NULL); * NODEMCU_MODULE(MYNAME, "myname", myname, NULL);
* *
* if you don't need an init function. * if you don't need an init function.
* *
...@@ -36,23 +35,6 @@ ...@@ -36,23 +35,6 @@
#define MODULE_PASTE_(x,y) x##y #define MODULE_PASTE_(x,y) x##y
#define MODULE_EXPAND_PASTE_(x,y) MODULE_PASTE_(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): /* For the ROM table, we name the variable according to ( | denotes concat):
* cfgname | _module_selected | CONFIG_NODEMCU_CMODULE_##cfgname * cfgname | _module_selected | CONFIG_NODEMCU_CMODULE_##cfgname
* where the CONFIG_NODEMCU_CMODULE_XYZ macro is first expanded to yield either * where the CONFIG_NODEMCU_CMODULE_XYZ macro is first expanded to yield either
...@@ -65,10 +47,10 @@ ...@@ -65,10 +47,10 @@
*/ */
#define NODEMCU_MODULE(cfgname, luaname, map, initfunc) \ #define NODEMCU_MODULE(cfgname, luaname, map, initfunc) \
const LOCK_IN_SECTION(libs) \ 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) \ const LOCK_IN_SECTION(rotable) \
luaR_entry MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(CONFIG_NODEMCU_CMODULE_,cfgname))) \ ROTable_entry MODULE_EXPAND_PASTE_(cfgname,MODULE_EXPAND_PASTE_(_module_selected,MODULE_PASTE_(CONFIG_NODEMCU_CMODULE_,cfgname))) \
= {luaname, LRO_ROVAL(map ## _map)} = {luaname, LRO_ROVAL(map)}
#endif #endif
...@@ -89,6 +71,6 @@ ...@@ -89,6 +71,6 @@
// NODEMCU_MODULE_STD() defines the entry points for an external module: // NODEMCU_MODULE_STD() defines the entry points for an external module:
#define NODEMCU_MODULE_STD() \ #define NODEMCU_MODULE_STD() \
static const LOCK_IN_SECTION(libs) \ static const LOCK_IN_SECTION(libs) \
luaR_entry lua_lib_module = {MODNAME, LRO_FUNCVAL(module_init)}; \ ROTable_entry lua_lib_module = {MODNAME, LRO_FUNCVAL(module_init)}; \
const LOCK_IN_SECTION(rotable) \ const const LOCK_IN_SECTION(rotable) \
luaR_entry MODULE_EXPAND_PASTE_(EXTMODNAME, _entry) = {MODNAME, LRO_ROVAL(module_map)}; 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] [sections:lua_esp_event_cb_table]
entries: entries:
.lua_esp_event_cb_table .lua_esp_event_cb_table
[scheme:nodemcu_arrays] [scheme:nodemcu_arrays]
entries: 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 lua_esp_event_cb_table -> flash_rodata
# Important: don't change the alignments below without also updating the # 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] [mapping:nodemcu]
archive: * archive: *
entries: entries:
* (nodemcu_arrays); * (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) lua_esp_event_cb_table -> flash_rodata KEEP() ALIGN(4) SURROUND(esp_event_cb_table)
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* 2014/1/1, v1.0 create this file. * 2014/1/1, v1.0 create this file.
*******************************************************************************/ *******************************************************************************/
#include "lua.h" #include "lua.h"
#include "linput.h"
#include "platform.h" #include "platform.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -19,7 +20,6 @@ ...@@ -19,7 +20,6 @@
#include "nvs_flash.h" #include "nvs_flash.h"
#include "flash_api.h" #include "flash_api.h"
#include "driver/console.h"
#include "task/task.h" #include "task/task.h"
#include "sections.h" #include "sections.h"
#include "nodemcu_esp_event.h" #include "nodemcu_esp_event.h"
...@@ -93,24 +93,9 @@ static void handle_default_loop_event(task_param_t param, task_prio_t prio) ...@@ -93,24 +93,9 @@ static void handle_default_loop_event(task_param_t param, task_prio_t prio)
// +================== New task interface ==================+ // +================== New task interface ==================+
static void start_lua () static void start_lua ()
{ {
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
NODE_DBG("Task task_lua started.\n"); NODE_DBG("Task task_lua started.\n");
lua_main( 2, lua_argv ); if (lua_main()) // If it returns true then LFS restart is needed
} lua_main();
static void handle_input(task_param_t flag, task_prio_t priority) {
(void)priority;
lua_handle_input (flag);
}
static task_handle_t input_task;
task_handle_t user_get_input_sig(void) {
return input_task;
}
bool user_process_input(bool force) {
return task_post_low(input_task, force);
} }
void nodemcu_init(void) void nodemcu_init(void)
...@@ -144,8 +129,6 @@ void __attribute__((noreturn)) app_main(void) ...@@ -144,8 +129,6 @@ void __attribute__((noreturn)) app_main(void)
{ {
task_init(); task_init();
input_task = task_get_id (handle_input);
relayed_event_handled = xSemaphoreCreateBinary(); relayed_event_handled = xSemaphoreCreateBinary();
relayed_event_task = task_get_id(handle_default_loop_event); relayed_event_task = task_get_id(handle_default_loop_event);
...@@ -156,19 +139,7 @@ void __attribute__((noreturn)) app_main(void) ...@@ -156,19 +139,7 @@ void __attribute__((noreturn)) app_main(void)
relay_default_loop_events, relay_default_loop_events,
NULL); NULL);
ConsoleSetup_t cfg; platform_uart_start(CONFIG_ESP_CONSOLE_UART_NUM);
cfg.bit_rate = CONFIG_NODEMCU_CONSOLE_BIT_RATE;
cfg.data_bits = CONSOLE_NUM_BITS_8;
cfg.parity = CONSOLE_PARITY_NONE;
cfg.stop_bits = CONSOLE_STOP_BITS_1;
cfg.auto_baud =
#ifdef CONFIG_NODEMCU_CONSOLE_BIT_RATE_AUTO
true;
#else
false;
#endif
console_init (&cfg, input_task);
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);
nodemcu_init (); nodemcu_init ();
......
if(NOT "${IDF_TARGET}" STREQUAL "esp32c3") if(IDF_TARGET STREQUAL "esp32")
idf_component_register( idf_component_register(
SRCS "CAN.c" SRCS "CAN.c"
......
idf_component_register(
SRCS "console.c"
INCLUDE_DIRS "include"
REQUIRES "task" "esp32"
)
/*
* Copyright 2016 Dius Computing Pty Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the copyright holders nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Johny Mattsson <jmattsson@dius.com.au>
*/
#include "driver/console.h"
#include "driver/uart.h"
#include "esp_intr_alloc.h"
#include "soc/soc.h"
#include "soc/uart_reg.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "sys/reent.h"
#include <unistd.h>
#include "rom/libc_stubs.h"
#include "rom/uart.h"
#define UART_INPUT_QUEUE_SZ 0x100
// These used to be available in soc/uart_register.h:
#define UART_GET_RXFIFO_RD_BYTE(i) GET_PERI_REG_BITS2(UART_FIFO_REG(i) , UART_RXFIFO_RD_BYTE_V, UART_RXFIFO_RD_BYTE_S)
#define UART_GET_RXFIFO_CNT(i) GET_PERI_REG_BITS2(UART_STATUS_REG(i) , UART_RXFIFO_CNT_V, UART_RXFIFO_CNT_S)
#define UART_SET_AUTOBAUD_EN(i,val) SET_PERI_REG_BITS(UART_AUTOBAUD_REG(i) ,UART_AUTOBAUD_EN_V,(val),UART_AUTOBAUD_EN_S)
typedef int (*_read_r_fn) (struct _reent *r, int fd, void *buf, int size);
static _read_r_fn _read_r_app;
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
static _read_r_fn _read_r_pro;
#endif
static xQueueHandle uart0Q;
static task_handle_t input_task = 0;
// --- Syscall support for reading from STDIN_FILENO ---------------
static int console_read_r (struct _reent *r, int fd, void *buf, int size, _read_r_fn next)
{
if (fd == STDIN_FILENO)
{
static _lock_t stdin_lock;
_lock_acquire_recursive (&stdin_lock);
char *c = (char *)buf;
int i = 0;
for (; i < size; ++i)
{
if (!console_getc (c++))
break;
}
_lock_release_recursive (&stdin_lock);
return i;
}
else if (next)
return next (r, fd, buf, size);
else
return -1;
}
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
static int console_read_r_pro (struct _reent *r, int fd, void *buf, int size)
{
return console_read_r (r, fd, buf, size, _read_r_pro);
}
#endif
static int console_read_r_app (struct _reent *r, int fd, void *buf, int size)
{
return console_read_r (r, fd, buf, size, _read_r_app);
}
// --- End syscall support -------------------------------------------
static void uart0_rx_intr_handler (void *arg)
{
(void)arg;
bool received = false;
uint32_t status = READ_PERI_REG(UART_INT_ST_REG(CONSOLE_UART));
while (status)
{
if (status & UART_FRM_ERR_INT_ENA)
{
// TODO: report somehow?
WRITE_PERI_REG(UART_INT_CLR_REG(CONSOLE_UART), UART_FRM_ERR_INT_ENA);
}
if ((status & UART_RXFIFO_TOUT_INT_ENA) ||
(status & UART_RXFIFO_FULL_INT_ENA))
{
uint32_t fifo_len = UART_GET_RXFIFO_CNT(CONSOLE_UART);
for (uint32_t i = 0; i < fifo_len; ++i)
{
received = true;
char c = UART_GET_RXFIFO_RD_BYTE(CONSOLE_UART);
if (uart0Q)
xQueueSendToBackFromISR (uart0Q, &c, NULL);
}
WRITE_PERI_REG(UART_INT_CLR_REG(CONSOLE_UART),
UART_RXFIFO_TOUT_INT_ENA | UART_RXFIFO_FULL_INT_ENA);
}
status = READ_PERI_REG(UART_INT_ST_REG(CONSOLE_UART));
}
if (received && input_task)
task_post_isr_low (input_task, false);
}
void console_setup (const ConsoleSetup_t *cfg)
{
esp_rom_uart_tx_wait_idle (CONSOLE_UART);
uart_config_t uart_conf = {
.baud_rate = cfg->bit_rate,
.data_bits =
cfg->data_bits == CONSOLE_NUM_BITS_5 ? UART_DATA_5_BITS :
cfg->data_bits == CONSOLE_NUM_BITS_6 ? UART_DATA_6_BITS :
cfg->data_bits == CONSOLE_NUM_BITS_7 ? UART_DATA_7_BITS :
UART_DATA_8_BITS,
.stop_bits =
cfg->stop_bits == CONSOLE_STOP_BITS_1 ? UART_STOP_BITS_1 :
cfg->stop_bits == CONSOLE_STOP_BITS_2 ? UART_STOP_BITS_2 :
UART_STOP_BITS_1_5,
.parity =
cfg->parity == CONSOLE_PARITY_NONE ? UART_PARITY_DISABLE :
cfg->parity == CONSOLE_PARITY_EVEN ? UART_PARITY_EVEN :
UART_PARITY_ODD,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
};
uart_param_config(CONSOLE_UART, &uart_conf);
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
// TODO: Make this actually work
UART_SET_AUTOBAUD_EN(CONSOLE_UART, cfg->auto_baud);
#endif
}
void console_init (const ConsoleSetup_t *cfg, task_handle_t tsk)
{
input_task = tsk;
uart0Q = xQueueCreate (UART_INPUT_QUEUE_SZ, sizeof (char));
console_setup (cfg);
uart_isr_register(CONSOLE_UART, uart0_rx_intr_handler, NULL, 0, NULL);
uart_set_rx_timeout(CONSOLE_UART, 2);
uart_set_rx_full_threshold(CONSOLE_UART, 10);
uart_enable_intr_mask(CONSOLE_UART,
UART_RXFIFO_TOUT_INT_ENA_M |
UART_RXFIFO_FULL_INT_ENA_M |
UART_FRM_ERR_INT_ENA_M);
// Register our console_read_r_xxx functions to support stdin input
#if defined(CONFIG_IDF_TARGET_ESP32C3)
_read_r_app = syscall_table_ptr->_read_r;
syscall_table_ptr->_read_r = console_read_r_app;
#else
_read_r_app = syscall_table_ptr_app->_read_r;
_read_r_pro = syscall_table_ptr_pro->_read_r;
syscall_table_ptr_app->_read_r = console_read_r_app;
syscall_table_ptr_pro->_read_r = console_read_r_pro;
#endif
}
bool console_getc (char *c)
{
return (uart0Q && (xQueueReceive (uart0Q, c, 0) == pdTRUE));
}
/*
* Copyright 2016 Dius Computing Pty Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
* - Neither the name of the copyright holders nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Johny Mattsson <jmattsson@dius.com.au>
*/
#include "esp_rom_uart.h"
#include "task/task.h"
#include <stdint.h>
#include <stdbool.h>
#define CONSOLE_UART CONFIG_ESP_CONSOLE_UART_NUM
typedef enum
{
CONSOLE_NUM_BITS_5 = 0x0,
CONSOLE_NUM_BITS_6 = 0x1,
CONSOLE_NUM_BITS_7 = 0x2,
CONSOLE_NUM_BITS_8 = 0x3
} ConsoleNumBits_t;
typedef enum
{
CONSOLE_PARITY_NONE = 0x2,
CONSOLE_PARITY_ODD = 0x1,
CONSOLE_PARITY_EVEN = 0x0
} ConsoleParity_t;
typedef enum
{
CONSOLE_STOP_BITS_1 = 0x1,
CONSOLE_STOP_BITS_1_5 = 0x2,
CONSOLE_STOP_BITS_2 = 0x3
} ConsoleStopBits_t;
typedef struct
{
uint32_t bit_rate;
ConsoleNumBits_t data_bits;
ConsoleParity_t parity;
ConsoleStopBits_t stop_bits;
bool auto_baud;
} ConsoleSetup_t;
void console_init (const ConsoleSetup_t *cfg, task_handle_t tsk);
void console_setup (const ConsoleSetup_t *cfg);
bool console_getc (char *c);
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( idf_component_register(
SRCS "lapi.c" "lauxlib.c" "lbaselib.c" "lcode.c" "ldblib.c" "ldebug.c" SRCS ${srcs} ${common_srcs}
"ldo.c" "ldump.c" "legc.c" "lflash.c" "lfunc.c" "lgc.c" "llex.c" "lmathlib.c" INCLUDE_DIRS ${luadir} "common"
"lmem.c" "loadlib.c" "lobject.c" "lopcodes.c" "lparser.c" "lrotable.c" REQUIRES "platform" "nvs_flash" "uzlib"
"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"
PRIV_REQUIRES "base_nodemcu" "embedded_lfs" 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" 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 config LUA_NUMBER_INTEGRAL
depends on LUA_VERSION_51
bool "Integer-only build" bool "Integer-only build"
default "n" default "n"
help help
Build Lua without support for floating point numbers. Build Lua without support for floating point numbers.
Not generally recommended, but can save on code size. 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" menu "Core Lua modules"
config LUA_BUILTIN_STRING config LUA_BUILTIN_STRING
...@@ -33,6 +67,13 @@ menu "Lua configuration" ...@@ -33,6 +67,13 @@ menu "Lua configuration"
help help
Includes the math module (recommended). Includes the math module (recommended).
config LUA_BUILTIN_UTF8
depends on !LUA_VERSION_51
bool "UTF8 module"
default "y"
help
Includes the debug module (required by our Lua VM).
config LUA_BUILTIN_DEBUG config LUA_BUILTIN_DEBUG
bool "Debug module" bool "Debug module"
default "n" default "n"
...@@ -78,4 +119,11 @@ menu "Lua configuration" ...@@ -78,4 +119,11 @@ menu "Lua configuration"
endmenu endmenu
config LUA_REQUIRED_MODULES
bool
default y
select NODEMCU_CMODULE_PIPE
select NODEMCU_CMODULE_UART
select LUA_BUILTIN_DEBUG
endmenu 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 "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"
bool input_echo = true;
bool run_input = true;
/*
** 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;
}
size_t feed_lua_input(const char *buf, size_t n)
{
for (size_t i = 0; i < n; ++i) {
char ch = buf[i];
if (!run_input) // We're no longer interested in the remaining bytes
return i;
/* 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(input_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 (input_echo) putchar(LF);
if (ins.line_pos == 0) {
/* Get a empty line, then go to get a new line */
printf(ins.prompt);
fflush(stdout);
} else {
ins.data[ins.line_pos++] = LF;
lua_input_string(ins.data, ins.line_pos);
ins.line_pos = 0;
}
continue;
}
else
ins.last_nl_char = NUL;
if(input_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;
}
return n; // we consumed/buffered all the provided data
}
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 _LINPUT_H_
#define _LINPUT_H_
#include <stdbool.h>
#include <stddef.h>
void input_setup(int bufsize, const char *prompt);
void input_setprompt (const char *prompt);
unsigned feed_lua_input(const char *buf, size_t n);
extern bool input_echo;
extern bool run_input;
#endif /* READLINE_APP_H */
...@@ -99,7 +99,7 @@ char* luaX_alloc_string(lua_State* L, int idx, int max_length) { ...@@ -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 // luaX_free_string deallocates memory of a string allocated with luaX_alloc_string
void luaX_free_string(lua_State* L, char* st) { void luaX_free_string(lua_State* L, char* st) {
if (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 // luaX_unset_ref unpins a reference to a lua object in the registry
......
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