1
0
Fork 0
mirror of https://github.com/EdgeTX/edgetx.git synced 2025-07-24 00:35:14 +03:00

Lua: Use incremental GC and also call it for Widgets (#4369)

Fixes #3885: Error in Lua Widget options handled better (does not disable entire Lua state)
Disable Lua Widget if any of its functions has error.
This commit is contained in:
Damjan Adamic 2017-02-04 10:58:06 +01:00 committed by Bertrand Songis
parent d594843de2
commit b493973d7d
11 changed files with 213 additions and 89 deletions

View file

@ -418,9 +418,15 @@ int cliMemoryInfo(const char ** argv)
#if defined(LUA) #if defined(LUA)
serialPrint("\nLua:"); serialPrint("\nLua:");
serialPrint("\tScripts %d", luaGetMemUsed(lsScripts)); uint32_t s = luaGetMemUsed(lsScripts);
#if defined(PCBHORUS) serialPrint("\tScripts %u", s);
serialPrint("\tWidgets %d", luaGetMemUsed(lsWidgets)); #if defined(COLORLCD)
uint32_t w = luaGetMemUsed(lsWidgets);
uint32_t e = luaExtraMemoryUsage;
serialPrint("\tWidgets %u", w);
serialPrint("\tExtra %u", e);
serialPrint("------------");
serialPrint("\tTotal %u", s + w + e);
#endif #endif
#endif #endif
return 0; return 0;

View file

@ -79,6 +79,11 @@ class BitmapBufferBase
return data; return data;
} }
uint32_t getDataSize() const
{
return width * height * sizeof(T);
}
inline const display_t * getPixelPtr(coord_t x, coord_t y) const inline const display_t * getPixelPtr(coord_t x, coord_t y) const
{ {
#if defined(PCBX10) #if defined(PCBX10)

View file

@ -176,6 +176,23 @@ int getOptionsCount(const ZoneOption * options)
template <class T> template <class T>
bool menuSettings(const char * title, const T * object, uint32_t i_flags, event_t event) bool menuSettings(const char * title, const T * object, uint32_t i_flags, event_t event)
{ {
if (object->getErrorMessage()) {
// display error instead of widget settings
// TODO nicer display (proper word-wrap)
SIMPLE_SUBMENU("Widget Error", ICON_MODEL_LUA_SCRIPTS, 1);
int len = strlen(object->getErrorMessage());
int y = 3*FH;
const char * p = object->getErrorMessage();
while (len > 0) {
lcdDrawSizedText(MENUS_MARGIN_LEFT, y, p, 30);
p += 30;
y += FH;
len -= 30;
}
return true;
}
const ZoneOption * options = object->getOptions(); const ZoneOption * options = object->getOptions();
linesCount = getOptionsCount(options); linesCount = getOptionsCount(options);
uint8_t mstate_tab[MAX_WIDGET_OPTIONS]; uint8_t mstate_tab[MAX_WIDGET_OPTIONS];

View file

@ -139,6 +139,16 @@ bool menuStatsDebug(event_t event)
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua interval"); lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua interval");
lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaInterval, LEFT, 0, NULL, "ms"); lcdDrawNumber(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH, 10*maxLuaInterval, LEFT, 0, NULL, "ms");
++line; ++line;
lcdDrawText(MENUS_MARGIN_LEFT, MENU_CONTENT_TOP+line*FH, "Lua memory");
lcdDrawText(MENU_STATS_COLUMN1, MENU_CONTENT_TOP+line*FH+1, "[S]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsScripts), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[W]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaGetMemUsed(lsWidgets), LEFT);
lcdDrawText(lcdNextPos+20, MENU_CONTENT_TOP+line*FH+1, "[B]", HEADER_COLOR|SMLSIZE);
lcdDrawNumber(lcdNextPos+5, MENU_CONTENT_TOP+line*FH, luaExtraMemoryUsage, LEFT);
++line;
#endif #endif
lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED); lcdDrawText(LCD_W/2, MENU_FOOTER_TOP+2, STR_MENUTORESET, CENTERED);

View file

@ -56,6 +56,11 @@ class Widget
inline const ZoneOption * getOptions() const; inline const ZoneOption * getOptions() const;
virtual const char * getErrorMessage() const
{
return NULL;
}
inline ZoneOptionValue * getOptionValue(unsigned int index) const inline ZoneOptionValue * getOptionValue(unsigned int index) const
{ {
return &persistentData->options[index]; return &persistentData->options[index];

View file

@ -22,7 +22,7 @@
#include <stdio.h> #include <stdio.h>
#include "opentx.h" #include "opentx.h"
#include "stamp.h" #include "stamp.h"
#include "lua/lua_api.h" #include "lua_api.h"
#include "telemetry/frsky.h" #include "telemetry/frsky.h"
#if defined(PCBX12S) #if defined(PCBX12S)

View file

@ -21,7 +21,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include "opentx.h" #include "opentx.h"
#include "lua/lua_api.h" #include "lua_api.h"
/*luadoc /*luadoc
@function lcd.refresh() @function lcd.refresh()
@ -339,12 +339,16 @@ static int luaOpenBitmap(lua_State * L)
BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *)); BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
*ptr = BitmapBuffer::load(filename); *ptr = BitmapBuffer::load(filename);
TRACE("luaOpenBitmap: %p", *ptr);
if (*ptr == NULL && G(L)->gcrunning) { if (*ptr == NULL && G(L)->gcrunning) {
luaC_fullgc(L, 1); /* try to free some memory... */ luaC_fullgc(L, 1); /* try to free some memory... */
*ptr = BitmapBuffer::load(filename); /* try again */ *ptr = BitmapBuffer::load(filename); /* try again */
TRACE("luaOpenBitmap: %p (second try)", *ptr); }
if (*ptr) {
uint32_t size = (*ptr)->getDataSize();
luaExtraMemoryUsage += size;
TRACE("luaOpenBitmap: %p (%u)", *ptr, size);
} }
luaL_getmetatable(L, LUA_BITMAPHANDLE); luaL_getmetatable(L, LUA_BITMAPHANDLE);
@ -389,7 +393,9 @@ static int luaGetBitmapSize(lua_State * L)
static int luaDestroyBitmap(lua_State * L) static int luaDestroyBitmap(lua_State * L)
{ {
BitmapBuffer * ptr = checkBitmap(L, 1); BitmapBuffer * ptr = checkBitmap(L, 1);
TRACE("luaDestroyBitmap: %p", ptr); uint32_t size = ptr->getDataSize();
TRACE("luaDestroyBitmap: %p (%u)", ptr, size);
if (luaExtraMemoryUsage > size) luaExtraMemoryUsage -= size;
delete ptr; delete ptr;
return 0; return 0;
} }

View file

@ -21,7 +21,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include "opentx.h" #include "opentx.h"
#include "lua/lua_api.h" #include "lua_api.h"
#include "timers.h" #include "timers.h"
/*luadoc /*luadoc

View file

@ -24,7 +24,7 @@
#include <stdio.h> #include <stdio.h>
#include "opentx.h" #include "opentx.h"
#include "bin_allocator.h" #include "bin_allocator.h"
#include "lua/lua_api.h" #include "lua_api.h"
#include "sdcard.h" #include "sdcard.h"
extern "C" { extern "C" {
@ -47,11 +47,14 @@ bool luaLcdAllowed;
int instructionsPercent = 0; int instructionsPercent = 0;
char lua_warning_info[LUA_WARNING_INFO_LEN+1]; char lua_warning_info[LUA_WARNING_INFO_LEN+1];
struct our_longjmp * global_lj = 0; struct our_longjmp * global_lj = 0;
#if defined(COLORLCD)
uint32_t luaExtraMemoryUsage = 0;
#endif
/* custom panic handler */ /* custom panic handler */
int custom_lua_atpanic(lua_State * L) int custom_lua_atpanic(lua_State * L)
{ {
TRACE("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); TRACE("PANIC: unprotected error in call to Lua API (%s)", lua_tostring(L, -1));
if (global_lj) { if (global_lj) {
longjmp(global_lj->b, 1); longjmp(global_lj->b, 1);
/* will never return */ /* will never return */
@ -66,7 +69,7 @@ void luaHook(lua_State * L, lua_Debug *ar)
// From now on, as soon as a line is executed, error // From now on, as soon as a line is executed, error
// keep erroring until you're script reaches the top // keep erroring until you're script reaches the top
lua_sethook(L, luaHook, LUA_MASKLINE, 0); lua_sethook(L, luaHook, LUA_MASKLINE, 0);
luaL_error(L, ""); luaL_error(L, "CPU limit");
} }
} }
@ -177,23 +180,45 @@ void luaRegisterLibraries(lua_State * L)
#endif #endif
} }
void luaDoGc(lua_State * L) #define GC_REPORT_TRESHOLD (2*1024)
void luaDoGc(lua_State * L, bool full)
{ {
if (L) { if (L) {
PROTECT_LUA() { PROTECT_LUA() {
lua_gc(L, LUA_GCCOLLECT, 0); if (full) {
#if defined(SIMU) || defined(DEBUG) lua_gc(L, LUA_GCCOLLECT, 0);
static int lastgc = 0;
int gc = luaGetMemUsed(L);
if (gc != lastgc) {
lastgc = gc;
TRACE("GC Use: %dbytes", gc);
} }
else {
lua_gc(L, LUA_GCSTEP, 10);
}
#if defined(SIMU) || defined(DEBUG)
if (L == lsScripts) {
static uint32_t lastgcSctipts = 0;
uint32_t gc = luaGetMemUsed(L);
if (gc > (lastgcSctipts + GC_REPORT_TRESHOLD) || (gc + GC_REPORT_TRESHOLD) < lastgcSctipts) {
lastgcSctipts = gc;
TRACE("GC Use Scripts: %u bytes", gc);
}
}
#if defined(COLORLCD)
if (L == lsWidgets) {
static uint32_t lastgcWidgets = 0;
uint32_t gc = luaGetMemUsed(L);
if (gc > (lastgcWidgets + GC_REPORT_TRESHOLD) || (gc + GC_REPORT_TRESHOLD) < lastgcWidgets) {
lastgcWidgets = gc;
TRACE("GC Use Widgets: %u bytes + Extra %u", gc, luaExtraMemoryUsage);
}
}
#endif
#endif #endif
} }
else { else {
// we disable Lua for the rest of the session // we disable Lua for the rest of the session
luaDisable(); if (L == lsScripts) luaDisable();
#if defined(COLORLCD)
if (L == lsWidgets) lsWidgets = 0;
#endif
} }
UNPROTECT_LUA(); UNPROTECT_LUA();
} }
@ -216,7 +241,7 @@ void luaFree(lua_State * L, ScriptInternalData & sid)
} }
UNPROTECT_LUA(); UNPROTECT_LUA();
luaDoGc(L); luaDoGc(L, true);
} }
#if defined(LUA_COMPILER) #if defined(LUA_COMPILER)
@ -494,7 +519,7 @@ static int luaLoad(lua_State * L, const char * filename, ScriptInternalData & si
luaFree(L, sid); luaFree(L, sid);
} }
luaDoGc(L); luaDoGc(L, true);
return sid.state; return sid.state;
} }
@ -922,11 +947,14 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage)
//todo gc step between scripts //todo gc step between scripts
} }
} }
luaDoGc(lsScripts); luaDoGc(lsScripts, false);
#if defined(COLORLCD)
luaDoGc(lsWidgets, false);
#endif
return scriptWasRun; return scriptWasRun;
} }
int luaGetMemUsed(lua_State * L) uint32_t luaGetMemUsed(lua_State * L)
{ {
return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0; return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0;
} }

View file

@ -44,6 +44,9 @@ extern "C" {
extern lua_State * lsScripts; extern lua_State * lsScripts;
extern lua_State * lsWidgets; extern lua_State * lsWidgets;
extern bool luaLcdAllowed; extern bool luaLcdAllowed;
#if defined(COLORLCD)
extern uint32_t luaExtraMemoryUsage;
#endif
void luaInit(); void luaInit();
void luaInitThemesAndWidgets(); void luaInitThemesAndWidgets();
@ -116,8 +119,9 @@ extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS];
void luaClose(lua_State ** L); void luaClose(lua_State ** L);
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage); bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage);
void luaExec(const char * filename); void luaExec(const char * filename);
void luaDoGc(lua_State * L, bool full);
void luaError(lua_State * L, uint8_t error, bool acknowledge=true); void luaError(lua_State * L, uint8_t error, bool acknowledge=true);
int luaGetMemUsed(lua_State * L); uint32_t luaGetMemUsed(lua_State * L);
void luaGetValueAndPush(lua_State * L, int src); void luaGetValueAndPush(lua_State * L, int src);
#define luaGetCpuUsed(idx) scriptInternalData[idx].instructions #define luaGetCpuUsed(idx) scriptInternalData[idx].instructions
uint8_t isTelemetryScriptAvailable(uint8_t index); uint8_t isTelemetryScriptAvailable(uint8_t index);

View file

@ -22,7 +22,7 @@
#include <stdio.h> #include <stdio.h>
#include "opentx.h" #include "opentx.h"
#include "bin_allocator.h" #include "bin_allocator.h"
#include "lua/lua_api.h" #include "lua_api.h"
#define WIDGET_SCRIPTS_MAX_INSTRUCTIONS (10000/100) #define WIDGET_SCRIPTS_MAX_INSTRUCTIONS (10000/100)
#define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100) #define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100)
@ -42,6 +42,7 @@ void exec(int function, int nresults=0)
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, function); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, function);
if (lua_pcall(lsWidgets, 0, nresults, 0) != 0) { if (lua_pcall(lsWidgets, 0, nresults, 0) != 0) {
TRACE("Error in theme %s", lua_tostring(lsWidgets, -1)); TRACE("Error in theme %s", lua_tostring(lsWidgets, -1));
// TODO disable theme - revert back to default theme???
} }
} }
} }
@ -63,46 +64,52 @@ ZoneOption * createOptionsArray(int reference)
return NULL; return NULL;
} }
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference); PROTECT_LUA() {
ZoneOption * option = options; lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { ZoneOption * option = options;
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
uint8_t field = 0; luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field<5; lua_pop(lsWidgets, 1), field++) { uint8_t field = 0;
switch (field) { for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field<5; lua_pop(lsWidgets, 1), field++) {
case 0: switch (field) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number case 0:
luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
option->name = lua_tostring(lsWidgets, -1); luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string
break; option->name = lua_tostring(lsWidgets, -1);
case 1: break;
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number case 1:
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
option->type = (ZoneOption::Type)lua_tointeger(lsWidgets, -1); luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
break; option->type = (ZoneOption::Type)lua_tointeger(lsWidgets, -1);
case 2: break;
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number case 2:
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
option->deflt.signedValue = lua_tointeger(lsWidgets, -1); luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
break; option->deflt.signedValue = lua_tointeger(lsWidgets, -1);
case 3: break;
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number case 3:
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
option->min.signedValue = lua_tointeger(lsWidgets, -1); luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
break; option->min.signedValue = lua_tointeger(lsWidgets, -1);
case 4: break;
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number case 4:
luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
option->max.signedValue = lua_tointeger(lsWidgets, -1); luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number
break; option->max.signedValue = lua_tointeger(lsWidgets, -1);
break;
}
} }
option++;
} }
option++; option->name = NULL; // sentinel
} }
else {
option->name = NULL; // sentinel TRACE("error in theme/widget options");
free(options);
return NULL;
}
UNPROTECT_LUA();
return options; return options;
} }
@ -111,8 +118,8 @@ class LuaTheme: public Theme
friend void luaLoadThemeCallback(); friend void luaLoadThemeCallback();
public: public:
LuaTheme(const char * name, int options): LuaTheme(const char * name, ZoneOption * options):
Theme(name, createOptionsArray(options)), Theme(name, options),
loadFunction(0), loadFunction(0),
drawBackgroundFunction(0), drawBackgroundFunction(0),
drawTopbarBackgroundFunction(0), drawTopbarBackgroundFunction(0),
@ -182,11 +189,14 @@ void luaLoadThemeCallback()
} }
if (name) { if (name) {
LuaTheme * theme = new LuaTheme(name, themeOptions); ZoneOption * options = createOptionsArray(themeOptions);
theme->loadFunction = loadFunction; if (options) {
theme->drawBackgroundFunction = drawBackgroundFunction; LuaTheme * theme = new LuaTheme(name, options);
theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; theme->loadFunction = loadFunction;
TRACE("Loaded Lua theme %s", name); theme->drawBackgroundFunction = drawBackgroundFunction;
theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction;
TRACE("Loaded Lua theme %s", name);
}
} }
} }
@ -195,23 +205,30 @@ class LuaWidget: public Widget
public: public:
LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData): LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData):
Widget(factory, zone, persistentData), Widget(factory, zone, persistentData),
widgetData(widgetData) widgetData(widgetData),
errorMessage(0)
{ {
} }
virtual ~LuaWidget() virtual ~LuaWidget()
{ {
luaL_unref(lsWidgets, LUA_REGISTRYINDEX, widgetData); luaL_unref(lsWidgets, LUA_REGISTRYINDEX, widgetData);
if (errorMessage) free(errorMessage);
} }
virtual void update() const; virtual void update();
virtual void refresh(); virtual void refresh();
virtual void background(); virtual void background();
virtual const char * getErrorMessage() const;
protected: protected:
int widgetData; int widgetData;
char * errorMessage;
void setErrorMessage(const char * funcName);
}; };
void l_pushtableint(const char * key, int value) void l_pushtableint(const char * key, int value)
@ -227,8 +244,8 @@ class LuaWidgetFactory: public WidgetFactory
friend class LuaWidget; friend class LuaWidget;
public: public:
LuaWidgetFactory(const char * name, int widgetOptions, int createFunction): LuaWidgetFactory(const char * name, ZoneOption * widgetOptions, int createFunction):
WidgetFactory(name, createOptionsArray(widgetOptions)), WidgetFactory(name, widgetOptions),
createFunction(createFunction), createFunction(createFunction),
updateFunction(0), updateFunction(0),
refreshFunction(0), refreshFunction(0),
@ -273,9 +290,9 @@ class LuaWidgetFactory: public WidgetFactory
int backgroundFunction; int backgroundFunction;
}; };
void LuaWidget::update() const void LuaWidget::update()
{ {
if (lsWidgets == 0) return; if (lsWidgets == 0 || errorMessage) return;
luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS);
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
@ -289,26 +306,48 @@ void LuaWidget::update() const
} }
if (lua_pcall(lsWidgets, 2, 0, 0) != 0) { if (lua_pcall(lsWidgets, 2, 0, 0) != 0) {
TRACE("Error in widget %s update() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); setErrorMessage("update()");
} }
} }
void LuaWidget::setErrorMessage(const char * funcName)
{
TRACE("Error in widget %s %s function: %s", factory->getName(), funcName, lua_tostring(lsWidgets, -1));
TRACE("Widget disabled");
size_t needed = snprintf(NULL, 0, "%s: %s", funcName, lua_tostring(lsWidgets, -1)) + 1;
errorMessage = (char *)malloc(needed);
if (errorMessage) {
snprintf(errorMessage, needed, "%s: %s", funcName, lua_tostring(lsWidgets, -1));
}
}
const char * LuaWidget::getErrorMessage() const
{
return errorMessage;
}
void LuaWidget::refresh() void LuaWidget::refresh()
{ {
if (lsWidgets == 0) return; if (lsWidgets == 0) return;
if (errorMessage) {
lcdSetColor(RED);
lcdDrawText(zone.x, zone.y, "Disabled", SMLSIZE|CUSTOM_COLOR);
return;
}
luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS);
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData);
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
TRACE("Error in widget %s refresh() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); setErrorMessage("refresh()");
} }
} }
void LuaWidget::background() void LuaWidget::background()
{ {
if (lsWidgets == 0) return; if (lsWidgets == 0 || errorMessage) return;
luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS);
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
@ -316,7 +355,7 @@ void LuaWidget::background()
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData);
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
TRACE("Error in widget %s background() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); setErrorMessage("background()");
} }
} }
} }
@ -357,11 +396,14 @@ void luaLoadWidgetCallback()
} }
if (name && createFunction) { if (name && createFunction) {
LuaWidgetFactory * factory = new LuaWidgetFactory(name, widgetOptions, createFunction); ZoneOption * options = createOptionsArray(widgetOptions);
factory->updateFunction = updateFunction; if (options) {
factory->refreshFunction = refreshFunction; LuaWidgetFactory * factory = new LuaWidgetFactory(name, options, createFunction);
factory->backgroundFunction = backgroundFunction; factory->updateFunction = updateFunction;
TRACE("Loaded Lua widget %s", name); factory->refreshFunction = refreshFunction;
factory->backgroundFunction = backgroundFunction;
TRACE("Loaded Lua widget %s", name);
}
} }
} }
@ -385,8 +427,8 @@ void luaLoadFile(const char * filename, void (*callback)())
} }
} }
else { else {
// luaDisable(); // error while loading Lua widget/theme,
lsWidgets = 0; // do not disable whole Lua state, just ingnore bad widget/theme
return; return;
} }
UNPROTECT_LUA(); UNPROTECT_LUA();
@ -453,5 +495,6 @@ void luaInitThemesAndWidgets()
TRACE("lsWidgets %p", lsWidgets); TRACE("lsWidgets %p", lsWidgets);
luaLoadFiles(THEMES_PATH, luaLoadThemeCallback); luaLoadFiles(THEMES_PATH, luaLoadThemeCallback);
luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback); luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback);
luaDoGc(lsWidgets, true);
} }
} }