Merge pull request #2836 from TerryE/dev-new-lua.c

Lua 5.1 to 5.3 realignement phase 1
This commit is contained in:
Terry Ellison 2019-09-07 10:54:41 +01:00 committed by GitHub
commit fff9f95e4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1223 additions and 1209 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

@ -162,8 +162,6 @@ end:
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_NOT_FOUND, COAP_CONTENTTYPE_NONE);
}
extern int lua_put_line(const char *s, size_t l);
static const coap_endpoint_path_t path_command = {2, {"v1", "c"}};
static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scratch, const coap_packet_t *inpkt, coap_packet_t *outpkt, uint8_t id_hi, uint8_t id_lo)
{
@ -171,11 +169,11 @@ static int handle_post_command(const coap_endpoint_t *ep, coap_rw_buffer_t *scra
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_BAD_REQUEST, COAP_CONTENTTYPE_TEXT_PLAIN);
if (inpkt->payload.len > 0)
{
char line[LUA_MAXINPUT];
if (!coap_buffer_to_string(line, LUA_MAXINPUT, &inpkt->payload) &&
lua_put_line(line, strlen(line))) {
NODE_DBG("\nResult(if any):\n");
system_os_post (LUA_TASK_PRIO, LUA_PROCESS_LINE_SIG, 0);
char line[LUA_MAXINPUT+1];
if (!coap_buffer_to_string(line, LUA_MAXINPUT, &inpkt->payload)) {
int l = strlen(line);
line[l] = '\n';
lua_input_string(line, l+1);
}
return coap_make_response(scratch, outpkt, NULL, 0, id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, COAP_CONTENTTYPE_TEXT_PLAIN);
}

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

@ -7,11 +7,13 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "mem.h"
#include "pin_map.h"
#include "platform.h"
#include "hw_timer.h"
#include "driver/pwm2.h"
#include "user_interface.h"
#define PWM2_TMR_MAGIC_80MHZ 16
#define PWM2_TMR_MAGIC_160MHZ 32

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
@ -166,30 +166,6 @@ uart_tx_one_char(uint8 uart, uint8 TxChar)
return OK;
}
/******************************************************************************
* FunctionName : uart1_write_char
* Description : Internal used function
* Do some special deal while tx char is '\r' or '\n'
* Parameters : char c - character to tx
* Returns : NONE
*******************************************************************************/
LOCAL void ICACHE_FLASH_ATTR
uart1_write_char(char c)
{
if (c == '\n')
{
uart_tx_one_char(UART1, '\r');
uart_tx_one_char(UART1, '\n');
}
else if (c == '\r')
{
}
else
{
uart_tx_one_char(UART1, c);
}
}
/******************************************************************************
* FunctionName : uart0_tx_buffer
* Description : use uart0 to transfer buffer
@ -300,13 +276,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 +302,6 @@ uart_autobaud_timeout(void *timer_arg)
}
}
#include "pm/swtimer.h"
static void
uart_init_autobaud(uint32_t uart_no)
{
@ -339,22 +316,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 +350,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,10 @@
#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);
#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

@ -15,7 +15,7 @@
#if defined(PMSLEEP_DEBUG)
#define PMSLEEP_DBG(fmt, ...) dbg_printf("\tPMSLEEP(%s):"fmt"\n", __FUNCTION__, ##__VA_ARGS__)
#else
#define PMSLEEP_DBG(...) //c_printf(__VA_ARGS__)
#define PMSLEEP_DBG(...) //printf(__VA_ARGS__)
#endif
#if defined(NODE_ERROR)

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

@ -14,6 +14,7 @@
#include "lfunc.h"
#include "lflash.h"
#include "platform.h"
#include "user_interface.h"
#include "vfs.h"
#include "uzlib.h"
@ -70,7 +71,7 @@ struct OUTPUT {
outBlock buffer;
int ndx;
uint32_t crc;
int (*fullBlkCB) (void);
void (*fullBlkCB) (void);
int flashLen;
int flagsLen;
int flagsNdx;
@ -79,7 +80,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;
@ -122,7 +122,7 @@ static char *flashSetPosition(uint32_t offset){
static char *flashBlock(const void* b, size_t size) {
void *cur = flashPosition();
NODE_DBG("flashBlock((%04x),%08x,%04x)\n", curOffset,b,size);
NODE_DBG("flashBlock((%04x),%p,%04x)\n", curOffset,b,size);
lua_assert(ALIGN_BITS(b) == 0 && ALIGN_BITS(size) == 0);
platform_flash_write(b, flashAddrPhys+curOffset, size);
curOffset += size;
@ -173,15 +173,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 +194,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 +270,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 +405,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 +440,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 +452,8 @@ 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;
uint32_t 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 +489,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 +538,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]);
}

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

@ -0,0 +1,112 @@
/*
** $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);
/*
** 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 nres, 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, (nres < 0 ? LUA_MULTRET : nres), base);
lua_remove(L, base); /* remove traceback function */
if (status && nres >=0)
lua_settop(L, base + nres); /* balance the stack on error */
/* 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

@ -11,6 +11,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include <math.h>
/****************************************************/

View File

@ -9,6 +9,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include <math.h>
#include "bme680_defs.h"

View File

@ -1,6 +1,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include <stdlib.h>
#include <string.h>

View File

@ -585,7 +585,7 @@ static int file_putfile( lua_State* L )
// Lua: fsinfo()
static int file_fsinfo( lua_State* L )
{
u32_t total, used;
uint32_t total, used;
if (vfs_fsinfo("", &total, &used)) {
return luaL_error(L, "file system failed");
}

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

@ -7,6 +7,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>

View File

@ -3,6 +3,7 @@
* vowstar@gmail.com
* 2015-12-29
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include "module.h"
#include "lauxlib.h"

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

@ -227,69 +227,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(CB, medium_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;
}
@ -330,7 +320,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));
}
@ -371,39 +361,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

