Lua 5.1 to 5.3 realignement phase 1

This commit is contained in:
Terry Ellison 2019-07-18 17:02:02 +01:00
parent c7ff86ff27
commit 14c1b8fd54
44 changed files with 1120 additions and 1103 deletions

View File

@ -3,9 +3,9 @@ set pagination off
set print null-stop
define prTS
set $o = &(((TString *)($arg0))->tsv)
set $o = &(((TString *)(($arg0).value))->tsv)
printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
printf "String: hash = 0x%08x, len = %u : %s\n", $o->hash, $o->len, (char *)(&$o[1])
printf "String: hash = 0x%08x, len = %u : %s\n", $o->hash, $o->len, (char *)($o+1)
end
define prTnodes
@ -24,6 +24,18 @@ define prTnodes
set $i = $i +1
end
end
define prTarray
set $o = (Table *)($arg0)
set $n = $o->sizearray
set $i = 0
while $i < $n
set $nd = ($o->array) + $i
prTV $nd
set $i = $i +1
end
end
define prTV
if $arg0
set $type = ($arg0).tt
@ -78,6 +90,10 @@ define prTV
end
if $type == 9
# UserData
set $o = &($val->gc.u.uv)
printf "Common header: next = %p, marked = 0x%01x\n", $o->next, $o->marked
printf "UD = %p Userdata: metatable = ", ($o+1))
print ($o)->metatable
end
if $type == 10
# Thread

View File

@ -36,7 +36,6 @@ SUBDIRS= \
libc \
lua \
lwip \
task \
smart \
modules \
spiffs \
@ -64,8 +63,7 @@ COMPONENTS_eagle.app.v6 = \
user/libuser.a \
crypto/libcrypto.a \
driver/libdriver.a \
platform/libplatform.a \
task/libtask.a \
platform/libplatform.a \
libc/liblibc.a \
lua/liblua.a \
lwip/liblwip.a \

View File

@ -15,7 +15,7 @@ ifndef PDIR
GEN_LIBS = libdriver.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
STD_CFLAGS=-std=gnu11 -Wimplicit -Wall
#############################################################
# Configuration i.e. compile options etc.

196
app/driver/input.c Normal file
View File

@ -0,0 +1,196 @@
#include "platform.h"
#include "driver/uart.h"
#include "driver/input.h"
#include <stdint.h>
#include "mem.h"
/**DEBUG**/extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
static void input_handler(platform_task_param_t flag, uint8 priority);
static struct input_state {
char *data;
int line_pos;
size_t len;
const char *prompt;
uart_cb_t uart_cb;
platform_task_handle_t input_sig;
int data_len;
bool run_input;
bool uart_echo;
char last_char;
char end_char;
uint8 input_sig_flag;
} ins = {0};
#define NUL '\0'
#define BS '\010'
#define CR '\r'
#define LF '\n'
#define DEL 0x7f
#define BS_OVER "\010 \010"
#define sendStr(s) uart0_sendStr(s)
#define putc(c) uart0_putc(c)
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
static bool uart_getc(char *c){
RcvMsgBuff *pRxBuff = &(UartDev.rcv_buff);
if(pRxBuff->pWritePos == pRxBuff->pReadPos){ // empty
return false;
}
// ETS_UART_INTR_DISABLE();
ETS_INTR_LOCK();
*c = (char)*(pRxBuff->pReadPos);
if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) {
pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ;
} else {
pRxBuff->pReadPos++;
}
// ETS_UART_INTR_ENABLE();
ETS_INTR_UNLOCK();
return true;
}
/*
** input_handler at high-priority is a system post task used to process pending Rx
** data on UART0. The flag is used as a latch to stop the interrupt handler posting
** multiple pending requests. At low priority it is used the trigger interactive
** compile.
**
** The ins.data check detects up the first task call which used to initialise
** everything.
*/
int lua_main (void);
static bool input_readline(void);
static void input_handler(platform_task_param_t flag, uint8 priority) {
(void) priority;
if (!ins.data) {
lua_main();
return;
}
ins.input_sig_flag = flag & 0x1;
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. The second routine input_setup_receive() is
** called in lua.c after the Lua environment is available to bind the Lua
** input handler. Any UART input before this receive setup is ignored.
*/
void input_setup(int bufsize, const char *prompt) {
// Initialise non-zero elements
ins.run_input = true;
ins.uart_echo = true;
ins.data = os_malloc(bufsize);
ins.len = bufsize;
ins.prompt = prompt;
ins.input_sig = platform_task_get_id(input_handler);
// pass the task CB parameters to the uart driver
uart_init_task(ins.input_sig, &ins.input_sig_flag);
ETS_UART_INTR_ENABLE();
}
void input_setup_receive(uart_cb_t uart_on_data_cb, int data_len, char end_char, bool run_input) {
ins.uart_cb = uart_on_data_cb;
ins.data_len = data_len;
ins.end_char = end_char;
ins.run_input = run_input;
}
void input_setecho (bool flag) {
ins.uart_echo = flag;
}
void input_setprompt (const char *prompt) {
ins.prompt = prompt;
}
/*
** input_readline() is called from the input_handler() event routine which is
** posted by the UART Rx ISR posts. This works in one of two modes depending on
** the bool ins.run_input.
** - TRUE: it clears the UART FIFO up to EOL, doing any callback and sending
** the line to Lua.
** - FALSE: it clears the UART FIFO doing callbacks according to the data_len /
** end_char break.
*/
void lua_input_string (const char *line, int len);
static bool input_readline(void) {
char ch = NUL;
if (ins.run_input) {
while (uart_getc(&ch)) {
/* handle CR & LF characters and aggregate \n\r and \r\n pairs */
if ((ch == CR && ins.last_char == LF) ||
(ch == LF && ins.last_char == CR)) {
ins.last_char = NUL;
continue;
}
/* backspace key */
if (ch == DEL || ch == BS) {
if (ins.line_pos > 0) {
if(ins.uart_echo) sendStr(BS_OVER);
ins.line_pos--;
}
ins.data[ins.line_pos] = 0;
ins.last_char = NUL;
continue;
}
ins.last_char = ch;
/* end of data */
if (ch == CR || ch == LF) {
if (ins.uart_echo) putc(LF);
if (ins.uart_cb) ins.uart_cb(ins.data, ins.line_pos);
if (ins.line_pos == 0) {
/* Get a empty data, then go to get a new data */
sendStr(ins.prompt);
continue;
} else {
ins.data[ins.line_pos++] = LF;
lua_input_string(ins.data, ins.line_pos);
ins.line_pos = 0;
return true;
}
}
if(ins.uart_echo) putc(ch);
/* it's a large data, discard it */
if ( ins.line_pos + 1 >= ins.len ){
ins.line_pos = 0;
}
ins.data[ins.line_pos++] = ch;
}
} else {
if (!ins.uart_cb) {
while (uart_getc(&ch)) {}
} else if (ins.data_len == 0) {
while (uart_getc(&ch)) {
ins.uart_cb(&ch, 1);
}
} else {
while (uart_getc(&ch)) {
ins.data[ins.line_pos++] = ch;
if( ins.line_pos >= ins.len ||
(ins.data_len > 0 && ins.line_pos >= ins.data_len) ||
ch == ins.end_char ) {
ins.uart_cb(ins.data, ins.line_pos);
ins.line_pos = 0;
}
}
}
}
return false;
}

View File

@ -20,7 +20,7 @@
#include "driver/pwm.h"
// #define PWM_DBG os_printf
#define PWM_DBG
#define PWM_DBG( ... )
// Enabling the next line will cause the interrupt handler to toggle
// this output pin during processing so that the timing is obvious
@ -253,7 +253,7 @@ pwm_set_freq(uint16 freq, uint8 channel)
pwm.period = PWM_1S / pwm.freq;
}
#if 0
/******************************************************************************
* FunctionName : pwm_set_freq_duty
* Description : set pwm frequency and each channel's duty
@ -274,7 +274,7 @@ pwm_set_freq_duty(uint16 freq, uint16 *duty)
pwm_set_duty(duty[i], pwm_out_io_num[i]);
}
}
#endif
/******************************************************************************
* FunctionName : pwm_get_duty
* Description : get duty of each channel

View File

@ -1,111 +0,0 @@
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "driver/uart.h"
#include <stdint.h>
LOCAL os_timer_t readline_timer;
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
#define uart_putc uart0_putc
bool uart_getc(char *c){
RcvMsgBuff *pRxBuff = &(UartDev.rcv_buff);
if(pRxBuff->pWritePos == pRxBuff->pReadPos){ // empty
return false;
}
// ETS_UART_INTR_DISABLE();
ETS_INTR_LOCK();
*c = (char)*(pRxBuff->pReadPos);
if (pRxBuff->pReadPos == (pRxBuff->pRcvMsgBuff + RX_BUFF_SIZE)) {
pRxBuff->pReadPos = pRxBuff->pRcvMsgBuff ;
} else {
pRxBuff->pReadPos++;
}
// ETS_UART_INTR_ENABLE();
ETS_INTR_UNLOCK();
return true;
}
#if 0
int readline4lua(const char *prompt, char *buffer, int length){
char ch;
int line_position;
start:
/* show prompt */
uart0_sendStr(prompt);
line_position = 0;
os_memset(buffer, 0, length);
while (1)
{
while (uart_getc(&ch))
{
/* handle CR key */
if (ch == '\r')
{
char next;
if (uart_getc(&next))
ch = next;
}
/* backspace key */
else if (ch == 0x7f || ch == 0x08)
{
if (line_position > 0)
{
uart_putc(0x08);
uart_putc(' ');
uart_putc(0x08);
line_position--;
}
buffer[line_position] = 0;
continue;
}
/* EOF(ctrl+d) */
else if (ch == 0x04)
{
if (line_position == 0)
/* No input which makes lua interpreter close */
return 0;
else
continue;
}
/* end of line */
if (ch == '\r' || ch == '\n')
{
buffer[line_position] = 0;
uart_putc('\n');
if (line_position == 0)
{
/* Get a empty line, then go to get a new line */
goto start;
}
else
{
return line_position;
}
}
/* other control character or not an acsii character */
if (ch < 0x20 || ch >= 0x80)
{
continue;
}
/* echo */
uart_putc(ch);
buffer[line_position] = ch;
ch = 0;
line_position++;
/* it's a large line, discard it */
if (line_position >= length)
line_position = 0;
}
}
}
#endif

View File

