Glider wizard running in simu

Text fields are still displayed as a black box (needs to be fixed)
This commit is contained in:
Raphael Coeffic
2021-05-06 12:55:59 +02:00
committed by Raphael Coeffic
parent fcf9683f2d
commit 1fa99fdeb2
9 changed files with 264 additions and 178 deletions
+1 -2
View File
@@ -387,9 +387,8 @@ enum DebugTimers {
debugTimerPerMain,
debugTimerPerMain1,
debugTimerGuiMain,
debugTimerLuaBg,
debugTimerLua,
debugTimerLcdRefreshWait,
debugTimerLuaFg,
debugTimerLcdRefresh,
debugTimerMenus,
debugTimerMenuHandlers,
+1
View File
@@ -60,6 +60,7 @@ set(GUI_SRC
menu_screen.cpp
screen_setup.cpp
switch_warn_dialog.cpp
standalone_lua.cpp
)
macro(add_gui_src src)
@@ -24,6 +24,7 @@
#include "io/frsky_firmware_update.h"
#include "io/multi_firmware_update.h"
#include "io/bootloader_flash.h"
#include "standalone_lua.h"
RadioSdManagerPage::RadioSdManagerPage() :
PageTab(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, ICON_RADIO_SD_MANAGER)
@@ -247,6 +248,8 @@ void RadioSdManagerPage::build(FormWindow * window)
else if (isExtensionMatching(ext, SCRIPTS_EXT)) {
menu->addLine(STR_EXECUTE_FILE, [=]() {
luaExec(getFullPath(name));
//TODO: check 'luaState'
new StandaloneLuaWindow(window);
});
}
#endif
+113
View File
@@ -0,0 +1,113 @@
/*
* 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 "standalone_lua.h"
#include "view_main.h"
#include "lua/lua_api.h"
constexpr uint32_t STANDALONE_LUA_REFRESH = 1000 / 1; // 1Hz
uint16_t* lcdGetBackupBuffer();
// #if !defined(SIMU)
// // LUA script draw into the backup buffer
// extern uint8_t * LCD_BACKUP_FRAME_BUFFER;
// #define LUA_LCD_BUFFER ((uint16_t *)LCD_BACKUP_FRAME_BUFFER)
// #else
// extern pixel_t* simuLcdBuf;
// #define LUA_LCD_BUFFER ((uint16_t *)simuLcdBuf)
// #endif
StandaloneLuaWindow::StandaloneLuaWindow(Window* parent) :
Window(parent->getFullScreenWindow(), {0, 0, LCD_W, LCD_H}, OPAQUE),
lcdBuffer(BMP_RGB565, LCD_W, LCD_H, lcdGetBackupBuffer())
{
TRACE("backup frame buffer = %p", lcdGetBackupBuffer());
TRACE("lcdBuffer.getData() = %p", lcdBuffer.getData());
assert(lcdBuffer.getData());
Layer::push(this);
setFocus();
}
void StandaloneLuaWindow::deleteLater(bool detach, bool trash)
{
Layer::pop(this);
Window::deleteLater(detach, trash);
}
void StandaloneLuaWindow::paint(BitmapBuffer* dc)
{
dc->drawSolidFilledRect(0, 0, width(), height(), DEFAULT_BGCOLOR);
// TODO:
// -> grab coords from 'dc'
// -> copy from backup buffer into 'dc'
dc->drawBitmap(0 - dc->getOffsetX(), 0 - dc->getOffsetY(), &lcdBuffer);
}
void StandaloneLuaWindow::checkEvents()
{
// Execute first in case onEvent() is called.
// (would trigger refresh)
Window::checkEvents();
uint32_t now = RTOS_GET_MS();
if (now - lastRefresh >= STANDALONE_LUA_REFRESH) {
lastRefresh = now;
runLua(0);
}
}
#if defined(HARDWARE_KEYS)
void StandaloneLuaWindow::onEvent(event_t evt)
{
lastRefresh = RTOS_GET_MS(); // mark as 'refreshed'
runLua(evt);
}
#endif
extern BitmapBuffer* luaLcdBuffer;
void StandaloneLuaWindow::runLua(event_t evt)
{
// Set global LUA LCD buffer
luaLcdBuffer = &lcdBuffer;
TRACE("evt = 0x%x", evt);
bool hasRun = luaTask(evt, RUN_STNDAL_SCRIPT, true);
if (hasRun) {
#if defined(DEBUG_WINDOWS)
TRACE("# StandaloneLuaWindow::invalidate()");
#endif
invalidate();
} else {
// Script does not run anymore...
TRACE("LUA standalone script exited: deleting window!");
deleteLater();
}
// Kill global LUA LCD buffer
luaLcdBuffer = nullptr;
}
+47
View File
@@ -0,0 +1,47 @@
/*
* 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.
*/
#pragma once
#include "libopenui.h"
class StandaloneLuaWindow : public Window
{
public:
explicit StandaloneLuaWindow(Window* parent);
void deleteLater(bool detach=true, bool trash=true) override;
void paint(BitmapBuffer* dc) override;
void checkEvents() override;
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "StandaloneLuaWindow"; }
#endif
#if defined(HARDWARE_KEYS)
void onEvent(event_t evt) override;
#endif
protected:
BitmapBuffer lcdBuffer;
uint32_t lastRefresh = 0;
void runLua(event_t evt);
};
+70 -72
View File
@@ -22,21 +22,25 @@
#include <cstdio>
#include "opentx.h"
#include "lua_api.h"
#include "libopenui.h"
// TODO: obsolete definition
#define INVERS 0
BitmapBuffer* luaLcdBuffer = nullptr;
/*luadoc
@function lcd.refresh()
Refresh the LCD screen
@status current Introduced in 2.2.0
@notice This function only works in stand-alone and telemetry scripts.
@status current Obsoleted in 2.4.0
*/
static int luaLcdRefresh(lua_State *L)
{
#if 0
if (luaLcdAllowed) lcdRefresh();
#endif
// This one does not seem to be used by any script
// (at least none of the opentx LUA scripts)
// we cannot possibly force a re-draw here
return 0;
}
@@ -53,16 +57,10 @@ Clear the LCD screen
*/
static int luaLcdClear(lua_State * L)
{
#if 0
if (luaLcdAllowed) {
#if defined(COLORLCD)
LcdFlags color = luaL_optunsigned(L, 1, TEXT_BGCOLOR);
lcd->clear(color);
#else
lcdClear();
#endif
if (luaLcdAllowed && luaLcdBuffer) {
LcdFlags color = luaL_optunsigned(L, 1, DEFAULT_BGCOLOR);
luaLcdBuffer->clear(color);
}
#endif
return 0;
}
@@ -100,14 +98,14 @@ bottom line is 63. Drawing on an existing black pixel produces white pixel (TODO
*/
static int luaLcdDrawPoint(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
LcdFlags att = luaL_optunsigned(L, 3, 0);
lcdDrawPoint(x, y, att);
#endif
luaLcdBuffer->drawPixel(x, y, lcdColorTable[COLOR_IDX(att)]);
return 0;
}
@@ -131,9 +129,9 @@ whole line will not be drawn (starting from OpenTX 2.1.5)
*/
static int luaLcdDrawLine(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
coord_t x1 = luaL_checkunsigned(L, 1);
coord_t y1 = luaL_checkunsigned(L, 2);
coord_t x2 = luaL_checkunsigned(L, 3);
@@ -146,17 +144,17 @@ static int luaLcdDrawLine(lua_State *L)
if (pat == SOLID) {
if (x1 == x2) {
lcdDrawSolidVerticalLine(x1, y1<y2 ? y1 : y2, y1<y2 ? (y2-y1)+1 : (y1-y2)+1, flags);
luaLcdBuffer->drawSolidVerticalLine(x1, y1<y2 ? y1 : y2, y1<y2 ? (y2-y1)+1 : (y1-y2)+1, flags);
return 0;
}
else if (y1 == y2) {
lcdDrawSolidHorizontalLine(x1<x2 ? x1 : x2, y1, x1<x2 ? (x2-x1)+1 : (x1-x2)+1, flags);
luaLcdBuffer->drawSolidHorizontalLine(x1<x2 ? x1 : x2, y1, x1<x2 ? (x2-x1)+1 : (x1-x2)+1, flags);
return 0;
}
}
lcdDrawLine(x1, y1, x2, y2, pat, flags);
#endif
luaLcdBuffer->drawLine(x1, y1, x2, y2, pat, flags);
return 0;
}
@@ -185,18 +183,19 @@ See the [Appendix](../appendix/fonts.md) for available characters in each font s
*/
static int luaLcdDrawText(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
const char * s = luaL_checkstring(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
#if defined(COLORLCD)
if ((att&SHADOWED) && !(att&INVERS)) lcdDrawText(x+1, y+1, s, att&0xFFFF);
#endif
lcdDrawText(x, y, s, att);
#endif
if ((att&SHADOWED) && !(att&INVERS)) {
luaLcdBuffer->drawText(x+1, y+1, s, att&0xFFFF);
}
luaLcdBuffer->drawText(x, y, s, att);
return 0;
}
@@ -219,20 +218,21 @@ Display a value formatted as time at (x,y)
*/
static int luaLcdDrawTimer(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
#if 0 // TODO
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int seconds = luaL_checkinteger(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
#if defined(COLORLCD)
if (att&SHADOWED) drawTimer(x+1, y+1, seconds, (att&0xFFFF)|LEFT);
drawTimer(x, y, seconds, att|LEFT);
#else
drawTimer(x, y, seconds, att|LEFT, att);
#endif
if (att & SHADOWED) {
luaLcdBuffer->drawTimer(x+1, y+1, seconds, (att & 0xFFFF) | LEFT);
}
luaLcdBuffer->drawTimer(x, y, seconds, att | LEFT);
#endif
return 0;
}
@@ -256,18 +256,19 @@ Display a number at (x,y)
*/
static int luaLcdDrawNumber(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int val = luaL_checkinteger(L, 3);
unsigned int att = luaL_optunsigned(L, 4, 0);
#if defined(COLORLCD)
if ((att&SHADOWED) && !(att&INVERS)) lcdDrawNumber(x, y, val, att&0xFFFF);
#endif
lcdDrawNumber(x, y, val, att);
#endif
if ((att&SHADOWED) && !(att&INVERS)) {
luaLcdBuffer->drawNumber(x, y, val, att&0xFFFF);
}
luaLcdBuffer->drawNumber(x, y, val, att);
return 0;
}
@@ -390,7 +391,6 @@ Bitmap loading can fail if:
*/
static int luaOpenBitmap(lua_State * L)
{
#if 0
const char * filename = luaL_checkstring(L, 1);
BitmapBuffer ** b = (BitmapBuffer **)lua_newuserdata(L, sizeof(BitmapBuffer *));
@@ -401,10 +401,10 @@ static int luaOpenBitmap(lua_State * L)
*b = 0;
}
else {
*b = BitmapBuffer::load(filename);
*b = BitmapBuffer::loadBitmap(filename);
if (*b == NULL && G(L)->gcrunning) {
luaC_fullgc(L, 1); /* try to free some memory... */
*b = BitmapBuffer::load(filename); /* try again */
*b = BitmapBuffer::loadBitmap(filename); /* try again */
}
}
@@ -416,7 +416,7 @@ static int luaOpenBitmap(lua_State * L)
luaL_getmetatable(L, LUA_BITMAPHANDLE);
lua_setmetatable(L, -2);
#endif
return 1;
}
@@ -443,17 +443,15 @@ Return width, height of a bitmap object
*/
static int luaGetBitmapSize(lua_State * L)
{
#if 0
const BitmapBuffer * b = checkBitmap(L, 1);
if (b) {
lua_pushinteger(L, b->getWidth());
lua_pushinteger(L, b->getHeight());
lua_pushinteger(L, b->width());
lua_pushinteger(L, b->height());
}
else {
lua_pushinteger(L, 0);
lua_pushinteger(L, 0);
}
#endif
return 2;
}
@@ -508,9 +506,9 @@ Omitting scale draws image in 1:1 scale and is faster than specifying 100 for sc
*/
static int luaLcdDrawBitmap(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
const BitmapBuffer * b = checkBitmap(L, 1);
if (b) {
@@ -518,13 +516,13 @@ static int luaLcdDrawBitmap(lua_State *L)
unsigned int y = luaL_checkunsigned(L, 3);
unsigned int scale = luaL_optunsigned(L, 4, 0);
if (scale) {
lcd->drawBitmap(x, y, b, 0, 0, 0, 0, scale/100.0f);
luaLcdBuffer->drawBitmap(x, y, b, 0, 0, 0, 0, scale/100.0f);
}
else {
lcd->drawBitmap(x, y, b);
luaLcdBuffer->drawBitmap(x, y, b);
}
}
#endif
return 0;
}
@@ -547,21 +545,18 @@ Draw a rectangle from top left corner (x,y) of specified width and height
*/
static int luaLcdDrawRectangle(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
int h = luaL_checkinteger(L, 4);
unsigned int flags = luaL_optunsigned(L, 5, 0);
#if defined(PCBHORUS)
unsigned int t = luaL_optunsigned(L, 6, 1);
lcdDrawRect(x, y, w, h, t, 0xff, flags);
#else
lcdDrawRect(x, y, w, h, 0xff, flags);
#endif
#endif
luaLcdBuffer->drawRect(x, y, w, h, t, 0xff, flags);
return 0;
}
@@ -582,16 +577,17 @@ Draw a solid rectangle from top left corner (x,y) of specified width and height
*/
static int luaLcdDrawFilledRectangle(lua_State *L)
{
#if 0
if (!luaLcdAllowed)
if (!luaLcdAllowed || !luaLcdBuffer)
return 0;
int x = luaL_checkinteger(L, 1);
int y = luaL_checkinteger(L, 2);
int w = luaL_checkinteger(L, 3);
int h = luaL_checkinteger(L, 4);
unsigned int flags = luaL_optunsigned(L, 5, 0);
lcdDrawFilledRect(x, y, w, h, SOLID, flags);
#endif
luaLcdBuffer->drawFilledRect(x, y, w, h, SOLID, flags);
return 0;
}
@@ -744,10 +740,12 @@ static int luaRGB(lua_State *L)
{
if (!luaLcdAllowed)
return 0;
int r = luaL_checkinteger(L, 1);
int g = luaL_checkinteger(L, 2);
int b = luaL_checkinteger(L, 3);
lua_pushinteger(L, RGB(r, g, b));
return 1;
}
+11 -2
View File
@@ -882,8 +882,7 @@ void luaDoOneRunStandalone(event_t evt)
return;
}
else if (luaDisplayStatistics) {
#if defined(COLORLCD)
#else
#if !defined(COLORLCD)
lcdDrawSolidHorizontalLine(0, 7*FH-1, lcdLastRightPos+6, ERASE);
lcdDrawText(0, 7*FH, "GV Use: ");
lcdDrawNumber(lcdLastRightPos, 7*FH, luaGetMemUsed(lsScripts), LEFT);
@@ -1025,12 +1024,22 @@ bool luaDoOneRunPermanentScript(event_t evt, int i, uint32_t scriptType)
return true;
}
// This loop-pass should run in checkEvents().
// However, libopenui has 2 main separated routines:
// - checkEvents(): runs the event loop and can effect an async redraw (if visible)
// - paint(): (if visible) the redraw itself
//
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage)
{
if (luaState == INTERPRETER_PANIC) return false;
luaLcdAllowed = allowLcdUsage;
bool scriptWasRun = false;
// TRACE("luaTask(0x%x,0x%x,%s)",
// evt, scriptType,
// allowLcdUsage ? "true" : "false");
// we run either standalone script or permanent scripts
if (luaState & INTERPRETER_RUNNING_STANDALONE_SCRIPT) {
// run standalone script
+13 -102
View File
@@ -284,9 +284,8 @@ void periodicTick()
#if defined(GUI) && defined(COLORLCD)
void guiMain(event_t evt)
{
bool refreshNeeded = false;
#if defined(LUA) && !defined(LIBOPENUI)
#if defined(LUA)
uint32_t t0 = get_tmr10ms();
static uint32_t lastLuaTime = 0;
uint16_t interval = (lastLuaTime == 0 ? 0 : (t0 - lastLuaTime));
@@ -295,123 +294,35 @@ void guiMain(event_t evt)
maxLuaInterval = interval;
}
// run Lua scripts that don't use LCD (to use CPU time while LCD DMA is running)
DEBUG_TIMER_START(debugTimerLuaBg);
luaTask(0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT | RUN_TELEM_BG_SCRIPT, false);
DEBUG_TIMER_STOP(debugTimerLuaBg);
// wait for LCD DMA to finish before continuing, because code from this point
// is allowed to change the contents of LCD buffer
//
// WARNING: make sure no code above this line does any change to the LCD display buffer!
//
DEBUG_TIMER_START(debugTimerLcdRefreshWait);
lcdRefreshWait();
DEBUG_TIMER_STOP(debugTimerLcdRefreshWait);
DEBUG_TIMER_START(debugTimerLua);
// draw LCD from menus or from Lua script
// run Lua scripts that use LCD
// Run Lua scripts first that don't use LCD
luaTask( 0, RUN_MIX_SCRIPT | RUN_FUNC_SCRIPT, false);
DEBUG_TIMER_START(debugTimerLuaFg);
refreshNeeded = luaTask(evt, RUN_STNDAL_SCRIPT, true);
if (!refreshNeeded) {
refreshNeeded = luaTask(evt, RUN_TELEM_FG_SCRIPT, true);
}
DEBUG_TIMER_STOP(debugTimerLuaFg);
// This is run from StandaloneLuaWindow::checkEvents()
// luaTask(evt, RUN_STNDAL_SCRIPT, true);
// TODO: Telemetry scripts are run from Window::checkEvents()
// luaTask( 0, RUN_TELEM_BG_SCRIPT, false/* NO LCD */);
// luaTask(evt, RUN_TELEM_FG_SCRIPT, true/* LCD YES */);
DEBUG_TIMER_STOP(debugTimerLua);
t0 = get_tmr10ms() - t0;
if (t0 > maxLuaDuration) {
maxLuaDuration = t0;
}
#elif !defined(LIBOPENUI)
lcdRefreshWait(); // WARNING: make sure no code above this line does any change to the LCD display buffer!
#endif
bool screenshotRequested = (mainRequestFlags & (1u << REQUEST_SCREENSHOT));
#if defined(LIBOPENUI)
MainWindow::instance()->run();
#else
if (!refreshNeeded) {
DEBUG_TIMER_START(debugTimerMenus);
while (true) {
// normal GUI from menus
const char * warn = warningText;
uint8_t menu = popupMenuItemsCount;
static bool popupDisplayed = false;
if (warn || menu) {
if (popupDisplayed == false) {
menuHandlers[menuLevel](EVT_REFRESH);
lcdDrawBlackOverlay();
TIME_MEASURE_START(storebackup);
lcdStoreBackupBuffer();
TIME_MEASURE_STOP(storebackup);
}
if (popupDisplayed == false || evt || screenshotRequested) {
popupDisplayed = lcdRestoreBackupBuffer();
if (warn) {
DISPLAY_WARNING(evt);
}
if (menu) {
const char * result = runPopupMenu(evt);
if (result) {
TRACE("popupMenuHandler(%s)", result);
auto handler = popupMenuHandler;
if (result != STR_UPDATE_LIST)
CLEAR_POPUP();
handler(result);
if (menuEvent == 0) {
evt = EVT_REFRESH;
continue;
}
}
}
refreshNeeded = true;
}
}
else {
if (popupDisplayed) {
if (evt == 0) {
evt = EVT_REFRESH;
}
popupDisplayed = false;
}
DEBUG_TIMER_START(debugTimerMenuHandlers);
refreshNeeded = menuHandlers[menuLevel](evt);
DEBUG_TIMER_STOP(debugTimerMenuHandlers);
}
if (menuEvent == EVT_ENTRY) {
menuVerticalPosition = 0;
menuHorizontalPosition = 0;
evt = menuEvent;
menuEvent = 0;
}
else if (menuEvent == EVT_ENTRY_UP) {
menuVerticalPosition = menuVerticalPositions[menuLevel];
menuHorizontalPosition = 0;
evt = menuEvent;
menuEvent = 0;
}
else {
break;
}
}
DEBUG_TIMER_STOP(debugTimerMenus);
}
bool screenshotRequested = (mainRequestFlags & (1u << REQUEST_SCREENSHOT));
if (screenshotRequested) {
writeScreenshot();
mainRequestFlags &= ~(1u << REQUEST_SCREENSHOT);
}
if (refreshNeeded) {
DEBUG_TIMER_START(debugTimerLcdRefresh);
lcdRefresh();
DEBUG_TIMER_STOP(debugTimerLcdRefresh);
}
#endif
}
#elif defined(GUI)
void handleGui(event_t event) {
// if Lua standalone, run it and don't clear the screen (Lua will do it)
// else if Lua telemetry view, run it and don't clear the screen
+5
View File
@@ -529,6 +529,11 @@ int lcdRestoreBackupBuffer()
return 1;
}
uint16_t* lcdGetBackupBuffer()
{
return simuLcdBackupBuf;
}
uint32_t pwrCheck()
{
// TODO: ability to simulate shutdown warning for a "soft" simulator restart