@ -1,7 +1,9 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include "rom.h"
//#include "driver/easygpio.h"
//static Ping_Data pingA;
#define defPulseLen 185

View File

@ -9,6 +9,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "task/task.h"
#include <stdint.h>
#include <stdlib.h>
#include "user_interface.h"

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

@ -22,6 +22,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
#include <math.h>
// #define TCS34725_ADDRESS (0x29<<1)
@ -352,4 +353,4 @@ LROT_BEGIN(tcs34725)
LROT_END( tcs34725, NULL, 0 )
NODEMCU_MODULE(TCS34725, "tcs34725", tcs34725, NULL);
NODEMCU_MODULE(TCS34725, "tcs34725", tcs34725, NULL);

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_isanyfunction(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

@ -4,6 +4,7 @@
#include "module.h"
#include "lauxlib.h"
#include "platform.h"
#include "user_interface.h"
static int wps_callback_ref;

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 *) 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 *) 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

@ -1,7 +1,7 @@
#include "platform.h"
#include "driver/spi.h"
#include <stdint.h>
#include "user_interface.h"
#include "sdcard.h"

View File

@ -9,6 +9,7 @@
#include <stdlib.h>
#include "platform.h"
#include "user_interface.h"
#define U8X8_USE_PINS
#define U8X8_WITH_USER_PTR

View File

@ -8,6 +8,7 @@
#include <stdlib.h>
#include "platform.h"
#include "user_interface.h"
#define USE_PIN_LIST
#include "ucg_nodemcu_hal.h"

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

@ -341,11 +341,7 @@ print(node.info("sw_version").git_release)
## 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)`
@ -360,56 +356,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.

View File

