Fixed output redirection regression (and improved it).

This commit is contained in:
Johny Mattsson 2016-06-02 18:29:00 +10:00
parent 860aa47dc1
commit af9df2ae98
2 changed files with 99 additions and 39 deletions

View File

@ -27,10 +27,19 @@
#include "user_version.h" #include "user_version.h"
#include "rom.h" #include "rom.h"
#include "task/task.h" #include "task/task.h"
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#define CPU80MHZ 80 #define CPU80MHZ 80
#define CPU160MHZ 160 #define CPU160MHZ 160
#define REDIRECT_BUFFER_SZ 128
static xQueueHandle redirQ;
static task_handle_t redir_task;
static int output_redir_ref = LUA_NOREF;
static int serial_output = 1;
// Lua: restart() // Lua: restart()
static int node_restart( lua_State* L ) static int node_restart( lua_State* L )
{ {
@ -324,54 +333,100 @@ static int node_input( lua_State* L )
return 0; return 0;
} }
static int output_redir_ref = LUA_NOREF; void output_redirect(task_param_t arg, task_prio_t prio)
static int serial_debug = 1; {
void output_redirect(const char *str) { (void)arg;
(void)prio;
lua_State *L = lua_getstate(); lua_State *L = lua_getstate();
// if(strlen(str)>=TX_BUFF_SIZE){
// NODE_ERR("output too long.\n");
// return;
// }
if (output_redir_ref == LUA_NOREF || !L) { luaL_Buffer buf;
uart0_sendStr(str);
return;
}
if (serial_debug != 0) {
uart0_sendStr(str);
}
char *p;
size_t total = 0;
unsigned qd = uxQueueMessagesWaitingFromISR (redirQ);
while (qd)
{
if (!total) /* load function onto stack and prepare a new buffer */
{
lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref); lua_rawgeti(L, LUA_REGISTRYINDEX, output_redir_ref);
lua_pushstring(L, str); luaL_buffinit (L, &buf);
lua_call(L, 1, 0); // this call back function should never user output. p = luaL_prepbuffer (&buf);
}
xQueueReceive (redirQ, p++, portMAX_DELAY);
++total;
if (--qd == 0) /* Has anything been appended since we started? */
qd = uxQueueMessagesWaitingFromISR (redirQ);
/* Invoke callback either when we're out of characters, or when we've
* filled up the available buffer space. */
if (!qd || total == LUAL_BUFFERSIZE)
{
luaL_addsize (&buf, total);
luaL_pushresult (&buf);
lua_call(L, 1, 0);
total = 0;
}
}
} }
/* This function may be invoked from any context, so we use xxxFromISR
* functions for all queue handling. */
static void redir_putc (char c)
{
if (serial_output)
uart0_putc (c);
if (redirQ)
{
bool wasEmpty = xQueueIsQueueEmptyFromISR (redirQ);
/* If we get pre-empted and re-entered here we'll end up posting two copies
* to our task, which is mostly harmless (just some wasted cycles) */
xQueueSendToBackFromISR(redirQ, &c, NULL);
if (wasEmpty)
task_post_high (redir_task, 0); /* Limited buffer, service often! */
}
}
// Lua: output(function(c), debug) // Lua: output(function(c), debug)
static int node_output( lua_State* L ) 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); luaL_unref(L, LUA_REGISTRYINDEX, output_redir_ref);
output_redir_ref = LUA_NOREF; output_redir_ref = LUA_NOREF;
serial_debug = 1;
return 0; unsigned len = REDIRECT_BUFFER_SZ;
if (lua_isnumber (L, 3))
len = lua_tonumber (L, 3);
if (lua_type(L, 1) == LUA_TFUNCTION || lua_type(L, 1) == LUA_TLIGHTFUNCTION)
{
lua_pushvalue(L, 1);
output_redir_ref = luaL_ref(L, LUA_REGISTRYINDEX);
if (!redirQ)
redirQ = xQueueCreate (len, sizeof(char));
if (!redir_task)
redir_task = task_get_id (output_redirect);
os_install_putc1 (redir_putc); /* It doesn't give us back the original :( */
}
else
{
if (redirQ)
{
xQueueHandle tmp = redirQ;
/* Dumb "locking" before free, relying on 32bit load/store atomicity */
redirQ = NULL;
vQueueDelete (tmp);
}
serial_output = 1; /* support node.output(nil, 0) to suppress all output */
} }
if ( lua_isnumber(L, 2) ) if ( lua_isnumber(L, 2) )
{ serial_output = lua_tointeger(L, 2) ? 1 : 0;
serial_debug = lua_tointeger(L, 2); else
if (serial_debug != 0) serial_output = 1; // default to 1
serial_debug = 1;
} else {
serial_debug = 1; // default to 1
}
return 0; return 0;
} }

View File

@ -257,11 +257,11 @@ Redirects the Lua interpreter output to a callback function. Optionally also pri
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. 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.
#### Syntax #### Syntax
`node.output(function(str), serial_debug)` `node.output(function(str), serial_output)`
#### Parameters #### 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(str)` a function accept every output as str, and can send the output to a socket (or maybe a file). `nil` to unregister the previous function.
- `serial_debug` 1 output also show in serial. 0: no serial output. - `serial_output` 1 output also sent out the serial port. 0: no serial output. Defaults to 1 if not specified.
#### Returns #### Returns
`nil` `nil`
@ -294,6 +294,11 @@ s:listen(2323,function(c)
end) end)
end) end)
``` ```
```lua
-- disable all output completely
node.output(nil, 0)
```
#### See also #### See also
[`node.input()`](#nodeinput) [`node.input()`](#nodeinput)