From f1baa383aeea7337a370da0474a74b2c06baaf6f Mon Sep 17 00:00:00 2001 From: Jesper Frickmann Date: Sun, 14 Nov 2021 20:57:14 -0500 Subject: [PATCH] Fix standalone Lua script screen flicker and improve error messages (#982) * Relax assumptions about when Lua is called in foreground and background * Start Lua cycle timer both in foreground and background Do not assume that background/foreground alternates * Lua is called at every Standalone GUI cycle instead of 5 Hz Since Lua preempts every 50 ms or so, the GUI should remain responsive. * In standalone script, only call Lua once per GUI cycle, to avoid messing up buffer handling. * Revamped error reporting for Standalone and Telemetry Lua scripts * Font size for Lua error is reduced from XL to L on color if LCD_W < LCD_H * In drawTextLines, also possible linebreaks for opening brackets. * Smaller font for error message on tall color screen * Make titlebar height match font size on narrow LCD --- radio/src/gui/128x64/popups.h | 12 +- radio/src/gui/128x64/view_telemetry.cpp | 15 +- radio/src/gui/212x64/popups.h | 6 +- radio/src/gui/212x64/view_telemetry.cpp | 13 +- radio/src/gui/colorlcd/draw_functions.cpp | 3 + radio/src/gui/colorlcd/radio_sdmanager.cpp | 3 +- radio/src/gui/colorlcd/radio_tools.cpp | 3 +- radio/src/gui/colorlcd/standalone_lua.cpp | 17 +- radio/src/gui/colorlcd/standalone_lua.h | 2 +- radio/src/gui/common/stdlcd/popups.cpp | 2 +- radio/src/lua/interface.cpp | 301 +++++++++++---------- radio/src/lua/lua_api.h | 6 +- 12 files changed, 175 insertions(+), 208 deletions(-) diff --git a/radio/src/gui/128x64/popups.h b/radio/src/gui/128x64/popups.h index 38221dba7..6f8a31ab4 100644 --- a/radio/src/gui/128x64/popups.h +++ b/radio/src/gui/128x64/popups.h @@ -24,17 +24,17 @@ #include -#define MESSAGEBOX_X 10 -#define MESSAGEBOX_Y 16 -#define MESSAGEBOX_W (LCD_W - 19) +#define MESSAGEBOX_X 8 +#define MESSAGEBOX_Y 8 +#define MESSAGEBOX_W (LCD_W - 15) #define MENU_X MESSAGEBOX_X #define MENU_Y MESSAGEBOX_Y #define MENU_W MESSAGEBOX_W -#define WARNING_LINE_LEN 20 -#define WARNING_LINE_X 16 -#define WARNING_LINE_Y 3*FH +#define WARNING_LINE_LEN 24 +#define WARNING_LINE_X 12 +#define WARNING_LINE_Y MESSAGEBOX_Y + 2 #define POPUP_MENU_MAX_LINES 12 #define MENU_MAX_DISPLAY_LINES 6 diff --git a/radio/src/gui/128x64/view_telemetry.cpp b/radio/src/gui/128x64/view_telemetry.cpp index dd621b1ab..38775dfb5 100644 --- a/radio/src/gui/128x64/view_telemetry.cpp +++ b/radio/src/gui/128x64/view_telemetry.cpp @@ -170,18 +170,7 @@ bool displayTelemetryScreen() { #if defined(LUA) if (TELEMETRY_SCREEN_TYPE(s_frsky_view) == TELEMETRY_SCREEN_TYPE_SCRIPT) { - uint8_t state = isTelemetryScriptAvailable(s_frsky_view); - switch (state) { - case SCRIPT_OK: - return true; // contents will be drawed by Lua Task - case SCRIPT_NOFILE: - return false; // requested lua telemetry screen not available - case SCRIPT_SYNTAX_ERROR: - case SCRIPT_PANIC: - luaError(lsScripts, state, false); - return true; - } - return false; + return isTelemetryScriptAvailable(); // contents will be drawn by Lua Task } #endif @@ -195,7 +184,5 @@ bool displayTelemetryScreen() return displayCustomTelemetryScreen(s_frsky_view); } - - return true; } diff --git a/radio/src/gui/212x64/popups.h b/radio/src/gui/212x64/popups.h index bab5d652c..b8acecb5d 100644 --- a/radio/src/gui/212x64/popups.h +++ b/radio/src/gui/212x64/popups.h @@ -23,16 +23,16 @@ #define _POPUPS_H_ #define MESSAGEBOX_X 10 -#define MESSAGEBOX_Y 16 +#define MESSAGEBOX_Y 8 #define MESSAGEBOX_W LCD_W - (2 * MESSAGEBOX_X) #define MENU_X 30 #define MENU_Y 16 #define MENU_W LCD_W - (2 * MENU_X) -#define WARNING_LINE_LEN 32 +#define WARNING_LINE_LEN 40 #define WARNING_LINE_X 16 -#define WARNING_LINE_Y 3*FH +#define WARNING_LINE_Y MESSAGEBOX_Y + 2 #define POPUP_MENU_MAX_LINES 12 #define MENU_MAX_DISPLAY_LINES 6 diff --git a/radio/src/gui/212x64/view_telemetry.cpp b/radio/src/gui/212x64/view_telemetry.cpp index ff5c01aba..010488f77 100644 --- a/radio/src/gui/212x64/view_telemetry.cpp +++ b/radio/src/gui/212x64/view_telemetry.cpp @@ -172,18 +172,7 @@ bool displayTelemetryScreen() { #if defined(LUA) if (TELEMETRY_SCREEN_TYPE(s_frsky_view) == TELEMETRY_SCREEN_TYPE_SCRIPT) { - uint8_t state = isTelemetryScriptAvailable(s_frsky_view); - switch (state) { - case SCRIPT_OK: - return true; // contents will be drawed by Lua Task - case SCRIPT_NOFILE: - return false; // requested lua telemetry screen not available - case SCRIPT_SYNTAX_ERROR: - case SCRIPT_PANIC: - luaError(lsScripts, state, false); - return true; - } - return false; + return isTelemetryScriptAvailable(); // contents will be drawn by Lua Task } #endif diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index 63257519f..9a03a14bb 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -517,6 +517,9 @@ void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, case '-': case '/': case ':': + case '(': + case '{': + case '[': nxt++; case ' ': case '\n': diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index e7ea62289..a145c87ab 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -334,8 +334,7 @@ void RadioSdManagerPage::build(FormWindow * window) std::string fullpath = currentPath + "/" + name; menu->addLine(STR_EXECUTE_FILE, [=]() { luaExec(fullpath.c_str()); - if (luaState != INTERPRETER_RELOAD_PERMANENT_SCRIPTS) - StandaloneLuaWindow::instance()->attach(window); + StandaloneLuaWindow::instance()->attach(window); }); } #endif diff --git a/radio/src/gui/colorlcd/radio_tools.cpp b/radio/src/gui/colorlcd/radio_tools.cpp index 85d103fc7..8d58ff27f 100644 --- a/radio/src/gui/colorlcd/radio_tools.cpp +++ b/radio/src/gui/colorlcd/radio_tools.cpp @@ -127,8 +127,7 @@ void RadioToolsPage::rebuild(FormWindow * window) f_chdir(toolPath); luaExec(path_str.c_str()); - if (luaState != INTERPRETER_RELOAD_PERMANENT_SCRIPTS) - StandaloneLuaWindow::instance()->attach(window); + StandaloneLuaWindow::instance()->attach(window); return 0; }, diff --git a/radio/src/gui/colorlcd/standalone_lua.cpp b/radio/src/gui/colorlcd/standalone_lua.cpp index 1870e5718..8d2d59124 100644 --- a/radio/src/gui/colorlcd/standalone_lua.cpp +++ b/radio/src/gui/colorlcd/standalone_lua.cpp @@ -25,8 +25,6 @@ using std::string; -constexpr uint32_t STANDALONE_LUA_REFRESH = 1000 / 50; // 5Hz - void LuaPopup::paint(BitmapBuffer* dc, uint8_t type, const char* text, const char* info) { // popup background @@ -104,22 +102,15 @@ void StandaloneLuaWindow::paint(BitmapBuffer* dc) void StandaloneLuaWindow::checkEvents() { - // Execute first in case onEvent() is called. - // (would trigger refresh) Window::checkEvents(); - - uint32_t now = RTOS_GET_MS(); - if (now - lastRefresh >= STANDALONE_LUA_REFRESH) { - lastRefresh = now; - runLua(0); - } + runLua(event); + event = 0; } #if defined(HARDWARE_KEYS) void StandaloneLuaWindow::onEvent(event_t evt) { - lastRefresh = RTOS_GET_MS(); // mark as 'refreshed' - runLua(evt); + event = evt; } #endif @@ -162,8 +153,6 @@ void StandaloneLuaWindow::runLua(event_t evt) TRACE("# StandaloneLuaWindow::invalidate()"); #endif invalidate(); - } else { - // The script was preempted, and the LCD should not be updated yet } } diff --git a/radio/src/gui/colorlcd/standalone_lua.h b/radio/src/gui/colorlcd/standalone_lua.h index 08a43a727..064b00683 100644 --- a/radio/src/gui/colorlcd/standalone_lua.h +++ b/radio/src/gui/colorlcd/standalone_lua.h @@ -58,11 +58,11 @@ public: protected: // GFX BitmapBuffer lcdBuffer; - uint32_t lastRefresh = 0; // pop-ups LuaPopup popup; // run LUA code void runLua(event_t evt); + event_t event = 0; }; diff --git a/radio/src/gui/common/stdlcd/popups.cpp b/radio/src/gui/common/stdlcd/popups.cpp index ab5d5b9a6..3926d9ff1 100644 --- a/radio/src/gui/common/stdlcd/popups.cpp +++ b/radio/src/gui/common/stdlcd/popups.cpp @@ -50,7 +50,7 @@ void drawMessageBoxBackground(coord_t top, coord_t height) void drawMessageBox(const char * title) { // background + border - drawMessageBoxBackground(MESSAGEBOX_Y, 40); + drawMessageBoxBackground(MESSAGEBOX_Y, 48); // title lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y, title, WARNING_LINE_LEN); diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index b7a6d4dba..f032f1ca8 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -41,8 +41,12 @@ extern "C" { #include } -#define PERMANENT_SCRIPTS_MAX_INSTRUCTIONS 100 +#if defined(COLORLCD) +#define LUA_WARNING_INFO_LEN 256 +#else #define LUA_WARNING_INFO_LEN 64 +#endif +#define PERMANENT_SCRIPTS_MAX_INSTRUCTIONS 100 #define LUA_TASK_PERIOD_TICKS 5 // 50 ms // Since we may not run FG every time, keep the first two events in a buffer @@ -61,6 +65,7 @@ uint16_t maxLuaDuration = 0; uint8_t instructionsPercent = 0; tmr10ms_t luaCycleStart; char lua_warning_info[LUA_WARNING_INFO_LEN+1]; +uint8_t errorState; struct our_longjmp * global_lj = 0; #if defined(COLORLCD) uint32_t luaExtraMemoryUsage = 0; @@ -536,7 +541,6 @@ int luaLoadScriptFileToState(lua_State * L, const char * filename, const char * return ret; } -#if defined(SIMU) || defined(DEBUG) // Get the name of a script for error reporting etc. static const char * getScriptName(uint8_t idx) { @@ -562,7 +566,6 @@ static const char * getScriptName(uint8_t idx) return "standalone"; } } -#endif static bool luaLoad(const char * filename, ScriptInternalData & sid) { @@ -663,92 +666,96 @@ static bool luaLoadTelemetryScript(uint8_t ref) } #endif -uint8_t isTelemetryScriptAvailable(uint8_t idx) +bool isTelemetryScriptAvailable() { #if defined(PCBTARANIS) for (int i = 0; i < luaScriptsCount; i++) { ScriptInternalData & sid = scriptInternalData[i]; - if (sid.reference == SCRIPT_TELEMETRY_FIRST + idx) { - return sid.state; + if (sid.reference == SCRIPT_TELEMETRY_FIRST + s_frsky_view) { + return true; } } - #endif - return SCRIPT_NOFILE; + return false; } -void displayLuaError(const char * title) +void displayLuaError(bool firstCall = false) { -#if !defined(COLORLCD) - drawMessageBox(title); -#endif - - if (lua_warning_info[0]) { - char *split = strstr(lua_warning_info, ": "); -#if !defined(COLORLCD) - if (split) { -#if LCD_W == 128 - if (strlen(split + 2) <= 20) { - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH + 3, - lua_warning_info, split - lua_warning_info, SMLSIZE); - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 2 * FH + 2, split + 2, - strlen(split + 2), SMLSIZE); - } else { - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH, lua_warning_info, - split - lua_warning_info, SMLSIZE); - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 2 * FH, split + 2, 20, - SMLSIZE); - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 3 * FH, split + 22, - strlen(split + 22), SMLSIZE); - } -#else - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH + 3, - lua_warning_info, split - lua_warning_info, SMLSIZE); - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + 2 * FH + 2, split + 2, - lua_warning_info + LUA_WARNING_INFO_LEN - split, - SMLSIZE); -#endif - } else { - // TODO lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y + FH + 3, - // lua_warning_info, 40, SMLSIZE); - } -#else - // Split line... - //if (split) { *(split+1) = '\n'; } - (void)split; // mark as unused - POPUP_WARNING(title, lua_warning_info); -#endif - } -} - -#if !defined(COLORLCD) -void displayAcknowledgeLuaError(event_t event) -{ - warningResult = false; - displayLuaError(warningText); - if (event == EVT_KEY_BREAK(KEY_EXIT)) { - warningText = nullptr; - } -} -#endif - -void luaError(lua_State * L, uint8_t error, bool acknowledge) -{ - const char * errorTitle; - switch (error) { + const char * title; + switch (errorState) { case SCRIPT_SYNTAX_ERROR: - errorTitle = STR_SCRIPT_SYNTAX_ERROR; - break; + title = STR_SCRIPT_SYNTAX_ERROR; break; case SCRIPT_PANIC: - errorTitle = STR_SCRIPT_PANIC; + title = STR_SCRIPT_PANIC; break; default: - errorTitle = STR_SCRIPT_ERROR; - break; + title = STR_SCRIPT_ERROR; } - const char * msg = lua_tostring(L, -1); +#if defined(COLORLCD) + static bool drewBackground = false; + + if (firstCall) + drewBackground = false; + + if (!luaLcdAllowed || luaLcdBuffer == nullptr) + return; + + coord_t w = 0.75 * LCD_W; + coord_t left = (LCD_W - w) / 2; +#if (LCD_W > LCD_H) + coord_t hh = getFontHeight(FONT(XL)) + 4; +#else + coord_t hh = getFontHeight(FONT(L)) + 4; +#endif + coord_t h = 0.75 * LCD_H - hh; + coord_t top = (LCD_H - h + hh / 2) / 2; + + if (!drewBackground) { + drewBackground = true; + luaLcdBuffer->drawFilledRect(0, 0, LCD_W, LCD_H, SOLID, BLACK, OPACITY(6)); + } + + luaLcdBuffer->drawSolidFilledRect(left, top - hh, w, hh, COLOR_THEME_SECONDARY1); + luaLcdBuffer->drawSolidFilledRect(left, top, w, h, COLOR_THEME_SECONDARY3); +#if (LCD_W > LCD_H) + luaLcdBuffer->drawText(left + 10, top - hh + 2, title, FONT(XL) | COLOR_THEME_PRIMARY2); + drawTextLines(luaLcdBuffer, left + 10, top + 5, w - 20, h - 10, lua_warning_info, FONT(L) | COLOR_THEME_PRIMARY1); +#else + luaLcdBuffer->drawText(left + 10, top - hh + 2, title, FONT(L) | COLOR_THEME_PRIMARY2); + drawTextLines(luaLcdBuffer, left + 10, top + 5, w - 20, h - 10, lua_warning_info, FONT(STD) | COLOR_THEME_PRIMARY1); +#endif +#else + if (!luaLcdAllowed) + return; + + drawMessageBox(title); + coord_t y = WARNING_LINE_Y + FH + 4; + + char *str = lua_warning_info; + char *split = strstr(str, ": "); + + if (split) { + lcdDrawSizedText(WARNING_LINE_X, y, str, split - str, SMLSIZE); + y += FH; + str = split + 2; + } + + while(strlen(str)) { + split = strlen(str) > WARNING_LINE_LEN ? str + WARNING_LINE_LEN : str + strlen(str); + lcdDrawSizedText(WARNING_LINE_X, y, str, split - str, SMLSIZE); + y += FH; + str = split; + } +#endif +} + +void luaError(lua_State * L, uint8_t error) +{ + errorState = error; + const char* msg = lua_tostring(L, -1); + if (msg) { #if defined(SIMU) if (!strncmp(msg, ".", 2)) msg += 1; @@ -761,22 +768,9 @@ void luaError(lua_State * L, uint8_t error, bool acknowledge) strncpy(lua_warning_info, msg, LUA_WARNING_INFO_LEN); lua_warning_info[LUA_WARNING_INFO_LEN] = '\0'; } - else { - lua_warning_info[0] = '\0'; - } - - if (acknowledge) { -#if !defined(COLORLCD) - warningText = errorTitle; - warningType = WARNING_TYPE_INFO; - popupFunc = displayAcknowledgeLuaError; -#else - displayLuaError(errorTitle); -#endif - } - else { - displayLuaError(errorTitle); - } + + displayLuaError(true); + TRACE_ERROR("%s\n", lua_warning_info); } // Register a function from a table on the top of the stack @@ -834,15 +828,24 @@ static void luaLoadScripts(bool init, const char * filename = nullptr) if (luaStatus == LUA_OK) { #if defined(LUA_MODEL_SCRIPTS) if (ref <= SCRIPT_MIX_LAST) { - if (luaLoadMixScript(ref)) continue; // If error then skip the rest of the loop + if (luaLoadMixScript(ref)) { + luaError(lsScripts, scriptInternalData[luaScriptsCount - 1].state); + continue; // If error then skip the rest of the loop + } } else #endif if (ref <= SCRIPT_GFUNC_LAST) { - if (luaLoadFunctionScript(ref)) continue; + if (luaLoadFunctionScript(ref)) { + luaError(lsScripts, scriptInternalData[luaScriptsCount - 1].state); + continue; + } } #if defined(PCBTARANIS) else if (ref <= SCRIPT_TELEMETRY_LAST) { - if (luaLoadTelemetryScript(ref)) continue; + if (luaLoadTelemetryScript(ref)) { + luaError(lsScripts, scriptInternalData[luaScriptsCount - 1].state); + continue; + } } #endif else { @@ -850,18 +853,17 @@ static void luaLoadScripts(bool init, const char * filename = nullptr) ScriptInternalData & sid = scriptInternalData[luaScriptsCount++]; sid.reference = SCRIPT_STANDALONE; if (luaLoad(filename, sid)) { - luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; - luaError(lsScripts, sid.state, true); - return; + luaError(lsScripts, sid.state); + continue; } } // Skip the rest of the loop if we did not get a new script if (countBefore == luaScriptsCount) continue; } - + int idx = luaScriptsCount - 1; ScriptInternalData & sid = scriptInternalData[idx]; - + // 1. run chunk() 2. run init(), if available: do { // Resume running the coroutine @@ -889,7 +891,7 @@ static void luaLoadScripts(bool init, const char * filename = nullptr) sid.background = luaRegisterFunction("background"); initFunction = luaRegisterFunction("init"); if (sid.run == LUA_NOREF) { - TRACE_ERROR("luaLoadScripts(%s): No run function\n", getScriptName(idx)); + snprintf(lua_warning_info, LUA_WARNING_INFO_LEN, "luaLoadScripts(%s): No run function\n", getScriptName(idx)); sid.state = SCRIPT_SYNTAX_ERROR; initFunction = LUA_NOREF; } @@ -907,7 +909,7 @@ static void luaLoadScripts(bool init, const char * filename = nullptr) #endif } else { - TRACE_ERROR("luaLoadScripts(%s): The script did not return a table\n", getScriptName(idx)); + snprintf(lua_warning_info, LUA_WARNING_INFO_LEN, "luaLoadScripts(%s): The script did not return a table\n", getScriptName(idx)); sid.state = SCRIPT_SYNTAX_ERROR; initFunction = LUA_NOREF; } @@ -925,27 +927,17 @@ static void luaLoadScripts(bool init, const char * filename = nullptr) else { // Error sid.state = SCRIPT_SYNTAX_ERROR; - - if (initFunction != LUA_NOREF) - TRACE_ERROR("luaLoadScripts(%s): init function: %s\n", getScriptName(idx), lua_tostring(lsScripts, -1)); - else - TRACE_ERROR("luaLoadScripts(%s): %s\n", getScriptName(idx), lua_tostring(lsScripts, -1)); - initFunction = LUA_NOREF; - - // Replace the dead coroutine with a new one - lua_pop(L, 1); // Pop the dead coroutine off the main stack - lsScripts = lua_newthread(L); // Push the new coroutine } - - luaDoGc(lsScripts, true); - } while(initFunction != LUA_NOREF); - if (ref == SCRIPT_STANDALONE && sid.state != SCRIPT_OK) { - luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; - luaError(lsScripts, sid.state, true); - return; + if (sid.state != SCRIPT_OK) { + luaError(lsScripts, sid.state); + + // Replace the dead coroutine with a new one + lua_pop(L, 1); // Pop the dead coroutine off the main stack + lsScripts = lua_newthread(L); // Push the new coroutine + luaDoGc(lsScripts, true); } } while(++ref < SCRIPT_STANDALONE); @@ -971,25 +963,44 @@ static bool resumeLua(bool init, bool allowLcdUsage) static uint8_t luaDisplayStatistics = false; // Run in the right interactive mode - if (allowLcdUsage != luaLcdAllowed) { + if (lua_status(lsScripts) == LUA_YIELD && allowLcdUsage != luaLcdAllowed) { #if defined(PCBTARANIS) - if (luaLcdAllowed && scriptInternalData[0].reference != SCRIPT_STANDALONE && menuHandlers[menuLevel] != menuViewTelemetry) { + uint8_t ref = scriptInternalData[idx].reference; + if (luaLcdAllowed && menuHandlers[menuLevel] != menuViewTelemetry && ref >= SCRIPT_TELEMETRY_FIRST && ref <= SCRIPT_TELEMETRY_LAST) { // Telemetry screen was exited while foreground function was preempted - finish in the background luaLcdAllowed = false; - } - else + } else #endif - if (lua_status(lsScripts) == LUA_YIELD) + { return scriptWasRun; - else - luaLcdAllowed = allowLcdUsage; + } + } else { + luaLcdAllowed = allowLcdUsage; } - + for (; idx < luaScriptsCount; idx++) { ScriptInternalData & sid = scriptInternalData[idx]; - if (sid.state != SCRIPT_OK) continue; - uint8_t ref = sid.reference; + + if (sid.state != SCRIPT_OK) { + displayLuaError(); + scriptWasRun = true; + + if (ref == SCRIPT_STANDALONE) { + // Pull a new event from the buffer + evt = events[0]; + events[0] = events[1]; + events[1] = 0; + + if (evt == EVT_KEY_LONG(KEY_EXIT)) { + killEvents(evt); + luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; + } + } + + continue; + } + int inputsCount = 0; int luaStatus = lua_status(lsScripts); @@ -1079,8 +1090,9 @@ static bool resumeLua(bool init, bool allowLcdUsage) for (int j = sio -> outputsCount - 1; j >= 0; j--) { if (!lua_isnumber(lsScripts, -1)) { - TRACE_ERROR("Script %s: run function did not return a number\n", getScriptName(idx)); sid.state = SCRIPT_SYNTAX_ERROR; + snprintf(lua_warning_info, LUA_WARNING_INFO_LEN, "Script %s: run function did not return a number\n", getScriptName(idx)); + luaError(lsScripts, sid.state); break; } sio -> outputs[j].value = lua_tointeger(lsScripts, -1); @@ -1096,7 +1108,7 @@ static bool resumeLua(bool init, bool allowLcdUsage) if (scriptResult != 0) { TRACE("Script finished with status %d", scriptResult); - sid.state = SCRIPT_FINISHED; + luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } else if (luaDisplayStatistics) { #if defined(COLORLCD) @@ -1118,15 +1130,16 @@ static bool resumeLua(bool init, bool allowLcdUsage) return scriptWasRun; } else { - TRACE_ERROR("Script run function returned unexpected value\n"); sid.state = SCRIPT_SYNTAX_ERROR; + snprintf(lua_warning_info, LUA_WARNING_INFO_LEN, "Script run function returned unexpected value\n"); + luaError(lsScripts, sid.state); } if (evt == EVT_KEY_LONG(KEY_EXIT)) { TRACE("Script force exit"); killEvents(evt); luaEmptyEventBuffer(); - sid.state = SCRIPT_FINISHED; + luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } #if defined(KEYS_GPIO_REG_MENU) // TODO find another key and add a #define @@ -1141,28 +1154,19 @@ static bool resumeLua(bool init, bool allowLcdUsage) else { // Error sid.state = SCRIPT_SYNTAX_ERROR; - TRACE_ERROR("%s: %s\n", getScriptName(idx), lua_tostring(lsScripts, -1)); + luaError(lsScripts, sid.state); - if (sid.reference == SCRIPT_STANDALONE) - luaError(lsScripts, sid.state); - else { - // Replace the dead coroutine with a new one - lua_pop(L, 1); // Pop the dead coroutine off the main stack - lsScripts = lua_newthread(L); // Push the new coroutine - } - } - - if (sid.state != SCRIPT_OK) { - if (sid.reference == SCRIPT_STANDALONE) { - luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; - return scriptWasRun; - } - else luaFree(lsScripts, sid); + // Replace the dead coroutine with a new one + lua_pop(L, 1); // Pop the dead coroutine off the main stack + lsScripts = lua_newthread(L); // Push the new coroutine + luaFree(lsScripts, sid); + luaDoGc(lsScripts, true); } + + scriptWasRun = true; } // for - // Toggle between background and foreground scripts - luaLcdAllowed = !luaLcdAllowed; + // Start a new cycle idx = 0; return scriptWasRun; @@ -1181,7 +1185,7 @@ bool luaTask(event_t evt, bool allowLcdUsage) } // For preemption - if (!allowLcdUsage) luaCycleStart = get_tmr10ms(); + luaCycleStart = get_tmr10ms(); // Trying to replace CPU usage measure instructionsPercent = 100 * maxLuaDuration / LUA_TASK_PERIOD_TICKS; @@ -1234,7 +1238,6 @@ void checkLuaMemoryUsage() #endif } - uint32_t luaGetMemUsed(lua_State * L) { return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0; diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index 6c64b6e68..063714f68 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -113,8 +113,7 @@ enum ScriptState { SCRIPT_OK, SCRIPT_NOFILE, SCRIPT_SYNTAX_ERROR, - SCRIPT_PANIC, - SCRIPT_FINISHED + SCRIPT_PANIC }; enum ScriptReference { @@ -169,10 +168,9 @@ bool luaTask(event_t evt, bool allowLcdUsage); void checkLuaMemoryUsage(); void luaExec(const char * filename); void luaDoGc(lua_State * L, bool full); -void luaError(lua_State * L, uint8_t error, bool acknowledge=true); uint32_t luaGetMemUsed(lua_State * L); void luaGetValueAndPush(lua_State * L, int src); -uint8_t isTelemetryScriptAvailable(uint8_t index); +bool isTelemetryScriptAvailable(); #define luaGetCpuUsed(idx) scriptInternalData[idx].instructions #define LUA_LOAD_MODEL_SCRIPTS() luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS