Fix uart.on('data') on console
With the switch to use the IDF's stdin for feeding the Lua VM, we unintentionally lost the ability to use uart.on('data') on the console uart. This is since we no longer install the nodemcu uart driver on said uart. In order to resolve this shortcoming, this commit refactors the uart.on('data') delimiter handling and moves it away from platform.c into uart.c where it really belongs. A new function, uart_feed_data(), is introduced, which is used both by the nodemcu uart driver task as well as the nodemcu console driver task (assuming the console is in fact a uart). The linebuffer allocation/freeing is still in response to uart.start()/uart.stop(), but it is now in uart.c rather than platform.c. The whole uart integration is still too tightly coupled between the platform component and the module component's uart.c, but this makes it slightly better at least.
This commit is contained in:
parent
6036c8a6ed
commit
53da95b5ae
|
@ -148,11 +148,29 @@ static void nodemcu_init(void)
|
|||
}
|
||||
|
||||
|
||||
static bool have_console_on_data_cb(void)
|
||||
{
|
||||
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
|
||||
return uart_has_on_data_cb(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void console_nodemcu_task(task_param_t param, task_prio_t prio)
|
||||
{
|
||||
(void)prio;
|
||||
char c = (char)param;
|
||||
feed_lua_input(&c, 1);
|
||||
|
||||
if (run_input)
|
||||
feed_lua_input(&c, 1);
|
||||
|
||||
#if CONFIG_ESP_CONSOLE_UART_DEFAULT || CONFIG_ESP_CONSOLE_UART_CUSTOM
|
||||
if (have_console_on_data_cb())
|
||||
uart_feed_data(CONFIG_ESP_CONSOLE_UART_NUM, &c, 1);
|
||||
#endif
|
||||
|
||||
// The IDF doesn't seem to honor setvbuf(stdout, NULL, _IONBF, 0) :(
|
||||
fsync(fileno(stdout));
|
||||
}
|
||||
|
@ -168,7 +186,7 @@ static void console_task(void *)
|
|||
*/
|
||||
char c;
|
||||
ssize_t n = read(fileno(stdin), &c, 1);
|
||||
if (n > 0 && run_input)
|
||||
if (n > 0 && (run_input || have_console_on_data_cb()))
|
||||
{
|
||||
if (!task_post_block_high(lua_feed_task, (task_param_t)c))
|
||||
{
|
||||
|
|
|
@ -4,48 +4,93 @@
|
|||
#include "lauxlib.h"
|
||||
#include "platform.h"
|
||||
#include "linput.h"
|
||||
#include "lmem.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int receive_rf;
|
||||
int error_rf;
|
||||
char *line_buffer;
|
||||
size_t line_position;
|
||||
uint16_t need_len;
|
||||
int16_t end_char;
|
||||
} uart_cb_cfg_t;
|
||||
|
||||
static lua_State *gL = NULL;
|
||||
static uart_cb_cfg_t uart_cb_cfg[NUM_UART];
|
||||
|
||||
bool uart_has_on_data_cb(unsigned id){
|
||||
return uart_status[id].receive_rf != LUA_NOREF;
|
||||
}
|
||||
|
||||
bool uart_on_data_cb(unsigned id, const char *buf, size_t len){
|
||||
static bool uart_on_data_cb(unsigned id, const char *buf, size_t len){
|
||||
if(!buf || len==0)
|
||||
return false;
|
||||
if(uart_status[id].receive_rf == LUA_NOREF)
|
||||
if(uart_cb_cfg[id].receive_rf == LUA_NOREF)
|
||||
return false;
|
||||
if(!gL)
|
||||
return false;
|
||||
|
||||
int top = lua_gettop(gL);
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, uart_status[id].receive_rf);
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, uart_cb_cfg[id].receive_rf);
|
||||
lua_pushlstring(gL, buf, len);
|
||||
luaL_pcallx(gL, 1, 0);
|
||||
lua_settop(gL, top);
|
||||
return !run_input;
|
||||
}
|
||||
|
||||
|
||||
bool uart_on_error_cb(unsigned id, const char *buf, size_t len){
|
||||
if(!buf || len==0)
|
||||
return false;
|
||||
if(uart_status[id].error_rf == LUA_NOREF)
|
||||
if(uart_cb_cfg[id].error_rf == LUA_NOREF)
|
||||
return false;
|
||||
if(!gL)
|
||||
return false;
|
||||
|
||||
int top = lua_gettop(gL);
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, uart_status[id].error_rf);
|
||||
lua_rawgeti(gL, LUA_REGISTRYINDEX, uart_cb_cfg[id].error_rf);
|
||||
lua_pushlstring(gL, buf, len);
|
||||
luaL_pcallx(gL, 1, 0);
|
||||
lua_settop(gL, top);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool uart_has_on_data_cb(unsigned id){
|
||||
return uart_cb_cfg[id].receive_rf != LUA_NOREF;
|
||||
}
|
||||
|
||||
|
||||
void uart_feed_data(unsigned id, const char *buf, size_t len)
|
||||
{
|
||||
if (id >= NUM_UART)
|
||||
return;
|
||||
|
||||
uart_cb_cfg_t *cfg = &uart_cb_cfg[id];
|
||||
if (!cfg->line_buffer)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < len; ++i)
|
||||
{
|
||||
char ch = buf[i];
|
||||
cfg->line_buffer[cfg->line_position] = ch;
|
||||
cfg->line_position++;
|
||||
|
||||
uint16_t need_len = cfg->need_len;
|
||||
int16_t end_char = cfg->end_char;
|
||||
size_t max_wanted =
|
||||
(end_char >= 0 && need_len == 0) ? LUA_MAXINPUT : need_len;
|
||||
bool at_end = (cfg->line_position >= max_wanted);
|
||||
bool end_char_found =
|
||||
(end_char >= 0 && (uint8_t)ch == (uint8_t)end_char);
|
||||
if (at_end || end_char_found) {
|
||||
uart_on_data_cb(id, cfg->line_buffer, cfg->line_position);
|
||||
cfg->line_position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Lua: uart.on([id], "method", [number/char], function, [run_input])
|
||||
static int uart_on( lua_State* L )
|
||||
{
|
||||
|
@ -54,14 +99,15 @@ static int uart_on( lua_State* L )
|
|||
int32_t run = 1;
|
||||
uint8_t stack = 1;
|
||||
const char *method;
|
||||
uart_status_t *us;
|
||||
|
||||
if( lua_isnumber( L, stack ) ) {
|
||||
id = ( unsigned )luaL_checkinteger( L, stack );
|
||||
MOD_CHECK_ID( uart, id );
|
||||
stack++;
|
||||
}
|
||||
us = & uart_status[id];
|
||||
|
||||
uart_cb_cfg_t *cfg = &uart_cb_cfg[id];
|
||||
|
||||
method = luaL_checklstring( L, stack, &sl );
|
||||
stack++;
|
||||
if (method == NULL)
|
||||
|
@ -69,11 +115,12 @@ static int uart_on( lua_State* L )
|
|||
|
||||
if( lua_type( L, stack ) == LUA_TNUMBER )
|
||||
{
|
||||
us->need_len = ( uint16_t )luaL_checkinteger( L, stack );
|
||||
cfg->need_len = (uint16_t)luaL_checkinteger(L, stack);
|
||||
stack++;
|
||||
us->end_char = -1;
|
||||
if( us->need_len > 255 ){
|
||||
us->need_len = 255;
|
||||
cfg->end_char = -1;
|
||||
if(cfg->need_len > 255)
|
||||
{
|
||||
cfg->need_len = 255;
|
||||
return luaL_error( L, "wrong arg range" );
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +131,8 @@ static int uart_on( lua_State* L )
|
|||
if(el!=1){
|
||||
return luaL_error( L, "wrong arg range" );
|
||||
}
|
||||
us->end_char = (int16_t)end[0];
|
||||
us->need_len = 0;
|
||||
cfg->end_char = (int16_t)end[0];
|
||||
cfg->need_len = 0;
|
||||
}
|
||||
|
||||
if (lua_isfunction(L, stack)) {
|
||||
|
@ -99,12 +146,12 @@ static int uart_on( lua_State* L )
|
|||
if(sl == 4 && strcmp(method, "data") == 0){
|
||||
if(id == CONFIG_ESP_CONSOLE_UART_NUM)
|
||||
run_input = true;
|
||||
if(us->receive_rf != LUA_NOREF){
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, us->receive_rf);
|
||||
us->receive_rf = LUA_NOREF;
|
||||
if(cfg->receive_rf != LUA_NOREF){
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, cfg->receive_rf);
|
||||
cfg->receive_rf = LUA_NOREF;
|
||||
}
|
||||
if(!lua_isnil(L, -1)){
|
||||
us->receive_rf = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
cfg->receive_rf = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
gL = L;
|
||||
if(id == CONFIG_ESP_CONSOLE_UART_NUM && run==0)
|
||||
run_input = false;
|
||||
|
@ -112,12 +159,12 @@ static int uart_on( lua_State* L )
|
|||
lua_pop(L, 1);
|
||||
}
|
||||
} else if(sl == 5 && strcmp(method, "error") == 0){
|
||||
if(us->error_rf != LUA_NOREF){
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, us->error_rf);
|
||||
us->error_rf = LUA_NOREF;
|
||||
if(cfg->error_rf != LUA_NOREF){
|
||||
luaL_unref(L, LUA_REGISTRYINDEX, cfg->error_rf);
|
||||
cfg->error_rf = LUA_NOREF;
|
||||
}
|
||||
if(!lua_isnil(L, -1)){
|
||||
us->error_rf = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
cfg->error_rf = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
gL = L;
|
||||
} else {
|
||||
lua_pop(L, 1);
|
||||
|
@ -183,7 +230,7 @@ static int uart_setup( lua_State* L )
|
|||
static int uart_setmode(lua_State* L)
|
||||
{
|
||||
unsigned id, mode;
|
||||
|
||||
|
||||
id = luaL_checkinteger( L, 1 );
|
||||
MOD_CHECK_ID( uart, id );
|
||||
mode = luaL_checkinteger( L, 2 );
|
||||
|
@ -230,6 +277,11 @@ static int uart_stop( lua_State* L )
|
|||
id = luaL_checkinteger( L, 1 );
|
||||
MOD_CHECK_ID( uart, id );
|
||||
platform_uart_stop( id );
|
||||
if (uart_cb_cfg[id].line_buffer)
|
||||
{
|
||||
luaM_freemem(L, uart_cb_cfg[id].line_buffer, LUA_MAXINPUT);
|
||||
uart_cb_cfg[id].line_buffer = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -240,6 +292,8 @@ static int uart_start( lua_State* L )
|
|||
int err;
|
||||
id = luaL_checkinteger( L, 1 );
|
||||
MOD_CHECK_ID( uart, id );
|
||||
if (!uart_cb_cfg[id].line_buffer)
|
||||
uart_cb_cfg[id].line_buffer = luaM_malloc(L, LUA_MAXINPUT);
|
||||
err = platform_uart_start( id );
|
||||
lua_pushboolean( L, err == 0 );
|
||||
return 1;
|
||||
|
@ -303,21 +357,23 @@ LROT_BEGIN(uart, NULL, 0)
|
|||
LROT_NUMENTRY( FLOWCTRL_NONE, PLATFORM_UART_FLOW_NONE )
|
||||
LROT_NUMENTRY( FLOWCTRL_CTS, PLATFORM_UART_FLOW_CTS )
|
||||
LROT_NUMENTRY( FLOWCTRL_RTS, PLATFORM_UART_FLOW_RTS )
|
||||
LROT_NUMENTRY( MODE_UART, PLATFORM_UART_MODE_UART )
|
||||
LROT_NUMENTRY( MODE_UART, PLATFORM_UART_MODE_UART )
|
||||
LROT_NUMENTRY( MODE_RS485_COLLISION_DETECT, PLATFORM_UART_MODE_RS485_COLLISION_DETECT )
|
||||
LROT_NUMENTRY( MODE_RS485_APP_CONTROL, PLATFORM_UART_MODE_RS485_APP_CONTROL )
|
||||
LROT_NUMENTRY( MODE_RS485_HALF_DUPLEX, PLATFORM_UART_MODE_HALF_DUPLEX )
|
||||
LROT_NUMENTRY( MODE_IRDA, PLATFORM_UART_MODE_IRDA )
|
||||
LROT_NUMENTRY( MODE_IRDA, PLATFORM_UART_MODE_IRDA )
|
||||
LROT_END(uart, NULL, 0)
|
||||
|
||||
int luaopen_uart( lua_State *L ) {
|
||||
uart_status_t *us;
|
||||
for(int id = 0; id < NUM_UART; id++) {
|
||||
us = & uart_status[id];
|
||||
us->receive_rf = LUA_NOREF;
|
||||
us->error_rf = LUA_NOREF;
|
||||
us->need_len = 0;
|
||||
us->end_char = -1;
|
||||
for(int id = 0; id < sizeof(uart_cb_cfg)/sizeof(uart_cb_cfg[0]); id++)
|
||||
{
|
||||
uart_cb_cfg_t *cfg = &uart_cb_cfg[id];
|
||||
cfg->receive_rf = LUA_NOREF;
|
||||
cfg->error_rf = LUA_NOREF;
|
||||
cfg->line_buffer = NULL;
|
||||
cfg->line_position = 0;
|
||||
cfg->need_len = 0;
|
||||
cfg->end_char = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -91,15 +91,12 @@ typedef struct {
|
|||
typedef struct {
|
||||
QueueHandle_t queue;
|
||||
TaskHandle_t taskHandle;
|
||||
int receive_rf;
|
||||
int error_rf;
|
||||
char *line_buffer;
|
||||
size_t line_position;
|
||||
uint16_t need_len;
|
||||
int16_t end_char;
|
||||
} uart_status_t;
|
||||
|
||||
extern uart_status_t uart_status[NUM_UART];
|
||||
// We have a bit of legacy spaghetti - these point into modules/uart.c
|
||||
extern bool uart_has_on_data_cb(unsigned id);
|
||||
extern void uart_feed_data(unsigned id, const char *buf, size_t len);
|
||||
extern bool uart_on_error_cb(unsigned id, const char *buf, size_t len);
|
||||
|
||||
// Flow control types (this is a bit mask, one can specify PLATFORM_UART_FLOW_RTS | PLATFORM_UART_FLOW_CTS )
|
||||
#define PLATFORM_UART_FLOW_NONE 0
|
||||
|
|
|
@ -83,14 +83,9 @@ uart_status_t uart_status[NUM_UART];
|
|||
task_handle_t uart_event_task_id = 0;
|
||||
SemaphoreHandle_t sem = NULL;
|
||||
|
||||
extern bool uart_has_on_data_cb(unsigned id);
|
||||
extern bool uart_on_data_cb(unsigned id, const char *buf, size_t len);
|
||||
extern bool uart_on_error_cb(unsigned id, const char *buf, size_t len);
|
||||
|
||||
void uart_event_task( task_param_t param, task_prio_t prio ) {
|
||||
uart_event_post_t *post = (uart_event_post_t *)param;
|
||||
unsigned id = post->id;
|
||||
uart_status_t *us = &uart_status[id];
|
||||
xSemaphoreGive(sem);
|
||||
if(post->type == PLATFORM_UART_EVENT_DATA) {
|
||||
if (id == CONFIG_ESP_CONSOLE_UART_NUM && run_input) {
|
||||
|
@ -101,28 +96,9 @@ void uart_event_task( task_param_t param, task_prio_t prio ) {
|
|||
i += used;
|
||||
}
|
||||
}
|
||||
if (uart_has_on_data_cb(id)) {
|
||||
size_t i = 0;
|
||||
while (i < post->size)
|
||||
{
|
||||
char ch = post->data[i];
|
||||
us->line_buffer[us->line_position] = ch;
|
||||
us->line_position++;
|
||||
if (uart_has_on_data_cb(id))
|
||||
uart_feed_data(id, post->data, post->size);
|
||||
|
||||
uint16_t need_len = us->need_len;
|
||||
int16_t end_char = us->end_char;
|
||||
size_t max_wanted =
|
||||
(end_char >= 0 && need_len == 0) ? LUA_MAXINPUT : need_len;
|
||||
bool at_end = (us->line_position >= max_wanted);
|
||||
bool end_char_found =
|
||||
(end_char >= 0 && (uint8_t)ch == (uint8_t)end_char);
|
||||
if (at_end || end_char_found) {
|
||||
uart_on_data_cb(id, us->line_buffer, us->line_position);
|
||||
us->line_position = 0;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
free(post->data);
|
||||
} else {
|
||||
const char *err;
|
||||
|
@ -353,20 +329,12 @@ int platform_uart_start( unsigned id )
|
|||
if(ret != ESP_OK) {
|
||||
return -1;
|
||||
}
|
||||
us->line_buffer = malloc(LUA_MAXINPUT);
|
||||
us->line_position = 0;
|
||||
if(us->line_buffer == NULL) {
|
||||
uart_driver_delete(id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char pcName[6];
|
||||
snprintf( pcName, 6, "uart%d", id );
|
||||
pcName[5] = '\0';
|
||||
if(xTaskCreate(task_uart, pcName, 2048, (void*)id, ESP_TASK_MAIN_PRIO + 1, & us->taskHandle) != pdPASS) {
|
||||
uart_driver_delete(id);
|
||||
free(us->line_buffer);
|
||||
us->line_buffer = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -381,8 +349,6 @@ void platform_uart_stop( unsigned id )
|
|||
#endif
|
||||
uart_status_t *us = & uart_status[id];
|
||||
uart_driver_delete(id);
|
||||
if(us->line_buffer) free(us->line_buffer);
|
||||
us->line_buffer = NULL;
|
||||
if(us->taskHandle) vTaskDelete(us->taskHandle);
|
||||
us->taskHandle = NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue