Merge pull request #501 from EdgeTX/main

Merge from main
This commit is contained in:
richardclli
2021-07-26 10:50:32 +08:00
committed by GitHub
19 changed files with 884 additions and 547 deletions
+4 -1
View File
@@ -47,7 +47,10 @@ static int8_t getTextVerticalOffset(LcdFlags flags)
if (font_index >= sizeof(text_vertical_offset)) {
return 0;
}
return text_vertical_offset[font_index];
int vcenter = 0;
if (flags & VCENTERED)
vcenter = 0.5 * getFontHeight(flags & 0xFFFF);
return text_vertical_offset[font_index] - vcenter;
}
/*luadoc
+12 -3
View File
@@ -1083,12 +1083,13 @@ Stops key state machine. See [Key Events](../key_events.md) for the detailed des
*/
static int luaKillEvents(lua_State * L)
{
uint8_t key = EVT_KEY_MASK(luaL_checkinteger(L, 1));
event_t key = EVT_KEY_MASK(luaL_checkinteger(L, 1));
// prevent killing maskable keys (only in telemetry scripts)
// TODO add which tpye of script is running before p_call()
// TODO add which type of script is running before lua_resume()
if (IS_MASKABLE(key)) {
killEvents(key);
}
luaEmptyEventBuffer();
}
return 0;
}
@@ -1862,6 +1863,7 @@ const luaR_value_entry opentxConstants[] = {
#endif
#if defined(COLORLCD)
{ "BOLD", FONT(BOLD) },
{ "VCENTER", VCENTERED },
#else
{ "BOLD", BOLD },
#endif
@@ -2099,6 +2101,13 @@ const luaR_value_entry opentxConstants[] = {
{ "EVT_ROT_RIGHT", EVT_ROTARY_RIGHT },
#endif
#if defined(HARDWARE_TOUCH)
{ "EVT_TOUCH_FIRST", EVT_TOUCH_FIRST },
{ "EVT_TOUCH_BREAK", EVT_TOUCH_BREAK },
{ "EVT_TOUCH_SLIDE", EVT_TOUCH_SLIDE },
{ "EVT_TOUCH_TAP", EVT_TOUCH_TAP },
#endif
#if LCD_DEPTH > 1 && !defined(COLORLCD)
{ "FILL_WHITE", FILL_WHITE },
{ "GREY_DEFAULT", GREY_DEFAULT },
File diff suppressed because it is too large Load Diff
+42 -21
View File
@@ -47,15 +47,19 @@ extern Fifo<uint8_t, LUA_FIFO_SIZE> * luaRxFifo;
#endif
extern lua_State * lsScripts;
extern lua_State * lsWidgets;
extern bool luaLcdAllowed;
#if defined(COLORLCD)
extern lua_State * lsWidgets;
extern uint32_t luaExtraMemoryUsage;
void luaInitThemesAndWidgets();
#endif
void luaInit();
void luaInitThemesAndWidgets();
void luaEmptyEventBuffer();
#define LUA_INIT_THEMES_AND_WIDGETS() 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)))
#define lua_pushtablenil(L, k) (lua_pushstring(L, (k)), lua_pushnil(L), lua_settable(L, -3))
@@ -78,12 +82,6 @@ void luaInitThemesAndWidgets();
#define lua_registerlib(L, name, tab) (luaL_newmetatable(L, name), luaL_setfuncs(L, tab, 0), lua_setglobal(L, name))
#define RUN_MIX_SCRIPT (1 << 0)
#define RUN_FUNC_SCRIPT (1 << 1)
#define RUN_TELEM_BG_SCRIPT (1 << 2)
#define RUN_TELEM_FG_SCRIPT (1 << 3)
#define RUN_STNDAL_SCRIPT (1 << 4)
enum luaScriptInputType {
INPUT_TYPE_FIRST = 0,
INPUT_TYPE_VALUE = INPUT_TYPE_FIRST,
@@ -98,27 +96,36 @@ struct ScriptInput {
int16_t max;
int16_t def;
};
struct ScriptOutput {
const char *name;
int16_t value;
};
enum ScriptState {
SCRIPT_OK,
SCRIPT_NOFILE,
SCRIPT_SYNTAX_ERROR,
SCRIPT_PANIC,
SCRIPT_KILLED
SCRIPT_FINISHED
};
enum ScriptReference {
#if defined(LUA_MODEL_SCRIPTS)
SCRIPT_MIX_FIRST,
SCRIPT_MIX_LAST=SCRIPT_MIX_FIRST+MAX_SCRIPTS-1,
#endif
SCRIPT_FUNC_FIRST,
SCRIPT_FUNC_LAST=SCRIPT_FUNC_FIRST+MAX_SPECIAL_FUNCTIONS-1, // model functions
SCRIPT_GFUNC_FIRST,
SCRIPT_GFUNC_LAST=SCRIPT_GFUNC_FIRST+MAX_SPECIAL_FUNCTIONS-1, // global functions
#if defined(PCBTARANIS)
SCRIPT_TELEMETRY_FIRST,
SCRIPT_TELEMETRY_LAST=SCRIPT_TELEMETRY_FIRST+MAX_SCRIPTS, // telem0 and telem1 .. telem7
SCRIPT_TELEMETRY_LAST=SCRIPT_TELEMETRY_FIRST+MAX_SCRIPTS, // telem0 and telem1 .. telem7
#endif
SCRIPT_STANDALONE // Standalone script
};
struct ScriptInternalData {
uint8_t reference;
uint8_t state;
@@ -126,41 +133,55 @@ struct ScriptInternalData {
int background;
uint8_t instructions;
};
struct ScriptInputsOutputs {
uint8_t inputsCount;
ScriptInput inputs[MAX_SCRIPT_INPUTS];
uint8_t outputsCount;
ScriptOutput outputs[MAX_SCRIPT_OUTPUTS];
};
#define INTERPRETER_RUNNING_STANDALONE_SCRIPT 1
#define INTERPRETER_RELOAD_PERMANENT_SCRIPTS 2
#define INTERPRETER_PANIC 255
enum InterpreterState {
INTERPRETER_RELOAD_PERMANENT_SCRIPTS = 1,
INTERPRETER_LOADING,
INTERPRETER_START_RUNNING,
INTERPRETER_RUNNING,
INTERPRETER_PANIC = 255
};
extern uint8_t luaState;
extern uint8_t luaScriptsCount;
extern bool luaLcdAllowed;
extern ScriptInternalData standaloneScript;
extern ScriptInternalData scriptInternalData[MAX_SCRIPTS];
extern ScriptInputsOutputs scriptInputsOutputs[MAX_SCRIPTS];
void luaClose(lua_State ** L);
bool luaTask(event_t evt, uint8_t scriptType, bool allowLcdUsage);
bool luaTask(event_t evt, bool allowLcdUsage);
void checkLuaMemoryUsage();
void luaExec(const char * filename);
void luaDoGc(lua_State * L, bool full);
void luaError(lua_State * L, uint8_t error, bool acknowledge=true);
uint32_t luaGetMemUsed(lua_State * L);
void luaGetValueAndPush(lua_State * L, int src);
#define luaGetCpuUsed(idx) scriptInternalData[idx].instructions
uint8_t isTelemetryScriptAvailable(uint8_t index);
#define LUA_LOAD_MODEL_SCRIPTS() luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPT(idx) luaState |= INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define luaGetCpuUsed(idx) scriptInternalData[idx].instructions
#define LUA_LOAD_MODEL_SCRIPTS() luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS
#define LUA_LOAD_MODEL_SCRIPT(idx) luaState = INTERPRETER_RELOAD_PERMANENT_SCRIPTS
// Lua PROTECT/UNPROTECT
#include <setjmp.h>
struct our_longjmp {
struct our_longjmp *previous;
jmp_buf b;
volatile int status; /* error code */
};
extern struct our_longjmp * global_lj;
#define PROTECT_LUA() { struct our_longjmp lj; \
lj.previous = global_lj; /* chain new error handler */ \
global_lj = &lj; \
@@ -172,14 +193,16 @@ extern uint16_t maxLuaDuration;
extern uint8_t instructionsPercent;
#if defined(KEYS_GPIO_REG_PAGE)
#define IS_MASKABLE(key) ((key) != KEY_EXIT && (key) != KEY_ENTER && ((luaState & INTERPRETER_RUNNING_STANDALONE_SCRIPT) || (key) != KEY_PAGE))
#define IS_MASKABLE(key) ((key) != KEY_EXIT && (key) != KEY_ENTER && ((scriptInternalData[0].reference == SCRIPT_STANDALONE) || (key) != KEY_PAGE))
#else
#define IS_MASKABLE(key) ((key) != KEY_EXIT && (key) != KEY_ENTER)
#endif
struct LuaField {
uint16_t id;
char desc[50];
};
bool luaFindFieldByName(const char * name, LuaField & field, unsigned int flags=0);
void luaLoadThemes();
void luaRegisterLibraries(lua_State * L);
@@ -207,8 +230,6 @@ struct LuaMemTracer {
};
void * tracer_alloc(void * ud, void * ptr, size_t osize, size_t nsize);
void luaHook(lua_State * L, lua_Debug *ar);
#else // defined(LUA)
+226 -3
View File
@@ -31,6 +31,13 @@
#define MANUAL_SCRIPTS_MAX_INSTRUCTIONS (20000/100)
#define LUA_WARNING_INFO_LEN 64
#if defined(HARDWARE_TOUCH)
#define EVT_TOUCH_TAP_TIME 25
#define EVT_TOUCH_SWIPE_LOCK 4
#define EVT_TOUCH_SWIPE_SPEED 35
#define EVT_TOUCH_SWIPE_TIMEOUT 50
#endif
constexpr int LUA_WIDGET_REFRESH = 1000 / 10; // 10 Hz
lua_State * lsWidgets = NULL;
@@ -40,6 +47,57 @@ extern int custom_lua_atpanic(lua_State *L);
#define LUA_WIDGET_FILENAME "/main.lua"
#define LUA_FULLPATH_MAXLEN (LEN_FILE_PATH_MAX + LEN_SCRIPT_FILENAME + LEN_FILE_EXTENSION_MAX) // max length (example: /SCRIPTS/THEMES/mytheme.lua)
static void luaHook(lua_State * L, lua_Debug *ar)
{
if (ar->event == LUA_HOOKCOUNT) {
instructionsPercent++;
#if defined(DEBUG)
// Disable Lua script instructions limit in DEBUG mode,
// just report max value reached
static uint16_t max = 0;
if (instructionsPercent > 100) {
if (max + 10 < instructionsPercent) {
max = instructionsPercent;
TRACE("LUA instructionsPercent %u%%", (uint32_t)max);
}
}
else if (instructionsPercent < 10) {
max = 0;
}
#else
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, luaHook, LUA_MASKLINE, 0);
luaL_error(L, "CPU limit");
}
#endif
}
#if defined(LUA_ALLOCATOR_TRACER)
else if (ar->event == LUA_HOOKLINE) {
lua_getinfo(L, "nSl", ar);
LuaMemTracer * tracer = GET_TRACER(L);
if (tracer->alloc || tracer->free) {
TRACE("LT: [+%u,-%u] %s:%d", tracer->alloc, tracer->free, tracer->script, tracer->lineno);
}
tracer->script = ar->source;
tracer->lineno = ar->currentline;
tracer->alloc = 0;
tracer->free = 0;
}
#endif // #if defined(LUA_ALLOCATOR_TRACER)
}
void luaSetInstructionsLimit(lua_State * L, int count)
{
instructionsPercent = 0;
#if defined(LUA_ALLOCATOR_TRACER)
lua_sethook(L, luaHook, LUA_MASKCOUNT|LUA_MASKLINE, count);
#else
lua_sethook(L, luaHook, LUA_MASKCOUNT, count);
#endif
}
void exec(int function, int nresults=0)
{
if (lsWidgets == 0) return;
@@ -190,6 +248,16 @@ class LuaWidget: public Widget
const char * getErrorMessage() const override;
void update() override;
void background() override;
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchStart(coord_t x, coord_t y) override;
bool onTouchEnd(coord_t x, coord_t y) override;
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override;
#endif
// Calls LUA widget 'refresh' method
void refresh(BitmapBuffer* dc) override;
@@ -199,11 +267,36 @@ class LuaWidget: public Widget
char * errorMessage;
uint32_t lastRefresh = 0;
bool refreshed = false;
static event_t event;
#if defined(HARDWARE_TOUCH)
static coord_t touchX;
static coord_t touchY;
static coord_t startX;
static coord_t startY;
static coord_t slideX;
static coord_t slideY;
static tmr10ms_t lastTouchDown;
static tmr10ms_t swipeTimeOut;
#endif
void checkEvents() override;
void setErrorMessage(const char * funcName);
};
event_t LuaWidget::event = 0;
#if defined(HARDWARE_TOUCH)
coord_t LuaWidget::touchX = 0;
coord_t LuaWidget::touchY = 0;
coord_t LuaWidget::startX = 0;
coord_t LuaWidget::startY = 0;
coord_t LuaWidget::slideX = 0;
coord_t LuaWidget::slideY = 0;
tmr10ms_t LuaWidget::lastTouchDown = 0;
tmr10ms_t LuaWidget::swipeTimeOut = 0;
#endif
void l_pushtableint(const char * key, int value)
{
lua_pushstring(lsWidgets, key);
@@ -211,6 +304,13 @@ void l_pushtableint(const char * key, int value)
lua_settable(lsWidgets, -3);
}
void l_pushtablebool(const char * key, bool value)
{
lua_pushstring(lsWidgets, key);
lua_pushboolean(lsWidgets, value);
lua_settable(lsWidgets, -3);
}
class LuaWidgetFactory: public WidgetFactory
{
friend void luaLoadWidgetCallback();
@@ -341,15 +441,66 @@ void LuaWidget::refresh(BitmapBuffer* dc)
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, factory->refreshFunction);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaWidgetDataRef);
// Pass key event to fullscreen Lua widget
if (fullscreen)
lua_pushinteger(lsWidgets, event);
else
lua_pushnil(lsWidgets);
#if defined(HARDWARE_TOUCH)
if (fullscreen && IS_TOUCH_EVENT(event)) {
lua_newtable(lsWidgets);
l_pushtableint("x", touchX);
l_pushtableint("y", touchY);
if (LuaWidget::event == EVT_TOUCH_SLIDE) {
l_pushtableint("startX", startX);
l_pushtableint("startY", startY);
l_pushtableint("slideX", slideX);
l_pushtableint("slideY", slideY);
// Do we have a swipe? Only one at a time!
if (get_tmr10ms() > swipeTimeOut) {
coord_t absX = (slideX < 0) ? -slideX : slideX;
coord_t absY = (slideY < 0) ? -slideY : slideY;
bool swiped = false;
if (absX > EVT_TOUCH_SWIPE_LOCK * absY) {
if ((swiped = (slideX > EVT_TOUCH_SWIPE_SPEED)))
l_pushtablebool("swipeRight", true);
else if ((swiped = (slideX < -EVT_TOUCH_SWIPE_SPEED)))
l_pushtablebool("swipeLeft", true);
}
else if (absY > EVT_TOUCH_SWIPE_LOCK * absX) {
if ((swiped = (slideY > EVT_TOUCH_SWIPE_SPEED)))
l_pushtablebool("swipeDown", true);
else if ((swiped = (slideY < -EVT_TOUCH_SWIPE_SPEED)))
l_pushtablebool("swipeUp", true);
}
if (swiped)
swipeTimeOut = get_tmr10ms() + EVT_TOUCH_SWIPE_TIMEOUT;
}
}
} else
#endif
lua_pushnil(lsWidgets);
event = 0;
// Enable drawing into the current LCD buffer
luaLcdBuffer = dc;
// This little hack is needed to not interfere with the LCD usage of preempted scripts
bool lla = luaLcdAllowed;
luaLcdAllowed = true;
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
if (lua_pcall(lsWidgets, 3, 0, 0) != 0) {
setErrorMessage("refresh()");
}
// Remove LCD
luaLcdAllowed = false;
luaLcdAllowed = lla;
luaLcdBuffer = nullptr;
// mark as refreshed
@@ -360,7 +511,7 @@ void LuaWidget::background()
{
if (lsWidgets == 0 || errorMessage) return;
TRACE("LuaWidget::background()");
// TRACE("LuaWidget::background()");
luaSetInstructionsLimit(lsWidgets, WIDGET_SCRIPTS_MAX_INSTRUCTIONS);
LuaWidgetFactory * factory = (LuaWidgetFactory *)this->factory;
if (factory->backgroundFunction) {
@@ -372,6 +523,78 @@ void LuaWidget::background()
}
}
#if defined(HARDWARE_KEYS)
void LuaWidget::onEvent(event_t event)
{
if (fullscreen && EVT_KEY_LONG(KEY_EXIT) != event)
LuaWidget::event = event;
else
LuaWidget::event = 0;
Widget::onEvent(event);
}
#endif
#if defined(HARDWARE_TOUCH)
bool LuaWidget::onTouchStart(coord_t x, coord_t y)
{
TRACE_WINDOWS("LuaWidget received touch start (%d) x=%d;y=%d", hasFocus(), x, y);
// Only one EVT_TOUCH_FIRST at a time, and also start timer for possible TAP
if (fullscreen) {
if (lastTouchDown == 0) {
event = EVT_TOUCH_FIRST;
touchX = x;
touchY = y;
lastTouchDown = get_tmr10ms();
}
return true;
}
return Widget::onTouchStart(x, y);
}
bool LuaWidget::onTouchEnd(coord_t x, coord_t y)
{
TRACE_WINDOWS("LuaWidget received touch end (%d) x=%d;y=%d", hasFocus(), x, y);
if (fullscreen) {
if (get_tmr10ms() - lastTouchDown <= EVT_TOUCH_TAP_TIME)
event = EVT_TOUCH_TAP;
else
event = EVT_TOUCH_BREAK;
touchX = x;
touchY = y;
lastTouchDown = 0;
return true;
}
return Widget::onTouchEnd(x, y);
}
bool LuaWidget::onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY)
{
TRACE_WINDOWS("LuaWidget touch slide");
if (fullscreen) {
event = EVT_TOUCH_SLIDE;
touchX = x;
touchY = y;
LuaWidget::startX = startX;
LuaWidget::startY = startY;
LuaWidget::slideX = slideX;
LuaWidget::slideY = slideY;
lastTouchDown = 0;
return true;
}
return Widget::onTouchSlide(x, y, startX, startY, slideX, slideY);
}
#endif
void luaLoadWidgetCallback()
{
TRACE("luaLoadWidgetCallback()");