1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-17 13:25:20 +03:00

Fixes #1643 - Thanks to projectkk2glider for his help on this one

Conflicts:
	radio/src/lua.cpp
	radio/src/opentx.cpp
This commit is contained in:
bsongis 2014-09-05 16:23:55 +02:00
parent 04f9eb5c0f
commit 500602e8cc
8 changed files with 417 additions and 219 deletions

View file

@ -289,6 +289,10 @@ USB = JOYSTICK
# NO - normal behaviour, show real channel values
CHANNELS_MONITOR_INV_HIDE = NO
# Use newlib-nano
# Values = NO, YES
NANO = YES
#------- END BUILD OPTIONS ---------------------------
# Define programs and commands.
@ -1116,6 +1120,12 @@ MATH_LIB = -lm
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += $(MATH_LIB)
ifeq ($(NANO), YES)
# use newlib-nano for linking
NEWLIB_NANO_FLAGS = --specs=nano.specs -u _printf_float
CPPDEFS += -DNANO
endif
# Define Messages
# English
MSG_BEGIN = -------- begin --------
@ -1324,7 +1334,7 @@ FOXLIB=-L/usr/local/lib \
-Wl,-rpath,$(FOXPATH)/src/.libs
simu: $(LUADEP) stamp_header $(BOARDSRC) $(CPPSRC) Makefile simu.cpp targets/simu/simpgmspace.cpp *.h tra lbm eeprom.bin
g++ $(CPPFLAGS) $(INCFLAGS) simu.cpp $(BOARDSRC) $(CPPSRC) $(LUASRC) targets/simu/simpgmspace.cpp -MD -DSIMU -O0 -o simu $(FOXINC) $(FOXLIB) -pthread -fexceptions
g++ $(CPPFLAGS) $(INCFLAGS) simu.cpp $(BOARDSRC) $(CPPSRC) $(LUASRC) targets/simu/simpgmspace.cpp -MD -DSIMU -DLUA_USE_APICHECK -O0 -o simu $(FOXINC) $(FOXLIB) -pthread -fexceptions
eeprom.bin:
dd if=/dev/zero of=$@ bs=1 count=2048
@ -1390,7 +1400,7 @@ OBJS = $(TMP:.s=.o)
@echo
@echo $(MSG_COMPILING) $@
$(CC) $(ARMCPPFLAGS) $< -o allsrc.o
$(CC) $(OBJS) allsrc.o -mcpu=cortex-m3 -mthumb -nostartfiles -lm -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref,--no-warn-mismatch,--gc-sections -o $@
$(CC) $(OBJS) allsrc.o -mcpu=cortex-m3 -mthumb -nostartfiles -lm -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref,--no-warn-mismatch,--gc-sections $(NEWLIB_NANO_FLAGS) -o $@
endif
# Target: clean project.

View file