@ -14,9 +14,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include "task/task.h"
#include "driver/rotary.h"
#include "user_interface.h"
#include "task/task.h"
#include "ets_sys.h"
//
@ -37,7 +37,7 @@
#define GET_READ_STATUS(d) (d->queue[d->read_offset & (QUEUE_SIZE - 1)])
#define ADVANCE_IF_POSSIBLE(d) if (d->read_offset < d->write_offset) { d->read_offset++; }
#define STATUS_IS_PRESSED(x) ((x & 0x80000000) != 0)
#define STATUS_IS_PRESSED(x) (((x) & 0x80000000) != 0)
typedef struct {
int8_t phase_a_pin;
@ -213,7 +213,6 @@ int rotary_setup(uint32_t channel, int phase_a, int phase_b, int press, task_han
}
data[channel] = d;
int i;
d->tasknumber = tasknumber;

View File

@ -15,7 +15,6 @@ static uint32_t spi_clkdiv[2];
*******************************************************************************/
void spi_lcd_mode_init(uint8 spi_no)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
//bit9 of PERIPHS_IO_MUX should be cleared when HSPI clock doesn't equal CPU clock
//bit8 of PERIPHS_IO_MUX should be cleared when SPI clock doesn't equal CPU clock
@ -112,8 +111,6 @@ uint32_t spi_set_clkdiv(uint8 spi_no, uint32_t clock_div)
*******************************************************************************/
void spi_master_init(uint8 spi_no, unsigned cpol, unsigned cpha, uint32_t clock_div)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_CS_SETUP|SPI_CS_HOLD|SPI_RD_BYTE_ORDER|SPI_WR_BYTE_ORDER);
@ -258,7 +255,7 @@ void spi_mast_set_mosi(uint8 spi_no, uint16 offset, uint8 bitlen, uint32 data)
}
shift = 64 - (offset & 0x1f) - bitlen;
spi_buf.dword &= ~((1ULL << bitlen)-1 << shift);
spi_buf.dword &= ~(((1ULL << bitlen)-1) << shift);
spi_buf.dword |= (uint64)data << shift;
if (wn < 15) {
@ -344,7 +341,7 @@ void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8
uint16 cmd = cmd_data << (16 - cmd_bitlen); // align to MSB
cmd = (cmd >> 8) | (cmd << 8); // swap byte order
WRITE_PERI_REG(SPI_USER2(spi_no),
((cmd_bitlen - 1 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
(((cmd_bitlen - 1) & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S) |
(cmd & SPI_USR_COMMAND_VALUE));
SET_PERI_REG_MASK(SPI_USER(spi_no), SPI_USR_COMMAND);
}
@ -387,8 +384,6 @@ void spi_mast_transaction(uint8 spi_no, uint8 cmd_bitlen, uint16 cmd_data, uint8
*******************************************************************************/
void spi_byte_write_espslave(uint8 spi_no,uint8 data)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
@ -413,8 +408,6 @@ void spi_byte_write_espslave(uint8 spi_no,uint8 data)
*******************************************************************************/
void spi_byte_read_espslave(uint8 spi_no,uint8 *data)
{
uint32 regvalue;
if(spi_no>1) return; //handle invalid input number
while(READ_PERI_REG(SPI_CMD(spi_no))&SPI_USR);
@ -440,7 +433,7 @@ void spi_byte_write_espslave(uint8 spi_no,uint8 data)
*******************************************************************************/
void spi_slave_init(uint8 spi_no)
{
uint32 regvalue;
// uint32 regvalue;
if(spi_no>1)
return; //handle invalid input number
@ -565,7 +558,6 @@ void hspi_master_readwrite_repeat(void)
#include "mem.h"
static uint8 spi_data[32] = {0};
static uint8 idx = 0;
static uint8 spi_flg = 0;
#define SPI_MISO
#define SPI_QUEUE_LEN 8
os_event_t * spiQueue;
@ -596,9 +588,8 @@ void ICACHE_FLASH_ATTR
void spi_slave_isr_handler(void *para)
{
uint32 regvalue,calvalue;
static uint8 state =0;
uint32 recv_data,send_data;
uint32 regvalue;
uint32 recv_data;
if(READ_PERI_REG(0x3ff00020)&BIT4){
//following 3 lines is to clear isr signal

View File

@ -18,13 +18,13 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include "task/task.h"
#include "driver/switec.h"
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "hw_timer.h"
#include "user_interface.h"
#include "task/task.h"
#define N_STATES 6
//

View File

@ -12,7 +12,7 @@
#include "ets_sys.h"
#include "osapi.h"
#include "driver/uart.h"
#include "task/task.h"
#include "platform.h"
#include "user_config.h"
#include "user_interface.h"
#include "osapi.h"
@ -29,15 +29,15 @@
// For event signalling
static task_handle_t sig = 0;
static platform_task_handle_t sig = 0;
static uint8 *sig_flag;
static uint8 isr_flag = 0;
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
#ifdef BIT_RATE_AUTOBAUD
static os_timer_t autobaud_timer;
#endif
static void (*alt_uart0_tx)(char txchar);
LOCAL void ICACHE_RAM_ATTR
@ -165,7 +165,7 @@ uart_tx_one_char(uint8 uart, uint8 TxChar)
WRITE_PERI_REG(UART_FIFO(uart) , TxChar);
return OK;
}
#if 0
/******************************************************************************
* FunctionName : uart1_write_char
* Description : Internal used function
@ -189,7 +189,7 @@ uart1_write_char(char c)
uart_tx_one_char(UART1, c);
}
}
#endif
/******************************************************************************
* FunctionName : uart0_tx_buffer
* Description : use uart0 to transfer buffer
@ -300,13 +300,15 @@ uart0_rx_intr_handler(void *para)
}
if (got_input && sig) {
// Only post a new handler request once the handler has fired clearing the last post
if (isr_flag == *sig_flag) {
isr_flag ^= 0x01;
task_post_low (sig, 0x8000 | isr_flag << 14 | false);
platform_post_high(sig, isr_flag);
}
}
}
#ifdef BIT_RATE_AUTOBAUD
static void
uart_autobaud_timeout(void *timer_arg)
{
@ -324,7 +326,6 @@ uart_autobaud_timeout(void *timer_arg)
}
}
#include "pm/swtimer.h"
static void
uart_init_autobaud(uint32_t uart_no)
{
@ -339,22 +340,17 @@ uart_stop_autobaud()
{
os_timer_disarm(&autobaud_timer);
}
#endif
/******************************************************************************
* FunctionName : uart_init
* Description : user interface for init uart
* Parameters : UartBautRate uart0_br - uart0 bautrate
* UartBautRate uart1_br - uart1 bautrate
* os_signal_t sig_input - signal to post
* uint8 *flag_input - flag of consumer task
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR
uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input, uint8 *flag_input)
uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
{
sig = sig_input;
sig_flag = flag_input;
// rom use 74880 baut_rate, here reinitialize
UartDev.baut_rate = uart0_br;
uart_config(UART0);
@ -378,6 +374,19 @@ uart_setup(uint8 uart_no)
ETS_UART_INTR_ENABLE();
}
/******************************************************************************
* FunctionName : uart_init_task
* Description : user interface for init uart task callback
* Parameters : os_signal_t sig_input - signal to post
* uint8 *flag_input - flag of consumer task
* Returns : NONE
*******************************************************************************/
void ICACHE_FLASH_ATTR uart_init_task(os_signal_t sig_input, uint8 *flag_input) {
sig = sig_input;
sig_flag = flag_input;
}
void ICACHE_FLASH_ATTR uart_set_alt_output_uart0(void (*fn)(char)) {
alt_uart0_tx = fn;
}

View File

@ -0,0 +1,11 @@
#ifndef READLINE_APP_H
#define READLINE_APP_H
typedef void (*uart_cb_t)(const char *buf, size_t len);
extern void input_setup(int bufsize, const char *prompt);
extern void input_setup_receive(uart_cb_t uart_on_data_cb, int data_len, char end_char, bool run_input);
extern void input_setecho (bool flag);
extern void input_setprompt (const char *prompt);
extern void input_process_arm(void);
#endif /* READLINE_APP_H */

View File

@ -1,6 +0,0 @@
#ifndef READLINE_APP_H
#define READLINE_APP_H
bool uart_getc(char *c);
#endif /* READLINE_APP_H */

View File

@ -110,7 +110,8 @@ typedef struct {
UartStopBitsNum stop_bits;
} UartConfig;
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br, os_signal_t sig_input, uint8 *flag_input);
void uart_init(UartBautRate uart0_br, UartBautRate uart1_br);
void uart_init_task(os_signal_t sig_input, uint8 *flag_input);
UartConfig uart_get_config(uint8 uart_no);
void uart0_alt(uint8 on);
void uart0_sendStr(const char *str);

View File

@ -1,35 +1,24 @@
#ifndef _TASK_H_
#define _TASK_H_
#include "ets_sys.h"
#include "osapi.h"
#include "os_type.h"
#include "user_interface.h"
/* use LOW / MEDIUM / HIGH since it isn't clear from the docs which is higher */
#define TASK_PRIORITY_LOW 0
#define TASK_PRIORITY_MEDIUM 1
#define TASK_PRIORITY_HIGH 2
#define TASK_PRIORITY_COUNT 3
/*
* Signals are a 32-bit number of the form header:14; count:16, priority:2. The header
* is just a fixed fingerprint and the count is allocated serially by the task get_id()
* function.
*/
#define task_post(priority,handle,param) system_os_post(priority, ((handle) | priority), param)
#define task_post_low(handle,param) task_post(TASK_PRIORITY_LOW, handle, param)
#define task_post_medium(handle,param) task_post(TASK_PRIORITY_MEDIUM, handle, param)
#define task_post_high(handle,param) task_post(TASK_PRIORITY_HIGH, handle, param)
** The task interface is now part of the core platform interface.
** This header is preserved for backwards compatability only.
*/
#include "platform.h"
#define task_handle_t os_signal_t
#define task_param_t os_param_t
#define TASK_PRIORITY_LOW PLATFORM_TASK_PRIORITY_LOW
#define TASK_PRIORITY_MEDIUM PLATFORM_TASK_PRIORITY_MEDIUM
#define TASK_PRIORITY_HIGH PLATFORM_TASK_PRIORITY_HIGH
typedef void (*task_callback_t)(task_param_t param, uint8 prio);
#define task_post(priority,handle,param) platform_post(priority,handle,param)
#define task_post_low(handle,param) platform_post_low(handle,param)
#define task_post_medium(handle,param) platform_post_medium(handle,param)
#define task_post_high(handle,param) platform_post_high(handle,param)
bool task_init_handler(uint8 priority, uint8 qlen);
task_handle_t task_get_id(task_callback_t t);
#define task_handle_t platform_task_handle_t
#define task_param_t platform_task_param_t
#define task_callback_t platform_task_callback_t
#define task_get_id platform_task_get_id
#endif

View File

@ -263,14 +263,14 @@ extern void dbg_printf(const char *fmt, ...);
#ifdef NODE_DEBUG
#define NODE_DBG dbg_printf
#else
#define NODE_DBG
#define NODE_DBG( ... )
#endif /* NODE_DEBUG */
#define NODE_ERROR
#ifdef NODE_ERROR
#define NODE_ERR dbg_printf
#else
#define NODE_ERR
#define NODE_ERR( ... )
#endif /* NODE_ERROR */
// #define GPIO_SAFE_NO_INTR_ENABLE

View File

@ -16,7 +16,7 @@ SUBDIRS = luac_cross
GEN_LIBS = liblua.a
endif
STD_CFLAGS=-std=gnu11 -Wimplicit
STD_CFLAGS=-std=gnu11 -Wimplicit -Wall
#############################################################
# Configuration i.e. compile options etc.

View File

@ -824,10 +824,9 @@ static int errfsfile (lua_State *L, const char *what, int fnameindex) {
}
LUALIB_API int luaL_loadfsfile (lua_State *L, const char *filename) {
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
LoadFSF lf;
int status, readstatus;
int c;
int status, c;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
lf.extraline = 0;
if (filename == NULL) {

View File

@ -79,7 +79,7 @@ LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
#ifdef LUA_CROSS_COMPILER
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
#else
LUALIB_API int (luaL_loadfsfile) (lua_State *L, const char *filename);
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
#endif
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
const char *name);
@ -119,7 +119,7 @@ LUALIB_API void luaL_assertfail(const char *file, int line, const char *message)
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#else
#define luaL_dofile(L, fn) \
(luaL_loadfsfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#endif
#define luaL_dostring(L, s) \

View File

@ -19,8 +19,6 @@
#include "lrotable.h"
/*
** If your system does not support `stdout', you can just remove this function.
** If you need, you can define your own `print' function, following this
@ -40,20 +38,11 @@ static int luaB_print (lua_State *L) {
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "
LUA_QL("print"));
#if defined(LUA_USE_STDIO)
if (i>1) fputs("\t", c_stdout);
fputs(s, c_stdout);
#else
if (i>1) luai_writestring("\t", 1);
luai_writestring(s, strlen(s));
#endif
if (i>1) puts("\t");
puts(s);
lua_pop(L, 1); /* pop result */
}
#if defined(LUA_USE_STDIO)
fputs("\n", c_stdout);
#else
luai_writeline();
#endif
puts("\n");
return 0;
}
@ -296,7 +285,7 @@ static int luaB_loadfile (lua_State *L) {
#ifdef LUA_CROSS_COMPILER
return load_aux(L, luaL_loadfile(L, fname));
#else
return load_aux(L, luaL_loadfsfile(L, fname));
return load_aux(L, luaL_loadfile(L, fname));
#endif
}
@ -343,7 +332,7 @@ static int luaB_dofile (lua_State *L) {
#ifdef LUA_CROSS_COMPILER
if (luaL_loadfile(L, fname) != 0) lua_error(L);
#else
if (luaL_loadfsfile(L, fname) != 0) lua_error(L);
if (luaL_loadfile(L, fname) != 0) lua_error(L);
#endif
lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - n;

View File

@ -365,7 +365,7 @@ static int db_debug (lua_State *L) {
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
static int db_errorfb (lua_State *L) {
int debug_errorfb (lua_State *L) {
int level;
int firstpart = 1; /* still before eventual `...' */
int arg;
@ -436,7 +436,7 @@ LROT_PUBLIC_BEGIN(dblib)
LROT_FUNCENTRY( setmetatable, db_setmetatable )
LROT_FUNCENTRY( setupvalue, db_setupvalue )
#endif
LROT_FUNCENTRY( traceback, db_errorfb )
LROT_FUNCENTRY( traceback, debug_errorfb )
LROT_END(dblib, NULL, 0)
LUALIB_API int luaopen_debug (lua_State *L) {

View File

@ -70,7 +70,7 @@ struct OUTPUT {
outBlock buffer;
int ndx;
uint32_t crc;
int (*fullBlkCB) (void);
void (*fullBlkCB) (void);
int flashLen;
int flagsLen;
int flagsNdx;
@ -79,7 +79,6 @@ struct OUTPUT {
} *out;
#ifdef NODE_DEBUG
extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
void dumpStrt(stringtable *tb, const char *type) {
int i,j;
GCObject *o;
@ -173,15 +172,15 @@ LUAI_FUNC void luaN_init (lua_State *L) {
}
if ((fh->flash_sig & (~FLASH_SIG_ABSOLUTE)) != FLASH_SIG ) {
NODE_ERR("Flash sig not correct: %p vs %p\n",
NODE_ERR("Flash sig not correct: 0x%08x vs 0x%08x\n",
fh->flash_sig & (~FLASH_SIG_ABSOLUTE), FLASH_SIG);
return;
}
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);
NODE_ERR("Flash size check failed: 0x%08x vs 0xFFFFFFFF; 0x%08x >= 0x%08x\n",
fh->pROhash, fh->mainProto - cast(FlashAddr, fh), fh->flash_size);
return;
}
@ -194,7 +193,7 @@ LUAI_FUNC void luaN_init (lua_State *L) {
//extern void software_reset(void);
static int loadLFS (lua_State *L);
static int loadLFSgc (lua_State *L);
static int procFirstPass (void);
static void procFirstPass (void);
/*
* Library function called by node.flashreload(filename).
@ -270,7 +269,6 @@ LUALIB_API int luaN_reload_reboot (lua_State *L) {
* - An array of the module names in the LFS
*/
LUAI_FUNC int luaN_index (lua_State *L) {
int i;
int n = lua_gettop(L);
/* Return nil + the LFS base address if the LFS size > 0 and it isn't loaded */
@ -406,11 +404,10 @@ static uint8_t recall_byte (unsigned offset) {
* - Once the flags array is in-buffer this is also captured.
* This logic is slightly complicated by the last buffer is typically short.
*/
int procFirstPass (void) {
void procFirstPass (void) {
int len = (out->ndx % WRITE_BLOCKSIZE) ?
out->ndx % WRITE_BLOCKSIZE : WRITE_BLOCKSIZE;
if (out->ndx <= WRITE_BLOCKSIZE) {
uint32_t fl;
/* Process the flash header and cache the FlashHeader fields we need */
FlashHeader *fh = cast(FlashHeader *, out->block[0]);
out->flashLen = fh->flash_size; /* in bytes */
@ -442,12 +439,10 @@ int procFirstPass (void) {
memcpy(out->flags + out->flagsNdx, out->block[0]->byte + start, len - start);
out->flagsNdx += (len -start) / WORDSIZE; /* flashLen and len are word aligned */
}
return 1;
}
int procSecondPass (void) {
void procSecondPass (void) {
/*
* The length rules are different for the second pass since this only processes
* upto the flashLen and not the full image. This also works in word units.
@ -456,7 +451,7 @@ int procSecondPass (void) {
int i, len = (out->ndx > out->flashLen) ?
(out->flashLen % WRITE_BLOCKSIZE) / WORDSIZE :
WRITE_BLOCKSIZE / WORDSIZE;
uint32_t *buf = (uint32_t *) out->buffer.byte, flags;
uint32_t *buf = (uint32_t *) out->buffer.byte, flags = 0;
/*
* Relocate all the addresses tagged in out->flags. This can't be done in
* place because the out->blocks are still in use as dictionary content so
@ -492,7 +487,7 @@ int procSecondPass (void) {
*/
static int loadLFS (lua_State *L) {
const char *fn = cast(const char *, lua_touserdata(L, 1));
int i, n, res;
int i, res;
uint32_t crc;
/* Allocate and zero in and out structures */
@ -541,12 +536,11 @@ static int loadLFS (lua_State *L) {
flashErase(0,(out->flashLen - 1)/FLASH_PAGE_SIZE);
flashSetPosition(0);
if (uzlib_inflate(get_byte, put_byte, recall_byte,
in->len, &crc, &in->inflate_state) != UZLIB_OK)
if (res < 0) {
if ((res = uzlib_inflate(get_byte, put_byte, recall_byte,
in->len, &crc, &in->inflate_state)) != UZLIB_OK) {
const char *err[] = {"Data_error during decompression",
"Chksum_error during decompression",
"Dictionary error during decompression"
"Dictionary error during decompression",
"Memory_error during decompression"};
flash_error(err[UZLIB_DATA_ERROR - res]);
}

116
app/lua/lnodemcu.c Normal file
View File

@ -0,0 +1,116 @@
/*
** $Id: ltm.c,v 2.8.1.1 2007/12/27 13:02:25 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
#define lnodemcu_c
#define LUA_CORE
#include "lua.h"
#include <string.h>
#include "lobject.h"
#include "lstate.h"
#include "lauxlib.h"
#include "lgc.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lrotable.h"
#include "platform.h"
extern int debug_errorfb (lua_State *L);
#if 0
extern int pipe_create(lua_State *L);
extern int pipe_read(lua_State *L);
extern int pipe_unread(lua_State *L);
extern int pipe_write(lua_State *L);
#endif
/*
** Error Reporting Task. We can't pass a string parameter to the error reporter
** directly through the task interface the call is wrapped in a C closure with
** the error string as an Upval and this is posted to call the Lua reporter.
*/
static int report_traceback (lua_State *L) {
// **Temp** lua_rawgeti(L, LUA_REGISTRYINDEX, G(L)->error_reporter);
lua_getglobal(L, "print");
lua_pushvalue(L, lua_upvalueindex(1));
lua_call(L, 1, 0); /* Using an error handler would cause an infinite loop! */
return 0;
}
/*
** Catch all error handler for CB calls. This uses debug.traceback() to
** generate a full Lua traceback.
*/
int luaN_traceback (lua_State *L) {
if (lua_isstring(L, 1)) {
lua_pushlightfunction(L, &debug_errorfb);
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback and return it as a string */
lua_pushcclosure(L, report_traceback, 1); /* report with str as upval */
luaN_posttask(L, LUA_TASK_HIGH);
}
return 0;
}
/*
** Use in CBs and other C functions to call a Lua function. This includes
** an error handler which will catch any error and then post this to the
** registered reporter function as a separate follow-on task.
*/
int luaN_call (lua_State *L, int narg, int res, int doGC) { // [-narg, +0, v]
int status;
int base = lua_gettop(L) - narg;
lua_pushcfunction(L, luaN_traceback);
lua_insert(L, base); /* put under args */
status = lua_pcall(L, narg, (res < 0 ? LUA_MULTRET : res), base);
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection if requested */
if (doGC)
lua_gc(L, LUA_GCCOLLECT, 0);
return status;
}
static platform_task_handle_t task_handle = 0;
/*
** Task callback handler. Uses luaN_call to do a protected call with full traceback
*/
static void do_task (platform_task_param_t task_fn_ref, uint8_t prio) {
lua_State* L = lua_getstate();
if (prio < 0|| prio > 2)
luaL_error(L, "invalid posk task");
/* Pop the CB func from the Reg */
//dbg_printf("calling Reg[%u]\n", task_fn_ref);
lua_rawgeti(L, LUA_REGISTRYINDEX, (int) task_fn_ref);
luaL_checkanyfunction(L, -1);
luaL_unref(L, LUA_REGISTRYINDEX, (int) task_fn_ref);
lua_pushinteger(L, prio);
luaN_call (L, 1, 0, 1);
}
/*
** Schedule a Lua function for task execution
*/
#include "lstate.h" /*DEBUG*/
LUA_API int luaN_posttask( lua_State* L, int prio ) { // [-1, +0, -]
if (!task_handle)
task_handle = platform_task_get_id(do_task);
if (!lua_isanyfunction(L, -1) || prio < LUA_TASK_LOW|| prio > LUA_TASK_HIGH)
luaL_error(L, "invalid posk task");
//void *cl = clvalue(L->top-1);
int task_fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
//dbg_printf("posting Reg[%u]=%p\n",task_fn_ref,cl);
if(!platform_post(prio, task_handle, (platform_task_param_t)task_fn_ref)) {
luaL_unref(L, LUA_REGISTRYINDEX, task_fn_ref);
luaL_error(L, "Task queue overflow. Task not posted");
}
return task_fn_ref;
}

View File

@ -397,7 +397,7 @@ static int loader_Lua (lua_State *L) {
#ifdef LUA_CROSS_COMPILER
if (luaL_loadfile(L, filename) != 0)
#else
if (luaL_loadfsfile(L, filename) != 0)
if (luaL_loadfile(L, filename) != 0)
#endif
loaderror(L, filename);
return 1; /* library loaded successfully */

View File

@ -113,7 +113,7 @@ typedef struct lua_TValue {
#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
#define ttisrotable(o) (ttype(o) == LUA_TROTABLE)
#define ttislightfunction(o) (ttype(o) == LUA_TLIGHTFUNCTION)
#define ttisanyfunction(o) (ttisfunction(o) || ttislightfunction(o))
/* Macros to access values */

View File

@ -197,11 +197,12 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->memlimit = 0;
#endif
#ifndef LUA_CROSS_COMPILER
g->ROstrt.size = 0;
g->ROstrt.nuse = 0;
g->ROstrt.hash = NULL;
g->ROpvmain = NULL;
g->LFSsize = 0;
g->ROstrt.size = 0;
g->ROstrt.nuse = 0;
g->ROstrt.hash = NULL;
g->ROpvmain = NULL;
g->LFSsize = 0;
g->error_reporter = 0;
#endif
for (i=0; i<NUM_TAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {

View File

@ -98,6 +98,7 @@ typedef struct global_State {
stringtable ROstrt; /* Flash-based hash table for RO strings */
Proto *ROpvmain; /* Flash-based Proto main */
int LFSsize; /* Size of Lua Flash Store */
int error_reporter; /* Registry Index of error reporter task */
#endif
} global_State;

View File

@ -1,18 +1,16 @@
/*
** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
** Lua stand-alone interpreter
** NodeMCU Lua 5.1 main initiator and comand interpreter
** See Copyright Notice in lua.h
**
** Note this is largely a backport of some new Lua 5.3 version but
** with API changes for Lua 5.1 compatability
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "user_interface.h"
#include "user_version.h"
#include "driver/readline.h"
#include "driver/uart.h"
#include "platform.h"
#include "driver/input.h"
#define lua_c
@ -21,498 +19,283 @@
#include "lauxlib.h"
#include "lualib.h"
#include "legc.h"
#include "lflash.h"
#include "os_type.h"
extern int debug_errorfb (lua_State *L);
extern int pipe_create(lua_State *L);
extern int pipe_read(lua_State *L);
extern int pipe_unread(lua_State *L);
#ifndef LUA_INIT_STRING
#define LUA_INIT_STRING "@init.lua"
#endif
static int MLref = LUA_NOREF;
lua_State *globalL = NULL;
static lua_Load gLoad;
static const char *progname = LUA_PROGNAME;
static int pmain (lua_State *L);
static int dojob (lua_State *L);
static void l_message (const char *pname, const char *msg) {
#if defined(LUA_USE_STDIO)
if (pname) fprintf(c_stderr, "%s: ", pname);
fprintf(c_stderr, "%s\n", msg);
fflush(c_stderr);
#else
if (pname) luai_writestringerror("%s: ", pname);
static void l_message (const char *msg) {
luai_writestringerror("%s\n", msg);
#endif
}
static int report (lua_State *L, int status) {
if (status && !lua_isnil(L, -1)) {
const char *msg = lua_tostring(L, -1);
if (msg == NULL) msg = "(error object is not a string)";
l_message(progname, msg);
l_message(msg);
lua_pop(L, 1);
}
return status;
}
static void l_print(lua_State *L, int n) {
lua_getglobal(L, "print");
lua_insert(L, -n-1);
if (lua_pcall(L, n, 0, 0) != 0)
l_message(lua_pushfstring(L, "error calling " LUA_QL("print") " (%s)",
lua_tostring(L, -1)));
}
static int traceback (lua_State *L) {
if (!lua_isstring(L, 1)) /* 'message' not a string? */
return 1; /* keep it intact */
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1) && !lua_isrotable(L, -1)) {
lua_pop(L, 1);
return 1;
if (lua_isstring(L, 1)) {
lua_pushlightfunction(L, &debug_errorfb);
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1) && !lua_islightfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
lua_settop(L, 1);
return 1;
}
static int docall (lua_State *L, int narg, int clear) {
int status;
int base = lua_gettop(L) - narg; /* function index */
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
// signal(SIGINT, laction);
int base = lua_gettop(L) - narg; /* function index */
lua_pushlightfunction(L, &traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
status = lua_pcall(L, narg, (clear ? 0 : LUA_MULTRET), base);
// signal(SIGINT, SIG_DFL);
lua_remove(L, base); /* remove traceback function */
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
return status;
}
static void print_version (lua_State *L) {
lua_pushliteral (L, "\n" NODE_VERSION " build " BUILD_DATE " powered by " LUA_RELEASE " on SDK ");
lua_pushliteral (L, "\n" NODE_VERSION " build " BUILD_DATE
" powered by " LUA_RELEASE " on SDK ");
lua_pushstring (L, SDK_VERSION);
lua_concat (L, 2);
const char *msg = lua_tostring (L, -1);
l_message (NULL, msg);
l_message (msg);
lua_pop (L, 1);
}
static int getargs (lua_State *L, char **argv, int n) {
int narg;
int i;
int argc = 0;
while (argv[argc]) argc++; /* count total number of arguments */
narg = argc - (n + 1); /* number of arguments to the script */
luaL_checkstack(L, narg + 3, "too many arguments to script");
for (i=n+1; i < argc; i++)
lua_pushstring(L, argv[i]);
lua_createtable(L, narg, n + 1);
for (i=0; i < argc; i++) {
lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i - n);
}
return narg;
}
static int dofsfile (lua_State *L, const char *name) {
int status = luaL_loadfsfile(L, name) || docall(L, 0, 1);
static int dofile (lua_State *L, const char *name) {
int status = luaL_loadfile(L, name) || docall(L, 0, 1);
return report(L, status);
}
static int dostring (lua_State *L, const char *s, const char *name) {
int status = luaL_loadbuffer(L, s, strlen(s), name) || docall(L, 0, 1);
return report(L, status);
}
static int dolibrary (lua_State *L, const char *name) {
lua_getglobal(L, "require");
lua_pushstring(L, name);
return report(L, docall(L, 1, 1));
}
static const char *get_prompt (lua_State *L, int firstline) {
const char *p;
lua_getfield(L, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2");
p = lua_tostring(L, -1);
if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2);
lua_pop(L, 1); /* remove global */
return p;
}
#define EOFMARK LUA_QL("<eof>")
static int incomplete (lua_State *L, int status) {
if (status == LUA_ERRSYNTAX) {
size_t lmsg;
const char *msg = lua_tolstring(L, -1, &lmsg);
const char *tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
if (strstr(msg, LUA_QL("<eof>")) == tp) {
if (!strcmp(msg+lmsg-sizeof(EOFMARK)+1, EOFMARK)) {
lua_pop(L, 1);
return 1;
}
}
return 0; /* else... */
}
/* check that argument has no extra characters at the end */
#define notail(x) {if ((x)[2] != '\0') return -1;}
static int collectargs (char **argv, int *pi, int *pv, int *pe) {
int i;
for (i = 1; argv[i] != NULL; i++) {
if (argv[i][0] != '-') /* not an option? */
return i;
switch (argv[i][1]) { /* option */
case '-':
notail(argv[i]);
return (argv[i+1] != NULL ? i+1 : 0);
case '\0':
return i;
case 'i':
notail(argv[i]);
*pi = 1; /* go through */
case 'v':
notail(argv[i]);
*pv = 1;
break;
case 'e':
*pe = 1; /* go through */
case 'm': /* go through */
case 'l':
if (argv[i][2] == '\0') {
i++;
if (argv[i] == NULL) return -1;
}
break;
default: return -1; /* invalid option */
}
}
return 0;
}
static int runargs (lua_State *L, char **argv, int n) {
int i;
for (i = 1; i < n; i++) {
if (argv[i] == NULL) continue;
lua_assert(argv[i][0] == '-');
switch (argv[i][1]) { /* option */
case 'e': {
const char *chunk = argv[i] + 2;
if (*chunk == '\0') chunk = argv[++i];
lua_assert(chunk != NULL);
if (dostring(L, chunk, "=(command line)") != 0)
return 1;
break;
}
case 'm': {
const char *limit = argv[i] + 2;
int memlimit=0;
if (*limit == '\0') limit = argv[++i];
lua_assert(limit != NULL);
memlimit = atoi(limit);
lua_gc(L, LUA_GCSETMEMLIMIT, memlimit);
break;
}
case 'l': {
const char *filename = argv[i] + 2;
if (*filename == '\0') filename = argv[++i];
lua_assert(filename != NULL);
if (dolibrary(L, filename))
return 1; /* stop if file fails */
break;
}
default: break;
}
}
return 0;
}
#ifndef LUA_INIT_STRING
#define LUA_INIT_STRING "@init.lua"
#endif
static int handle_luainit (lua_State *L) {
const char *init = LUA_INIT_STRING;
if (init[0] == '@')
return dofsfile(L, init+1);
else
return dostring(L, init, LUA_INIT);
}
struct Smain {
int argc;
char **argv;
/*
** dojob is the CB reader for the input pipe and follows the calling convention
** for pipe reader CBs. It has one argument: the stdin pipe that it is reading.
*/
static int dojob (lua_State *L) {
size_t l;
int status;
};
const char *prompt;
//dbg_printf("dojob entered\n");
lua_settop(L, 1); /* pipe obj at S[1] */
lua_pushlightfunction(L, &pipe_read); /* pobj:read at S[2] */
lua_pushvalue(L, 1); /* dup pobj to S[3] */
lua_pushliteral(L, "\n+"); /* S[4] = "\n+" */
lua_call(L, 2, 1); /* S[2] = pobj:read("\n+") */
const char* b = lua_tolstring(L, 2, &l); /* b = NULL if S[2] is nil */
if ((lua_isnil(L, 2) || l == 0)) {
/* If the pipe is empty then return false to suppress automatic reposting */
//dbg_printf("stdin empty\n");
lua_pushboolean(L, false);
return 1; /* return false */
}
if (b[l-1] != '\n') {
//dbg_printf("unreading part line\n");
/* likewise if not CR terminated, then unread and ditto */
lua_pushlightfunction(L, &pipe_unread); /* pobj:read at S[1] */
lua_insert(L, 1);
lua_call(L, 2, 0); /* pobj:unread(line) */
lua_pushboolean(L, false);
return 1; /* return false */
} else {
//dbg_printf("popping CR terminated string(%d) %s", l-1, b);
}
/*
* Now we can process a proper CR terminated line
*/
lua_pushlstring(L, b, --l); /* remove end CR */
lua_remove(L, 2);
b = lua_tostring(L, 2);
if (MLref != LUA_NOREF) {
/* processing multiline */
lua_rawgeti(L, LUA_REGISTRYINDEX, MLref); /* insert prev lines(s) */
lua_pushliteral(L, "\n"); /* insert CR */
lua_pushvalue(L, 2); /* dup new line */
lua_concat(L, 3); /* concat all 3 */
lua_remove(L, 2); /* and shift down to S[2] */
} else if (b[0] == '=') {
/* If firstline and of the format =<expression> */
lua_pushfstring(L, "return %s", b+1);
lua_remove(L, 2);
}
/* ToS is at S[2] which contains the putative chunk to be compiled */
status = luaL_loadbuffer(L, lua_tostring(L, 2), lua_strlen(L, 2), "=stdin");
if (incomplete(L, status)) {
/* Store line back in the Reg mlref sot */
if (MLref == LUA_NOREF) {
MLref = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_rawseti(L, LUA_REGISTRYINDEX, MLref);
}
} else {
/* compile finished OK or with hard error */
lua_remove(L, 2); /* remove line because now redundant */
if (MLref!= LUA_NOREF) { /* also remove multiline if it exists */
luaL_unref(L, LUA_REGISTRYINDEX, MLref);
MLref= LUA_NOREF;
}
/* Execute the compiled chunk of successful */
if (status == 0) {
status = docall(L, 0, 0);
}
/* print any returned results or error message */
if (status && !lua_isnil(L, -1))
l_print(L, 1);
if (status == 0 && lua_gettop(L) - 1)
l_print(L, lua_gettop(L) - 1);
lua_settop(L, 2);
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
}
prompt = get_prompt(L, MLref!= LUA_NOREF ? 0 : 1);
input_setprompt(prompt);
puts(prompt);
lua_pushnil(L);
return 1; /* return nil will retask if pipe not empty */
}
/*
* Kick off library and UART input handling before opening the module
* libraries. Note that as this is all done within a Lua task, so error
* handling is left to the Lua task traceback mechanism.
*/
extern void luaL_dbgbreak(void);
static int pmain (lua_State *L) {
struct Smain *s = (struct Smain *)lua_touserdata(L, 1);
char **argv = s->argv;
int script;
int has_i = 0, has_v = 0, has_e = 0;
const char *init = LUA_INIT_STRING;
globalL = L;
if (argv[0] && argv[0][0]) progname = argv[0];
lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
luaL_openlibs(L); /* open libraries */
lua_gc(L, LUA_GCRESTART, 0);
lua_gc(L, LUA_GCSTOP, 0); /* stop GC during initialization */
luaL_openlibs(L); /* open libraries */
lua_gc(L, LUA_GCRESTART, 0); /* restart GC and set EGC mode */
legc_set_mode( L, EGC_ALWAYS, 4096 );
lua_settop(L, 0);
lua_pushliteral(L, "stdin");
lua_pushlightfunction(L, &pipe_create);
lua_pushlightfunction(L, &dojob);
lua_pushinteger(L, LUA_TASK_LOW);
lua_call(L, 2, 1); /* ToS = pipe.create(dojob, low_priority) */
lua_rawset(L, LUA_REGISTRYINDEX); /* and stash input pipe in Reg["stdin"] */
input_setup(LUA_MAXINPUT, get_prompt(L, 1));
lua_input_string(" \n", 2); /* queue CR to issue first prompt */
print_version(L);
s->status = handle_luainit(L);
script = collectargs(argv, &has_i, &has_v, &has_e);
if (script < 0) { /* invalid args? */
s->status = 1;
return 0;
}
s->status = runargs(L, argv, (script > 0) ? script : s->argc);
if (s->status != 0) return 0;
/* and last of all, kick off application initialisation */
if (init[0] == '@')
dofile(L, init+1);
else
dostring(L, init, LUA_INIT);
return 0;
}
static void dojob(lua_Load *load);
static bool readline(lua_Load *load);
#ifdef LUA_RPC
int main (int argc, char **argv) {
#else
int lua_main (int argc, char **argv) {
#endif
int status;
struct Smain s;
#if defined(NODE_DEBUG) && defined(DEVELOPMENT_USE_GDB) && \
defined(DEVELOPMENT_BREAK_ON_STARTUP_PIN) && DEVELOPMENT_BREAK_ON_STARTUP_PIN > 0
platform_gpio_mode( DEVELOPMENT_BREAK_ON_STARTUP_PIN, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_PULLUP );
lua_assert(platform_gpio_read(DEVELOPMENT_BREAK_ON_STARTUP_PIN)); // Break if pin pulled low
#endif
lua_State *L = lua_open(); /* create state */
/*
** The system initialisation CB nodemcu_init() calls lua_main() to startup
** the Lua environment by calling lua_open() which initiates the core Lua VM.
** The initialisation of the libraries, etc. is carried out by pmain in a
** separate Lua task, which also kicks off the user application through the
** LUA_INIT_STRING hook.
*/
void lua_main (void) {
lua_State *L = lua_open(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
l_message("cannot create state: not enough memory");
return;
}
s.argc = argc;
s.argv = argv;
status = lua_cpcall(L, &pmain, &s);
report(L, status);
gLoad.L = L;
gLoad.firstline = 1;
gLoad.done = 0;
gLoad.line = malloc(LUA_MAXINPUT);
gLoad.len = LUA_MAXINPUT;
gLoad.line_position = 0;
gLoad.prmt = get_prompt(L, 1);
dojob(&gLoad);
NODE_DBG("Heap size:%d.\n",system_get_free_heap_size());
legc_set_mode( L, EGC_ALWAYS, 4096 );
// legc_set_mode( L, EGC_ON_MEM_LIMIT, 4096 );
// lua_close(L);
return (status || s.status) ? EXIT_FAILURE : EXIT_SUCCESS;
lua_pushlightfunction(L, &pmain); /* Call 'pmain' as a high priority task */
luaN_posttask(L, LUA_TASK_HIGH);
}
int lua_put_line(const char *s, size_t l) {
if (s == NULL || ++l > LUA_MAXINPUT || gLoad.line_position > 0)
return 0;
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)
{
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, strlen(gLoad.line), gLoad.line);
dojob (&gLoad);
force = false;
}
}
void donejob(lua_Load *load){
lua_close(load->L);
}
static void dojob(lua_Load *load){
size_t l, rs;
int status;
char *b = load->line;
lua_State *L = load->L;
const char *oldprogname = progname;
progname = NULL;
do{
if(load->done == 1){
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
b[l-1] = '\0'; /* remove it */
if (load->firstline && b[0] == '=') /* first line starts with `=' ? */
lua_pushfstring(L, "return %s", b+1); /* change it to `return' */
else
lua_pushstring(L, b);
if(load->firstline != 1){
lua_pushliteral(L, "\n"); /* add a new line... */
lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */
}
status = luaL_loadbuffer(L, lua_tostring(L, 1), lua_strlen(L, 1), "=stdin");
if (!incomplete(L, status)) { /* cannot try to add lines? */
lua_remove(L, 1); /* remove line */
if (status == 0) {
status = docall(L, 0, 0);
}
report(L, status);
if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
lua_getglobal(L, "print");
lua_insert(L, 1);
if (lua_pcall(L, lua_gettop(L)-1, 0, 0) != 0)
l_message(progname, lua_pushfstring(L,
"error calling " LUA_QL("print") " (%s)",
lua_tostring(L, -1)));
}
load->firstline = 1;
load->prmt = get_prompt(L, 1);
lua_settop(L, 0);
/* force a complete garbage collection in case of errors */
if (status != 0) lua_gc(L, LUA_GCCOLLECT, 0);
} else {
load->firstline = 0;
load->prmt = get_prompt(L, 0);
}
}
}while(0);
progname = oldprogname;
load->done = 0;
load->line_position = 0;
memset(load->line, 0, load->len);
puts(load->prmt);
}
#ifndef uart_putc
#define uart_putc uart0_putc
#endif
extern bool uart_on_data_cb(const char *buf, size_t len);
extern bool uart0_echo;
extern bool run_input;
extern uint16_t need_len;
extern int16_t end_char;
static char last_nl_char = '\0';
static bool readline(lua_Load *load){
// NODE_DBG("readline() is called.\n");
bool need_dojob = false;
char ch;
while (uart_getc(&ch))
{
if(run_input)
{
char tmp_last_nl_char = last_nl_char;
// reset marker, will be finally set below when newline is processed
last_nl_char = '\0';
/* handle CR & LF characters
filters second char of LF&CR (\n\r) or CR&LF (\r\n) sequences */
if ((ch == '\r' && tmp_last_nl_char == '\n') || // \n\r sequence -> skip \r
(ch == '\n' && tmp_last_nl_char == '\r')) // \r\n sequence -> skip \n
{
continue;
}
/* backspace key */
else if (ch == 0x7f || ch == 0x08)
{
if (load->line_position > 0)
{
if(uart0_echo) uart_putc(0x08);
if(uart0_echo) uart_putc(' ');
if(uart0_echo) uart_putc(0x08);
load->line_position--;
}
load->line[load->line_position] = 0;
continue;
}
/* EOT(ctrl+d) */
// else if (ch == 0x04)
// {
// if (load->line_position == 0)
// // No input which makes lua interpreter close
// donejob(load);
// else
// continue;
// }
/* end of line */
if (ch == '\r' || ch == '\n')
{
last_nl_char = ch;
load->line[load->line_position] = 0;
if(uart0_echo) uart_putc('\n');
uart_on_data_cb(load->line, load->line_position);
if (load->line_position == 0)
{
/* Get a empty line, then go to get a new line */
puts(load->prmt);
continue;
} else {
load->done = 1;
need_dojob = true;
break;
}
}
/* other control character or not an acsii character */
// if (ch < 0x20 || ch >= 0x80)
// {
// continue;
// }
/* echo */
if(uart0_echo) uart_putc(ch);
/* it's a large line, discard it */
if ( load->line_position + 1 >= load->len ){
load->line_position = 0;
}
}
load->line[load->line_position] = ch;
load->line_position++;
if(!run_input)
{
if( ((need_len!=0) && (load->line_position >= need_len)) || \
(load->line_position >= load->len) || \
((end_char>=0) && ((unsigned char)ch==(unsigned char)end_char)) )
{
uart_on_data_cb(load->line, load->line_position);
load->line_position = 0;
}
}
ch = 0;
}
if( (load->line_position > 0) && (!run_input) && (need_len==0) && (end_char<0) )
{
uart_on_data_cb(load->line, load->line_position);
load->line_position = 0;
}
return need_dojob;
/*
** The Lua interpreter is event-driven and task-oriented in NodeMCU rather than
** based on a readline poll loop as in the standard implementation. Input lines
** can come from one of two sources: the application can "push" lines for the
** interpreter to compile and execute, or they can come from the UART. To
** minimise application blocking, the lines are queued in a pipe when received,
** with the Lua interpreter task attached to the pipe as its reader task. This
** CB processes one line of input per task execution.
**
** Even though lines can be emitted from independent sources (the UART and the
** node API), and they could in theory get interleaved, the strategy here is
** "let the programmer beware": interactive input will normally only occur in
** development and injected input occur in telnet type applications. If there
** is a need for interlocks, then the application should handle this.
*/
//static int n = 0;
void lua_input_string (const char *line, int len) {
lua_State *L = globalL;
lua_getfield(L, LUA_REGISTRYINDEX, "stdin");
lua_rawgeti(L, -1, 1); /* get the pipe_write from stdin[1] */
lua_insert(L, -2); /* stick above the pipe */
lua_pushlstring(L, line, len);
//const char*b = lua_tostring(L, -1);
//dbg_printf("Pushing (%u): %s", len, b);
lua_call(L, 2, 0); /* stdin:write(line) */
}

View File

@ -273,9 +273,11 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_islightfunction(L,n) (lua_type(L, (n)) == LUA_TLIGHTFUNCTION)
#define lua_isanyfunction(L,n) (lua_isfunction(L,n) || lua_islightfunction(L,n))
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_isrotable(L,n) (lua_type(L, (n)) == LUA_TROTABLE)
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
#define lua_isanytable(L,n) (lua_istable(L,n) || lua_isrotable(L,n))
#define lua_islightuserdata(L,n) (lua_type(L, (n) == LUA_TLIGHTUSERDATA)
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
@ -375,20 +377,19 @@ struct lua_Debug {
/* }====================================================================== */
typedef struct __lua_load{
lua_State *L;
int firstline;
char *line;
int line_position;
size_t len;
int done;
const char *prmt;
}lua_Load;
int lua_main( int argc, char **argv );
#ifndef LUA_CROSS_COMPILER
void lua_handle_input (bool force);
#define LUA_QUEUE_APP 0
#define LUA_QUEUE_UART 1
#define LUA_TASK_LOW 0
#define LUA_TASK_MEDIUM 1
#define LUA_TASK_HIGH 2
void lua_main (void);
void lua_input_string (const char *line, int len);
int luaN_posttask (lua_State* L, int prio);
int luaN_call (lua_State *L, int narg, int res, int dogc);
/**DEBUG**/extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
#endif
/******************************************************************************

View File

@ -5,6 +5,7 @@
#include "lauxlib.h"
#include "lmem.h"
#include "platform.h"
#include "task/task.h"
#include "user_interface.h"
#include <stdint.h>
#include <string.h>

View File

@ -45,7 +45,7 @@ typedef struct {
static int active_pulser_ref;
static pulse_t *active_pulser;
static task_handle_t tasknumber;
static platform_task_handle_t tasknumber;
static int gpio_pulse_push_state(lua_State *L, pulse_t *pulser) {
uint32_t now;
@ -321,7 +321,7 @@ static void ICACHE_RAM_ATTR gpio_pulse_timeout(os_param_t p) {
active_pulser->steps++;
}
platform_hw_timer_close(TIMER_OWNER);
task_post_low(tasknumber, (task_param_t)0);
platform_post_low(tasknumber, 0);
return;
}
active_pulser->steps++;
@ -341,7 +341,7 @@ static void ICACHE_RAM_ATTR gpio_pulse_timeout(os_param_t p) {
int16_t stop = active_pulser->stop_pos;
if (stop == -2 || stop == active_pulser->entry_pos) {
platform_hw_timer_close(TIMER_OWNER);
task_post_low(tasknumber, (task_param_t)0);
platform_post_low(tasknumber, 0);
return;
}
@ -488,7 +488,7 @@ LROT_END( gpio_pulse, gpio_pulse, LROT_MASK_INDEX )
int gpio_pulse_init(lua_State *L)
{
luaL_rometatable(L, "gpio.pulse", LROT_TABLEREF(pulse));
tasknumber = task_get_id(gpio_pulse_task);
tasknumber = platform_task_get_id(gpio_pulse_task);
return 0;
}

View File

@ -736,6 +736,14 @@ int net_getaddr( lua_State *L ) {
lua_pushstring(L, addr_str);
return 2;
}
#if 0
static void dbg_print_ud(const char *title, lnet_userdata *ud) {
int i;
dbg_printf("%s: Userdata %p:", title, ud);
for (i=0; i<(sizeof(*ud)/sizeof(uint32_t)); i++)
dbg_printf( " 0x%08x", ((uint32_t *)ud)[i]);
dbg_printf("\n");
#endif
// Lua: client/server/socket:close()
int net_close( lua_State *L ) {
@ -764,11 +772,14 @@ int net_close( lua_State *L ) {
}
if (ud->type == TYPE_TCP_SERVER ||
(ud->pcb == NULL && ud->client.wait_dns == 0)) {
lua_gc(L, LUA_GCSTOP, 0);
// lua_gc(L, LUA_GCSTOP, 0);
luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
ud->self_ref = LUA_NOREF;
lua_gc(L, LUA_GCRESTART, 0);
// lua_gc(L, LUA_GCRESTART, 0);
}
#if 0
dbg_print_ud("close exit", ud);
#endif
return 0;
}
@ -813,10 +824,13 @@ int net_delete( lua_State *L ) {
ud->server.cb_accept_ref = LUA_NOREF;
break;
}
lua_gc(L, LUA_GCSTOP, 0);
// lua_gc(L, LUA_GCSTOP, 0);
luaL_unref(L, LUA_REGISTRYINDEX, ud->self_ref);
ud->self_ref = LUA_NOREF;
lua_gc(L, LUA_GCRESTART, 0);
// lua_gc(L, LUA_GCRESTART, 0);
#if 0
dbg_print_ud("delete end", ud);
#endif
return 0;
}

View File

@ -171,69 +171,59 @@ static int node_heap( lua_State* L )
return 1;
}
extern int lua_put_line(const char *s, size_t l);
extern bool user_process_input(bool force);
// Lua: input("string")
static int node_input( lua_State* L ) {
size_t l = 0;
const char *s = luaL_checklstring(L, 1, &l);
if (lua_put_line(s, l)) {
NODE_DBG("Result (if any):\n");
user_process_input(true);
}
luaL_checkstring(L, 1);
lua_getfield(L, LUA_REGISTRYINDEX, "stdin");
lua_rawgeti(L, -1, 1); /* get the pipe_write func from stdin[1] */
lua_insert(L, -2); /* and move above the pipe ref */
lua_pushvalue(L, 1);
lua_call(L, 2, 0); /* stdin:write(line) */
return 0;
}
static int output_redir_ref = LUA_NOREF;
static int serial_debug = 1;
void output_redirect(const char *str) {
lua_State *L = lua_getstate();
// if(strlen(str)>=TX_BUFF_SIZE){
// NODE_ERR("output too long.\n");
// return;
// }
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 */
if (serial_debug) {
uart0_sendStr(str);
}
lua_rawgeti(L, -1, 1); /* get the pipe_write func from stdout[1] */
lua_insert(L, -2); /* and move above the pipe ref */
lua_pushstring(L, str);
lua_call(L, 2, 0); /* Reg.stdout:write(str) */
if (output_redir_ref == LUA_NOREF) {
uart0_sendStr(str);
return;
}
if (serial_debug != 0) {
} else { /* reg.stdout == nil */
uart0_sendStr(str);
}
lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref);
lua_pushstring(L, str);
lua_call(L, 1, 0); // this call back function should never user output.
lua_settop(L, n); /* Make sure all code paths leave stack unchanged */
}
extern int pipe_create(lua_State *L);
// Lua: output(function(c), debug)
static int node_output( lua_State* L )
{
// luaL_checkanyfunction(L, 1);
if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION) {
lua_pushvalue(L, 1); // copy argument (func) to the top of stack
if (output_redir_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX);
} else { // unref the key press function
if (output_redir_ref != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = LUA_NOREF;
serial_debug = (lua_isnumber(L, 2) && lua_tointeger(L, 2) == 0) ? 0 : 1;
lua_settop(L, 1);
if (lua_isanyfunction(L, 1)) {
lua_pushlightfunction(L, &pipe_create);
lua_insert(L, 1);
lua_pushinteger(L, LUA_TASK_MEDIUM);
lua_call(L, 2, 1); /* T[1] = pipe.create(dojob, low_priority) */
} else { // remove the stdout pipe
lua_pop(L,1);
lua_pushnil(L); /* T[1] = nil */
serial_debug = 1;
return 0;
}
if ( lua_isnumber(L, 2) )
{
serial_debug = lua_tointeger(L, 2);
if (serial_debug != 0)
serial_debug = 1;
} else {
serial_debug = 1; // default to 1
}
lua_pushliteral(L, "stdout");
lua_insert(L, 1);
lua_rawset(L, LUA_REGISTRYINDEX); /* Reg.stdout = nil or pipe */
return 0;
}
@ -274,7 +264,7 @@ static int node_compile( lua_State* L )
output[strlen(output) - 1] = '\0';
NODE_DBG(output);
NODE_DBG("\n");
if (luaL_loadfsfile(L, fname) != 0) {
if (luaL_loadfile(L, fname) != 0) {
luaM_free( L, output );
return luaL_error(L, lua_tostring(L, -1));
}
@ -315,39 +305,19 @@ static int node_compile( lua_State* L )
return 0;
}
// Task callback handler for node.task.post()
static task_handle_t do_node_task_handle;
static void do_node_task (task_param_t task_fn_ref, uint8_t prio)
{
lua_State* L = lua_getstate();
lua_rawgeti(L, LUA_REGISTRYINDEX, (int)task_fn_ref);
luaL_unref(L, LUA_REGISTRYINDEX, (int)task_fn_ref);
lua_pushinteger(L, prio);
lua_call(L, 1, 0);
}
// Lua: node.task.post([priority],task_cb) -- schedule a task for execution next
static int node_task_post( lua_State* L )
{
int n = 1, Ltype = lua_type(L, 1);
int n=1;
unsigned priority = TASK_PRIORITY_MEDIUM;
if (Ltype == LUA_TNUMBER) {
if (lua_type(L, 1) == LUA_TNUMBER) {
priority = (unsigned) luaL_checkint(L, 1);
luaL_argcheck(L, priority <= TASK_PRIORITY_HIGH, 1, "invalid priority");
Ltype = lua_type(L, ++n);
}
luaL_argcheck(L, Ltype == LUA_TFUNCTION || Ltype == LUA_TLIGHTFUNCTION, n, "invalid function");
lua_pushvalue(L, n);
int task_fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
if (!do_node_task_handle) // bind the task handle to do_node_task on 1st call
do_node_task_handle = task_get_id(do_node_task);
if(!task_post(priority, do_node_task_handle, (task_param_t)task_fn_ref)) {
luaL_unref(L, LUA_REGISTRYINDEX, task_fn_ref);
luaL_error(L, "Task queue overflow. Task not posted");
n++;
}
luaL_checkanyfunction(L, n);
lua_settop(L, n);
(void) luaN_posttask(L, priority);
return 0;
}

View File

@ -3,15 +3,45 @@
** table to store the LUAL_BUFFERSIZE byte array chunks instead of the stack.
** Writing is always to the last UD in the table and overflow pushes a new UD to
** the end of the table. Reading is always from the first UD in the table and
** underrun removes the first UD to shift a new one into slot 1.
** underrun removes the first UD to shift a new one into slot 2. (Slot 1 of the
** table is reserved for the pipe reader function with 0 denoting no reader.)
**
** Reads and writes may span multiple UD buffers and if the read spans multiple UDs
** then the parts are collected as strings on the Lua stack and then concatenated
** with a `lua_concat()`.
** with a lua_concat().
**
** Note that pipes also support the undocumented length and tostring operators
** for debugging puposes, so if p is a pipe then #p[1] gives the effective
** length of pipe slot 1 and printing p[1] gives its contents
** Note that pipe tables also support the undocumented length and tostring
** operators for debugging puposes, so if p is a pipe then #p[i] gives the
** effective length of pipe slot i and printing p[i] gives its contents.
**
** The pipe library also supports the automatic scheduling of a reader task. This
** is declared by including a Lua CB function and an optional prioirty for it to
** execute at in the pipe.create() call. The reader task may or may not empty the
** FIFO (and there is also nothing to stop the task also writing to the FIFO. The
** reader automatically reschedules itself if the pipe contains unread content.
**
** The reader tasks may be interleaved with other tasks that write to the pipe and
** others that don't. Any task writing to the pipe will also trigger the posting
** of a read task if one is not already pending. In this way at most only one
** pending reader task is pending, and this prevents overrun of the task queueing
** system.
**
** Implementation Notes:
**
** - The Pipe slot 1 is used to store the Lua CB function reference of the reader
** task. Note that is actually an auxiliary wrapper around the supplied Lua CB
** function, and this wrapper also uses upvals to store internal pipe state.
** The remaining slots are the Userdata buffer chunks.
**
** - This internal state needs to be shared with the pipe_write function, but a
** limitation of Lua 5.1 is that C functions cannot share upvals; to avoid this
** constraint, this function is also denormalised to act as the pipe_write
** function: if Arg1 is the pipe then its a pipe:write() otherwise its a
** CB wrapper.
**
** Also note that the pipe module is used by the Lua VM and therefore the create
** read, and unread methods are exposed as directly callable C functions. (Write
** is available throogh pipe[1].)
**
** Read the docs/modules/pipe.md documentation for a functional description.
*/
@ -19,6 +49,8 @@
#include "module.h"
#include "lauxlib.h"
#include <string.h>
#include "platform.h"
#include "lstate.h"
#define INVALID_LEN ((unsigned)-1)
@ -31,10 +63,36 @@ typedef struct buffer {
LROT_TABLE(pipe_meta)
/* Validation and utility functions */
#define AT_TAIL 0x00
#define AT_HEAD 0x01
#define WRITING 0x02
#define AT_HEAD 1
#define AT_TAIL 0
static buffer_t *checkPipeUD (lua_State *L, int ndx);
static buffer_t *newPipeUD(lua_State *L, int ndx, int n);
static int pipe_write_aux(lua_State *L);
/* Validation and utility functions */
// [-0, +0, v]
static buffer_t *checkPipeTable (lua_State *L, int tbl, int flags) {
int m = lua_gettop(L), n = lua_objlen(L, tbl);
if (lua_istable(L, tbl) && lua_getmetatable(L, tbl)) {
lua_pushrotable(L, LROT_TABLEREF(pipe_meta));/* push comparison metatable */
if (lua_rawequal(L, -1, -2)) { /* check these match */
buffer_t *ud;
if (n == 1) {
ud = (flags & WRITING) ? newPipeUD(L, tbl, 2) : NULL;
} else {
int i = flags & AT_HEAD ? 2 : n; /* point to head or tail of T */
lua_rawgeti(L, tbl, i); /* and fetch UD */
ud = checkPipeUD(L, -1);
}
lua_settop(L, m);
return ud; /* and return ptr to buffer_t rec */
}
}
luaL_typerror(L, tbl, "pipe table");
return NULL; /* NORETURN avoid compiler error */
}
static buffer_t *checkPipeUD (lua_State *L, int ndx) { // [-0, +0, v]
buffer_t *ud = lua_touserdata(L, ndx);
@ -59,27 +117,6 @@ static buffer_t *newPipeUD(lua_State *L, int ndx, int n) { // [-0,+0,-]
return ud; /* ud points to new T[#T] */
}
static buffer_t *checkPipeTable (lua_State *L, int tbl, int head) {//[-0, +0, v]
int m = lua_gettop(L), n = lua_objlen(L, tbl);
if (lua_type(L, tbl) == LUA_TTABLE && lua_getmetatable(L, tbl)) {
lua_pushrotable(L, LROT_TABLEREF(pipe_meta));/* push comparison metatable */
if (lua_rawequal(L, -1, -2)) { /* check these match */
buffer_t *ud;
if (n == 0) {
ud = head ? NULL : newPipeUD(L, tbl, 1);
} else {
int i = head ? 1 : n; /* point to head or tail of T */
lua_rawgeti(L, tbl, i); /* and fetch UD */
ud = checkPipeUD(L, -1);
}
lua_settop(L, m);
return ud; /* and return ptr to buffer_t rec */
}
}
luaL_typerror(L, tbl, "pipe table");
return NULL; /* NORETURN avoid compiler error */
}
#define CHAR_DELIM -1
#define CHAR_DELIM_KEEP -2
static char getsize_delim (lua_State *L, int ndx, int *len) { // [-0, +0, v]
@ -104,22 +141,115 @@ static char getsize_delim (lua_State *L, int ndx, int *len) { // [-0, +0, v]
return delim;
}
/* Lua callable methods */
/*
** Read CB Initiator AND pipe_write. If arg1 == the pipe, then this is a pipe
** write(); otherwise it is the Lua CB wapper for the task post. This botch allows
** these two functions to share Upvals within the Lua 5.1 VM:
*/
#define UVpipe lua_upvalueindex(1) // The pipe table object
#define UVfunc lua_upvalueindex(2) // The CB's Lua function
#define UVprio lua_upvalueindex(3) // The task priority
#define UVstate lua_upvalueindex(4) // Pipe state;
#define CB_NOT_USED 0
#define CB_ACTIVE 1
#define CB_WRITE_UPDATED 2
#define CB_QUIESCENT 4
/*
** Note that nothing precludes the Lua CB function from itself writing to the
** pipe and in this case this routine will call itself recursively.
**
** The Lua CB itself takes the pipe object as a parameter and returns an optional
** boolean to force or to suppress automatic retasking if needed. If omitted,
** then the default is to repost if the pipe is not empty, otherwise the task
** chain is left to lapse.
*/
static int pipe_write_and_read_poster (lua_State *L) {
int state = lua_tointeger(L, UVstate);
if (lua_rawequal(L, 1, UVpipe)) {
/* arg1 == the pipe, so this was invoked as a pipe_write() */
if (pipe_write_aux(L) && state && !(state & CB_WRITE_UPDATED)) {
/*
* if this resulted in a write and not already in a CB and not already
* toggled the write update then post the task
*/
state |= CB_WRITE_UPDATED;
lua_pushinteger(L, state);
lua_replace(L, UVstate); /* Set CB state write updated flag */
if (state == CB_QUIESCENT | CB_WRITE_UPDATED) {
lua_rawgeti(L, 1, 1); /* Get CB ref from pipe[1] */
luaN_posttask(L, (int) lua_tointeger(L, UVprio)); /* and repost task */
}
}
//Lua s = pipeUD:tostring()
static int pipe__tostring (lua_State *L) {
if (lua_type(L, 1) == LUA_TTABLE) {
lua_pushfstring(L, "Pipe: %p", lua_topointer(L, 1));
} else {
buffer_t *ud = checkPipeUD(L, 1);
lua_pushlstring(L, ud->buf + ud->start, ud->end - ud->start);
} else if (state != CB_NOT_USED) {
/* invoked by the luaN_taskpost() so call the Lua CB */
int repost; /* can take the values CB_WRITE_UPDATED or 0 */
lua_pushinteger(L, CB_ACTIVE); /* CB state set to active only */
lua_replace(L, UVstate);
lua_pushvalue(L, UVfunc); /* Lua CB function */
lua_pushvalue(L, UVpipe); /* pipe table */
lua_call(L, 1, 1);
/*
* On return from the Lua CB, the task is never reposted if the pipe is empty.
* If it is not empty then the Lua CB return status determines when reposting
* occurs:
* - true = repost
* - false = don't repost
* - nil = only repost if there has been a write update.
*/
if (lua_isboolean(L,-1)) {
repost = (lua_toboolean(L, -1) == true &&
lua_objlen(L, UVpipe) > 1) ? CB_WRITE_UPDATED : 0;
} else {
repost = state & CB_WRITE_UPDATED;
}
state = CB_QUIESCENT | repost;
lua_pushinteger(L, state); /* Update the CB state */
lua_replace(L, UVstate);
if (repost) {
lua_rawgeti(L, UVpipe, 1); /* Get CB ref from pipe[1] */
luaN_posttask(L, (int) lua_tointeger(L, UVprio)); /* and repost task */
}
}
return 1;
return 0;
}
// len = #pipeobj[1]
/* Lua callable methods. Since the metatable is linked to both the pipe table */
/* and the userdata entries the __len & __tostring functions must handle both */
// Lua: buf = pipe.create()
int pipe_create(lua_State *L) {
int prio = -1;
lua_settop(L, 2); /* fix stack sze as 2 */
if (!lua_isnil(L, 1)) {
luaL_checkanyfunction(L, 1); /* non-nil arg1 must be a function */
if (lua_isnil(L, 2)) {
prio = PLATFORM_TASK_PRIORITY_MEDIUM;
} else {
prio = (int) lua_tointeger(L, 2);
luaL_argcheck(L, prio >= PLATFORM_TASK_PRIORITY_LOW &&
prio <= PLATFORM_TASK_PRIORITY_HIGH, 2, "invalid priority");
}
}
lua_createtable (L, 1, 0); /* create pipe table */
lua_pushrotable(L, LROT_TABLEREF(pipe_meta));
lua_setmetatable(L, -2); /* set pipe table's metabtable to pipe_meta */
lua_pushvalue(L, -1); /* UV1: pipe object */
lua_pushvalue(L, 1); /* UV2: CB function */
lua_pushinteger(L, prio); /* UV3: task priority */
lua_pushinteger(L, prio == -1 ? CB_NOT_USED : CB_QUIESCENT);
lua_pushcclosure(L, pipe_write_and_read_poster, 4); /* post aux func as C task */
lua_rawseti(L, -2, 1); /* and wrtie to T[1] */
return 1; /* return the table */
}
// len = #pipeobj[i]
static int pipe__len (lua_State *L) {
if (lua_type(L, 1) == LUA_TTABLE) {
if (lua_type(L, 1) == LUA_TTABLE) {
lua_pushinteger(L, lua_objlen(L, 1));
} else {
buffer_t *ud = checkPipeUD(L, 1);
@ -128,16 +258,19 @@ static int pipe__len (lua_State *L) {
return 1;
}
// Lua: buf = pipe.create()
static int pipe_create(lua_State *L) {
lua_createtable (L, 1, 0);
lua_pushrotable(L, LROT_TABLEREF(pipe_meta));
lua_setmetatable(L, 1); /* set table's metabtable to pipe_meta */
return 1; /* return the table */
//Lua s = pipeUD:tostring()
static int pipe__tostring (lua_State *L) {
if (lua_istable(L, 1)) {
lua_pushfstring(L, "Pipe: %p", lua_topointer(L, 1));
} else {
buffer_t *ud = checkPipeUD(L, 1);
lua_pushlstring(L, ud->buf + ud->start, ud->end - ud->start);
}
return 1;
}
// Lua: rec = p:read(end_or_delim) // also [-2, +1,- ]
static int pipe_read(lua_State *L) {
int pipe_read(lua_State *L) {
buffer_t *ud = checkPipeTable(L, 1, AT_HEAD);
int i, k=0, n;
lua_settop(L,2);
@ -158,6 +291,7 @@ static int pipe_read(lua_State *L) {
want = used = i + 1 - ud->start; /* case where we've hit a delim */
if (n == CHAR_DELIM)
want--;
n = 0; /* force loop exit because delim found */
}
} else {
want = used = (n < avail) ? n : avail;
@ -169,12 +303,12 @@ static int pipe_read(lua_State *L) {
if (ud->start == ud->end) {
/* shift the pipe array down overwriting T[1] */
int nUD = lua_objlen(L, 1);
for (i = 1; i < nUD; i++) { /* for i = 1, nUD-1 */
for (i = 2; i < nUD; i++) { /* for i = 2, nUD-1 */
lua_rawgeti(L, 1, i+1); lua_rawseti(L, 1, i); /* T[i] = T[i+1] */
}
lua_pushnil(L); lua_rawseti(L, 1, nUD--); /* T[n] = nil */
if (nUD) {
lua_rawgeti(L, 1, 1);
if (nUD>1) {
lua_rawgeti(L, 1, 2);
ud = checkPipeUD(L, -1);
lua_pop(L, 1);
} else {
@ -190,29 +324,33 @@ static int pipe_read(lua_State *L) {
}
// Lua: buf:unread(some_string)
static int pipe_unread(lua_State *L) {
int pipe_unread(lua_State *L) {
size_t l = INVALID_LEN;
const char *s = lua_tolstring(L, 2, &l);
if (l==0)
return 0;
luaL_argcheck(L, l != INVALID_LEN, 2, "must be a string");
buffer_t *ud = checkPipeTable(L, 1, AT_HEAD);
buffer_t *ud = checkPipeTable(L, 1, AT_HEAD | WRITING);
do {
int used = ud->end - ud->start, lrem = LUAL_BUFFERSIZE-used;
int used = ud->end - ud->start;
int lrem = LUAL_BUFFERSIZE-used;
if (used == LUAL_BUFFERSIZE) {
/* If the current UD is full insert a new UD at T[2] */
int i, nUD = lua_objlen(L, 1);
for (i = nUD; i > 0; i--) { /* for i = nUD-1,1,-1 */
lua_rawgeti(L, 1, i); lua_rawseti(L, 1, i+1); /* T[i+1] = T[i] */
}
ud = newPipeUD(L, 1, 1);
used = 0; lrem = LUAL_BUFFERSIZE;
} else if (ud->end < LUAL_BUFFERSIZE) {
} else if (ud->start < l) {
/* If the unread can't fit it before the start then shift content to end */
memmove(ud->buf + lrem,
ud->buf + ud->start, used); /* must be memmove not cpy */
ud->start = lrem; ud->end = LUAL_BUFFERSIZE;
}
ud->start = lrem; ud->end = LUAL_BUFFERSIZE;
if (l <= (unsigned )lrem)
break;
@ -232,21 +370,24 @@ static int pipe_unread(lua_State *L) {
}
// Lua: buf:write(some_string)
static int pipe_write(lua_State *L) {
static int pipe_write_aux(lua_State *L) {
size_t l = INVALID_LEN;
const char *s = lua_tolstring(L, 2, &l);
//dbg_printf("pipe write(%u): %s", l, s);
if (l==0)
return 0;
return false;
luaL_argcheck(L, l != INVALID_LEN, 2, "must be a string");
buffer_t *ud = checkPipeTable(L, 1, AT_TAIL);
buffer_t *ud = checkPipeTable(L, 1, AT_TAIL | WRITING);
do {
int used = ud->end - ud->start;
if (used == LUAL_BUFFERSIZE) {
/* If the current UD is full insert a new UD at T[end] */
ud = newPipeUD(L, 1, lua_objlen(L, 1)+1);
used = 0;
} else if (ud->start) {
} else if (LUAL_BUFFERSIZE - ud->end < l) {
/* If the write can't fit it at the end then shift content to the start */
memmove(ud->buf, ud->buf + ud->start, used); /* must be memmove not cpy */
ud->start = 0; ud->end = used;
}
@ -267,7 +408,7 @@ static int pipe_write(lua_State *L) {
/* Copy any residual tail to the UD buffer. Note that this is l>0 and */
memcpy(ud->buf + ud->end, s, l);
ud->end += l;
return 0;
return true;
}
// Lua: fread = pobj:reader(1400) -- or other number
@ -289,21 +430,36 @@ static int pipe_reader(lua_State *L) {
return 1;
}
LROT_BEGIN(pipe_meta)
LROT_TABENTRY( __index, pipe_meta)
LROT_BEGIN(pipe_funcs)
LROT_FUNCENTRY( __len, pipe__len )
LROT_FUNCENTRY( __tostring, pipe__tostring )
LROT_FUNCENTRY( read, pipe_read )
LROT_FUNCENTRY( reader, pipe_reader )
LROT_FUNCENTRY( unread, pipe_unread )
LROT_FUNCENTRY( write, pipe_write )
LROT_END( pipe_meta, NULL, LROT_MASK_INDEX )
/* Using a index func is needed because the write method is at pipe[1] */
static int pipe__index(lua_State *L) {
lua_settop(L,2);
const char *k=lua_tostring(L,2);
if(!strcmp(k,"write")){
lua_rawgeti(L, 1, 1);
} else {
lua_pushrotable(L, LROT_TABLEREF(pipe_funcs));
lua_replace(L, 1);
lua_rawget(L, 1);
}
return 1;
}
LROT_BEGIN(pipe_meta)
LROT_FUNCENTRY( __index, pipe__index)
LROT_FUNCENTRY( __len, pipe__len )
LROT_FUNCENTRY( __tostring, pipe__tostring )
LROT_END( pipe_meta, NULL, LROT_MASK_INDEX )
LROT_BEGIN(pipe)
LROT_FUNCENTRY( create, pipe_create )
LROT_END( lb, NULL, 0 )
NODEMCU_MODULE(PIPE, "pipe", pipe, NULL);

View File

@ -20,6 +20,7 @@
#include "lauxlib.h"
#include "lmem.h"
#include "platform.h"
#include "task/task.h"
#include "hw_timer.h"
#include "user_interface.h"

View File

@ -7,83 +7,57 @@
#include <stdint.h>
#include <string.h>
#include "rom.h"
#include "driver/input.h"
static int uart_receive_rf = LUA_NOREF;
bool run_input = true;
bool uart_on_data_cb(const char *buf, size_t len){
if(!buf || len==0)
return false;
if(uart_receive_rf == LUA_NOREF)
return false;
void uart_on_data_cb(const char *buf, size_t len){
lua_State *L = lua_getstate();
if(!L)
return false;
lua_rawgeti(L, LUA_REGISTRYINDEX, uart_receive_rf);
lua_pushlstring(L, buf, len);
lua_call(L, 1, 0);
return !run_input;
luaN_call(L, 1, 0, 0);
}
uint16_t need_len = 0;
int16_t end_char = -1;
// Lua: uart.on("method", [number/char], function, [run_input])
static int l_uart_on( lua_State* L )
{
size_t sl, el;
int32_t run = 1;
uint8_t stack = 1;
const char *method = luaL_checklstring( L, stack, &sl );
stack++;
if (method == NULL)
return luaL_error( L, "wrong arg type" );
size_t el;
int stack = 2, data_len = -1;
char end_char = 0;
const char *method = lua_tostring( L, 1);
bool run_input = true;
luaL_argcheck(L, method && !strcmp(method, "data"), 1, "method not supported");
if( lua_type( L, stack ) == LUA_TNUMBER )
if (lua_type( L, stack ) == LUA_TNUMBER)
{
need_len = ( uint16_t )luaL_checkinteger( L, stack );
data_len = luaL_checkinteger( L, stack );
luaL_argcheck(L, data_len >= 0 && data_len <= LUA_MAXINPUT, stack, "wrong arg range");
stack++;
end_char = -1;
if( need_len > 255 ){
need_len = 255;
return luaL_error( L, "wrong arg range" );
}
}
else if(lua_isstring(L, stack))
else if (lua_isstring(L, stack))
{
const char *end = luaL_checklstring( L, stack, &el );
data_len = 0;
end_char = (int16_t) end[0];
stack++;
if(el!=1){
if(el!=1) {
return luaL_error( L, "wrong arg range" );
}
end_char = (int16_t)end[0];
need_len = 0;
}
// luaL_checkanyfunction(L, stack);
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){
if ( lua_isnumber(L, stack+1) ){
run = lua_tointeger(L, stack+1);
if (lua_anyfunction(L, stack)) {
if (lua_isnumber(L, stack+1) && lua_tointeger(L, stack+1) == 0) {
run_input = false;
}
lua_pushvalue(L, stack); // copy argument (func) to the top of stack
lua_pushvalue(L, stack);
luaL_unref(L, LUA_REGISTRYINDEX, uart_receive_rf);
uart_receive_rf = luaL_ref(L, LUA_REGISTRYINDEX);
} else {
lua_pushnil(L);
}
if(sl == 4 && strcmp(method, "data") == 0){
run_input = true;
if(uart_receive_rf != LUA_NOREF){
luaL_unref(L, LUA_REGISTRYINDEX, uart_receive_rf);
uart_receive_rf = LUA_NOREF;
}
if(!lua_isnil(L, -1)){
uart_receive_rf = luaL_ref(L, LUA_REGISTRYINDEX);
if(run==0)
run_input = false;
} else {
lua_pop(L, 1);
}
}else{
lua_pop(L, 1);
return luaL_error( L, "method not supported" );
luaL_unref(L, LUA_REGISTRYINDEX, uart_receive_rf);
uart_receive_rf = LUA_NOREF;
}
input_setup_receive(uart_on_data_cb, data_len, end_char, run_input);
return 0;
}
@ -91,7 +65,7 @@ bool uart0_echo = true;
// Lua: actualbaud = setup( id, baud, databits, parity, stopbits, echo )
static int l_uart_setup( lua_State* L )
{
uint32_t id, databits, parity, stopbits, echo = 1;
uint32_t id, databits, parity, stopbits;
uint32_t baud, res;
id = luaL_checkinteger( L, 1 );
@ -101,12 +75,8 @@ static int l_uart_setup( lua_State* L )
databits = luaL_checkinteger( L, 3 );
parity = luaL_checkinteger( L, 4 );
stopbits = luaL_checkinteger( L, 5 );
if(lua_isnumber(L,6)){
echo = lua_tointeger(L,6);
if(echo!=0)
uart0_echo = true;
else
uart0_echo = false;
if (lua_isnumber(L,6)) {
input_setecho(lua_tointeger(L,6) ? true : false);
}
res = platform_uart_setup( id, baud, databits, parity, stopbits );

View File

@ -17,7 +17,8 @@
#define INTERRUPT_TYPE_IS_LEVEL(x) ((x) >= GPIO_PIN_INTR_LOLEVEL)
#ifdef GPIO_INTERRUPT_ENABLE
static task_handle_t gpio_task_handle;
static platform_task_handle_t gpio_task_handle;
static int task_init_handler(void);
#ifdef GPIO_INTERRUPT_HOOK_ENABLE
struct gpio_hook_entry {
@ -55,11 +56,13 @@ static const int uart_bitrates[] = {
BIT_RATE_3686400
};
int platform_init()
int platform_init ()
{
// Setup the various forward and reverse mappings for the pins
get_pin_map();
(void) task_init_handler();
cmn_platform_init();
// All done
return PLATFORM_OK;
@ -83,7 +86,7 @@ uint8_t platform_key_led( uint8_t level){
/*
* Set GPIO mode to output. Optionally in RAM helper because interrupts are dsabled
*/
static void NO_INTR_CODE set_gpio_no_interrupt(uint8 pin, uint8_t push_pull) {
static void NO_INTR_CODE set_gpio_no_interrupt(uint8_t pin, uint8_t push_pull) {
unsigned pnum = pin_num[pin];
ETS_GPIO_INTR_DISABLE();
#ifdef GPIO_INTERRUPT_ENABLE
@ -113,7 +116,7 @@ static void NO_INTR_CODE set_gpio_no_interrupt(uint8 pin, uint8_t push_pull) {
* Set GPIO mode to interrupt. Optionally RAM helper because interrupts are dsabled
*/
#ifdef GPIO_INTERRUPT_ENABLE
static void NO_INTR_CODE set_gpio_interrupt(uint8 pin) {
static void NO_INTR_CODE set_gpio_interrupt(uint8_t pin) {
ETS_GPIO_INTR_DISABLE();
PIN_FUNC_SELECT(pin_mux[pin], pin_func[pin]);
GPIO_DIS_OUTPUT(pin_num[pin]);
@ -209,9 +212,9 @@ int platform_gpio_read( unsigned pin )
#ifdef GPIO_INTERRUPT_ENABLE
static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){
uint32 j=0;
uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
uint32 now = system_get_time();
uint32_t j=0;
uint32_t gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
uint32_t now = system_get_time();
UNUSED(dummy);
#ifdef GPIO_INTERRUPT_HOOK_ENABLE
@ -244,8 +247,8 @@ static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){
GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, BIT(j));
if (diff == 0 || diff & 0x8000) {
uint32 level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(j));
if (!task_post_high (gpio_task_handle, (now << 8) + (i<<1) + level)) {
uint32_t level = 0x1 & GPIO_INPUT_GET(GPIO_ID_PIN(j));
if (!platform_post_high (gpio_task_handle, (now << 8) + (i<<1) + level)) {
// If we fail to post, then try on the next interrupt
pin_counter[i].seen |= 0x8000;
}
@ -260,7 +263,7 @@ static void ICACHE_RAM_ATTR platform_gpio_intr_dispatcher (void *dummy){
}
}
void platform_gpio_init( task_handle_t gpio_task )
void platform_gpio_init( platform_task_handle_t gpio_task )
{
gpio_task_handle = gpio_task;
@ -871,7 +874,7 @@ uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t siz
memcpy(apbuf, from, size);
}
system_soft_wdt_feed ();
r = flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size);
r = flash_write(toaddr, apbuf?(uint32_t *)apbuf:(uint32_t *)from, size);
if(apbuf)
free(apbuf);
if(SPI_FLASH_RESULT_OK == r)
@ -899,7 +902,7 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size )
if( ((uint32_t)to) & blkmask )
{
uint32_t size2=size-INTERNAL_FLASH_READ_UNIT_SIZE;
uint32* to2=(uint32*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE);
uint32_t* to2=(uint32_t*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE);
r = flash_read(fromaddr, to2, size2);
if(SPI_FLASH_RESULT_OK == r)
{
@ -910,7 +913,7 @@ uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size )
}
}
else
r = flash_read(fromaddr, (uint32 *)to, size);
r = flash_read(fromaddr, (uint32_t *)to, size);
if(SPI_FLASH_RESULT_OK == r)
return size;
@ -1079,3 +1082,84 @@ void* platform_print_deprecation_note( const char *msg, const char *time_frame)
{
printf( "Warning, deprecated API! %s. It will be removed %s. See documentation for details.\n", msg, time_frame );
}
#define TH_MONIKER 0x68680000
#define TH_MASK 0xFFF80000
#define TH_UNMASK (~TH_MASK)
#define TH_SHIFT 2
#define TH_ALLOCATION_BRICK 4 // must be a power of 2
#define TASK_DEFAULT_QUEUE_LEN 8
#define TASK_PRIORITY_MASK 3
#define TASK_PRIORITY_COUNT 3
/*
* Private struct to hold the 3 event task queues and the dispatch callbacks
*/
static struct taskQblock {
os_event_t *task_Q[TASK_PRIORITY_COUNT];
platform_task_callback_t *task_func;
int task_count;
} TQB = {0};
static void platform_task_dispatch (os_event_t *e) {
platform_task_handle_t handle = e->sig;
if ( (handle & TH_MASK) == TH_MONIKER) {
uint16_t entry = (handle & TH_UNMASK) >> TH_SHIFT;
uint8_t priority = handle & TASK_PRIORITY_MASK;
if ( priority <= PLATFORM_TASK_PRIORITY_HIGH &&
TQB.task_func &&
entry < TQB.task_count ){
/* call the registered task handler with the specified parameter and priority */
TQB.task_func[entry](e->par, priority);
return;
}
}
/* Invalid signals are ignored */
NODE_DBG ( "Invalid signal issued: %08x", handle);
}
/*
* Initialise the task handle callback for a given priority.
*/
static int task_init_handler (void) {
int p, qlen = TASK_DEFAULT_QUEUE_LEN;
for (p = 0; p < TASK_PRIORITY_COUNT; p++){
TQB.task_Q[p] = (os_event_t *) c_malloc( sizeof(os_event_t)*qlen );
if (TQB.task_Q[p]) {
os_memset(TQB.task_Q[p], 0, sizeof(os_event_t)*qlen);
system_os_task(platform_task_dispatch, p, TQB.task_Q[p], TASK_DEFAULT_QUEUE_LEN);
} else {
NODE_DBG ( "Malloc failure in platform_task_init_handler" );
return PLATFORM_ERR;
}
}
}
/*
* Allocate a task handle in the relevant TCB.task_Q. Note that these Qs are resized
* as needed growing in 4 unit bricks. No GC is adopted so handles are permanently
* allocated during boot life. This isn't an issue in practice as only a few handles
* are created per priority during application init and the more volitile Lua tasks
* are allocated in the Lua registery using the luaX interface which is layered on
* this mechanism.
*/
platform_task_handle_t platform_task_get_id (platform_task_callback_t t) {
if ( (TQB.task_count & (TH_ALLOCATION_BRICK - 1)) == 0 ) {
TQB.task_func = (platform_task_callback_t *) os_realloc(
TQB.task_func,
sizeof(platform_task_callback_t) * (TQB.task_count+TH_ALLOCATION_BRICK));
if (!TQB.task_func) {
NODE_DBG ( "Malloc failure in platform_task_get_id");
return 0;
}
os_memset (TQB.task_func+TQB.task_count, 0,
sizeof(platform_task_callback_t)*TH_ALLOCATION_BRICK);
}
TQB.task_func[TQB.task_count++] = t;
return TH_MONIKER + ((TQB.task_count-1) << TH_SHIFT);
}
bool platform_post (uint8 prio, platform_task_handle_t handle, platform_task_param_t par) {
return system_os_post(prio, handle | prio, par);
}

View File

@ -8,8 +8,6 @@
#include "driver/pwm.h"
#include "driver/uart.h"
#include "task/task.h"
// Error / status codes
enum
{
@ -18,6 +16,9 @@ enum
PLATFORM_UNDERFLOW = -1
};
typedef uint32_t platform_task_handle_t;
typedef uint32_t platform_task_param_t;
// Platform initialization
int platform_init(void);
void platform_int_init(void);
@ -52,7 +53,7 @@ int platform_gpio_register_intr_hook(uint32_t gpio_bits, platform_hook_function
#define platform_gpio_unregister_intr_hook(hook) \
platform_gpio_register_intr_hook(0, hook);
void platform_gpio_intr_init( unsigned pin, GPIO_INT_TYPE type );
void platform_gpio_init( task_handle_t gpio_task );
void platform_gpio_init( platform_task_handle_t gpio_task );
// *****************************************************************************
// Timer subsection
@ -353,4 +354,22 @@ typedef union {
uint32_t platform_rcr_read (uint8_t rec_id, void **rec);
uint32_t platform_rcr_write (uint8_t rec_id, const void *rec, uint8_t size);
#define PLATFORM_TASK_PRIORITY_LOW 0
#define PLATFORM_TASK_PRIORITY_MEDIUM 1
#define PLATFORM_TASK_PRIORITY_HIGH 2
/*
* Signals are a 32-bit number of the form header:14; count:16, priority:2. The header
* is just a fixed fingerprint and the count is allocated serially by the task get_id()
* function.
*/
#define platform_post_low(handle,param) platform_post(PLATFORM_TASK_PRIORITY_LOW, handle, param)
#define platform_post_medium(handle,param) platform_post(PLATFORM_TASK_PRIORITY_MEDIUM, handle, param)
#define platform_post_high(handle,param) platform_post(PLATFORM_TASK_PRIORITY_HIGH, handle, param)
typedef void (*platform_task_callback_t)(platform_task_param_t param, uint8 prio);
platform_task_handle_t platform_task_get_id(platform_task_callback_t t);
bool platform_post(uint8 prio, platform_task_handle_t h, platform_task_param_t par);
#endif

View File

@ -15,7 +15,7 @@
// vfs_close - close file descriptor and free memory
// fd: file descriptor
// Returns: VFS_RES_OK or negative value in case of error
static int32_t vfs_close( int fd ) {
static inline int32_t vfs_close( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->close( f ) : VFS_RES_ERR;
}
@ -25,7 +25,7 @@ static int32_t vfs_close( int fd ) {
// ptr: destination data buffer
// len: requested length
// Returns: Number of bytes read, or VFS_RES_ERR in case of error
static int32_t vfs_read( int fd, void *ptr, size_t len ) {
static inline int32_t vfs_read( int fd, void *ptr, size_t len ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->read( f, ptr, len ) : VFS_RES_ERR;
}
@ -35,7 +35,7 @@ static int32_t vfs_read( int fd, void *ptr, size_t len ) {
// ptr: source data buffer
// len: requested length
// Returns: Number of bytes written, or VFS_RES_ERR in case of error
static int32_t vfs_write( int fd, const void *ptr, size_t len ) {
static inline sint32_t vfs_write( int fd, const void *ptr, size_t len ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->write( f, ptr, len ) : VFS_RES_ERR;
}
@ -51,7 +51,7 @@ int vfs_ungetc( int c, int fd );
// VFS_SEEK_CUR - set pointer to current position + off
// VFS_SEEK_END - set pointer to end of file + off
// Returns: New position, or VFS_RES_ERR in case of error
static int32_t vfs_lseek( int fd, int32_t off, int whence ) {
static inline int32_t vfs_lseek( int fd, sint32_t off, int whence ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->lseek( f, off, whence ) : VFS_RES_ERR;
}
@ -59,7 +59,7 @@ static int32_t vfs_lseek( int fd, int32_t off, int whence ) {
// vfs_eof - test for end-of-file
// fd: file descriptor
// Returns: 0 if not at end, != 0 if end of file
static int32_t vfs_eof( int fd ) {
static inline int32_t vfs_eof( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->eof( f ) : VFS_RES_ERR;
}
@ -67,7 +67,7 @@ static int32_t vfs_eof( int fd ) {
// vfs_tell - get read/write position
// fd: file descriptor
// Returns: Current position
static int32_t vfs_tell( int fd ) {
static inline int32_t vfs_tell( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->tell( f ) : VFS_RES_ERR;
}
@ -75,7 +75,7 @@ static int32_t vfs_tell( int fd ) {
// vfs_flush - flush write cache to file
// fd: file descriptor
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
static int32_t vfs_flush( int fd ) {
static inline int32_t vfs_flush( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->flush( f ) : VFS_RES_ERR;
}
@ -83,7 +83,7 @@ static int32_t vfs_flush( int fd ) {
// vfs_size - get current file size
// fd: file descriptor
// Returns: File size
static uint32_t vfs_size( int fd ) {
static inline uint32_t vfs_size( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->size( f ) : 0;
}
@ -100,13 +100,13 @@ int32_t vfs_ferrno( int fd );
// vfs_closedir - close directory descriptor and free memory
// dd: dir descriptor
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
static int32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); }
static inline int32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); }
// vfs_readdir - read next directory item
// dd: dir descriptor
// buf: pre-allocated stat structure to be filled in
// Returns: VFS_RES_OK if next item found, otherwise VFS_RES_ERR
static int32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns->readdir( dd, buf ); }
static inline int32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns->readdir( dd, buf ); }
// ---------------------------------------------------------------------------
// volume functions
@ -115,7 +115,7 @@ static int32_t vfs_readdir( vfs_dir *dd, struct vfs_stat *buf ) { return dd->fns
// vfs_umount - unmount logical drive and free memory
// vol: volume object
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
static int32_t vfs_umount( vfs_vol *vol ) { return vol->fns->umount( vol ); }
static inline int32_t vfs_umount( vfs_vol *vol ) { return vol->fns->umount( vol ); }
// ---------------------------------------------------------------------------
// file system functions

View File

@ -41,6 +41,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "task/task.h"
#include "user_interface.h"
#include "user_modules.h"

View File

@ -1,41 +0,0 @@
#############################################################
# Required variables for each makefile
# Discard this section from all parent makefiles
# Expected variables (with automatic defaults):
# CSRCS (all "C" files in the dir)
# SUBDIRS (all subdirs with a Makefile)
# GEN_LIBS - list of libs to be generated ()
# GEN_IMAGES - list of images to be generated ()
# COMPONENTS_xxx - a list of libs/objs in the form
# subdir/lib to be extracted and rolled up into
# a generated lib/image xxx.a ()
#
ifndef PDIR
GEN_LIBS = libtask.a
endif
#############################################################
# Configuration i.e. compile options etc.
# Target specific stuff (defines etc.) goes in here!
# Generally values applying to a tree are captured in the
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
#############################################################
# Recursion Magic - Don't touch this!!
#
# Each subtree potentially has an include directory
# corresponding to the common APIs applicable to modules
# rooted at that subtree. Accordingly, the INCLUDE PATH
# of a module can only contain the include directories up
# its parent path, and not its siblings
#
# Required for each makefile to inherit from the parent
#
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -1,72 +0,0 @@
/**
This file encapsulates the SDK-based task handling for the NodeMCU Lua firmware.
*/
#include "task/task.h"
#include "mem.h"
#include <stdio.h>
#define TASK_HANDLE_MONIKER 0x68680000
#define TASK_HANDLE_MASK 0xFFF80000
#define TASK_HANDLE_UNMASK (~TASK_HANDLE_MASK)
#define TASK_HANDLE_SHIFT 2
#define TASK_HANDLE_ALLOCATION_BRICK 4 // must be a power of 2
#define TASK_DEFAULT_QUEUE_LEN 8
#define TASK_PRIORITY_MASK 3
#define CHECK(p,v,msg) if (!(p)) { NODE_DBG ( msg ); return (v); }
/*
* Private arrays to hold the 3 event task queues and the dispatch callbacks
*/
LOCAL os_event_t *task_Q[TASK_PRIORITY_COUNT];
LOCAL task_callback_t *task_func;
LOCAL int task_count;
LOCAL void task_dispatch (os_event_t *e) {
task_handle_t handle = e->sig;
if ( (handle & TASK_HANDLE_MASK) == TASK_HANDLE_MONIKER) {
uint16 entry = (handle & TASK_HANDLE_UNMASK) >> TASK_HANDLE_SHIFT;
uint8 priority = handle & TASK_PRIORITY_MASK;
if ( priority <= TASK_PRIORITY_HIGH && task_func && entry < task_count ){
/* call the registered task handler with the specified parameter and priority */
task_func[entry](e->par, priority);
return;
}
}
/* Invalid signals are ignored */
NODE_DBG ( "Invalid signal issued: %08x", handle);
}
/*
* Initialise the task handle callback for a given priority. This doesn't need
* to be called explicitly as the get_id function will call this lazily.
*/
bool task_init_handler(uint8 priority, uint8 qlen) {
if (priority <= TASK_PRIORITY_HIGH && task_Q[priority] == NULL) {
task_Q[priority] = (os_event_t *) os_malloc( sizeof(os_event_t)*qlen );
os_memset (task_Q[priority], 0, sizeof(os_event_t)*qlen);
if (task_Q[priority]) {
return system_os_task( task_dispatch, priority, task_Q[priority], qlen );
}
}
return false;
}
task_handle_t task_get_id(task_callback_t t) {
int p = TASK_PRIORITY_COUNT;
/* Initialise and uninitialised Qs with the default Q len */
while(p--) if (!task_Q[p]) {
CHECK(task_init_handler( p, TASK_DEFAULT_QUEUE_LEN ), 0, "Task initialisation failed");
}
if ( (task_count & (TASK_HANDLE_ALLOCATION_BRICK - 1)) == 0 ) {
/* With a brick size of 4 this branch is taken at 0, 4, 8 ... and the new size is +4 */
task_func =(task_callback_t *) os_realloc(task_func,
sizeof(task_callback_t)*(task_count+TASK_HANDLE_ALLOCATION_BRICK));
CHECK(task_func, 0 , "Malloc failure in task_get_id");
os_memset (task_func+task_count, 0, sizeof(task_callback_t)*TASK_HANDLE_ALLOCATION_BRICK);
}
task_func[task_count++] = t;
return TASK_HANDLE_MONIKER + ((task_count-1) << TASK_HANDLE_SHIFT);
}

View File

@ -20,6 +20,7 @@
#include "ets_sys.h"
#include "driver/uart.h"
#include "driver/input.h"
#include "task/task.h"
#include "mem.h"
#include "espconn.h"
@ -29,9 +30,6 @@
#include "rtc/rtctime.h"
#endif
static task_handle_t input_sig;
static uint8 input_sig_flag = 0;
/* Contents of esp_init_data_default.bin */
extern const uint32_t init_data[], init_data_end[];
#define INIT_DATA_SIZE ((init_data_end - init_data)*sizeof(uint32_t))
@ -275,40 +273,11 @@ uint32 ICACHE_RAM_ATTR user_iram_memory_is_enabled(void) {
return FALSE; // NodeMCU runs like a dog if iRAM is enabled
}
// +================== New task interface ==================+
static void start_lua(task_param_t param, uint8 priority) {
char* lua_argv[] = { (char *)"lua", (char *)"-i", NULL };
NODE_DBG("Task task_lua started.\n");
lua_main( 2, lua_argv );
// Only enable UART interrupts once we've successfully started up,
// otherwise the task queue might fill up with input events and prevent
// the start_lua task from being posted.
ETS_UART_INTR_ENABLE();
}
static void handle_input(task_param_t flag, uint8 priority) {
(void)priority;
if (flag & 0x8000) {
input_sig_flag = flag & 0x4000 ? 1 : 0;
}
lua_handle_input (flag & 0x01);
}
bool user_process_input(bool force) {
return task_post_low(input_sig, force);
}
void nodemcu_init(void) {
NODE_ERR("\n");
// Initialize platform first for lua modules.
if( platform_init() != PLATFORM_OK )
{
// This should never happen
NODE_DBG("Can not init platform for modules.\n");
return;
}
if (!task_post_low(task_get_id(start_lua),'s'))
NODE_ERR("Failed to post the start_lua task!\n");
NODE_DBG("Task task_lua starting.\n");
// Call the Lua bootstrap startup directly. This uses the task interface
// internally to carry out the main lua libraries initialisation.
lua_main();
}
#ifdef LUA_USE_MODULES_WIFI
@ -328,18 +297,17 @@ void user_rf_pre_init(void)
* Parameters : none
* Returns : none
*******************************************************************************/
void user_init(void)
{
void user_init(void) {
#ifdef LUA_USE_MODULES_RTCTIME
rtctime_late_startup ();
#endif
if( platform_init() != PLATFORM_OK ) {
// This should never happen
NODE_DBG("Can not init platform for modules.\n");
return;
}
UartBautRate br = BIT_RATE_DEFAULT;
input_sig = task_get_id(handle_input);
uart_init (br, br, input_sig, &input_sig_flag);
uart_init (br, br);
#ifndef NODE_DEBUG
system_set_os_print(0);
#endif

View File

@ -298,11 +298,7 @@ print("NodeMCU "..majorVer.."."..minorVer.."."..devVer)
## node.input()
Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation.
!!! attention
This function only has an effect when invoked from a callback. Using it directly on the console **does not work**.
Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation. Note that the Line interpreter only actions complete Lua chunks. A Lue Lua chunk must comprise one or more complete `'\n'` terminaed lines that form a complete compilation unit.
#### Syntax
`node.input(str)`
@ -317,56 +313,29 @@ Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, bu
```lua
sk:on("receive", function(conn, payload) node.input(payload) end)
```
See the `telnet/telnet.lua` in `lua_examples` for a more comprehensive example.
#### See also
[`node.output()`](#nodeoutput)
## node.output()
Redirects the Lua interpreter output to a callback function. Optionally also prints it to the serial console.
!!! caution
Do **not** attempt to `print()` or otherwise induce the Lua interpreter to produce output from within the callback function. Doing so results in infinite recursion, and leads to a watchdog-triggered restart.
Redirects the Lua interpreter to a `stdout` pipe when a CB function is specified (See `pipe` module) and resets output to normal otherwise. Optionally also prints to the serial console.
#### Syntax
`node.output(function(str), serial_debug)`
`node.output(function(pipe), serial_debug)`
#### Parameters
- `output_fn(str)` a function accept every output as str, and can send the output to a socket (or maybe a file).
- `output_fn(pipe)` a function accept every output as str, and can send the output to a socket (or maybe a file). Note that this function must conform to the fules for a pipe reader callback.
- `serial_debug` 1 output also show in serial. 0: no serial output.
#### Returns
`nil`
#### Example
```lua
function tonet(str)
sk:send(str)
end
node.output(tonet, 1) -- serial also get the Lua output.
```
```lua
-- a simple telnet server
s=net.createServer(net.TCP)
s:listen(2323,function(c)
con_std = c
function s_output(str)
if(con_std~=nil)
then con_std:send(str)
end
end
node.output(s_output, 0) -- re-direct output to function s_ouput.
c:on("receive",function(c,l)
node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line
end)
c:on("disconnection",function(c)
con_std = nil
node.output(nil) -- un-regist the redirect output function, output goes to serial
end)
end)
```
See the `telnet/telnet.lua` in `lua_examples` for a more comprehensive example of its use.
#### See also
[`node.input()`](#nodeinput)

View File

@ -11,15 +11,15 @@ task to another.
Create a pipe.
#### Syntax
`pobj = pipe.create()`
`pobj = pipe.create([CB_function],[task_priority])`
#### Parameters
None
- `CB_function` optional reader callback which is called through the `ǹode.task.post()` when the pipe is written to. If the CB returns a boolean, then the reposting action is forced: it is reposted if true and not if false. If the return is nil or omitted then the deault is to repost if a pipe write has occured since the last call.
- `task_priority` See `ǹode.task.post()`
#### Returns
A pipe resource.
## pobj:read()
Read a record from a pipe object.