@ -6,42 +6,19 @@
| 2018-05-24 | [Terry Ellison](https://github.com/TerryE) | [Terry Ellison](https://github.com/TerryE) | [telnet.lua](./telnet.lua) |
The Lua telnet example previously provided in our distro has been moved to this
file `simple_telnet.lua` in this folder. This README discusses the version complex
implementation at the Lua module `telnet.lua`. The main reason for this complex
alternative is that a single Lua command can produce a LOT of output, and the
telnet server has to work within four constraints:
This README discusses the packet marshalling versions of telnet. The first (fifosock)
version was written for SDK 2 implementations, with all of the marshalling imlemented
in Lua; the second (pipe) version uses the latest features added to the SDK 3 version
that have been added to prepare for the `lua53` implementation. These exploit the
stdin / stdout pipe functionality and task integration that is now build into the
NodeNMCU Lua core.
- The SDK rules are that you can only issue one send per task invocation, so any
overflow must be buffered, and the buffer emptied using an on:sent callback (CB).
There are two nice advantages of this core implementation:
- Since the interpeter invokes a node.output CB per field, you have a double whammy
that these fields are typically small, so using a simple array FIFO would rapidly
exhaust RAM.
- Errors are now written to stdout in a spearate task execution.
- The pipes pretty much eliminate uart and telnet overrun.
- For network efficiency, the module aggregates any FIFO buffered into sensible
sized packet, say 1024 bytes, but it must also need to handle the case when larger
string span multiple packets. However, you must flush the buffer if necessary.
- The overall buffering strategy needs to be reasonably memory efficient and avoid
hitting the GC too hard, so where practical avoid aggregating small strings to more
than 256 chars (as NodeMCU handles \<256 using stack buffers), and avoid serial
aggregation such as buf = buf .. str as this hammers the GC.
So this server adopts a simple buffering scheme using a two level FIFO. The
`node.output` CB adds records to the 1st level FIFO until the #recs is \> 32 or the
total size would exceed 256 bytes. Once over this threashold, the contents of the
FIFO are concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st
level FIFO cleared down to any residue.
The sender dumps the 2nd level FIFO aggregating records up to 1024 bytes and once this
is empty dumps an aggrate of the 1st level.
Lastly remember that owing to architectural limitations of the firmware, this server
can only service stdin and stdout. Lua errors are still sent to stderr which is
the UART0 device. Hence errors will fail silently. If you want to capture
errors then you will need to wrap any commands in a `pcall()` and print any
error return.
Both have the same interface if required into the variable `telnet`
## telnet:open()
@ -64,7 +41,7 @@ Nothing returned (this is evaluted as `nil` in a scalar context).
## telnet:close()
Close a telnet server and release all resources.
Close a telnet server and release all resources. Also set the variable `telnet` to nil to fully reference and GC the resources.
#### Syntax

View File

@ -1,35 +0,0 @@
-- a simple telnet server
telnet_srv = net.createServer(net.TCP, 180)
telnet_srv:listen(2323, function(socket)
local fifo = {}
local fifo_drained = true
local function sender(c)
if #fifo > 0 then
c:send(table.remove(fifo, 1))
else
fifo_drained = true
end
end
local function s_output(str)
table.insert(fifo, str)
if socket ~= nil and fifo_drained then
fifo_drained = false
sender(socket)
end
end
node.output(s_output, 0) -- re-direct output to function s_ouput.
socket:on("receive", function(c, l)
node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line
end)
socket:on("disconnection", function(c)
node.output(nil) -- un-regist the redirect output function, output goes to serial
end)
socket:on("sent", sender)
print("Welcome to NodeMCU world.")
end)

View File

@ -27,10 +27,11 @@ concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st level FI
cleared down to any residue.
]]
local node, table, tmr, wifi, uwrite, tostring =
node, table, tmr, wifi, uart.write, tostring
--luacheck: no unused args
local function telnet_listener(socket)
local node, tmr, wifi, uwrite = node, tmr, wifi, uart.write
local function telnet_listener(socket)
local queueLine = (require "fifosock").wrap(socket)
local function receiveLine(s, line)

View File

@ -0,0 +1,69 @@
--[[ A telnet server T. Ellison, June 2019
This version of the telnet server demonstrates the use of the new stdin and stout
pipes, which is a C implementation of the Lua fifosock concept moved into the
Lua core. These two pipes are referenced in the Lua registry.
]]
--luacheck: no unused args
local M = {}
local modname = ...
local function telnet_session(socket)
local node = node
local stdout
local function output_CB(opipe) -- upval: socket
stdout = opipe
local rec = opipe:read(1400)
if rec and #rec > 0 then socket:send(rec) end
return false -- don't repost as the on:sent will do this
end
local function onsent_CB(skt) -- upval: stdout
local rec = stdout:read(1400)
if rec and #rec > 0 then skt:send(rec) end
end
local function disconnect_CB(skt) -- upval: socket, stdout
node.output()
socket, stdout = nil, nil -- set upvals to nl to allow GC
end
node.output(output_CB, 0)
socket:on("receive", function(_,rec) node.input(rec) end)
socket:on("sent", onsent_CB)
socket:on("disconnection", disconnect_CB)
print(("Welcome to NodeMCU world (%d mem free, %s)"):format(
node.heap(), wifi.sta.getip()))
end
function M.open(this, ssid, pwd, port)
local tmr, wifi, uwrite = tmr, wifi, uart.write
if ssid then
wifi.setmode(wifi.STATION, false)
wifi.sta.config { ssid = ssid, pwd = pwd, save = false }
end
local t = tmr.create()
t:alarm(500, tmr.ALARM_AUTO, function()
if (wifi.sta.status() == wifi.STA_GOTIP) then
t:unregister()
t=nil
print(("Telnet server started (%d mem free, %s)"):format(
node.heap(), wifi.sta.getip()))
M.svr = net.createServer(net.TCP, 180)
M.svr:listen(port or 23, telnet_session)
else
uwrite(0,".")
end
end)
end
function M.close(this)
if this.svr then this.svr:close() end
package.loaded[modname] = nil
end
return M