@ -76,6 +76,19 @@ uint16_t maxLuaDuration = 0;
#define SCRIPTS_MAX_HEAP 50
#define SET_LUA_INSTRUCTIONS_COUNT(x) (instructionsPercent=0, lua_sethook(L, hook, LUA_MASKCOUNT, x))
struct our_longjmp * global_lj = 0;
/* custom panic handler */
static int custom_lua_atpanic(lua_State *lua)
{
TRACE("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1));
if (global_lj) {
longjmp(global_lj->b, 1);
/* will never return */
}
return 0;
}
static int instructionsPercent = 0;
void hook(lua_State* L, lua_Debug *ar)
{
@ -268,9 +281,10 @@ static int luaPlayFile(lua_State *L)
strncpy(str, filename, AUDIO_FILENAME_MAXLEN - (str-file));
file[AUDIO_FILENAME_MAXLEN] = 0;
PLAY_FILE(file, 0, 0);
return 0;
}
PLAY_FILE(filename, 0, 0);
else {
PLAY_FILE(filename, 0, 0);
}
return 0;
}
@ -1358,14 +1372,29 @@ static const luaL_Reg lcdLib[] = {
{ NULL, NULL } /* sentinel */
};
void luaInit()
void luaDisable()
{
POPUP_WARNING("Lua disabled!");
luaState = INTERPRETER_PANIC;
}
void luaClose()
{
if (L) {
lua_close(L);
PROTECT_LUA() {
lua_close(L); // this should not panic, but we make sure anyway
}
else {
// we can only disable Lua for the rest of the session
luaDisable();
}
UNPROTECT_LUA();
L = NULL;
}
}
L = luaL_newstate();
void luaRegisterAll()
{
// Init lua
luaL_openlibs(L);
@ -1441,13 +1470,50 @@ void luaInit()
lua_registerint(L, "TIMEHOUR", TIMEHOUR);
}
void luaInit()
{
luaClose();
if (luaState != INTERPRETER_PANIC) {
L = luaL_newstate();
if (L) {
// install our panic handler
lua_atpanic(L, &custom_lua_atpanic);
// protect libs and constants registration
PROTECT_LUA() {
luaRegisterAll();
}
else {
// if we got panic during registration
// we disable Lua for this session
luaDisable();
}
UNPROTECT_LUA();
}
else {
/* log error and return */
luaDisable();
}
}
}
void luaFree(ScriptInternalData & sid)
{
if (sid.run) {
luaL_unref(L, LUA_REGISTRYINDEX, sid.run);
sid.run = 0;
PROTECT_LUA() {
if (sid.run) {
luaL_unref(L, LUA_REGISTRYINDEX, sid.run);
sid.run = 0;
}
if (sid.background) {
luaL_unref(L, LUA_REGISTRYINDEX, sid.background);
sid.background = 0;
}
lua_gc(L, LUA_GCCOLLECT, 0);
}
else {
luaDisable();
}
UNPROTECT_LUA();
}
int luaLoad(const char *filename, ScriptInternalData & sid, ScriptInputsOutputs * sio=NULL)
@ -1461,47 +1527,55 @@ int luaLoad(const char *filename, ScriptInternalData & sid, ScriptInputsOutputs
SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS);
if (luaL_loadfile(L, filename) == 0 &&
lua_pcall(L, 0, 1, 0) == 0 &&
lua_istable(L, -1)) {
PROTECT_LUA() {
if (luaL_loadfile(L, filename) == 0 &&
lua_pcall(L, 0, 1, 0) == 0 &&
lua_istable(L, -1)) {
luaL_checktype(L, -1, LUA_TTABLE);
luaL_checktype(L, -1, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "init")) {
init = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
const char *key = lua_tostring(L, -2);
if (!strcmp(key, "init")) {
init = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (!strcmp(key, "run")) {
sid.run = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (!strcmp(key, "background")) {
sid.background = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (sio && !strcmp(key, "input")) {
luaGetInputs(*sio);
}
else if (sio && !strcmp(key, "output")) {
luaGetOutputs(*sio);
}
}
else if (!strcmp(key, "run")) {
sid.run = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (!strcmp(key, "background")) {
sid.background = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (sio && !strcmp(key, "input")) {
luaGetInputs(*sio);
}
else if (sio && !strcmp(key, "output")) {
luaGetOutputs(*sio);
if (init) {
lua_rawgeti(L, LUA_REGISTRYINDEX, init);
if (lua_pcall(L, 0, 0, 0) != 0) {
TRACE("Error in script %s init: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
luaL_unref(L, LUA_REGISTRYINDEX, init);
lua_gc(L, LUA_GCCOLLECT, 0);
}
}
if (init) {
lua_rawgeti(L, LUA_REGISTRYINDEX, init);
luaL_unref(L, LUA_REGISTRYINDEX, init);
if (lua_pcall(L, 0, 0, 0) != 0) {
TRACE("Error in script %s init: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
else {
TRACE("Error in script %s: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
}
else {
TRACE("Error in script %s: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
TRACE("Panic in script %s: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_PANIC;
}
UNPROTECT_LUA();
if (sid.state != SCRIPT_OK) {
luaFree(sid);
@ -1663,6 +1737,9 @@ void luaError(uint8_t error)
case SCRIPT_KILLED:
msg = "Script killed";
break;
case SCRIPT_PANIC:
msg = "Script panic";
break;
}
POPUP_WARNING(msg);
}
@ -1670,22 +1747,198 @@ void luaError(uint8_t error)
void luaExec(const char *filename)
{
LUA_RESET();
luaInit();
standaloneScript.state = SCRIPT_NOFILE;
int result = luaLoad(filename, standaloneScript);
// TODO the same with run ...
if (result == SCRIPT_OK) {
luaState = LUASTATE_STANDALONE_SCRIPT_RUNNING;
luaState = INTERPRETER_RUNNING_STANDALONE_SCRIPT;
}
else {
luaError(result);
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
}
void luaDoOneRunStandalone(uint8_t evt)
{
static uint8_t luaDisplayStatistics = false;
if (standaloneScript.state == SCRIPT_OK && standaloneScript.run) {
SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS);
lua_rawgeti(L, LUA_REGISTRYINDEX, standaloneScript.run);
lua_pushinteger(L, evt);
if (lua_pcall(L, 1, 1, 0) == 0) {
if (!lua_isnumber(L, -1)) {
if (instructionsPercent > 100) {
TRACE("Script killed");
standaloneScript.state = SCRIPT_KILLED;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
else if (lua_isstring(L, -1)) {
char nextScript[_MAX_LFN+1];
strncpy(nextScript, lua_tostring(L, -1), _MAX_LFN);
nextScript[_MAX_LFN] = '\0';
luaExec(nextScript);
}
else {
TRACE("Script error");
standaloneScript.state = SCRIPT_SYNTAX_ERROR;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
}
else {
int scriptResult = lua_tointeger(L, -1);
lua_pop(L, 1); /* pop returned value */
if (scriptResult != 0) {
TRACE("Script finished with status %d", scriptResult);
standaloneScript.state = SCRIPT_NOFILE;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
else if (luaDisplayStatistics) {
lcd_hline(0, 7*FH-1, lcdLastPos+FW, ERASE);
lcd_puts(0, 7*FH, "GV Use: ");
lcd_outdezAtt(lcdLastPos, 7*FH, luaGetMemUsed(), LEFT);
lcd_putc(lcdLastPos, 7*FH, 'b');
lcd_hline(0, 7*FH-2, lcdLastPos+FW, FORCE);
lcd_vlineStip(lcdLastPos+FW, 7*FH-2, FH+2, SOLID, FORCE);
}
}
}
else {
TRACE("Script error: %s", lua_tostring(L, -1));
standaloneScript.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR);
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
if (standaloneScript.state != SCRIPT_OK) {
luaError(standaloneScript.state);
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
if (evt == EVT_KEY_LONG(KEY_EXIT)) {
TRACE("Script force exit");
killEvents(evt);
standaloneScript.state = SCRIPT_NOFILE;
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
else if (evt == EVT_KEY_LONG(KEY_MENU)) {
killEvents(evt);
luaDisplayStatistics = !luaDisplayStatistics;
}
}
}
void luaDoOneRunPermanentScript(uint8_t evt, int i)
{
ScriptInternalData & sid = scriptInternalData[i];
if (sid.state == SCRIPT_OK) {
SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS);
int inputsCount = 0;
#if defined(SIMU) || defined(DEBUG)
const char *filename;
#endif
ScriptInputsOutputs * sio = NULL;
if (sid.reference >= SCRIPT_MIX_FIRST && sid.reference <= SCRIPT_MIX_LAST) {
ScriptData & sd = g_model.scriptsData[sid.reference-SCRIPT_MIX_FIRST];
sio = &scriptInputsOutputs[sid.reference-SCRIPT_MIX_FIRST];
inputsCount = sio->inputsCount;
#if defined(SIMU) || defined(DEBUG)
filename = sd.file;
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
for (int j=0; j<sio->inputsCount; j++) {
if (sio->inputs[j].type == 1)
luaGetValueAndPush((uint8_t)sd.inputs[j]);
else
lua_pushinteger(L, sd.inputs[j] + sio->inputs[j].def);
}
}
else if (sid.reference >= SCRIPT_FUNC_FIRST && sid.reference <= SCRIPT_FUNC_LAST) {
CustomFnData & fn = g_model.funcSw[sid.reference-SCRIPT_FUNC_FIRST];
if (!getSwitch(fn.swtch)) {
return;
}
#if defined(SIMU) || defined(DEBUG)
filename = fn.play.name;
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
}
else {
#if defined(SIMU) || defined(DEBUG)
filename = "[telem]";
#endif
if (g_menuStack[0]==menuTelemetryFrsky && sid.reference==SCRIPT_TELEMETRY_FIRST+s_frsky_view) {
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
lua_pushinteger(L, evt);
inputsCount = 1;
}
else if (sid.background) {
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.background);
}
else {
return;
}
}
if (lua_pcall(L, inputsCount, sio ? sio->outputsCount : 0, 0) == 0) {
if (sio) {
for (int j=sio->outputsCount-1; j>=0; j--) {
if (!lua_isnumber(L, -1)) {
sid.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR);
TRACE("Script %8s disabled", filename);
break;
}
sio->outputs[j].value = lua_tointeger(L, -1);
lua_pop(L, 1);
}
}
}
else {
if (instructionsPercent > 100) {
TRACE("Script %8s killed", filename);
sid.state = SCRIPT_KILLED;
}
else {
TRACE("Script %8s error: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
}
if (sid.state != SCRIPT_OK) {
luaFree(sid);
}
else {
if (instructionsPercent > sid.instructions) {
sid.instructions = instructionsPercent;
}
}
}
}
void luaDoGc()
{
PROTECT_LUA() {
lua_gc(L, LUA_GCSTEP /*LUA_GCCOLLECT*/, 0); // LUA_GCSTEP is enough
#if defined(SIMU) || defined(DEBUG)
static int lastgc = 0;
int gc = luaGetMemUsed();
if (gc != lastgc) {
lastgc = gc;
TRACE("GC Use: %dbytes", gc);
}
#endif
}
else {
// we disable Lua for the rest of the session
luaDisable();
}
UNPROTECT_LUA();
}
void luaTask(uint8_t evt)
{
lcd_locked = false;
static uint8_t luaDisplayStatistics = false;
uint32_t t0 = get_tmr10ms();
static uint32_t lastLuaTime = 0;
@ -1695,176 +1948,40 @@ void luaTask(uint8_t evt)
maxLuaInterval = interval;
}
if (luaState & LUASTATE_STANDALONE_SCRIPT_RUNNING) {
// standalone script
if (standaloneScript.state == SCRIPT_OK && standaloneScript.run) {
SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS);
lua_rawgeti(L, LUA_REGISTRYINDEX, standaloneScript.run);
lua_pushinteger(L, evt);
if (lua_pcall(L, 1, 1, 0) == 0) {
if (!lua_isnumber(L, -1)) {
if (instructionsPercent > 100) {
TRACE("Script killed");
standaloneScript.state = SCRIPT_KILLED;
luaState = LUASTATE_RELOAD_MODEL_SCRIPTS;
}
else if (lua_isstring(L, -1)) {
char nextScript[_MAX_LFN+1];
strncpy(nextScript, lua_tostring(L, -1), _MAX_LFN);
nextScript[_MAX_LFN] = '\0';
luaExec(nextScript);
}
else {
TRACE("Script error");
standaloneScript.state = SCRIPT_SYNTAX_ERROR;
luaState = LUASTATE_RELOAD_MODEL_SCRIPTS;
}
}
else {
int scriptResult = lua_tointeger(L, -1);
lua_pop(L, 1); /* pop returned value */
if (scriptResult != 0) {
TRACE("Script finished with status %d", scriptResult);
standaloneScript.state = SCRIPT_NOFILE;
luaState = LUASTATE_RELOAD_MODEL_SCRIPTS;
}
else if (luaDisplayStatistics) {
int gc = 1000*lua_gc(L, LUA_GCCOUNT, 0) + lua_gc(L, LUA_GCCOUNTB, 0);
lcd_hline(0, 7*FH-1, lcdLastPos+FW, ERASE);
lcd_puts(0, 7*FH, "GV Use: ");
lcd_outdezAtt(lcdLastPos, 7*FH, gc, LEFT);
lcd_putc(lcdLastPos, 7*FH, 'b');
lcd_hline(0, 7*FH-2, lcdLastPos+FW, FORCE);
lcd_vlineStip(lcdLastPos+FW, 7*FH-2, FH+2, SOLID, FORCE);
}
}
}
else {
TRACE("Script error: %s", lua_tostring(L, -1));
standaloneScript.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR);
luaState = LUASTATE_RELOAD_MODEL_SCRIPTS;
}
if (standaloneScript.state != SCRIPT_OK) {
luaError(standaloneScript.state);
}
if (evt == EVT_KEY_LONG(KEY_EXIT)) {
TRACE("Script force exit");
killEvents(evt);
standaloneScript.state = SCRIPT_NOFILE;
luaState = LUASTATE_RELOAD_MODEL_SCRIPTS;
}
else if (evt == EVT_KEY_LONG(KEY_MENU)) {
killEvents(evt);
luaDisplayStatistics = !luaDisplayStatistics;
}
if (luaState & INTERPRETER_RUNNING_STANDALONE_SCRIPT) {
PROTECT_LUA() {
luaDoOneRunStandalone(evt);
}
else {
POPUP_WARNING("Script Panic!");
luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS;
}
UNPROTECT_LUA();
}
else {
// model scripts
if (luaState & LUASTATE_RELOAD_MODEL_SCRIPTS) {
if (luaState & INTERPRETER_RELOAD_PERMANENT_SCRIPTS) {
luaState = 0;
LUA_RESET();
luaInit();
if (!L) return;
luaLoadPermanentScripts();
}
for (int i=0; i<luaScriptsCount; i++) {
ScriptInternalData & sid = scriptInternalData[i];
if (sid.state == SCRIPT_OK) {
SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS);
int inputsCount = 0;
#if defined(SIMU) || defined(DEBUG)
const char *filename;
#endif
ScriptInputsOutputs * sio = NULL;
if (sid.reference >= SCRIPT_MIX_FIRST && sid.reference <= SCRIPT_MIX_LAST) {
ScriptData & sd = g_model.scriptsData[sid.reference-SCRIPT_MIX_FIRST];
sio = &scriptInputsOutputs[sid.reference-SCRIPT_MIX_FIRST];
inputsCount = sio->inputsCount;
#if defined(SIMU) || defined(DEBUG)
filename = sd.file;
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
for (int j=0; j<sio->inputsCount; j++) {
if (sio->inputs[j].type == 1)
luaGetValueAndPush((uint8_t)sd.inputs[j]);
else
lua_pushinteger(L, sd.inputs[j] + sio->inputs[j].def);
}
}
else if (sid.reference >= SCRIPT_FUNC_FIRST && sid.reference <= SCRIPT_FUNC_LAST) {
CustomFnData & fn = g_model.funcSw[sid.reference-SCRIPT_FUNC_FIRST];
if (!getSwitch(fn.swtch)) {
continue;
}
#if defined(SIMU) || defined(DEBUG)
filename = fn.play.name;
#endif
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
}
else {
#if defined(SIMU) || defined(DEBUG)
filename = "[telem]";
#endif
if (g_menuStack[0]==menuTelemetryFrsky && sid.reference==SCRIPT_TELEMETRY_FIRST+s_frsky_view) {
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run);
lua_pushinteger(L, evt);
inputsCount = 1;
}
else if (sid.background) {
lua_rawgeti(L, LUA_REGISTRYINDEX, sid.background);
}
else {
continue;
}
}
if (lua_pcall(L, inputsCount, sio ? sio->outputsCount : 0, 0) == 0) {
if (sio) {
for (int j=sio->outputsCount-1; j>=0; j--) {
if (!lua_isnumber(L, -1)) {
sid.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR);
TRACE("Script %8s disabled", filename);
break;
}
sio->outputs[j].value = lua_tointeger(L, -1);
lua_pop(L, 1);
}
}
}
else {
if (instructionsPercent > 100) {
TRACE("Script %8s killed", filename);
sid.state = SCRIPT_KILLED;
}
else {
TRACE("Script %8s error: %s", filename, lua_tostring(L, -1));
sid.state = SCRIPT_SYNTAX_ERROR;
}
}
if (sid.state != SCRIPT_OK) {
luaFree(sid);
}
else {
if (instructionsPercent > sid.instructions) {
sid.instructions = instructionsPercent;
}
}
PROTECT_LUA() {
luaDoOneRunPermanentScript(evt, i);
}
else {
// we disable this script for the rest of the session
ScriptInternalData & sid = scriptInternalData[i];
sid.state = SCRIPT_PANIC;
luaFree(sid);
}
UNPROTECT_LUA();
}
}
lua_gc(L, LUA_GCCOLLECT, 0);
#if defined(SIMU) || defined(DEBUG)
static int lastgc = 0;
int gc = luaGetMemUsed();
if (gc != lastgc) {
lastgc = gc;
TRACE("GC Use: %dbytes", gc);
}
#endif
luaDoGc();
t0 = get_tmr10ms() - t0;
if (t0 > maxLuaDuration) {
@ -1874,5 +1991,5 @@ void luaTask(uint8_t evt)
int luaGetMemUsed()
{
return 1000*lua_gc(L, LUA_GCCOUNT, 0) + lua_gc(L, LUA_GCCOUNTB, 0);
return (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0);
}

View file

@ -2505,6 +2505,10 @@ void opentxClose()
// TODO needed? telemetryEnd();
#endif
#if defined(LUA)
luaClose();
#endif
#if defined(SDCARD)
closeLogs();
sdDone();
@ -3352,8 +3356,6 @@ void opentxInit(OPENTX_INIT_ARGS)
rtcInit();
#endif
LUA_INIT();
if (g_eeGeneral.backlightMode != e_backlight_mode_off) backlightOn(); // on Tx start turn the light on
if (UNEXPECTED_SHUTDOWN()) {

View file

@ -1475,7 +1475,8 @@ enum AUDIO_SOUNDS {
SCRIPT_OK,
SCRIPT_NOFILE,
SCRIPT_SYNTAX_ERROR,
SCRIPT_KILLED
SCRIPT_PANIC,
SCRIPT_KILLED,
};
enum ScriptReference {
SCRIPT_MIX_FIRST,
@ -1498,13 +1499,18 @@ enum AUDIO_SOUNDS {
uint8_t outputsCount;
ScriptOutput outputs[MAX_SCRIPT_OUTPUTS];
};
#define LUASTATE_STANDALONE_SCRIPT_RUNNING 1
#define LUASTATE_RELOAD_MODEL_SCRIPTS 2
enum InterpreterState {
INTERPRETER_RUNNING_PERMANENT_SCRIPTS,
INTERPRETER_RUNNING_STANDALONE_SCRIPT,
INTERPRETER_RELOAD_PERMANENT_SCRIPTS,
INTERPRETER_PANIC,
};
extern uint8_t luaState;
extern uint8_t luaScriptsCount;
extern ScriptInternalData standaloneScript;
extern ScriptInternalData scriptInternalData[MAX_SCRIPTS];
extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS];
void luaClose();
void luaInit();
void luaTask(uint8_t evt);
void luaExec(const char *filename);
@ -1513,13 +1519,23 @@ enum AUDIO_SOUNDS {
int luaGetMemUsed();
#define luaGetCpuUsed(idx) scriptInternalData[idx].instructions
bool isTelemetryScriptAvailable(uint8_t index);
#define LUA_INIT()
#define LUA_RESET() luaInit()
#define LUA_LOAD_MODEL_SCRIPTS() luaState |= LUASTATE_RELOAD_MODEL_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPT(idx) luaState |= LUASTATE_RELOAD_MODEL_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPTS() luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPT(idx) luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
// Lua PROTECT/UNPROTECT
#include <setjmp.h>
struct our_longjmp {
struct our_longjmp *previous;
jmp_buf b;
volatile int status; /* error code */
};
extern struct our_longjmp * global_lj;
#define PROTECT_LUA() { struct our_longjmp lj; \
lj.previous = global_lj; /* chain new error handler */ \
global_lj = &lj; \
if (setjmp(lj.b) == 0)
#define UNPROTECT_LUA() global_lj = lj.previous; } /* restore old error handler */
#else
#define LUA_INIT()
#define LUA_RESET()
#define LUA_LOAD_MODEL_SCRIPTS()
#define LUA_LOAD_MODEL_SCRIPT(idx)
#endif

View file

@ -309,8 +309,6 @@ void *main_thread(void *)
if (g_eeGeneral.backlightMode != e_backlight_mode_off) backlightOn(); // on Tx start turn the light on
LUA_INIT();
if (main_thread_running == 1) {
opentxStart();
}

View file

@ -99,6 +99,13 @@ uint32_t stack_free(uint32_t tid)
stack = audioStack;
size = AUDIO_STACK_SIZE;
break;
#if defined(PCBTARANIS)
case 255:
// main stack
stack = (OS_STK *)&_main_stack_start;
size = ((unsigned char *)&_estack - (unsigned char *)&_main_stack_start) / 4;
break;
#endif
default:
return 0;
}
@ -107,7 +114,7 @@ uint32_t stack_free(uint32_t tid)
for (; i<size; i++)
if (stack[i] != 0x55555555)
break;
return i;
return i*4;
}
void mixerTask(void * pdata)

View file

@ -183,7 +183,6 @@ int main(int argc, char **argv)
StartEepromThread(NULL);
g_menuStackPtr = 0;
g_menuStack[0] = menuMainView;
LUA_RESET();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View file

@ -52,6 +52,8 @@ extern const char * zchar2string(const char * zstring, int size);
void luaExecStr(const char * str)
{
extern lua_State * L;
if (!L) luaInit();
if (!L) FAIL() << "No Lua state!";
if (luaL_dostring(L, str)) {
FAIL() << "lua error: " << lua_tostring(L, -1);
}
@ -98,4 +100,51 @@ TEST(Lua, testSetTelemetryChannel)
}
TEST(Lua, testPanicProtection)
{
bool passed = false;
PROTECT_LUA() {
PROTECT_LUA() {
//simulate panic
longjmp(global_lj->b, 1);
}
else {
//we should come here
passed = true;
}
UNPROTECT_LUA();
}
else {
// an not here
// TRACE("testLuaProtection: test 1 FAILED");
FAIL() << "Failed test 1";
}
UNPROTECT_LUA()
EXPECT_EQ(passed, true);
passed = false;
PROTECT_LUA() {
PROTECT_LUA() {
int a = 5;
a = a; // avoids the warning
}
else {
//we should not come here
// TRACE("testLuaProtection: test 2 FAILED");
FAIL() << "Failed test 2";
}
UNPROTECT_LUA()
//simulate panic
longjmp(global_lj->b, 1);
}
else {
// we should come here
passed = true;
}
UNPROTECT_LUA()
EXPECT_EQ(passed, true);
}
#endif