Merge pull request #2836 from TerryE/dev-new-lua.c
Lua 5.1 to 5.3 realignement phase 1
This commit is contained in:
commit
fff9f95e4c
20
.gdbinitlua
20
.gdbinitlua
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef READLINE_APP_H
|
||||
#define READLINE_APP_H
|
||||
|
||||
bool uart_getc(char *c);
|
||||
|
||||
#endif /* READLINE_APP_H */
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
629
app/lua/lua.c
629
app/lua/lua.c
|
@ -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) */
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
#include "user_interface.h"
|
||||
#include <math.h>
|
||||
|
||||
/****************************************************/
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
#include "user_interface.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "bme680_defs.h"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
#include "user_interface.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* vowstar@gmail.com
|
||||
* 2015-12-29
|
||||
*******************************************************************************/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "module.h"
|
||||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
static int wps_callback_ref;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "platform.h"
|
||||
#include "driver/spi.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "user_interface.h"
|
||||
#include "sdcard.h"
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
#define U8X8_USE_PINS
|
||||
#define U8X8_WITH_USER_PTR
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "platform.h"
|
||||
#include "user_interface.h"
|
||||
|
||||
#define USE_PIN_LIST
|
||||
#include "ucg_nodemcu_hal.h"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue