From 92553b65895dd97fb479730643804521e04f04f2 Mon Sep 17 00:00:00 2001 From: Damjan Adamic Date: Mon, 28 Nov 2016 23:08:18 +0100 Subject: [PATCH] Projectkk2glider/lua bitmap free (#4075) * Better memory stats (CLI) * Bitmap buffer overflow check added * Lua bitmap improvements * Proper handling of symbolic links in simulator * S6R Lua script fixes: * added progress screen while loading bitmaps * memory for bitmaps is now freed when leaving the script * S6R Lua script: improved bitmap loading * * Lua Themes and Widgets moved to separate file and separate Lua state * Stand-alone, mixer and function scripts now behave the same as on Taranis (restarted after the stand-alone script was run) * both Lua states are independent: Themes and Widgets is initialized only at the start, the other one is initialized before and after the stand-alone script is run * Better leak test and report in BitmapBuffer * Re #3318: Lua compiler enabled in simu and Companion simulator. Usage: * any time .lua file is about to be loaded and if file .lua.src exists: * load contents of .lua.src * compile Lua code * save compiled code into .lua (effectively overwrites existing file) * immediately following the compilation the real file loading is done from .lua (which by now contains compiled Lua bytecode) --- radio/sdcard/horus/S6R/S6R.lua | 47 +- radio/sdcard/horus/THEMES/TBS/main.lua | 4 +- radio/src/CMakeLists.txt | 8 + radio/src/cli.cpp | 28 +- radio/src/gui/212x64/model_custom_scripts.cpp | 2 +- radio/src/gui/212x64/view_telemetry.cpp | 2 +- radio/src/gui/480x272/bitmapbuffer.h | 24 +- .../src/gui/480x272/model_custom_scripts.cpp | 2 +- radio/src/lua/api_general.cpp | 16 +- radio/src/lua/api_lcd.cpp | 22 +- radio/src/lua/interface.cpp | 543 +++--------------- radio/src/lua/lua_api.h | 17 +- radio/src/lua/widgets.cpp | 462 +++++++++++++++ radio/src/opentx.cpp | 7 +- radio/src/targets/horus/CMakeLists.txt | 1 + radio/src/targets/simu/CMakeLists.txt | 1 + radio/src/targets/simu/simpgmspace.cpp | 103 ++-- radio/src/tests/lua.cpp | 10 +- 18 files changed, 745 insertions(+), 554 deletions(-) create mode 100644 radio/src/lua/widgets.cpp diff --git a/radio/sdcard/horus/S6R/S6R.lua b/radio/sdcard/horus/S6R/S6R.lua index e696b426f..c1de1f662 100755 --- a/radio/sdcard/horus/S6R/S6R.lua +++ b/radio/sdcard/horus/S6R/S6R.lua @@ -4,7 +4,7 @@ local COMBO = 1 local COLUMN_2 = 300 local edit = false -local page = 1 +local page = 0 local current = 1 local refreshState = 0 local refreshIndex = 0 @@ -50,6 +50,10 @@ local calibrationFields = { {"Z:", VALUE, 0xA0, 0, -100, 100, "%"} } +local wingBitmaps = {} +local mountBitmaps = {} +local calibBitmaps = {} + local function drawScreenTitle(title,page, pages) lcd.drawFilledRectangle(0, 0, LCD_W, 30, TITLE_BGCOLOR) lcd.drawText(1, 5, title, MENU_TITLE_COLOR) @@ -238,10 +242,6 @@ local function runFieldsPage(event) return 0 end -local wingBitmaps = { Bitmap.open("img/plane_b.png"), Bitmap.open("img/delta_b.png"), Bitmap.open("img/planev_b.png") } -local mountBitmaps = { Bitmap.open("img/up.png"), Bitmap.open("img/down.png"), Bitmap.open("img/vert.png"), Bitmap.open("img/vert-r.png") } -local calibBitmaps = { Bitmap.open("img/up.png"), Bitmap.open("img/down.png"), Bitmap.open("img/left.png"), Bitmap.open("img/right.png"), Bitmap.open("img/forward.png"), Bitmap.open("img/back.png") } - local function runConfigPage(event) fields = configFields local result = runFieldsPage(event) @@ -310,8 +310,45 @@ local function init() } end +local loaded = 1 +local bitmaps = {"plane_b", "delta_b", "planev_b" + , "up", "down", "vert", "vert-r" + , "up", "down", "left", "right", "forward", "back"} + +local function loadBitmaps() + print("loaded "..loaded) + lcd.clear() + lcd.drawFilledRectangle(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR) + drawScreenTitle("S6R", 0, #pages) + lcd.drawText(120, 100, "Loading bitmaps "..loaded.."/12", TEXT_COLOR) + + if loaded > #bitmaps then + page = 1 + return + end + + local bitmap = Bitmap.open("img/"..bitmaps[loaded]..".png") + if loaded < 4 then + wingBitmaps[loaded] = bitmap + elseif loaded < 8 then + mountBitmaps[loaded-3] = bitmap + else + calibBitmaps[loaded-7] = bitmap + end + + loaded = loaded + 1 +end + + -- Main local function run(event) + + if page == 0 then + -- splash screen while bitmaps are loading + loadBitmaps() + return 0 + end + if event == nil then error("Cannot be run as a model script!") return 2 diff --git a/radio/sdcard/horus/THEMES/TBS/main.lua b/radio/sdcard/horus/THEMES/TBS/main.lua index b54df8bbe..e0a7f2921 100644 --- a/radio/sdcard/horus/THEMES/TBS/main.lua +++ b/radio/sdcard/horus/THEMES/TBS/main.lua @@ -26,14 +26,14 @@ local function load() lcd.setColor(HEADER_ICON_BGCOLOR, BLACK) lcd.setColor(HEADER_CURRENT_BGCOLOR, lcd.RGB(10, 78, 121)) lcd.setColor(OVERLAY_COLOR, BLACK) - bitmap = lcd.loadBitmap("THEMES/TBS/thumb.bmp") + bitmap = Bitmap.open("THEMES/TBS/thumb.bmp") return 0 end local function drawBackground() lcd.drawFilledRectangle(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR); - lcd.drawBitmap(50, 50, bitmap) + lcd.drawBitmap(bitmap, 50, 50) end local function drawTopbarBackground(icon) diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 5ce8a7d7b..23d7c6715 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -24,6 +24,7 @@ option(SIMU_DISKIO "Enable disk IO simulation in simulator. Simulator will use F option(FAS_PROTOTYPE "Support of old FAS prototypes (different resistors)" OFF) option(TEMPLATES "Model templates menu" OFF) option(WARNINGS_AS_ERRORS "Treat all compiler warnings as error" OFF) +option(TRACE_SIMPGMSPACE "Turn on traces in simpgmspace.cpp" ON) enable_language(ASM) set(OPT s) @@ -177,6 +178,9 @@ if(NOT LUA STREQUAL NO) set(GUI_SRC ${GUI_SRC} model_custom_scripts.cpp) endif() set(SRC ${SRC} lua/interface.cpp lua/api_general.cpp lua/api_lcd.cpp lua/api_model.cpp) + if(PCB STREQUAL HORUS) + set(SRC ${SRC} lua/widgets.cpp) + endif() set(LUA_SRC lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c ltable.c lrotable.c ltm.c lundump.c lvm.c lzio.c linit.c lbaselib.c lmathlib.c lbitlib.c loadlib.c lauxlib.c ltablib.c lcorolib.c liolib.c lstrlib.c @@ -275,6 +279,10 @@ if(SPLASH) add_definitions(-DSPLASH) endif() +if(TRACE_SIMPGMSPACE) + add_definitions(-DTRACE_SIMPGMSPACE) +endif() + set(SRC ${SRC} opentx.cpp diff --git a/radio/src/cli.cpp b/radio/src/cli.cpp index bf8f8cc8a..526325301 100644 --- a/radio/src/cli.cpp +++ b/radio/src/cli.cpp @@ -303,6 +303,10 @@ int cliStackInfo(const char ** argv) return 0; } +extern int _end; +extern int _heap_end; +extern unsigned char *heap; + int cliMemoryInfo(const char ** argv) { // struct mallinfo { @@ -318,11 +322,25 @@ int cliMemoryInfo(const char ** argv) // int keepcost; /* top-most, releasable (via malloc_trim) space */ // }; struct mallinfo info = mallinfo(); - serialPrint("arena %d", info.arena); - serialPrint("ordblks %d", info.ordblks); - serialPrint("uordblks %d", info.uordblks); - serialPrint("fordblks %d", info.fordblks); - serialPrint("keepcost %d", info.keepcost); + serialPrint("mallinfo:"); + serialPrint("\tarena %d bytes", info.arena); + serialPrint("\tordblks %d bytes", info.ordblks); + serialPrint("\tuordblks %d bytes", info.uordblks); + serialPrint("\tfordblks %d bytes", info.fordblks); + serialPrint("\tkeepcost %d bytes", info.keepcost); + + serialPrint("\nHeap:"); + serialPrint("\tstart %p", (unsigned char *)&_end); + serialPrint("\tend %p", (unsigned char *)&_heap_end); + serialPrint("\tcurr %p", heap); + serialPrint("\tused %d bytes", (int)(heap - (unsigned char *)&_end)); + serialPrint("\tfree %d bytes", (int)((unsigned char *)&_heap_end - heap)); + + serialPrint("\nLua:"); + serialPrint("\tScripts %d", luaGetMemUsed(lsScripts)); +#if defined(PCBHORUS) + serialPrint("\tWidgets %d", luaGetMemUsed(lsWidgets)); +#endif return 0; } diff --git a/radio/src/gui/212x64/model_custom_scripts.cpp b/radio/src/gui/212x64/model_custom_scripts.cpp index b0b82702b..a67364314 100644 --- a/radio/src/gui/212x64/model_custom_scripts.cpp +++ b/radio/src/gui/212x64/model_custom_scripts.cpp @@ -118,7 +118,7 @@ void menuModelCustomScriptOne(event_t event) void menuModelCustomScripts(event_t event) { - lcdDrawNumber(19*FW, 0, luaGetMemUsed(), RIGHT); + lcdDrawNumber(19*FW, 0, luaGetMemUsed(lsScripts), RIGHT); lcdDrawText(19*FW+1, 0, STR_BYTES); MENU(STR_MENUCUSTOMSCRIPTS, menuTabModel, MENU_MODEL_CUSTOM_SCRIPTS, MAX_SCRIPTS, { NAVIGATION_LINE_BY_LINE|3/*repeated*/ }); diff --git a/radio/src/gui/212x64/view_telemetry.cpp b/radio/src/gui/212x64/view_telemetry.cpp index 01237131f..91c3e1167 100644 --- a/radio/src/gui/212x64/view_telemetry.cpp +++ b/radio/src/gui/212x64/view_telemetry.cpp @@ -175,7 +175,7 @@ bool displayTelemetryScreen() case SCRIPT_SYNTAX_ERROR: case SCRIPT_PANIC: case SCRIPT_KILLED: - luaError(state, false); + luaError(lsScripts, state, false); return true; } return false; diff --git a/radio/src/gui/480x272/bitmapbuffer.h b/radio/src/gui/480x272/bitmapbuffer.h index d9e1de13c..72a6794b0 100644 --- a/radio/src/gui/480x272/bitmapbuffer.h +++ b/radio/src/gui/480x272/bitmapbuffer.h @@ -45,7 +45,8 @@ class BitmapBufferBase format(format), width(width), height(height), - data(data) + data(data), + data_end(data + (width * height)) { } @@ -74,6 +75,7 @@ class BitmapBufferBase uint16_t width; uint16_t height; T * data; + T * data_end; }; typedef BitmapBufferBase Bitmap; @@ -82,19 +84,29 @@ class BitmapBuffer: public BitmapBufferBase { private: bool dataAllocated; +#if defined(DEBUG) + bool leakReported; +#endif public: BitmapBuffer(uint8_t format, uint16_t width, uint16_t height): BitmapBufferBase(format, width, height, NULL), dataAllocated(true) +#if defined(DEBUG) + , leakReported(false) +#endif { data = (uint16_t *)malloc(width*height*sizeof(uint16_t)); + data_end = data + (width * height); } BitmapBuffer(uint8_t format, uint16_t width, uint16_t height, uint16_t * data): BitmapBufferBase(format, width, height, data), dataAllocated(false) +#if defined(DEBUG) + , leakReported(false) +#endif { } @@ -117,7 +129,15 @@ class BitmapBuffer: public BitmapBufferBase inline void drawPixel(display_t * p, display_t value) { - *p = value; + if (data && (data <= p || p < data_end)) { + *p = value; + } +#if defined(DEBUG) + else if (!leakReported) { + leakReported = true; + TRACE("BitmapBuffer(%p).drawPixel(): buffer overrun, data: %p, written at: %p", this, data, p); + } +#endif } inline display_t * getPixelPtr(coord_t x, coord_t y) diff --git a/radio/src/gui/480x272/model_custom_scripts.cpp b/radio/src/gui/480x272/model_custom_scripts.cpp index 3d391bf4a..d9b9bc9ed 100644 --- a/radio/src/gui/480x272/model_custom_scripts.cpp +++ b/radio/src/gui/480x272/model_custom_scripts.cpp @@ -124,7 +124,7 @@ bool menuModelCustomScriptOne(event_t event) bool menuModelCustomScripts(event_t event) { - // lcdDrawNumber(19*FW, 0, luaGetMemUsed(), 0); + // lcdDrawNumber(19*FW, 0, luaGetMemUsed(lsScripts), 0); // lcdDrawText(19*FW+1, 0, STR_BYTES); MENU(STR_MENUCUSTOMSCRIPTS, MODEL_ICONS, menuTabModel, MENU_MODEL_CUSTOM_SCRIPTS, MAX_SCRIPTS, { NAVIGATION_LINE_BY_LINE|3/*repeated*/ }); diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 9375b6389..2ca65d7fb 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -147,7 +147,7 @@ static int luaGetDateTime(lua_State * L) return 1; } -static void luaPushLatLon(TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem) +static void luaPushLatLon(lua_State* L, TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem) /* result is lua table containing members ["lat"] and ["lon"] as lua_Number (doubles) in decimal degrees */ { lua_createtable(L, 0, 4); @@ -157,13 +157,13 @@ static void luaPushLatLon(TelemetrySensor & telemetrySensor, TelemetryItem & tel lua_pushtablenumber(L, "pilot-lon", telemetryItem.pilotLongitude / 1000000.0); } -static void luaPushTelemetryDateTime(TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem) +static void luaPushTelemetryDateTime(lua_State* L, TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem) { luaPushDateTime(L, telemetryItem.datetime.year, telemetryItem.datetime.month, telemetryItem.datetime.day, telemetryItem.datetime.hour, telemetryItem.datetime.min, telemetryItem.datetime.sec); } -static void luaPushCells(TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem) +static void luaPushCells(lua_State* L, TelemetrySensor & telemetrySensor, TelemetryItem & telemetryItem) { if (telemetryItem.cells.count == 0) lua_pushinteger(L, (int)0); // returns zero if no cells @@ -177,7 +177,7 @@ static void luaPushCells(TelemetrySensor & telemetrySensor, TelemetryItem & tele } } -void luaGetValueAndPush(int src) +void luaGetValueAndPush(lua_State* L, int src) { getvalue_t value = getValue(src); // ignored for GPS, DATETIME, and CELLS @@ -188,14 +188,14 @@ void luaGetValueAndPush(int src) TelemetrySensor & telemetrySensor = g_model.telemetrySensors[qr.quot]; switch (telemetrySensor.unit) { case UNIT_GPS: - luaPushLatLon(telemetrySensor, telemetryItems[qr.quot]); + luaPushLatLon(L, telemetrySensor, telemetryItems[qr.quot]); break; case UNIT_DATETIME: - luaPushTelemetryDateTime(telemetrySensor, telemetryItems[qr.quot]); + luaPushTelemetryDateTime(L, telemetrySensor, telemetryItems[qr.quot]); break; case UNIT_CELLS: if (qr.rem == 0) { - luaPushCells(telemetrySensor, telemetryItems[qr.quot]); + luaPushCells(L, telemetrySensor, telemetryItems[qr.quot]); break; } // deliberate no break here to properly return `Cels-` and `Cels+` @@ -566,7 +566,7 @@ static int luaGetValue(lua_State * L) src = field.id; } } - luaGetValueAndPush(src); + luaGetValueAndPush(L, src); return 1; } diff --git a/radio/src/lua/api_lcd.cpp b/radio/src/lua/api_lcd.cpp index 0299b833d..2a2bb0713 100644 --- a/radio/src/lua/api_lcd.cpp +++ b/radio/src/lua/api_lcd.cpp @@ -317,6 +317,9 @@ static int luaLcdDrawSource(lua_State *L) } #if defined(COLORLCD) + +#define LUA_BITMAPHANDLE "BITMAP*" + /*luadoc @function Bitmap.open(name) @@ -334,8 +337,15 @@ static int luaOpenBitmap(lua_State * L) BitmapBuffer ** ptr = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *)); *ptr = BitmapBuffer::load(filename); + TRACE("luaOpenBitmap: %p", *ptr); - luaL_getmetatable(L, "luaL_Bitmap"); + if (*ptr == NULL && G(L)->gcrunning) { + luaC_fullgc(L, 1); /* try to free some memory... */ + *ptr = BitmapBuffer::load(filename); /* try again */ + TRACE("luaOpenBitmap: %p (second try)", *ptr); + } + + luaL_getmetatable(L, LUA_BITMAPHANDLE); lua_setmetatable(L, -2); return 1; @@ -343,7 +353,9 @@ static int luaOpenBitmap(lua_State * L) static BitmapBuffer * checkBitmap(lua_State * L, int index) { - return *(BitmapBuffer **)luaL_checkudata(L, index, "luaL_Bitmap"); + BitmapBuffer ** b = (BitmapBuffer **)luaL_checkudata(L, index, LUA_BITMAPHANDLE); + if (!*b) luaL_error(L, "null Image"); + return *b; } @@ -374,7 +386,9 @@ static int luaGetBitmapSize(lua_State * L) static int luaDestroyBitmap(lua_State * L) { - delete checkBitmap(L, 1); + BitmapBuffer * ptr = checkBitmap(L, 1); + TRACE("luaDestroyBitmap: %p", ptr); + delete ptr; return 0; } @@ -387,7 +401,7 @@ const luaL_Reg bitmapFuncs[] = { void registerBitmapClass(lua_State * L) { - luaL_newmetatable(L, "luaL_Bitmap"); + luaL_newmetatable(L, LUA_BITMAPHANDLE); luaL_setfuncs(L, bitmapFuncs, 0); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index e33a82024..7bfddd51a 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -25,16 +25,16 @@ #include "lua/lua_api.h" #if defined(LUA_COMPILER) && defined(SIMU) - #include - #include + extern "C" { + #include + } #endif #define PERMANENT_SCRIPTS_MAX_INSTRUCTIONS (10000/100) #define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100) -#define SET_LUA_INSTRUCTIONS_COUNT(x) (instructionsPercent=0, lua_sethook(L, hook, LUA_MASKCOUNT, x)) #define LUA_WARNING_INFO_LEN 64 -lua_State *L = NULL; +lua_State *lsScripts = NULL; uint8_t luaState = 0; uint8_t luaScriptsCount = 0; ScriptInternalData scriptInternalData[MAX_SCRIPTS] = { { SCRIPT_NOFILE, 0 } }; @@ -48,7 +48,7 @@ char lua_warning_info[LUA_WARNING_INFO_LEN+1]; struct our_longjmp * global_lj = 0; /* custom panic handler */ -static int custom_lua_atpanic(lua_State *lua) +int custom_lua_atpanic(lua_State * L) { TRACE("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); if (global_lj) { @@ -58,18 +58,24 @@ static int custom_lua_atpanic(lua_State *lua) return 0; } -void hook(lua_State* L, lua_Debug *ar) +void luaHook(lua_State * L, lua_Debug *ar) { instructionsPercent++; if (instructionsPercent > 100) { // From now on, as soon as a line is executed, error // keep erroring until you're script reaches the top - lua_sethook(L, hook, LUA_MASKLINE, 0); + lua_sethook(L, luaHook, LUA_MASKLINE, 0); luaL_error(L, ""); } } -int luaGetInputs(ScriptInputsOutputs & sid) +void luaSetInstructionsLimit(lua_State * L, int count) +{ + instructionsPercent=0; + lua_sethook(L, luaHook, LUA_MASKCOUNT, count); +} + +int luaGetInputs(lua_State * L, ScriptInputsOutputs & sid) { if (!lua_istable(L, -1)) return -1; @@ -123,7 +129,7 @@ int luaGetInputs(ScriptInputsOutputs & sid) return 0; } -int luaGetOutputs(ScriptInputsOutputs & sid) +int luaGetOutputs(lua_State * L, ScriptInputsOutputs & sid) { if (!lua_istable(L, -1)) return -1; @@ -146,10 +152,11 @@ void luaDisable() luaState = INTERPRETER_PANIC; } -void luaClose() +void luaClose(lua_State * L) { if (L) { PROTECT_LUA() { + TRACE("luaClose %p", L); lua_close(L); // this should not panic, but we make sure anyway } else { @@ -161,17 +168,15 @@ void luaClose() } } -void luaRegisterAll() +void luaRegisterLibraries(lua_State * L) { - // Init lua luaL_openlibs(L); - #if defined(COLORLCD) registerBitmapClass(L); #endif } -void luaFree(ScriptInternalData & sid) +void luaFree(lua_State * L, ScriptInternalData & sid) { PROTECT_LUA() { if (sid.run) { @@ -191,7 +196,7 @@ void luaFree(ScriptInternalData & sid) } #if defined(LUA_COMPILER) && defined(SIMU) -static int luaDumpWriter(lua_State* L, const void* p, size_t size, void* u) +static int luaDumpWriter(lua_State * L, const void* p, size_t size, void* u) { UNUSED(L); UINT written; @@ -199,7 +204,7 @@ static int luaDumpWriter(lua_State* L, const void* p, size_t size, void* u) return (result != FR_OK && !written); } -static void luaCompileAndSave(const char *bytecodeName) +void luaCompileAndSave(lua_State * L, const char *bytecodeName) { FIL D; char srcName[1024]; @@ -228,7 +233,7 @@ static void luaCompileAndSave(const char *bytecodeName) } #endif -int luaLoad(const char * filename, ScriptInternalData & sid, ScriptInputsOutputs * sio=NULL) +int luaLoad(lua_State * L, const char * filename, ScriptInternalData & sid, ScriptInputsOutputs * sio=NULL) { int init = 0; @@ -245,10 +250,10 @@ int luaLoad(const char * filename, ScriptInternalData & sid, ScriptInputsOutputs } #if defined(LUA_COMPILER) && defined(SIMU) - luaCompileAndSave(filename); + luaCompileAndSave(L, filename); #endif - SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS); + luaSetInstructionsLimit(L, MANUAL_SCRIPTS_MAX_INSTRUCTIONS); PROTECT_LUA() { if (luaL_loadfile(L, filename) == 0 && @@ -272,10 +277,10 @@ int luaLoad(const char * filename, ScriptInternalData & sid, ScriptInputsOutputs lua_pushnil(L); } else if (sio && !strcmp(key, "input")) { - luaGetInputs(*sio); + luaGetInputs(L, *sio); } else if (sio && !strcmp(key, "output")) { - luaGetOutputs(*sio); + luaGetOutputs(L, *sio); } } @@ -301,7 +306,7 @@ int luaLoad(const char * filename, ScriptInternalData & sid, ScriptInputsOutputs UNPROTECT_LUA(); if (sid.state != SCRIPT_OK) { - luaFree(sid); + luaFree(L, sid); } return sid.state; @@ -320,7 +325,7 @@ bool luaLoadMixScript(uint8_t index) strncpy(filename+sizeof(SCRIPTS_MIXES_PATH), sd.file, sizeof(sd.file)); filename[sizeof(SCRIPTS_MIXES_PATH)+sizeof(sd.file)] = '\0'; strcat(filename+sizeof(SCRIPTS_MIXES_PATH), SCRIPTS_EXT); - if (luaLoad(filename, sid, sio) == SCRIPT_PANIC) { + if (luaLoad(lsScripts, filename, sid, sio) == SCRIPT_PANIC) { return false; } } @@ -340,7 +345,7 @@ bool luaLoadFunctionScript(uint8_t index) strncpy(filename+sizeof(SCRIPTS_FUNCS_PATH), fn.play.name, sizeof(fn.play.name)); filename[sizeof(SCRIPTS_FUNCS_PATH)+sizeof(fn.play.name)] = '\0'; strcat(filename+sizeof(SCRIPTS_FUNCS_PATH), SCRIPTS_EXT); - if (luaLoad(filename, sid) == SCRIPT_PANIC) { + if (luaLoad(lsScripts, filename, sid) == SCRIPT_PANIC) { return false; } } @@ -368,7 +373,7 @@ bool luaLoadTelemetryScript(uint8_t index) strncpy(filename+sizeof(SCRIPTS_TELEM_PATH), script.file, sizeof(script.file)); filename[sizeof(SCRIPTS_TELEM_PATH)+sizeof(script.file)] = '\0'; strcat(filename+sizeof(SCRIPTS_TELEM_PATH), SCRIPTS_EXT); - if (luaLoad(filename, sid) == SCRIPT_PANIC) { + if (luaLoad(lsScripts, filename, sid) == SCRIPT_PANIC) { return false; } } @@ -449,7 +454,7 @@ void displayAcknowledgeLuaError(event_t event) } } -void luaError(uint8_t error, bool acknowledge) +void luaError(lua_State * L, uint8_t error, bool acknowledge) { const char * errorTitle; @@ -492,19 +497,17 @@ void luaError(uint8_t error, bool acknowledge) void luaExec(const char * filename) { -#if !defined(COLORLCD) luaInit(); -#endif if (luaState != INTERPRETER_PANIC) { standaloneScript.state = SCRIPT_NOFILE; - int result = luaLoad(filename, standaloneScript); + int result = luaLoad(lsScripts, filename, standaloneScript); // TODO the same with run ... if (result == SCRIPT_OK) { luaState = INTERPRETER_RUNNING_STANDALONE_SCRIPT; } else { - luaError(result); + luaError(lsScripts, result); luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } } @@ -515,19 +518,19 @@ void luaDoOneRunStandalone(event_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_pushunsigned(L, evt); - if (lua_pcall(L, 1, 1, 0) == 0) { - if (!lua_isnumber(L, -1)) { + luaSetInstructionsLimit(lsScripts, MANUAL_SCRIPTS_MAX_INSTRUCTIONS); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, standaloneScript.run); + lua_pushunsigned(lsScripts, evt); + if (lua_pcall(lsScripts, 1, 1, 0) == 0) { + if (!lua_isnumber(lsScripts, -1)) { if (instructionsPercent > 100) { TRACE("Script killed"); standaloneScript.state = SCRIPT_KILLED; luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } - else if (lua_isstring(L, -1)) { + else if (lua_isstring(lsScripts, -1)) { char nextScript[_MAX_LFN+1]; - strncpy(nextScript, lua_tostring(L, -1), _MAX_LFN); + strncpy(nextScript, lua_tostring(lsScripts, -1), _MAX_LFN); nextScript[_MAX_LFN] = '\0'; luaExec(nextScript); } @@ -538,8 +541,8 @@ void luaDoOneRunStandalone(event_t evt) } } else { - int scriptResult = lua_tointeger(L, -1); - lua_pop(L, 1); /* pop returned value */ + int scriptResult = lua_tointeger(lsScripts, -1); + lua_pop(lsScripts, 1); /* pop returned value */ if (scriptResult != 0) { TRACE("Script finished with status %d", scriptResult); standaloneScript.state = SCRIPT_NOFILE; @@ -551,7 +554,7 @@ void luaDoOneRunStandalone(event_t evt) #else lcdDrawSolidHorizontalLine(0, 7*FH-1, lcdLastPos+6, ERASE); lcdDrawText(0, 7*FH, "GV Use: "); - lcdDrawNumber(lcdLastPos, 7*FH, luaGetMemUsed(), LEFT); + lcdDrawNumber(lcdLastPos, 7*FH, luaGetMemUsed(lsScripts), LEFT); lcdDrawChar(lcdLastPos, 7*FH, 'b'); lcdDrawSolidHorizontalLine(0, 7*FH-2, lcdLastPos+6, FORCE); lcdDrawVerticalLine(lcdLastPos+6, 7*FH-2, FH+2, SOLID, FORCE); @@ -560,13 +563,13 @@ void luaDoOneRunStandalone(event_t evt) } } else { - TRACE("Script error: %s", lua_tostring(L, -1)); + TRACE("Script error: %s", lua_tostring(lsScripts, -1)); standaloneScript.state = (instructionsPercent > 100 ? SCRIPT_KILLED : SCRIPT_SYNTAX_ERROR); luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } if (standaloneScript.state != SCRIPT_OK) { - luaError(standaloneScript.state); + luaError(lsScripts, standaloneScript.state); luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS; } @@ -596,7 +599,7 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) ScriptInternalData & sid = scriptInternalData[i]; if (sid.state != SCRIPT_OK) return false; - SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); + luaSetInstructionsLimit(lsScripts, PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); int inputsCount = 0; #if defined(SIMU) || defined(DEBUG) const char *filename; @@ -613,12 +616,12 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) #if defined(SIMU) || defined(DEBUG) filename = sd.file; #endif - lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.run); for (int j=0; jinputsCount; j++) { if (sio->inputs[j].type == 1) - luaGetValueAndPush((uint8_t)sd.inputs[j]); + luaGetValueAndPush(lsScripts, (uint8_t)sd.inputs[j]); else - lua_pushinteger(L, sd.inputs[j] + sio->inputs[j].def); + lua_pushinteger(lsScripts, sd.inputs[j] + sio->inputs[j].def); } } else if ((scriptType & RUN_FUNC_SCRIPT) && (sid.reference >= SCRIPT_FUNC_FIRST && sid.reference <= SCRIPT_FUNC_LAST)) { @@ -627,9 +630,9 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) filename = fn.play.name; #endif if (getSwitch(fn.swtch)) - lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.run); else if (sid.background) - lua_rawgeti(L, LUA_REGISTRYINDEX, sid.background); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.background); else return false; } @@ -640,12 +643,12 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) filename = script.file; #endif if ((scriptType & RUN_TELEM_FG_SCRIPT) && (menuHandlers[0]==menuViewTelemetryFrsky && sid.reference==SCRIPT_TELEMETRY_FIRST+s_frsky_view)) { - lua_rawgeti(L, LUA_REGISTRYINDEX, sid.run); - lua_pushunsigned(L, evt); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.run); + lua_pushunsigned(lsScripts, evt); inputsCount = 1; } else if ((scriptType & RUN_TELEM_BG_SCRIPT) && (sid.background)) { - lua_rawgeti(L, LUA_REGISTRYINDEX, sid.background); + lua_rawgeti(lsScripts, LUA_REGISTRYINDEX, sid.background); } else { return false; @@ -655,16 +658,16 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) #endif } - if (lua_pcall(L, inputsCount, sio ? sio->outputsCount : 0, 0) == 0) { + if (lua_pcall(lsScripts, inputsCount, sio ? sio->outputsCount : 0, 0) == 0) { if (sio) { for (int j=sio->outputsCount-1; j>=0; j--) { - if (!lua_isnumber(L, -1)) { + if (!lua_isnumber(lsScripts, -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); + sio->outputs[j].value = lua_tointeger(lsScripts, -1); + lua_pop(lsScripts, 1); } } } @@ -674,13 +677,13 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) sid.state = SCRIPT_KILLED; } else { - TRACE("Script %8s error: %s", filename, lua_tostring(L, -1)); + TRACE("Script %8s error: %s", filename, lua_tostring(lsScripts, -1)); sid.state = SCRIPT_SYNTAX_ERROR; } } if (sid.state != SCRIPT_OK) { - luaFree(sid); + luaFree(lsScripts, sid); } else { if (instructionsPercent > sid.instructions) { @@ -690,14 +693,14 @@ bool luaDoOneRunPermanentScript(uint8_t evt, int i, uint32_t scriptType) return true; } -void luaDoGc() +void luaDoGc(lua_State * L) { if (L) { PROTECT_LUA() { lua_gc(L, LUA_GCCOLLECT, 0); #if defined(SIMU) || defined(DEBUG) static int lastgc = 0; - int gc = luaGetMemUsed(); + int gc = luaGetMemUsed(L); if (gc != lastgc) { lastgc = gc; TRACE("GC Use: %dbytes", gc); @@ -736,10 +739,8 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage) // run permanent scripts if (luaState & INTERPRETER_RELOAD_PERMANENT_SCRIPTS) { luaState = 0; -#if !defined(COLORLCD) luaInit(); if (luaState == INTERPRETER_PANIC) return false; -#endif luaLoadPermanentScripts(); if (luaState == INTERPRETER_PANIC) return false; } @@ -756,435 +757,47 @@ bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage) //todo gc step between scripts } } - luaDoGc(); + luaDoGc(lsScripts); return scriptWasRun; } -int luaGetMemUsed() +int luaGetMemUsed(lua_State * L) { - return (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0); + return L ? (lua_gc(L, LUA_GCCOUNT, 0) << 10) + lua_gc(L, LUA_GCCOUNTB, 0) : 0; } -#if defined(COLORLCD) -#define LUA_FULLPATH_MAXLEN (42) // max length (example: /SCRIPTS/THEMES/mytheme.lua) - -void exec(int function, int nresults=0) -{ - if (function) { - SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); - lua_rawgeti(L, LUA_REGISTRYINDEX, function); - if (lua_pcall(L, 0, nresults, 0) != 0) { - TRACE("Error in theme %s", lua_tostring(L, -1)); - } - } -} - -ZoneOption * createOptionsArray(int reference) -{ - if (reference == 0) { - return NULL; - } - - int count = 0; - lua_rawgeti(L, LUA_REGISTRYINDEX, reference); - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - count++; - } - - ZoneOption * options = (ZoneOption *)malloc(sizeof(ZoneOption) * (count+1)); - - lua_rawgeti(L, LUA_REGISTRYINDEX, reference); - ZoneOption * option = options; - for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { - luaL_checktype(L, -2, LUA_TNUMBER); // key is number - luaL_checktype(L, -1, LUA_TTABLE); // value is table - uint8_t field = 0; - for (lua_pushnil(L); lua_next(L, -2) && field<5; lua_pop(L, 1), field++) { - switch (field) { - case 0: - luaL_checktype(L, -2, LUA_TNUMBER); // key is number - luaL_checktype(L, -1, LUA_TSTRING); // value is string - option->name = lua_tostring(L, -1); - break; - case 1: - luaL_checktype(L, -2, LUA_TNUMBER); // key is number - luaL_checktype(L, -1, LUA_TNUMBER); // value is number - option->type = (ZoneOption::Type)lua_tointeger(L, -1); - break; - case 2: - luaL_checktype(L, -2, LUA_TNUMBER); // key is number - luaL_checktype(L, -1, LUA_TNUMBER); // value is number - option->deflt.signedValue = lua_tointeger(L, -1); - break; - case 3: - luaL_checktype(L, -2, LUA_TNUMBER); // key is number - luaL_checktype(L, -1, LUA_TNUMBER); // value is number - option->min.signedValue = lua_tointeger(L, -1); - break; - case 4: - luaL_checktype(L, -2, LUA_TNUMBER); // key is number - luaL_checktype(L, -1, LUA_TNUMBER); // value is number - option->max.signedValue = lua_tointeger(L, -1); - break; - } - } - option++; - } - - option->name = NULL; // sentinel - - return options; -} - -class LuaTheme: public Theme -{ - friend void luaLoadThemeCallback(); - - public: - LuaTheme(const char * name, int options): - Theme(name, createOptionsArray(options)), - loadFunction(0), - drawBackgroundFunction(0), - drawTopbarBackgroundFunction(0), - drawAlertBoxFunction(0) - { - } - - virtual void load() const - { - luaLcdAllowed = true; - exec(loadFunction); - } - - virtual void drawBackground() const - { - exec(drawBackgroundFunction); - } - - virtual void drawTopbarBackground(uint8_t icon) const - { - exec(drawTopbarBackgroundFunction); - } - -#if 0 - virtual void drawAlertBox(const char * title, const char * text, const char * action) const - { - exec(drawAlertBoxFunction); - } -#endif - - protected: - int loadFunction; - int drawBackgroundFunction; - int drawTopbarBackgroundFunction; - int drawAlertBoxFunction; -}; - -void luaLoadThemeCallback() -{ - const char * name=NULL; - int themeOptions=0, loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0; - - 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, "name")) { - name = luaL_checkstring(L, -1); - } - else if (!strcmp(key, "options")) { - themeOptions = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "load")) { - loadFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "drawBackground")) { - drawBackgroundFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "drawTopbarBackground")) { - drawTopbarBackgroundFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - } - - if (name) { - LuaTheme * theme = new LuaTheme(name, themeOptions); - theme->loadFunction = loadFunction; - theme->drawBackgroundFunction = drawBackgroundFunction; - theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; - } -} - -class LuaWidget: public Widget -{ - public: - LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData): - Widget(factory, zone, persistentData), - widgetData(widgetData) - { - } - - virtual ~LuaWidget() - { - luaL_unref(L, LUA_REGISTRYINDEX, widgetData); - } - - virtual void update() const; - - virtual void refresh(); - - virtual void background(); - - protected: - int widgetData; -}; - -void l_pushtableint(const char * key, int value) -{ - lua_pushstring(L, key); - lua_pushinteger(L, value); - lua_settable(L, -3); -} - -class LuaWidgetFactory: public WidgetFactory -{ - friend void luaLoadWidgetCallback(); - friend class LuaWidget; - - public: - LuaWidgetFactory(const char * name, int widgetOptions, int createFunction): - WidgetFactory(name, createOptionsArray(widgetOptions)), - createFunction(createFunction), - updateFunction(0), - refreshFunction(0), - backgroundFunction(0) - { - } - - virtual Widget * create(const Zone & zone, Widget::PersistentData * persistentData, bool init=true) const - { - if (init) { - initPersistentData(persistentData); - } - - SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); - lua_rawgeti(L, LUA_REGISTRYINDEX, createFunction); - - lua_newtable(L); - l_pushtableint("x", zone.x); - l_pushtableint("y", zone.y); - l_pushtableint("w", zone.w); - l_pushtableint("h", zone.h); - - lua_newtable(L); - int i = 0; - for (const ZoneOption * option = options; option->name; option++, i++) { - l_pushtableint(option->name, persistentData->options[i].signedValue); - } - - if (lua_pcall(L, 2, 1, 0) != 0) { - TRACE("Error in widget %s create() function: %s", getName(), lua_tostring(L, -1)); - } - int widgetData = luaL_ref(L, LUA_REGISTRYINDEX); - Widget * widget = new LuaWidget(this, zone, persistentData, widgetData); - return widget; - } - - protected: - int createFunction; - int updateFunction; - int refreshFunction; - int backgroundFunction; -}; - -void LuaWidget::update() const -{ - SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); - LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; - lua_rawgeti(L, LUA_REGISTRYINDEX, factory->updateFunction); - lua_rawgeti(L, LUA_REGISTRYINDEX, widgetData); - - lua_newtable(L); - int i = 0; - for (const ZoneOption * option = getOptions(); option->name; option++, i++) { - l_pushtableint(option->name, persistentData->options[i].signedValue); - } - - if (lua_pcall(L, 2, 0, 0) != 0) { - TRACE("Error in widget %s update() function: %s", factory->getName(), lua_tostring(L, -1)); - } -} - -void LuaWidget::refresh() -{ - SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); - LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; - lua_rawgeti(L, LUA_REGISTRYINDEX, factory->refreshFunction); - lua_rawgeti(L, LUA_REGISTRYINDEX, widgetData); - if (lua_pcall(L, 1, 0, 0) != 0) { - TRACE("Error in widget %s refresh() function: %s", factory->getName(), lua_tostring(L, -1)); - } -} - -void LuaWidget::background() -{ - SET_LUA_INSTRUCTIONS_COUNT(PERMANENT_SCRIPTS_MAX_INSTRUCTIONS); - LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; - if (factory->backgroundFunction) { - lua_rawgeti(L, LUA_REGISTRYINDEX, factory->backgroundFunction); - lua_rawgeti(L, LUA_REGISTRYINDEX, widgetData); - if (lua_pcall(L, 1, 0, 0) != 0) { - TRACE("Error in widget %s background() function: %s", factory->getName(), lua_tostring(L, -1)); - } - } -} - -void luaLoadWidgetCallback() -{ - const char * name=NULL; - int widgetOptions=0, createFunction=0, updateFunction=0, refreshFunction=0, backgroundFunction=0; - - 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, "name")) { - name = luaL_checkstring(L, -1); - } - else if (!strcmp(key, "options")) { - widgetOptions = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "create")) { - createFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "update")) { - updateFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "refresh")) { - refreshFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - else if (!strcmp(key, "background")) { - backgroundFunction = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnil(L); - } - } - - if (name && createFunction) { - LuaWidgetFactory * factory = new LuaWidgetFactory(name, widgetOptions, createFunction); - factory->updateFunction = updateFunction; - factory->refreshFunction = refreshFunction; - factory->backgroundFunction = backgroundFunction; - } -} - -void luaLoadFile(const char * filename, void (*callback)()) -{ - if (luaState == INTERPRETER_PANIC) { - return; - } - -#if defined(LUA_COMPILER) && defined(SIMU) - luaCompileAndSave(filename); -#endif - - SET_LUA_INSTRUCTIONS_COUNT(MANUAL_SCRIPTS_MAX_INSTRUCTIONS); - - PROTECT_LUA() { - if (luaL_loadfile(L, filename) == 0 && - lua_pcall(L, 0, 1, 0) == 0 && - lua_istable(L, -1)) { - (*callback)(); - } - else { - TRACE("Error in script %s: %s", filename, lua_tostring(L, -1)); - } - } - else { - luaDisable(); - return; - } - UNPROTECT_LUA(); -} - -void luaLoadFiles(const char * directory, void (*callback)()) -{ - char path[LUA_FULLPATH_MAXLEN+1]; - FILINFO fno; - DIR dir; - - strcpy(path, directory); - - FRESULT res = f_opendir(&dir, path); /* Open the directory */ - - if (res == FR_OK) { - int pathlen = strlen(path); - path[pathlen++] = '/'; - for (;;) { - res = f_readdir(&dir, &fno); /* Read a directory item */ - if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ - uint8_t len = strlen(fno.fname); - if (len > 0 && fno.fname[0]!='.' && (fno.fattrib & AM_DIR)) { - strcpy(&path[pathlen], fno.fname); - strcat(&path[pathlen], "/main.lua"); - if (isFileAvailable(path)) { - luaLoadFile(path, callback); - } - } - } - } - else { - TRACE("f_opendir(%s) failed, code=%d", path, res); - } - - f_closedir(&dir); -} - -#endif void luaInit() { TRACE("luaInit"); -#if !defined(COLORLCD) - luaClose(); -#endif + luaClose(lsScripts); if (luaState != INTERPRETER_PANIC) { #if defined(USE_BIN_ALLOCATOR) - L = lua_newstate(bin_l_alloc, NULL); //we use our own allocator! + lsScripts = lua_newstate(bin_l_alloc, NULL); //we use our own allocator! #else - L = lua_newstate(l_alloc, NULL); //we use Lua default allocator + lsScripts = lua_newstate(l_alloc, NULL); //we use Lua default allocator #endif - if (L) { + if (lsScripts) { // install our panic handler - lua_atpanic(L, &custom_lua_atpanic); + lua_atpanic(lsScripts, &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(); - } + luaRegisterLibraries(lsScripts); + } + else { + // if we got panic during registration + // we disable Lua for this session + luaDisable(); + } UNPROTECT_LUA(); + TRACE("lsScripts %p", lsScripts); } else { /* log error and return */ luaDisable(); } } - -#if defined(COLORLCD) - luaLoadFiles(THEMES_PATH, luaLoadThemeCallback); - luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback); -#endif } diff --git a/radio/src/lua/lua_api.h b/radio/src/lua/lua_api.h index bd9037082..dba2b8f2f 100644 --- a/radio/src/lua/lua_api.h +++ b/radio/src/lua/lua_api.h @@ -28,12 +28,16 @@ extern "C" { #include #include #include + #include } -extern lua_State *L; +extern lua_State * lsScripts; +extern lua_State * lsWidgets; extern bool luaLcdAllowed; void luaInit(); +void luaInitThemesAndWidgets(); + #define lua_registernumber(L, n, i) (lua_pushnumber(L, (i)), lua_setglobal(L, (n))) #define lua_registerint(L, n, i) (lua_pushinteger(L, (i)), lua_setglobal(L, (n))) @@ -99,12 +103,12 @@ extern uint8_t luaScriptsCount; extern ScriptInternalData standaloneScript; extern ScriptInternalData scriptInternalData[MAX_SCRIPTS]; extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS]; -void luaClose(); +void luaClose(lua_State * L); bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage); void luaExec(const char * filename); -void luaError(uint8_t error, bool acknowledge=true); -int luaGetMemUsed(); -void luaGetValueAndPush(int src); +void luaError(lua_State * L, uint8_t error, bool acknowledge=true); +int luaGetMemUsed(lua_State * L); +void luaGetValueAndPush(lua_State * L, int src); #define luaGetCpuUsed(idx) scriptInternalData[idx].instructions uint8_t isTelemetryScriptAvailable(uint8_t index); #define LUA_LOAD_MODEL_SCRIPTS() luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS @@ -137,7 +141,10 @@ struct LuaField { }; bool luaFindFieldByName(const char * name, LuaField & field, unsigned int flags=0); void luaLoadThemes(); +void luaRegisterLibraries(lua_State * L); void registerBitmapClass(lua_State * L); +void luaSetInstructionsLimit(lua_State* L, int count); +void luaCompileAndSave(lua_State * L, const char *bytecodeName); #else // defined(LUA) #define luaInit() #define LUA_LOAD_MODEL_SCRIPTS() diff --git a/radio/src/lua/widgets.cpp b/radio/src/lua/widgets.cpp new file mode 100644 index 000000000..94e248c0b --- /dev/null +++ b/radio/src/lua/widgets.cpp @@ -0,0 +1,462 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "opentx.h" +#include "bin_allocator.h" +#include "lua/lua_api.h" + +#if defined(LUA_COMPILER) && defined(SIMU) + #include + #include +#endif + +#define WIDGET_SCRIPTS_MAX_INSTRUCTIONS (10000/100) +#define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100) +#define LUA_WARNING_INFO_LEN 64 + +lua_State *lsWidgets = NULL; +extern int custom_lua_atpanic(lua_State *L); + +#define LUA_FULLPATH_MAXLEN (42) // max length (example: /SCRIPTS/THEMES/mytheme.lua) + +void exec(int function, int nresults=0) +{ + if (lsWidgets == 0) return; + + if (function) { + luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, function); + if (lua_pcall(lsWidgets, 0, nresults, 0) != 0) { + TRACE("Error in theme %s", lua_tostring(lsWidgets, -1)); + } + } +} + +ZoneOption * createOptionsArray(int reference) +{ + if (reference == 0) { + return NULL; + } + + int count = 0; + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference); + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { + count++; + } + + ZoneOption * options = (ZoneOption *)malloc(sizeof(ZoneOption) * (count+1)); + + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference); + ZoneOption * option = options; + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is table + uint8_t field = 0; + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2) && field<5; lua_pop(lsWidgets, 1), field++) { + switch (field) { + case 0: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TSTRING); // value is string + option->name = lua_tostring(lsWidgets, -1); + break; + case 1: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->type = (ZoneOption::Type)lua_tointeger(lsWidgets, -1); + break; + case 2: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->deflt.signedValue = lua_tointeger(lsWidgets, -1); + break; + case 3: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->min.signedValue = lua_tointeger(lsWidgets, -1); + break; + case 4: + luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number + luaL_checktype(lsWidgets, -1, LUA_TNUMBER); // value is number + option->max.signedValue = lua_tointeger(lsWidgets, -1); + break; + } + } + option++; + } + + option->name = NULL; // sentinel + + return options; +} + +class LuaTheme: public Theme +{ + friend void luaLoadThemeCallback(); + + public: + LuaTheme(const char * name, int options): + Theme(name, createOptionsArray(options)), + loadFunction(0), + drawBackgroundFunction(0), + drawTopbarBackgroundFunction(0), + drawAlertBoxFunction(0) + { + } + + virtual void load() const + { + luaLcdAllowed = true; + exec(loadFunction); + } + + virtual void drawBackground() const + { + exec(drawBackgroundFunction); + } + + virtual void drawTopbarBackground(uint8_t icon) const + { + exec(drawTopbarBackgroundFunction); + } + +#if 0 + virtual void drawAlertBox(const char * title, const char * text, const char * action) const + { + exec(drawAlertBoxFunction); + } +#endif + + protected: + int loadFunction; + int drawBackgroundFunction; + int drawTopbarBackgroundFunction; + int drawAlertBoxFunction; +}; + +void luaLoadThemeCallback() +{ + TRACE("luaLoadThemeCallback()"); + const char * name=NULL; + int themeOptions=0, loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0; + + luaL_checktype(lsWidgets, -1, LUA_TTABLE); + + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { + const char * key = lua_tostring(lsWidgets, -2); + if (!strcmp(key, "name")) { + name = luaL_checkstring(lsWidgets, -1); + } + else if (!strcmp(key, "options")) { + themeOptions = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "load")) { + loadFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "drawBackground")) { + drawBackgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "drawTopbarBackground")) { + drawTopbarBackgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + } + + if (name) { + LuaTheme * theme = new LuaTheme(name, themeOptions); + theme->loadFunction = loadFunction; + theme->drawBackgroundFunction = drawBackgroundFunction; + theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; + TRACE("Loaded Lua theme %s", name); + } +} + +class LuaWidget: public Widget +{ + public: + LuaWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData, int widgetData): + Widget(factory, zone, persistentData), + widgetData(widgetData) + { + } + + virtual ~LuaWidget() + { + luaL_unref(lsWidgets, LUA_REGISTRYINDEX, widgetData); + } + + virtual void update() const; + + virtual void refresh(); + + virtual void background(); + + protected: + int widgetData; +}; + +void l_pushtableint(const char * key, int value) +{ + lua_pushstring(lsWidgets, key); + lua_pushinteger(lsWidgets, value); + lua_settable(lsWidgets, -3); +} + +class LuaWidgetFactory: public WidgetFactory +{ + friend void luaLoadWidgetCallback(); + friend class LuaWidget; + + public: + LuaWidgetFactory(const char * name, int widgetOptions, int createFunction): + WidgetFactory(name, createOptionsArray(widgetOptions)), + createFunction(createFunction), + updateFunction(0), + refreshFunction(0), + backgroundFunction(0) + { + } + + virtual Widget * create(const Zone & zone, Widget::PersistentData * persistentData, bool init=true) const + { + if (lsWidgets == 0) return 0; + if (init) { + initPersistentData(persistentData); + } + + luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunction); + + lua_newtable(lsWidgets); + l_pushtableint("x", zone.x); + l_pushtableint("y", zone.y); + l_pushtableint("w", zone.w); + l_pushtableint("h", zone.h); + + lua_newtable(lsWidgets); + int i = 0; + for (const ZoneOption * option = options; option->name; option++, i++) { + l_pushtableint(option->name, persistentData->options[i].signedValue); + } + + if (lua_pcall(lsWidgets, 2, 1, 0) != 0) { + TRACE("Error in widget %s create() function: %s", getName(), lua_tostring(lsWidgets, -1)); + } + int widgetData = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + Widget * widget = new LuaWidget(this, zone, persistentData, widgetData); + return widget; + } + + protected: + int createFunction; + int updateFunction; + int refreshFunction; + int backgroundFunction; +}; + +void LuaWidget::update() const +{ + if (lsWidgets == 0) return; + + luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); + LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->updateFunction); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); + + lua_newtable(lsWidgets); + int i = 0; + for (const ZoneOption * option = getOptions(); option->name; option++, i++) { + l_pushtableint(option->name, persistentData->options[i].signedValue); + } + + if (lua_pcall(lsWidgets, 2, 0, 0) != 0) { + TRACE("Error in widget %s update() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); + } +} + +void LuaWidget::refresh() +{ + if (lsWidgets == 0) return; + + luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); + LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); + if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { + TRACE("Error in widget %s refresh() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); + } +} + +void LuaWidget::background() +{ + if (lsWidgets == 0) return; + + luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS); + LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory; + if (factory->backgroundFunction) { + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->backgroundFunction); + lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, widgetData); + if (lua_pcall(lsWidgets, 1, 0, 0) != 0) { + TRACE("Error in widget %s background() function: %s", factory->getName(), lua_tostring(lsWidgets, -1)); + } + } +} + +void luaLoadWidgetCallback() +{ + TRACE("luaLoadWidgetCallback()"); + const char * name=NULL; + int widgetOptions=0, createFunction=0, updateFunction=0, refreshFunction=0, backgroundFunction=0; + + luaL_checktype(lsWidgets, -1, LUA_TTABLE); + + for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) { + const char * key = lua_tostring(lsWidgets, -2); + if (!strcmp(key, "name")) { + name = luaL_checkstring(lsWidgets, -1); + } + else if (!strcmp(key, "options")) { + widgetOptions = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "create")) { + createFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "update")) { + updateFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "refresh")) { + refreshFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + else if (!strcmp(key, "background")) { + backgroundFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX); + lua_pushnil(lsWidgets); + } + } + + if (name && createFunction) { + LuaWidgetFactory * factory = new LuaWidgetFactory(name, widgetOptions, createFunction); + factory->updateFunction = updateFunction; + factory->refreshFunction = refreshFunction; + factory->backgroundFunction = backgroundFunction; + TRACE("Loaded Lua widget %s", name); + } +} + +void luaLoadFile(const char * filename, void (*callback)()) +{ + if (lsWidgets == 0) return; + + TRACE("luaLoadFile() %s", filename); + +#if defined(LUA_COMPILER) && defined(SIMU) + luaCompileAndSave(lsWidgets, filename); +#endif + + luaSetInstructionsLimit(lsWidgets, MANUAL_SCRIPTS_MAX_INSTRUCTIONS); + + PROTECT_LUA() { + if (luaL_loadfile(lsWidgets, filename) == 0 && + lua_pcall(lsWidgets, 0, 1, 0) == 0 && + lua_istable(lsWidgets, -1)) { + (*callback)(); + } + else { + TRACE("Error in script %s: %s", filename, lua_tostring(lsWidgets, -1)); + } + } + else { + // luaDisable(); + lsWidgets = 0; + return; + } + UNPROTECT_LUA(); +} + +void luaLoadFiles(const char * directory, void (*callback)()) +{ + char path[LUA_FULLPATH_MAXLEN+1]; + FILINFO fno; + DIR dir; + + strcpy(path, directory); + TRACE("luaLoadFiles() %s", path); + + FRESULT res = f_opendir(&dir, path); /* Open the directory */ + + if (res == FR_OK) { + int pathlen = strlen(path); + path[pathlen++] = '/'; + for (;;) { + res = f_readdir(&dir, &fno); /* Read a directory item */ + if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ + uint8_t len = strlen(fno.fname); + if (len > 0 && fno.fname[0]!='.' && (fno.fattrib & AM_DIR)) { + strcpy(&path[pathlen], fno.fname); + strcat(&path[pathlen], "/main.lua"); + if (isFileAvailable(path)) { + luaLoadFile(path, callback); + } + } + } + } + else { + TRACE("f_opendir(%s) failed, code=%d", path, res); + } + + f_closedir(&dir); +} + +void luaInitThemesAndWidgets() +{ + TRACE("luaInitThemesAndWidgets"); + +#if defined(USE_BIN_ALLOCATOR) + lsWidgets = lua_newstate(bin_l_alloc, NULL); //we use our own allocator! +#else + lsWidgets = lua_newstate(l_alloc, NULL); //we use Lua default allocator +#endif + if (lsWidgets) { + // install our panic handler + lua_atpanic(lsWidgets, &custom_lua_atpanic); + + // protect libs and constants registration + PROTECT_LUA() { + luaRegisterLibraries(lsWidgets); + } + else { + // if we got panic during registration + // we disable Lua for this session + // luaDisable(); + lsWidgets = 0; + } + UNPROTECT_LUA(); + TRACE("lsWidgets %p", lsWidgets); + luaLoadFiles(THEMES_PATH, luaLoadThemeCallback); + luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback); + } +} diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index b454e8710..92628f25c 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -1881,7 +1881,10 @@ void opentxClose(uint8_t shutdown) // TODO needed? telemetryEnd(); #endif #if defined(LUA) - luaClose(); + luaClose(lsScripts); +#if defined(PCBHORUS) + luaClose(lsWidgets); +#endif #endif #if defined(HAPTIC) hapticOff(); @@ -2432,7 +2435,7 @@ void opentxInit(OPENTX_INIT_ARGS) #if defined(PCBHORUS) topbar = new Topbar(&g_model.topbarData); - luaInit(); + luaInitThemesAndWidgets(); #endif #if defined(RAMBACKUP) diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 769c7eda1..3bd8d3028 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -23,6 +23,7 @@ set(FIRMWARE_DEPENDENCIES ${FIRMWARE_DEPENDENCIES} horus_bitmaps) set(LUA_EXPORT lua_export_horus) set(FLAVOUR horus) set(RAMBACKUP YES) +set(LUA YES) add_definitions(-DPCBHORUS -DPCBREV=${PCBREV} -DSTM32F429_439xx -DSDRAM -DCOLORLCD -DPPM_PIN_UART -DPPM_PIN_TIMER) add_definitions(-DEEPROM_VARIANT=0 -DAUDIO -DVOICE -DRTCLOCK) diff --git a/radio/src/targets/simu/CMakeLists.txt b/radio/src/targets/simu/CMakeLists.txt index 60ce25acc..2ab7bb450 100644 --- a/radio/src/targets/simu/CMakeLists.txt +++ b/radio/src/targets/simu/CMakeLists.txt @@ -9,6 +9,7 @@ set(SIMU_SRC ) add_definitions(-DSIMU) +add_definitions(-DLUA_COMPILER) remove_definitions(-DCLI) if(SDL_FOUND) diff --git a/radio/src/targets/simu/simpgmspace.cpp b/radio/src/targets/simu/simpgmspace.cpp index 9994ae57f..c377bae5f 100644 --- a/radio/src/targets/simu/simpgmspace.cpp +++ b/radio/src/targets/simu/simpgmspace.cpp @@ -39,6 +39,13 @@ #include #endif +#if defined(TRACE_SIMPGMSPACE) + #undef TRACE_SIMPGMSPACE + #define TRACE_SIMPGMSPACE TRACE +#else + #define TRACE_SIMPGMSPACE(...) +#endif + uint8_t MCUCSR, MCUSR, MCUCR; volatile uint8_t pina=0xff, pinb=0xff, pinc=0xff, pind, pine=0xff, pinf=0xff, ping=0xff, pinh=0xff, pinj=0, pinl=0; uint8_t portb, portc, porth=0, dummyport; @@ -154,7 +161,7 @@ void simuInit() void simuSetKey(uint8_t key, bool state) { - // if (state) TRACE("simuSetKey(%d, %d)", key, state); + // if (state) TRACE_SIMPGMSPACE("simuSetKey(%d, %d)", key, state); switch (key) { #if !defined(PCBHORUS) @@ -195,7 +202,7 @@ void simuSetKey(uint8_t key, bool state) void simuSetTrim(uint8_t trim, bool state) { - // TRACE("trim=%d state=%d", trim, state); + // TRACE_SIMPGMSPACE("trim=%d state=%d", trim, state); switch (trim) { TRIM_CASE(0, TRIMS_GPIO_REG_LHL, TRIMS_GPIO_PIN_LHL) @@ -218,7 +225,7 @@ void simuSetTrim(uint8_t trim, bool state) // TODO use a better numbering to allow google tests to work on Taranis void simuSetSwitch(uint8_t swtch, int8_t state) { - // TRACE("simuSetSwitch(%d, %d)", swtch, state); + // TRACE_SIMPGMSPACE("simuSetSwitch(%d, %d)", swtch, state); switch (swtch) { #if defined(PCBFLAMENCO) @@ -374,7 +381,7 @@ void audioConsumeCurrentBuffer() void setScaledVolume(uint8_t volume) { simuAudio.currentVolume = 127 * volume * simuAudio.volumeGain / VOLUME_LEVEL_MAX / 10; - // TRACE("setVolume(): in: %u, out: %u", volume, simuAudio.currentVolume); + // TRACE_SIMPGMSPACE("setVolume(): in: %u, out: %u", volume, simuAudio.currentVolume); } void setVolume(uint8_t volume) @@ -552,12 +559,12 @@ filemap_t fileMap; char *findTrueFileName(const char *path) { - TRACE("findTrueFileName(%s)", path); + // TRACE_SIMPGMSPACE("findTrueFileName(%s)", path); static char result[1024]; filemap_t::iterator i = fileMap.find(path); if (i != fileMap.end()) { strcpy(result, i->second.c_str()); - TRACE("\tfound in map: %s", result); + // TRACE_SIMPGMSPACE("\tfound in map: %s", result); return result; } else { @@ -572,17 +579,17 @@ char *findTrueFileName(const char *path) std::string fileName = std::string(fname) + std::string(ext); std::string dirName = std::string(drive) + std::string(dir); std::string searchName = dirName + "*"; - // TRACE("\tsearching for: %s", fileName.c_str()); + // TRACE_SIMPGMSPACE("\tsearching for: %s", fileName.c_str()); WIN32_FIND_DATA ffd; HANDLE hFind = FindFirstFile(searchName.c_str(), &ffd); if (INVALID_HANDLE_VALUE != hFind) { do { if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - //TRACE("comparing with: %s", ffd.cFileName); + //TRACE_SIMPGMSPACE("comparing with: %s", ffd.cFileName); if (!strcasecmp(fileName.c_str(), ffd.cFileName)) { strcpy(result, dirName.c_str()); strcat(result, ffd.cFileName); - TRACE("\tfound: %s", ffd.cFileName); + TRACE_SIMPGMSPACE("\tfound: %s", ffd.cFileName); fileMap.insert(filemap_t:: value_type(path, result)); return result; } @@ -597,7 +604,7 @@ char *findTrueFileName(const char *path) std::string dirName = simu::dirname(result); simu::DIR * dir = simu::opendir(dirName.c_str()); if (dir) { - // TRACE("\tsearching for: %s", fileName.c_str()); + // TRACE_SIMPGMSPACE("\tsearching for: %s", fileName.c_str()); for (;;) { struct simu::dirent * res = simu::readdir(dir); if (res == 0) break; @@ -606,12 +613,12 @@ char *findTrueFileName(const char *path) #else if ((res->d_type == simu::DT_REG) || (res->d_type == simu::DT_LNK)) { #endif - // TRACE("comparing with: %s", res->d_name); + // TRACE_SIMPGMSPACE("comparing with: %s", res->d_name); if (!strcasecmp(fileName.c_str(), res->d_name)) { strcpy(result, dirName.c_str()); strcat(result, "/"); strcat(result, res->d_name); - TRACE("\tfound: %s", res->d_name); + // TRACE_SIMPGMSPACE("\tfound: %s", res->d_name); fileMap.insert(filemap_t:: value_type(path, result)); simu::closedir(dir); return result; @@ -622,7 +629,7 @@ char *findTrueFileName(const char *path) } #endif } - TRACE("\tnot found"); + // TRACE_SIMPGMSPACE("\tnot found"); strcpy(result, path); return result; } @@ -633,11 +640,11 @@ FRESULT f_stat (const TCHAR * name, FILINFO *fno) char * realPath = findTrueFileName(path); struct stat tmp; if (stat(realPath, &tmp)) { - TRACE("f_stat(%s) = error %d (%s)", path, errno, strerror(errno)); + TRACE_SIMPGMSPACE("f_stat(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } else { - TRACE("f_stat(%s) = OK", path); + TRACE_SIMPGMSPACE("f_stat(%s) = OK", path); if (fno) { fno->fattrib = (tmp.st_mode & S_IFDIR) ? AM_DIR : 0; } @@ -658,7 +665,7 @@ FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag) if (!(flag & FA_WRITE)) { struct stat tmp; if (stat(realPath, &tmp)) { - TRACE("f_open(%s) = INVALID_NAME (FIL %p)", path, fil); + TRACE_SIMPGMSPACE("f_open(%s) = INVALID_NAME (FIL %p)", path, fil); return FR_INVALID_NAME; } fil->obj.objsize = tmp.st_size; @@ -667,10 +674,10 @@ FRESULT f_open (FIL * fil, const TCHAR *name, BYTE flag) fil->obj.fs = (FATFS*)fopen(realPath, (flag & FA_WRITE) ? ((flag & FA_CREATE_ALWAYS) ? "wb+" : "ab+") : "rb+"); fil->fptr = 0; if (fil->obj.fs) { - TRACE("f_open(%s, %x) = %p (FIL %p)", path, flag, fil->obj.fs, fil); + TRACE_SIMPGMSPACE("f_open(%s, %x) = %p (FIL %p)", path, flag, fil->obj.fs, fil); return FR_OK; } - TRACE("f_open(%s) = error %d (%s) (FIL %p)", path, errno, strerror(errno), fil); + TRACE_SIMPGMSPACE("f_open(%s) = error %d (%s) (FIL %p)", path, errno, strerror(errno), fil); return FR_INVALID_NAME; } @@ -679,7 +686,7 @@ FRESULT f_read (FIL* fil, void* data, UINT size, UINT* read) if (fil && fil->obj.fs) { *read = fread(data, 1, size, (FILE*)fil->obj.fs); fil->fptr += *read; - // TRACE("fread(%p) %u, %u", fil->obj.fs, size, *read); + // TRACE_SIMPGMSPACE("fread(%p) %u, %u", fil->obj.fs, size, *read); } return FR_OK; } @@ -689,7 +696,7 @@ FRESULT f_write (FIL* fil, const void* data, UINT size, UINT* written) if (fil && fil->obj.fs) { *written = fwrite(data, 1, size, (FILE*)fil->obj.fs); fil->fptr += size; - // TRACE("fwrite(%p) %u, %u", fil->obj.fs, size, *written); + // TRACE_SIMPGMSPACE("fwrite(%p) %u, %u", fil->obj.fs, size, *written); } return FR_OK; } @@ -701,7 +708,7 @@ TCHAR * f_gets (TCHAR* buff, int len, FIL* fil) if (buff != NULL) { fil->fptr = *buff; } - // TRACE("fgets(%p) %u, %s", fil->obj.fs, len, buff); + // TRACE_SIMPGMSPACE("fgets(%p) %u, %s", fil->obj.fs, len, buff); } return buff; } @@ -720,7 +727,7 @@ UINT f_size(FIL* fil) fseek((FILE*)fil->obj.fs, 0, SEEK_END); long size = ftell((FILE*)fil->obj.fs); fseek((FILE*)fil->obj.fs, curr, SEEK_SET); - TRACE("f_size(%p) %u", fil->obj.fs, size); + TRACE_SIMPGMSPACE("f_size(%p) %u", fil->obj.fs, size); return size; } return 0; @@ -728,7 +735,7 @@ UINT f_size(FIL* fil) FRESULT f_close (FIL * fil) { - TRACE("f_close(%p) (FIL:%p)", fil->obj.fs, fil); + TRACE_SIMPGMSPACE("f_close(%p) (FIL:%p)", fil->obj.fs, fil); if (fil->obj.fs) { fclose((FILE*)fil->obj.fs); fil->obj.fs = NULL; @@ -747,16 +754,16 @@ FRESULT f_opendir (DIR * rep, const TCHAR * name) char *path = convertSimuPath(name); rep->obj.fs = (FATFS *)simu::opendir(path); if ( rep->obj.fs ) { - TRACE("f_opendir(%s) = OK", path); + TRACE_SIMPGMSPACE("f_opendir(%s) = OK", path); return FR_OK; } - TRACE("f_opendir(%s) = error %d (%s)", path, errno, strerror(errno)); + TRACE_SIMPGMSPACE("f_opendir(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_NO_PATH; } FRESULT f_closedir (DIR * rep) { - TRACE("f_closedir(%p)", rep); + TRACE_SIMPGMSPACE("f_closedir(%p)", rep); if (rep->obj.fs) simu::closedir((simu::DIR *)rep->obj.fs); return FR_OK; } @@ -774,7 +781,7 @@ FRESULT f_readdir (DIR * rep, FILINFO * fil) #if defined(WIN32) || !defined(__GNUC__) || defined(__APPLE__) || defined(__FreeBSD__) fil->fattrib = (ent->d_type == DT_DIR ? AM_DIR : 0); #else - if (ent->d_type == simu::DT_UNKNOWN) { + if (ent->d_type == simu::DT_UNKNOWN || ent->d_type == simu::DT_LNK) { fil->fattrib = 0; struct stat buf; if (stat(ent->d_name, &buf) == 0) { @@ -788,13 +795,13 @@ FRESULT f_readdir (DIR * rep, FILINFO * fil) memset(fil->fname, 0, SD_SCREEN_FILE_LENGTH); strcpy(fil->fname, ent->d_name); - // TRACE("f_readdir(): %s", fil->fname); + // TRACE_SIMPGMSPACE("f_readdir(): %s", fil->fname); return FR_OK; } FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len) { - TRACE("Format SD..."); + TRACE_SIMPGMSPACE("Format SD..."); return FR_OK; } @@ -802,11 +809,11 @@ FRESULT f_mkdir (const TCHAR * name) { char * path = convertSimuPath(name); if (mkdir(path, 0777)) { - TRACE("mkdir(%s) = error %d (%s)", path, errno, strerror(errno)); + TRACE_SIMPGMSPACE("mkdir(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } else { - TRACE("mkdir(%s) = OK", path); + TRACE_SIMPGMSPACE("mkdir(%s) = OK", path); return FR_OK; } return FR_OK; @@ -816,11 +823,11 @@ FRESULT f_unlink (const TCHAR * name) { char * path = convertSimuPath(name); if (unlink(path)) { - TRACE("f_unlink(%s) = error %d (%s)", path, errno, strerror(errno)); + TRACE_SIMPGMSPACE("f_unlink(%s) = error %d (%s)", path, errno, strerror(errno)); return FR_INVALID_NAME; } else { - TRACE("f_unlink(%s) = OK", path); + TRACE_SIMPGMSPACE("f_unlink(%s) = OK", path); return FR_OK; } } @@ -832,10 +839,10 @@ FRESULT f_rename(const TCHAR *oldname, const TCHAR *newname) char * path = convertSimuPath(newname); if (rename(old, path) < 0) { - TRACE("f_rename(%s, %s) = error %d (%s)", old, path, errno, strerror(errno)); + TRACE_SIMPGMSPACE("f_rename(%s, %s) = error %d (%s)", old, path, errno, strerror(errno)); return FR_INVALID_NAME; } - TRACE("f_rename(%s, %s) = OK", old, path); + TRACE_SIMPGMSPACE("f_rename(%s, %s) = OK", old, path); return FR_OK; } @@ -867,19 +874,19 @@ FRESULT f_getcwd (TCHAR *path, UINT sz_path) { char cwd[1024]; if (!getcwd(cwd, 1024)) { - TRACE("f_getcwd() = getcwd() error %d (%s)", errno, strerror(errno)); + TRACE_SIMPGMSPACE("f_getcwd() = getcwd() error %d (%s)", errno, strerror(errno)); strcpy(path, "."); return FR_NO_PATH; } if (strlen(cwd) < strlen(simuSdDirectory)) { - TRACE("f_getcwd() = logic error strlen(cwd) < strlen(simuSdDirectory): cwd: \"%s\", simuSdDirectory: \"%s\"", cwd, simuSdDirectory); + TRACE_SIMPGMSPACE("f_getcwd() = logic error strlen(cwd) < strlen(simuSdDirectory): cwd: \"%s\", simuSdDirectory: \"%s\"", cwd, simuSdDirectory); strcpy(path, "."); return FR_NO_PATH; } if (sz_path < (strlen(cwd) - strlen(simuSdDirectory))) { - TRACE("f_getcwd(): buffer too short"); + TRACE_SIMPGMSPACE("f_getcwd(): buffer too short"); return FR_NOT_ENOUGH_CORE; } @@ -890,7 +897,7 @@ FRESULT f_getcwd (TCHAR *path, UINT sz_path) strcpy(path, "/"); // fix for the root directory } - TRACE("f_getcwd() = %s", path); + TRACE_SIMPGMSPACE("f_getcwd() = %s", path); return FR_OK; } @@ -962,7 +969,7 @@ unsigned int noDiskStatus = 0; void traceDiskStatus() { if (noDiskStatus > 0) { - TRACE("disk_status() called %d times", noDiskStatus); + TRACE_SIMPGMSPACE("disk_status() called %d times", noDiskStatus); noDiskStatus = 0; } } @@ -970,7 +977,7 @@ void traceDiskStatus() DSTATUS disk_initialize (BYTE pdrv) { traceDiskStatus(); - TRACE("disk_initialize(%u)", pdrv); + TRACE_SIMPGMSPACE("disk_initialize(%u)", pdrv); diskImage = fopen("sdcard.image", "r+"); return diskImage ? (DSTATUS)0 : (DSTATUS)STA_NODISK; } @@ -978,7 +985,7 @@ DSTATUS disk_initialize (BYTE pdrv) DSTATUS disk_status (BYTE pdrv) { ++noDiskStatus; - // TRACE("disk_status(%u)", pdrv); + // TRACE_SIMPGMSPACE("disk_status(%u)", pdrv); return (DSTATUS)0; } @@ -986,7 +993,7 @@ DRESULT __disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) { if (diskImage == 0) return RES_NOTRDY; traceDiskStatus(); - TRACE("disk_read(%u, %p, %u, %u)", pdrv, buff, sector, count); + TRACE_SIMPGMSPACE("disk_read(%u, %p, %u, %u)", pdrv, buff, sector, count); fseek(diskImage, sector*512, SEEK_SET); fread(buff, count, 512, diskImage); return RES_OK; @@ -996,7 +1003,7 @@ DRESULT __disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) { if (diskImage == 0) return RES_NOTRDY; traceDiskStatus(); - TRACE("disk_write(%u, %p, %u, %u)", pdrv, buff, sector, count); + TRACE_SIMPGMSPACE("disk_write(%u, %p, %u, %u)", pdrv, buff, sector, count); fseek(diskImage, sector*512, SEEK_SET); fwrite(buff, count, 512, diskImage); return RES_OK; @@ -1006,7 +1013,7 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) { if (diskImage == 0) return RES_NOTRDY; traceDiskStatus(); - TRACE("disk_ioctl(%u, %u, %p)", pdrv, cmd, buff); + TRACE_SIMPGMSPACE("disk_ioctl(%u, %u, %p)", pdrv, cmd, buff); if (pdrv) return RES_PARERR; DRESULT res; @@ -1041,14 +1048,14 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) if (stat("sdcard.image", &buf) == 0) { DWORD noSectors = buf.st_size / 512; *(DWORD*)buff = noSectors; - TRACE("disk_ioctl(GET_SECTOR_COUNT) = %u", noSectors); + TRACE_SIMPGMSPACE("disk_ioctl(GET_SECTOR_COUNT) = %u", noSectors); return RES_OK; } return RES_ERROR; } case GET_SECTOR_SIZE: /* Get sector size (needed at _MAX_SS != _MIN_SS) */ - TRACE("disk_ioctl(GET_SECTOR_SIZE) = 512"); + TRACE_SIMPGMSPACE("disk_ioctl(GET_SECTOR_SIZE) = 512"); *(WORD*)buff = 512; res = RES_OK; break; @@ -1105,7 +1112,7 @@ void sdInit(void) #endif } else { - TRACE("f_mount() failed"); + TRACE_SIMPGMSPACE("f_mount() failed"); } } diff --git a/radio/src/tests/lua.cpp b/radio/src/tests/lua.cpp index ddb249f53..a23568c84 100644 --- a/radio/src/tests/lua.cpp +++ b/radio/src/tests/lua.cpp @@ -31,11 +31,11 @@ extern const char * zchar2string(const char * zstring, int size); ::testing::AssertionResult __luaExecStr(const char * str) { - extern lua_State * L; - if (!L) luaInit(); - if (!L) return ::testing::AssertionFailure() << "No Lua state!"; - if (luaL_dostring(L, str)) { - return ::testing::AssertionFailure() << "lua error: " << lua_tostring(L, -1); + extern lua_State * lsScripts; + if (!lsScripts) luaInit(); + if (!lsScripts) return ::testing::AssertionFailure() << "No Lua state!"; + if (luaL_dostring(lsScripts, str)) { + return ::testing::AssertionFailure() << "lua error: " << lua_tostring(lsScripts, -1); } return ::testing::AssertionSuccess(); }