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 <xxx>.lua file is about to be loaded and if file <xxx>.lua.src exists: * load contents of <xxx>.lua.src * compile Lua code * save compiled code into <xxx>.lua (effectively overwrites existing file) * immediately following the compilation the real file loading is done from <xxx>.lua (which by now contains compiled Lua bytecode)
This commit is contained in:
committed by
Bertrand Songis
parent
ae383cd6a4
commit
92553b6589
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
+23
-5
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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*/ });
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<const uint16_t> Bitmap;
|
||||
@@ -82,19 +84,29 @@ class BitmapBuffer: public BitmapBufferBase<uint16_t>
|
||||
{
|
||||
private:
|
||||
bool dataAllocated;
|
||||
#if defined(DEBUG)
|
||||
bool leakReported;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
BitmapBuffer(uint8_t format, uint16_t width, uint16_t height):
|
||||
BitmapBufferBase<uint16_t>(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<uint16_t>(format, width, height, data),
|
||||
dataAllocated(false)
|
||||
#if defined(DEBUG)
|
||||
, leakReported(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
@@ -117,7 +129,15 @@ class BitmapBuffer: public BitmapBufferBase<uint16_t>
|
||||
|
||||
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)
|
||||
|
||||
@@ -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*/ });
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
+78
-465
@@ -25,16 +25,16 @@
|
||||
#include "lua/lua_api.h"
|
||||
|
||||
#if defined(LUA_COMPILER) && defined(SIMU)
|
||||
#include <lundump.h>
|
||||
#include <lstate.h>
|
||||
extern "C" {
|
||||
#include <lundump.h>
|
||||
}
|
||||
#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; j<sio->inputsCount; 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
|
||||
}
|
||||
|
||||
+12
-5
@@ -28,12 +28,16 @@ extern "C" {
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
#include <lrotable.h>
|
||||
#include <lgc.h>
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
@@ -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 <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include "opentx.h"
|
||||
#include "bin_allocator.h"
|
||||
#include "lua/lua_api.h"
|
||||
|
||||
#if defined(LUA_COMPILER) && defined(SIMU)
|
||||
#include <lundump.h>
|
||||
#include <lstate.h>
|
||||
#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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -9,6 +9,7 @@ set(SIMU_SRC
|
||||
)
|
||||
|
||||
add_definitions(-DSIMU)
|
||||
add_definitions(-DLUA_COMPILER)
|
||||
remove_definitions(-DCLI)
|
||||
|
||||
if(SDL_FOUND)
|
||||
|
||||
@@ -39,6 +39,13 @@
|
||||
#include <SDL.h>
|
||||
#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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user