feat(color): telemetry queues for Lua, enhance default widget options (#5926)

This commit is contained in:
philmoz
2025-03-21 10:56:07 +10:00
committed by GitHub
parent 5a0c8dbff6
commit 4f18632505
30 changed files with 1053 additions and 712 deletions
@@ -109,7 +109,7 @@ void InputMixButtonBase::setSource(mixsrc_t idx)
else
lv_obj_clear_state(source, LV_STATE_USER_1);
lv_label_set_text(source, s);
lv_label_set_text(source, s);
}
void InputMixButtonBase::setOpts(const char* s)
+1 -1
View File
@@ -49,7 +49,7 @@ class LayoutFactory
virtual const uint8_t* getBitmap() const = 0;
virtual const ZoneOption* getOptions() const = 0;
virtual const ZoneOption* getLayoutOptions() const = 0;
virtual WidgetsContainer* create(
Window* parent, LayoutPersistentData* persistentData) const = 0;
@@ -98,8 +98,6 @@ class Layout: public LayoutBase
return getOptionValue(LAYOUT_OPTION_MIRRORED)->boolValue;
}
virtual bool isAppMode() const { return false; }
// Set decoration visibility
void setTrimsVisible(bool visible);
void setSlidersVisible(bool visible);
@@ -182,7 +180,7 @@ class BaseLayoutFactory: public LayoutFactory
const uint8_t* getBitmap() const override { return bitmap; }
const ZoneOption * getOptions() const override
const ZoneOption * getLayoutOptions() const override
{
return options;
}
@@ -327,7 +327,7 @@ void ScreenSetupPage::buildLayoutOptions()
if (!factory) return;
int index = 0;
for (auto* option = factory->getOptions(); option->name; option++, index++) {
for (auto* option = factory->getLayoutOptions(); option->name; option++, index++) {
auto layoutData = &g_model.screenData[customScreenIndex].layoutData;
ZoneOptionValue* value = &layoutData->options[index].value;
+5 -4
View File
@@ -57,13 +57,13 @@ void Widget::openMenu()
return;
}
if (getOptions() || fsAllowed) {
if (hasOptions() || fsAllowed) {
Menu* menu = new Menu();
menu->setTitle(getFactory()->getDisplayName());
if (fsAllowed) {
menu->addLine(STR_WIDGET_FULLSCREEN, [&]() { setFullscreen(true); });
}
if (getOptions() && getOptions()->name) {
if (hasOptions()) {
menu->addLine(STR_WIDGET_SETTINGS,
[=]() { new WidgetSettings(this); });
}
@@ -146,9 +146,9 @@ bool Widget::onLongPress()
return true;
}
const ZoneOption* Widget::getOptions() const
const ZoneOption* Widget::getOptionDefinitions() const
{
return getFactory()->getOptions();
return getFactory()->getDefaultOptions();
}
void Widget::enableFocus(bool enable)
@@ -253,6 +253,7 @@ void WidgetFactory::initPersistentData(Widget::PersistentData* persistentData,
{
if (setDefault) {
memset(persistentData, 0, sizeof(Widget::PersistentData));
parseOptionDefaults();
}
if (options) {
int i = 0;
+4 -2
View File
@@ -42,7 +42,8 @@ class Widget : public ButtonBase
const WidgetFactory* getFactory() const { return factory; }
const ZoneOption* getOptions() const;
const ZoneOption* getOptionDefinitions() const;
bool hasOptions() const { return getOptionDefinitions() && getOptionDefinitions()->name; }
virtual const char* getErrorMessage() const { return nullptr; }
@@ -117,7 +118,8 @@ class WidgetFactory
const char* getName() const { return name; }
const ZoneOption* getOptions() const { return options; }
const ZoneOption* getDefaultOptions() const { return options; }
virtual const void parseOptionDefaults() const {}
const char* getDisplayName() const
{
@@ -49,7 +49,8 @@ WidgetSettings::WidgetSettings(Widget* w) :
FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY);
uint8_t optIdx = 0;
auto opt = widget->getOptions();
auto opt = widget->getOptionDefinitions();
while (opt && opt->name != nullptr) {
auto line = form->newLine(grid);
@@ -85,5 +85,6 @@ class WidgetsContainer: public Window
virtual void runBackground() = 0;
virtual bool isLayout() { return false; }
virtual bool isAppMode() const { return false; }
bool isWidgetsContainer() override { return true; }
};
@@ -41,7 +41,7 @@ SetupWidgetsPageSlot::SetupWidgetsPageSlot(Window* parent, const rect_t& rect,
menu->addLine(STR_SELECT_WIDGET,
[=]() { addNewWidget(container, slotIndex); });
auto widget = container->getWidget(slotIndex);
if (widget->getOptions() && widget->getOptions()->name)
if (widget->hasOptions())
menu->addLine(STR_WIDGET_SETTINGS,
[=]() { new WidgetSettings(widget); });
menu->addLine(STR_REMOVE_WIDGET,
@@ -103,7 +103,7 @@ void SetupWidgetsPageSlot::addNewWidget(WidgetsContainer* container,
menu->addLine(factory->getDisplayName(), [=]() {
container->createWidget(slotIndex, factory);
auto widget = container->getWidget(slotIndex);
if (widget->getOptions() && widget->getOptions()->name)
if (widget->hasOptions())
new WidgetSettings(widget);
});
if (cur && strcmp(cur, factory->getDisplayName()) == 0)
+6 -6
View File
@@ -133,6 +133,8 @@ StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl, int initFn, int runFn) :
etx_solid_bg(lvobj);
luaScriptManager = this;
if (useLvglLayout()) {
padAll(PAD_ZERO);
etx_scrollbar(lvobj);
@@ -146,8 +148,6 @@ StandaloneLuaWindow::StandaloneLuaWindow(bool useLvgl, int initFn, int runFn) :
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_CENTER, LV_PART_MAIN);
lv_obj_set_style_pad_top(lbl, (LCD_H - EdgeTxStyles::PAGE_LINE_HEIGHT) / 2, LV_PART_MAIN);
lv_label_set_text(lbl, STR_LOADING);
luaLvglManager = this;
} else {
lcdBuffer = new BitmapBuffer(BMP_RGB565, LCD_W, LCD_H);
@@ -218,7 +218,7 @@ void StandaloneLuaWindow::deleteLater(bool detach, bool trash)
if (lcdBuffer) delete lcdBuffer;
lcdBuffer = nullptr;
luaLvglManager = nullptr;
luaScriptManager = nullptr;
Layer::pop(this);
Layer::back()->show();
@@ -320,13 +320,13 @@ void StandaloneLuaWindow::checkEvents()
luaLcdAllowed = false;
}
void StandaloneLuaWindow::onClicked() { Keyboard::hide(false); LuaEventHandler::onClicked(); }
void StandaloneLuaWindow::onClicked() { Keyboard::hide(false); LuaScriptManager::onClickedEvent(); }
void StandaloneLuaWindow::onCancel() { LuaEventHandler::onCancel(); }
void StandaloneLuaWindow::onCancel() { LuaScriptManager::onCancelEvent(); }
void StandaloneLuaWindow::onEvent(event_t evt)
{
LuaEventHandler::onLuaEvent(evt);
LuaScriptManager::onLuaEvent(evt);
}
void StandaloneLuaWindow::popupPaint(BitmapBuffer* dc, coord_t x, coord_t y, coord_t w, coord_t h,
+1 -1
View File
@@ -28,7 +28,7 @@
extern void luaExecStandalone(const char * filename);
class StandaloneLuaWindow : public Window, public LuaEventHandler, public LuaLvglManager
class StandaloneLuaWindow : public Window, public LuaScriptManager
{
static StandaloneLuaWindow* _instance;
+2 -3
View File
@@ -36,7 +36,6 @@
#define BITMAP_METATABLE "BITMAP*"
BitmapBuffer* luaLcdBuffer = nullptr;
LuaWidget *runningFS = nullptr;
/*luadoc
@function lcd.refresh()
@@ -1386,8 +1385,8 @@ Exit full screen widget mode.
*/
static int luaLcdExitFullScreen(lua_State *L)
{
if (runningFS)
runningFS->closeFullscreen();
if (luaScriptManager)
luaScriptManager->exitFullscreen();
return 0;
}
+45 -35
View File
@@ -28,14 +28,11 @@
#include "api_colorlcd.h"
LuaLvglManager *luaLvglManager = nullptr;
static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, bool fullscreenOnly = false)
{
if (luaLvglManager && (!fullscreenOnly || luaLvglManager->isFullscreen())) {
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
auto obj = create();
obj->getParams(L, 1);
obj->build(L);
obj->create(L, 1);
obj->push(L);
} else {
lua_pushnil(L);
@@ -46,24 +43,23 @@ static int luaLvglObj(lua_State *L, std::function<LvglWidgetObject*()> create, b
static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> create, bool fullscreenOnly = false)
{
if (luaLvglManager && (!fullscreenOnly || luaLvglManager->isFullscreen())) {
if (luaScriptManager && (!fullscreenOnly || luaScriptManager->isFullscreen())) {
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(p);
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
}
}
auto obj = create();
obj->getParams(L, -1);
obj->build(L);
obj->create(L, -1);
obj->push(L);
if (p)
luaLvglManager->setTempParent((prevParent));
luaScriptManager->setTempParent((prevParent));
} else {
lua_pushnil(L);
}
@@ -74,8 +70,7 @@ static int luaLvglObjEx(lua_State *L, std::function<LvglWidgetObjectBase*()> cre
static int luaLvglPopup(lua_State *L, std::function<LvglWidgetObjectBase*()> create)
{
auto obj = create();
obj->getParams(L, 1);
obj->build(L);
obj->create(L, 1);
return 0;
}
@@ -100,14 +95,14 @@ static int luaLvglSet(lua_State *L)
static int luaLvglClear(lua_State *L)
{
if (luaLvglManager) {
if (luaScriptManager) {
if (lua_gettop(L) == 1) {
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->clear();
}
} else {
luaLvglManager->clear();
luaScriptManager->clear();
}
}
@@ -150,6 +145,15 @@ static int luaLvglDisable(lua_State *L)
return 0;
}
static int luaLvglClose(lua_State *L)
{
auto p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
p->close();
}
return 0;
}
class LvglWidgetParams
{
public:
@@ -177,6 +181,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
{
luaL_checktype(L, srcIndex, LUA_TTABLE);
for (lua_pushnil(L); lua_next(L, srcIndex - 1); lua_pop(L, 1)) {
auto t = lua_gettop(L);
LvglWidgetParams p(L, -1);
LvglWidgetObjectBase *obj = nullptr;
if (strcasecmp(p.type, "label") == 0)
@@ -201,7 +206,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
obj = new LvglWidgetQRCode();
else if (strcasecmp(p.type, "box") == 0)
obj = new LvglWidgetBox();
else if (luaLvglManager->isFullscreen()) {
else if (luaScriptManager->isFullscreen()) {
if (strcasecmp(p.type, "button") == 0)
obj = new LvglWidgetTextButton();
if (strcasecmp(p.type, "momentaryButton") == 0)
@@ -236,8 +241,7 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
obj = new LvglWidgetSetting();
}
if (obj) {
obj->getParams(L, -1);
obj->build(L);
obj->create(L, -1);
auto ref = obj->getRef(L);
if (p.name) {
lua_pushstring(L, p.name);
@@ -246,26 +250,27 @@ static void buildLvgl(lua_State *L, int srcIndex, int refIndex)
}
if (p.hasChildren && obj->getWindow()) {
lua_getfield(L, -1, "children");
auto prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(obj);
auto prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(obj);
buildLvgl(L, -1, refIndex - 3);
lua_pop(L, 1);
luaLvglManager->setTempParent(prevParent);
luaScriptManager->setTempParent(prevParent);
}
}
lua_settop(L, t); // In case of errors in build functions
}
}
static int luaLvglBuild(lua_State *L)
{
if (luaLvglManager) {
if (luaScriptManager) {
LvglWidgetObjectBase* p = nullptr;
LvglWidgetObjectBase* prevParent = nullptr;
if (lua_gettop(L) == 2) {
p = LvglWidgetObjectBase::checkLvgl(L, 1);
if (p) {
prevParent = luaLvglManager->getTempParent();
luaLvglManager->setTempParent(p);
prevParent = luaScriptManager->getTempParent();
luaScriptManager->setTempParent(p);
}
}
@@ -274,7 +279,7 @@ static int luaLvglBuild(lua_State *L)
buildLvgl(L, -2, -1);
if (p)
luaLvglManager->setTempParent((prevParent));
luaScriptManager->setTempParent((prevParent));
} else {
lua_pushnil(L);
}
@@ -283,8 +288,8 @@ static int luaLvglBuild(lua_State *L)
static int luaLvglIsAppMode(lua_State *L)
{
if (luaLvglManager) {
lua_pushboolean(L, luaLvglManager->isAppMode());
if (luaScriptManager) {
lua_pushboolean(L, luaScriptManager->isAppMode());
} else {
lua_pushboolean(L, false);
}
@@ -293,8 +298,8 @@ static int luaLvglIsAppMode(lua_State *L)
static int luaLvglIsFullscreen(lua_State *L)
{
if (luaLvglManager) {
lua_pushboolean(L, luaLvglManager->isFullscreen());
if (luaScriptManager) {
lua_pushboolean(L, luaScriptManager->isFullscreen());
} else {
lua_pushboolean(L, false);
}
@@ -303,16 +308,16 @@ static int luaLvglIsFullscreen(lua_State *L)
static int luaLvglExitFullscreen(lua_State *L)
{
if (luaLvglManager)
luaLvglManager->exitFullscreen();
if (luaScriptManager)
luaScriptManager->exitFullscreen();
return 0;
}
static int luaLvglGetContext(lua_State *L)
{
if (luaLvglManager && luaLvglManager->getContext() != LUA_REFNIL) {
if (luaScriptManager && luaScriptManager->getContext() != LUA_REFNIL) {
// Push context tanle onto Lua stack (return object)
lua_rawgeti(L, LUA_REGISTRYINDEX, luaLvglManager->getContext());
lua_rawgeti(L, LUA_REGISTRYINDEX, luaScriptManager->getContext());
} else {
lua_pushnil(L);
}
@@ -354,8 +359,8 @@ LROT_BEGIN(lvgllib, NULL, 0)
LROT_FUNCENTRY(switch, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSwitchPicker(); }, true); })
LROT_FUNCENTRY(source, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSourcePicker(); }, true); })
// Containers
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetBox(); }, true); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetSetting(); }, true); })
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetBox(); }); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSetting(); }, true); })
LROT_FUNCENTRY(page, [](lua_State* L) { return luaLvglObj(L, []() { return new LvglWidgetPage(); }, true); })
LROT_FUNCENTRY(dialog, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetDialog(); }, true); })
// Dialogs
@@ -367,6 +372,7 @@ LROT_BEGIN(lvgllib, NULL, 0)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_FUNCENTRY(enable, luaLvglEnable)
LROT_FUNCENTRY(disable, luaLvglDisable)
LROT_FUNCENTRY(close, luaLvglClose)
LROT_NUMENTRY(FLOW_ROW, LV_FLEX_FLOW_ROW)
LROT_NUMENTRY(FLOW_COLUMN, LV_FLEX_FLOW_COLUMN)
LROT_NUMENTRY(PAD_TINY, PAD_TINY)
@@ -440,12 +446,16 @@ LROT_BEGIN(lvgl_mt, NULL, LROT_MASK_GC_INDEX)
LROT_FUNCENTRY(timer, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetTimerPicker(); }, true); })
LROT_FUNCENTRY(switch, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSwitchPicker(); }, true); })
LROT_FUNCENTRY(source, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSourcePicker(); }, true); })
// Containers
LROT_FUNCENTRY(box, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetBox(); }); })
LROT_FUNCENTRY(setting, [](lua_State* L) { return luaLvglObjEx(L, []() { return new LvglWidgetSetting(); }, true); })
// Object manipulation functions
LROT_FUNCENTRY(set, luaLvglSet)
LROT_FUNCENTRY(show, luaLvglShow)
LROT_FUNCENTRY(hide, luaLvglHide)
LROT_FUNCENTRY(enable, luaLvglEnable)
LROT_FUNCENTRY(disable, luaLvglDisable)
LROT_FUNCENTRY(close, luaLvglClose)
LROT_END(lvgl_mt, NULL, LROT_MASK_GC_INDEX)
extern "C" {
+68 -92
View File
@@ -898,6 +898,24 @@ static int luaGetRotEncMode(lua_State * L)
return 1;
}
static TelemetryQueue* getTelemetryQueue()
{
#if defined(COLORLCD)
if (luaScriptManager) {
luaScriptManager->createTelemetryQueue();
return luaScriptManager->telemetryQueue();
} else {
if (!luaInputTelemetryFifo)
luaInputTelemetryFifo = new TelemetryQueue();
return luaInputTelemetryFifo;
}
#else
if (!luaInputTelemetryFifo)
luaInputTelemetryFifo = new TelemetryQueue();
return luaInputTelemetryFifo;
#endif
}
/*luadoc
@function sportTelemetryPop()
@@ -917,23 +935,20 @@ the LUA telemetry receive queue.
*/
static int luaSportTelemetryPop(lua_State * L)
{
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo = new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
if (!luaInputTelemetryFifo) {
return 0;
}
}
auto queue = getTelemetryQueue();
if (luaInputTelemetryFifo->size() >= sizeof(SportTelemetryPacket)) {
SportTelemetryPacket packet;
for (uint8_t i=0; i<sizeof(packet); i++) {
luaInputTelemetryFifo->pop(packet.raw[i]);
if (queue) {
if (queue->size() >= sizeof(SportTelemetryPacket)) {
SportTelemetryPacket packet;
for (uint8_t i=0; i<sizeof(packet); i++) {
queue->pop(packet.raw[i]);
}
lua_pushinteger(L, packet.physicalId);
lua_pushinteger(L, packet.primId);
lua_pushinteger(L, packet.dataId);
lua_pushinteger(L, packet.value);
return 4;
}
lua_pushinteger(L, packet.physicalId);
lua_pushinteger(L, packet.primId);
lua_pushinteger(L, packet.dataId);
lua_pushinteger(L, packet.value);
return 4;
}
return 0;
@@ -1144,27 +1159,24 @@ Pops a received Crossfire Telemetry packet from the queue.
*/
static int luaCrossfireTelemetryPop(lua_State * L)
{
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo = new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
if (!luaInputTelemetryFifo) {
return 0;
}
}
auto queue = getTelemetryQueue();
uint8_t length = 0, data = 0;
if (luaInputTelemetryFifo->probe(length) && luaInputTelemetryFifo->size() >= uint32_t(length)) {
// length value includes the length field
luaInputTelemetryFifo->pop(length);
luaInputTelemetryFifo->pop(data); // command
lua_pushinteger(L, data);
lua_newtable(L);
for (uint8_t i=1; i<length-1; i++) {
luaInputTelemetryFifo->pop(data);
lua_pushinteger(L, i);
if (queue) {
uint8_t length = 0, data = 0;
if (queue->probe(length) && queue->size() >= uint32_t(length)) {
// length value includes the length field
queue->pop(length);
queue->pop(data); // command
lua_pushinteger(L, data);
lua_settable(L, -3);
lua_newtable(L);
for (uint8_t i=1; i<length-1; i++) {
queue->pop(data);
lua_pushinteger(L, i);
lua_pushinteger(L, data);
lua_settable(L, -3);
}
return 2;
}
return 2;
}
return 0;
@@ -1268,27 +1280,24 @@ Pops a received Ghost Telemetry packet from the queue.
*/
static int luaGhostTelemetryPop(lua_State * L)
{
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo = new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
if (!luaInputTelemetryFifo) {
return 0;
}
}
auto queue = getTelemetryQueue();
uint8_t length = 0, data = 0;
if (luaInputTelemetryFifo->probe(length) && luaInputTelemetryFifo->size() >= uint32_t(length)) {
// length value includes type(1B), payload, crc(1B)
luaInputTelemetryFifo->pop(length);
luaInputTelemetryFifo->pop(data); // type
lua_pushinteger(L, data); // return type
lua_newtable(L);
for (uint8_t i=0; i<length-2; i++) {
luaInputTelemetryFifo->pop(data);
lua_pushinteger(L, i + 1);
lua_pushinteger(L, data);
lua_settable(L, -3);
if (queue) {
uint8_t length = 0, data = 0;
if (queue->probe(length) && queue->size() >= uint32_t(length)) {
// length value includes type(1B), payload, crc(1B)
queue->pop(length);
queue->pop(data); // type
lua_pushinteger(L, data); // return type
lua_newtable(L);
for (uint8_t i=0; i<length-2; i++) {
queue->pop(data);
lua_pushinteger(L, i + 1);
lua_pushinteger(L, data);
lua_settable(L, -3);
}
return 2;
}
return 2;
}
return 0;
@@ -2193,8 +2202,8 @@ Get percent of already used Lua instructions in current script execution cycle.
static int luaGetUsage(lua_State * L)
{
#if defined(COLORLCD)
if (luaLvglManager && luaLvglManager->useLvglLayout()) {
lua_pushinteger(L, luaLvglManager->refreshInstructionsPercent);
if (luaScriptManager && luaScriptManager->useLvglLayout()) {
lua_pushinteger(L, luaScriptManager->refreshInstructionsPercent);
} else {
lua_pushinteger(L, instructionsPercent);
}
@@ -2592,30 +2601,10 @@ to the fields in the table returned by `model.getLogicalSwitch(switch)` identify
static int luaGetSwitchIndex(lua_State * L)
{
const char * name = luaL_checkstring(L, 1);
bool negate = false;
bool found = false;
swsrc_t idx;
swsrc_t idx = getSwitchIndex(name, true);
if (name[0] == '!') {
name++;
negate = true;
}
for (idx = SWSRC_NONE; idx < SWSRC_COUNT; idx++) {
if (isSwitchAvailable(idx, ModelCustomFunctionsContext)) {
char* s = getSwitchPositionName(idx);
if (!strncasecmp(s, name, 31)) {
found = true;
break;
}
}
}
if (found) {
if (negate)
idx = -idx;
if (idx != SWSRC_INVERT)
lua_pushinteger(L, idx);
}
else
lua_pushnil(L);
@@ -2715,8 +2704,7 @@ static int luaSwitches(lua_State * L)
} else
last = SWSRC_LAST;
lua_pushcfunction(L, luaNextSwitch);
lua_pushinteger(L, last);
lua_pushcfunction(L, luaNextSwitch); lua_pushinteger(L, last);
lua_pushinteger(L, first);
return 3;
}
@@ -2737,21 +2725,9 @@ This function is rather time consuming, and should not be used repeatedly in a s
static int luaGetSourceIndex(lua_State* const L)
{
const char* const name = luaL_checkstring(L, 1);
bool found = false;
mixsrc_t idx;
mixsrc_t idx = getSourceIndex(name, true);
for (idx = MIXSRC_NONE; idx <= MIXSRC_LAST_TELEM; idx++) {
if (isSourceAvailable(idx)) {
char srcName[maxSourceNameLength];
getSourceString(srcName, idx);
if (!strncasecmp(srcName, name)) {
found = true;
break;
}
}
}
if (found)
if (idx >= 0)
lua_pushinteger(L, idx);
else
lua_pushnil(L);
-6
View File
@@ -61,12 +61,6 @@ extern bool luaLcdAllowed;
class BitmapBuffer;
extern BitmapBuffer* luaLcdBuffer;
class LuaWidget;
extern LuaWidget* runningFS;
class LuaLvglManager;
extern LuaLvglManager* luaLvglManager;
extern uint32_t luaExtraMemoryUsage;
void luaInitThemesAndWidgets();
#endif
File diff suppressed because it is too large Load Diff
+92 -68
View File
@@ -24,6 +24,30 @@
#define LVGL_METATABLE "LVGL*"
#define LVGL_SIMPLEMETATABLE "LVGLSIMPLE*"
class LuaScriptManager;
class LvglDialog;
//-----------------------------------------------------------------------------
struct LvglParamFuncOrValue
{
public:
enum ParamType {
PVALUE,
PTXT,
};
int function;
union {
LcdFlags flags;
coord_t coord;
const char* txt;
uint32_t value;
};
void parse(lua_State *L, ParamType typ = PVALUE);
};
//-----------------------------------------------------------------------------
class LvglWidgetObjectBase
@@ -36,9 +60,6 @@ class LvglWidgetObjectBase
void push(lua_State *L);
void saveLvglObjectRef(int ref);
void getParams(lua_State *L, int index);
virtual void build(lua_State *L);
virtual bool callRefs(lua_State *L);
virtual void clearRefs(lua_State *L);
void clearChildRefs(lua_State *L);
@@ -47,12 +68,14 @@ class LvglWidgetObjectBase
virtual void hide() = 0;
virtual void enable() {};
virtual void disable() {};
virtual void close() {};
virtual void setColor(LcdFlags newColor) {}
virtual void setOpacity(uint8_t newOpa) {}
virtual void setPos(coord_t x, coord_t y) {}
virtual void setSize(coord_t w, coord_t h) {}
void create(lua_State *L, int index);
void update(lua_State *L);
virtual Window *getWindow() const = 0;
@@ -66,21 +89,22 @@ class LvglWidgetObjectBase
std::vector<int> lvglObjectRefs;
const char* metatable = nullptr;
bool clearRequest = false;
LuaLvglManager *lvglManager = nullptr;
LuaScriptManager *lvglManager = nullptr;
coord_t x = 0, y = 0, w = LV_SIZE_CONTENT, h = LV_SIZE_CONTENT;
LcdFlags color = COLOR2FLAGS(COLOR_THEME_SECONDARY1_INDEX);
LcdFlags currentColor = -1;
uint8_t opacity = LV_OPA_COVER;
int getColorFunction = LUA_REFNIL;
int getOpacityFunction = LUA_REFNIL;
int getVisibleFunction = LUA_REFNIL;
int getSizeFunction = LUA_REFNIL;
int getPosFunction = LUA_REFNIL;
LvglParamFuncOrValue color = { .function = LUA_REFNIL, .flags = COLOR2FLAGS(COLOR_THEME_SECONDARY1_INDEX)};
LvglParamFuncOrValue opacity = { .function = LUA_REFNIL, .value = LV_OPA_COVER};
virtual void build(lua_State *L);
virtual void refresh();
virtual void parseParam(lua_State *L, const char *key);
void getParams(lua_State *L, int index);
bool colorChanged(LcdFlags newColor);
void clearRef(lua_State *L, int& ref);
@@ -128,26 +152,23 @@ class LvglWidgetLabel : public LvglSimpleWidgetObject
void setFont(LcdFlags font);
void setAlign(LcdFlags align);
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
uint32_t textHash = -1;
const char *txt = "";
LcdFlags font = FONT(STD);
LcdFlags align = LEFT;
int getTextFunction = LUA_REFNIL;
int getFontFunction = LUA_REFNIL;
int getAlignFunction = LUA_REFNIL;
LvglParamFuncOrValue font = { .function = LUA_REFNIL, .flags = FONT(STD)};
LvglParamFuncOrValue align = { .function = LUA_REFNIL, .flags = LEFT};
LvglParamFuncOrValue txt = { .function = LUA_REFNIL, .txt = ""};
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setText(txt);
setFont(font);
setAlign(align);
setText(txt.txt);
setFont(font.flags);
setAlign(align.flags);
LvglSimpleWidgetObject::refresh();
}
};
@@ -164,8 +185,6 @@ class LvglWidgetLineBase : public LvglSimpleWidgetObject
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
protected:
bool rounded = false;
int dashGap = 0;
@@ -174,6 +193,7 @@ class LvglWidgetLineBase : public LvglSimpleWidgetObject
virtual void setLine() = 0;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
@@ -205,24 +225,30 @@ class LvglWidgetVLine : public LvglWidgetLineBase
class LvglWidgetLine : public LvglSimpleWidgetObject
{
public:
LvglWidgetLine() : LvglSimpleWidgetObject() {}
LvglWidgetLine();
~LvglWidgetLine();
void setColor(LcdFlags newColor) override;
void setOpacity(uint8_t newOpa) override;
void setPos(coord_t x, coord_t y) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
coord_t thickness = 1;
bool rounded = false;
size_t ptCnt = 0;
lv_point_t* pts = nullptr;
uint32_t ptsHash = -1;
lv_obj_t* parent = nullptr;
int getPointsFunction = LUA_REFNIL;
void setLine();
void getPt(lua_State* L, int n);
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
@@ -232,22 +258,27 @@ class LvglWidgetLine : public LvglSimpleWidgetObject
class LvglWidgetTriangle : public LvglSimpleWidgetObject
{
public:
LvglWidgetTriangle() : LvglSimpleWidgetObject() {}
LvglWidgetTriangle();
~LvglWidgetTriangle();
void setColor(LcdFlags newColor) override;
void setSize(coord_t w, coord_t h) override;
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
coord_t px[3] = {0}, py[3] = {0};
lv_point_t pts[3] = {0};
uint32_t ptsHash = -1;
MaskBitmap* mask = nullptr;
lv_obj_t* parent = nullptr;
int getPointsFunction = LUA_REFNIL;
void fillTriangle();
void fillLine(coord_t x1, coord_t x2, coord_t y);
void getPt(lua_State* L, int n);
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override;
};
@@ -290,9 +321,8 @@ class LvglWidgetBox : public LvglWidgetObject
public:
LvglWidgetBox() : LvglWidgetObject() {}
void build(lua_State *L) override;
protected:
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
@@ -302,11 +332,10 @@ class LvglWidgetSetting : public LvglWidgetObject
public:
LvglWidgetSetting() : LvglWidgetObject() {}
void build(lua_State *L) override;
protected:
const char *txt = "";
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -320,12 +349,11 @@ class LvglWidgetBorderedObject : public LvglWidgetObject
void setColor(LcdFlags newColor) override;
void setOpacity(uint8_t newOpa) override;
void build(lua_State *L) override;
protected:
coord_t thickness = 1;
bool filled = false;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -343,14 +371,12 @@ class LvglWidgetRoundObject : public LvglWidgetBorderedObject
void clearRefs(lua_State *L) override;
protected:
coord_t radius = 0;
int getRadiusFunction = LUA_REFNIL;
LvglParamFuncOrValue radius = { .function = LUA_REFNIL, .coord = 0};
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setRadius(radius);
setRadius(radius.coord);
LvglWidgetObject::refresh();
}
};
@@ -362,11 +388,10 @@ class LvglWidgetRectangle : public LvglWidgetBorderedObject
public:
LvglWidgetRectangle() : LvglWidgetBorderedObject() {}
void build(lua_State *L) override;
protected:
coord_t rounded = 0;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -377,9 +402,8 @@ class LvglWidgetCircle : public LvglWidgetRoundObject
public:
LvglWidgetCircle() : LvglWidgetRoundObject() {}
void build(lua_State *L) override;
protected:
void build(lua_State *L) override;
};
//-----------------------------------------------------------------------------
@@ -394,21 +418,19 @@ class LvglWidgetArc : public LvglWidgetRoundObject
void setStartAngle(coord_t angle);
void setEndAngle(coord_t angle);
void build(lua_State *L) override;
bool callRefs(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
coord_t startAngle = 0, endAngle = 0;
int getStartAngleFunction = LUA_REFNIL;
int getEndAngleFunction = LUA_REFNIL;
LvglParamFuncOrValue startAngle = { .function = LUA_REFNIL, .coord = 0};
LvglParamFuncOrValue endAngle = { .function = LUA_REFNIL, .coord = 0};
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
setStartAngle(startAngle);
setEndAngle(endAngle);
setStartAngle(startAngle.coord);
setEndAngle(endAngle.coord);
LvglWidgetRoundObject::refresh();
}
};
@@ -420,12 +442,11 @@ class LvglWidgetImage : public LvglWidgetObject
public:
LvglWidgetImage() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
std::string filename;
bool fillFrame = false;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -436,12 +457,11 @@ class LvglWidgetQRCode : public LvglWidgetObject
public:
LvglWidgetQRCode() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
std::string data;
LcdFlags bgColor = COLOR2FLAGS(COLOR_THEME_SECONDARY3_INDEX);
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -452,7 +472,7 @@ class LvglWidgetTextButtonBase : public LvglWidgetObject
public:
LvglWidgetTextButtonBase() : LvglWidgetObject(LVGL_SIMPLEMETATABLE)
{
color = -1; // ignore unless overridden
color.flags = -1; // ignore unless overridden
}
void setText(const char *s);
@@ -485,13 +505,13 @@ class LvglWidgetTextButton : public LvglWidgetTextButtonBase
void setFont(LcdFlags font);
void setChecked(bool check);
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
bool checked = false;
int longPressFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
void refresh() override
{
@@ -509,12 +529,12 @@ class LvglWidgetMomentaryButton : public LvglWidgetTextButtonBase
void setFont(LcdFlags font);
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
int releaseFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -525,13 +545,13 @@ class LvglWidgetToggleSwitch : public LvglWidgetObject
public:
LvglWidgetToggleSwitch() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
int getStateFunction = LUA_REFNIL;
int setStateFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -542,7 +562,6 @@ class LvglWidgetTextEdit : public LvglWidgetObject
public:
LvglWidgetTextEdit() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -552,6 +571,7 @@ class LvglWidgetTextEdit : public LvglWidgetObject
int setFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -562,7 +582,6 @@ class LvglWidgetNumberEdit : public LvglWidgetObject
public:
LvglWidgetNumberEdit() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -572,6 +591,7 @@ class LvglWidgetNumberEdit : public LvglWidgetObject
int setFunction = LUA_REFNIL;
int dispFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -582,7 +602,7 @@ class LvglWidgetSliderBase : public LvglWidgetObject
public:
LvglWidgetSliderBase() : LvglWidgetObject(LVGL_SIMPLEMETATABLE)
{
color = -1;
color.flags = -1;
}
void setColor(LcdFlags newColor) override;
@@ -605,6 +625,7 @@ class LvglWidgetSlider : public LvglWidgetSliderBase
public:
LvglWidgetSlider() : LvglWidgetSliderBase() {}
protected:
void build(lua_State *L) override;
};
@@ -615,6 +636,7 @@ class LvglWidgetVerticalSlider : public LvglWidgetSliderBase
public:
LvglWidgetVerticalSlider() : LvglWidgetSliderBase() {}
protected:
void build(lua_State *L) override;
};
@@ -625,7 +647,6 @@ class LvglWidgetPage : public LvglWidgetObject
public:
LvglWidgetPage() : LvglWidgetObject() {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -635,6 +656,7 @@ class LvglWidgetPage : public LvglWidgetObject
int backActionFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -645,14 +667,16 @@ class LvglWidgetDialog : public LvglWidgetObject
public:
LvglWidgetDialog() : LvglWidgetObject() {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
void close() override;
protected:
const char *title = nullptr;
LvglDialog* dialog = nullptr;
int closeFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -663,7 +687,6 @@ class LvglWidgetConfirmDialog : public LvglWidgetObject
public:
LvglWidgetConfirmDialog() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
void clearRefs(lua_State *L) override;
protected:
@@ -673,6 +696,7 @@ class LvglWidgetConfirmDialog : public LvglWidgetObject
int confirmFunction = LUA_REFNIL;
int cancelFunction = LUA_REFNIL;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -683,13 +707,12 @@ class LvglWidgetMessageDialog : public LvglWidgetObject
public:
LvglWidgetMessageDialog() : LvglWidgetObject(LVGL_SIMPLEMETATABLE) {}
void build(lua_State *L) override;
protected:
const char *title = nullptr;
const char *message = nullptr;
const char *details = nullptr;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -716,12 +739,11 @@ class LvglWidgetChoice : public LvglWidgetPicker
public:
LvglWidgetChoice() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
std::string title;
std::vector<std::string> values;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -732,6 +754,7 @@ class LvglWidgetFontPicker : public LvglWidgetPicker
public:
LvglWidgetFontPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -742,6 +765,7 @@ class LvglWidgetAlignPicker : public LvglWidgetPicker
public:
LvglWidgetAlignPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -752,6 +776,7 @@ class LvglWidgetColorPicker : public LvglWidgetPicker
public:
LvglWidgetColorPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -762,6 +787,7 @@ class LvglWidgetTimerPicker : public LvglWidgetPicker
public:
LvglWidgetTimerPicker() : LvglWidgetPicker() {}
protected:
void build(lua_State *L) override;
};
@@ -772,11 +798,10 @@ class LvglWidgetSwitchPicker : public LvglWidgetPicker
public:
LvglWidgetSwitchPicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
uint32_t filter = 0xFFFFFFFF;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
@@ -787,11 +812,10 @@ class LvglWidgetSourcePicker : public LvglWidgetPicker
public:
LvglWidgetSourcePicker() : LvglWidgetPicker() {}
void build(lua_State *L) override;
protected:
uint32_t filter = 0xFFFFFFFF;
void build(lua_State *L) override;
void parseParam(lua_State *L, const char *key) override;
};
+62 -20
View File
@@ -31,6 +31,8 @@
#define MAX_INSTRUCTIONS (20000 / 100)
LuaScriptManager *luaScriptManager = nullptr;
#if defined(HARDWARE_TOUCH)
uint32_t LuaEventHandler::downTime = 0;
uint32_t LuaEventHandler::tapTime = 0;
@@ -140,7 +142,7 @@ void LuaEventHandler::event_cb(lv_event_t* e)
#endif
}
void LuaEventHandler::onClicked()
void LuaEventHandler::onClickedEvent()
{
#if defined(HARDWARE_TOUCH)
auto click_source = lv_indev_get_act();
@@ -167,7 +169,7 @@ void LuaEventHandler::onClicked()
luaPushEvent(EVT_KEY_BREAK(KEY_ENTER));
}
void LuaEventHandler::onCancel() {
void LuaEventHandler::onCancelEvent() {
luaPushEvent(EVT_KEY_BREAK(KEY_EXIT));
}
@@ -217,18 +219,41 @@ void LuaWidget::redraw_cb(lv_event_t* e)
buf.setClippingRect(clipping.x1 - a.x1, clipping.x2 + 1 - a.x1,
clipping.y1 - a.y1, clipping.y2 + 1 - a.y1);
auto save = luaScriptManager;
luaScriptManager = widget;
widget->refresh(&buf);
luaScriptManager = save;
}
}
LuaWidget::LuaWidget(const WidgetFactory* factory, Window* parent,
const rect_t& rect, WidgetPersistentData* persistentData,
int luaScriptContextRef, int zoneRectDataRef, int optionsDataRef) :
int zoneRectDataRef, int optionsDataRef,
int createFunctionRef, std::string path) :
Widget(factory, parent, rect, persistentData),
zoneRectDataRef(zoneRectDataRef), optionsDataRef(optionsDataRef),
errorMessage(nullptr)
{
this->luaScriptContextRef = luaScriptContextRef;
// Push create function
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunctionRef);
// Push stored zone for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, zoneRectDataRef);
// Push stored options for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionsDataRef);
// Push widget folder path
lua_pushstring(lsWidgets, path.c_str());
auto save = luaScriptManager;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 3, 1, 0) == LUA_OK) {
luaScriptContextRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
} else {
luaScriptContextRef = LUA_NOREF;
setErrorMessage("create()");
}
luaScriptManager = save;
if (useLvglLayout()) {
update();
@@ -252,7 +277,7 @@ void LuaWidget::onClicked()
return;
}
LuaEventHandler::onClicked();
LuaScriptManager::onClickedEvent();
}
void LuaWidget::onCancel()
@@ -262,7 +287,7 @@ void LuaWidget::onCancel()
return;
}
LuaEventHandler::onCancel();
LuaScriptManager::onCancelEvent();
}
void LuaWidget::checkEvents()
@@ -286,8 +311,9 @@ void LuaWidget::checkEvents()
lv_obj_get_coords(lvobj, &a);
// Check widget is at least partially visible
if (a.x2 >= 0 && a.x1 < LCD_W) {
auto save = luaScriptManager;
PROTECT_LUA() {
luaLvglManager = this;
luaScriptManager = this;
refresh(nullptr);
if (!errorMessage) {
if (!callRefs(lsWidgets)) {
@@ -298,7 +324,7 @@ void LuaWidget::checkEvents()
} else {
// TODO: error handling
}
luaLvglManager = nullptr;
luaScriptManager = save;
UNPROTECT_LUA();
}
}
@@ -325,7 +351,7 @@ void LuaWidget::update()
// Get options table and update values
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionsDataRef);
int i = 0;
for (const ZoneOption* option = getOptions(); option->name; option++, i++) {
for (const ZoneOption* option = getOptionDefinitions(); option->name; option++, i++) {
auto optVal = getOptionValue(i);
switch (option->type) {
case ZoneOption::String:
@@ -347,7 +373,7 @@ void LuaWidget::update()
lua_setfield(lsWidgets, -2, option->name);
}
if (useLvglLayout()) luaLvglManager = this;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 2, 0, 0) != 0)
setErrorMessage("update()");
@@ -370,7 +396,7 @@ void LuaWidget::update()
}
}
luaLvglManager = nullptr;
luaScriptManager = nullptr;
}
// Update table on top of Lua stack - set entry with name 'idx' to value 'val'
@@ -499,12 +525,10 @@ void LuaWidget::refresh(BitmapBuffer* dc)
// scripts
bool lla = luaLcdAllowed;
luaLcdAllowed = true;
runningFS = this;
if (lua_pcall(lsWidgets, 3, 0, 0) != 0) {
setErrorMessage("refresh()");
}
runningFS = nullptr;
// Remove LCD
luaLcdAllowed = lla;
luaLcdBuffer = nullptr;
@@ -521,18 +545,19 @@ void LuaWidget::background()
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaFactory()->backgroundFunction);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, luaScriptContextRef);
runningFS = this;
auto save = luaScriptManager;
luaScriptManager = this;
if (lua_pcall(lsWidgets, 1, 0, 0) != 0) {
setErrorMessage("background()");
}
runningFS = nullptr;
luaScriptManager = save;
}
}
void LuaWidget::onEvent(event_t event)
{
if (fullscreen) {
LuaEventHandler::onLuaEvent(event);
LuaScriptManager::onLuaEvent(event);
}
Widget::onEvent(event);
}
@@ -547,10 +572,10 @@ bool LuaWidget::useLvglLayout() const { return luaFactory()->useLvglLayout(); }
bool LuaWidget::isAppMode() const
{
return fullscreen && ViewMain::instance()->isAppMode();
return ((WidgetsContainer*)parent)->isAppMode();
}
void LuaLvglManager::saveLvglObjectRef(int ref)
void LuaScriptManager::saveLvglObjectRef(int ref)
{
if (tempParent)
tempParent->saveLvglObjectRef(ref);
@@ -558,7 +583,7 @@ void LuaLvglManager::saveLvglObjectRef(int ref)
lvglObjectRefs.push_back(ref);
}
void LuaLvglManager::clearRefs(lua_State *L)
void LuaScriptManager::clearRefs(lua_State *L)
{
for (size_t i = 0; i < lvglObjectRefs.size(); i += 1) {
lua_rawgeti(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
@@ -569,7 +594,7 @@ void LuaLvglManager::clearRefs(lua_State *L)
lvglObjectRefs.clear();
}
bool LuaLvglManager::callRefs(lua_State *L)
bool LuaScriptManager::callRefs(lua_State *L)
{
for (size_t i = 0; i < lvglObjectRefs.size(); i += 1) {
lua_rawgeti(L, LUA_REGISTRYINDEX, lvglObjectRefs[i]);
@@ -579,3 +604,20 @@ bool LuaLvglManager::callRefs(lua_State *L)
}
return true;
}
void LuaScriptManager::createTelemetryQueue()
{
if (luaInputTelemetryFifo == nullptr) {
luaInputTelemetryFifo = new TelemetryQueue();
registerTelemetryQueue(luaInputTelemetryFifo);
}
}
LuaScriptManager::~LuaScriptManager()
{
if (luaInputTelemetryFifo == nullptr) {
deregisterTelemetryQueue(luaInputTelemetryFifo);
delete luaInputTelemetryFifo;
luaInputTelemetryFifo = nullptr;
}
}
+40 -30
View File
@@ -28,6 +28,7 @@
#include "lua_states.h"
#include "lua_api.h"
#include "lua_lvgl_widget.h"
#include "telemetry/telemetry.h"
#include "edgetx_types.h"
@@ -35,10 +36,37 @@
class LuaWidgetFactory;
class LuaLvglManager
class LuaEventHandler
{
public:
LuaEventHandler() = default;
void setupHandler(Window* w);
void removeHandler(Window* w);
protected:
#if defined(HARDWARE_TOUCH)
// "tap" handling
static uint32_t downTime;
static uint32_t tapTime;
static uint32_t tapCount;
// "swipe" / "slide" handling
static tmr10ms_t swipeTimeOut;
static bool _sliding;
static coord_t _startX;
static coord_t _startY;
#endif
static void event_cb(lv_event_t* e);
void onClickedEvent();
void onCancelEvent();
void onLuaEvent(event_t event);
};
class LuaScriptManager : public LuaEventHandler
{
public:
LuaLvglManager() = default;
LuaScriptManager() = default;
~LuaScriptManager();
std::vector<int> getLvglObjectRefs() const { return lvglObjectRefs; }
void saveLvglObjectRef(int ref);
@@ -62,46 +90,26 @@ class LuaLvglManager
uint8_t refreshInstructionsPercent;
void createTelemetryQueue();
TelemetryQueue* telemetryQueue() { return luaInputTelemetryFifo; }
protected:
int luaScriptContextRef = 0;
std::vector<int> lvglObjectRefs;
LvglWidgetObjectBase* tempParent = nullptr;
};
class LuaEventHandler
{
public:
LuaEventHandler() = default;
void setupHandler(Window* w);
void removeHandler(Window* w);
protected:
#if defined(HARDWARE_TOUCH)
// "tap" handling
static uint32_t downTime;
static uint32_t tapTime;
static uint32_t tapCount;
// "swipe" / "slide" handling
static tmr10ms_t swipeTimeOut;
static bool _sliding;
static coord_t _startX;
static coord_t _startY;
#if defined(LUA)
TelemetryQueue* luaInputTelemetryFifo = nullptr;
#endif
static void event_cb(lv_event_t* e);
void onClicked();
void onCancel();
void onLuaEvent(event_t event);
};
class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
class LuaWidget : public Widget, public LuaScriptManager
{
friend class LuaWidgetFactory;
public:
LuaWidget(const WidgetFactory* factory, Window* parent, const rect_t& rect,
WidgetPersistentData* persistentData, int luaScriptContextRef, int zoneRectDataRef,
int optionsDataRef);
WidgetPersistentData* persistentData, int zoneRectDataRef,
int optionsDataRef, int createFunctionRef, std::string path);
~LuaWidget() override;
#if defined(DEBUG_WINDOWS)
@@ -160,3 +168,5 @@ class LuaWidget : public Widget, public LuaEventHandler, public LuaLvglManager
static void redraw_cb(lv_event_t *e);
};
extern LuaScriptManager* luaScriptManager;
+220 -17
View File
@@ -24,18 +24,26 @@
#include "lua_api.h"
#include "lua_states.h"
#include "strhelpers.h"
#define MAX_INSTRUCTIONS (20000/100)
LuaWidgetFactory::LuaWidgetFactory(const char* name, ZoneOption* widgetOptions,
int createFunction) :
LuaWidgetFactory::LuaWidgetFactory(const char* name, ZoneOption* widgetOptions, int optionDefinitionsReference,
int createFunction, int updateFunction, int refreshFunction,
int backgroundFunction, int translateFunction, bool lvglLayout,
const char* filename) :
WidgetFactory(name, widgetOptions),
optionDefinitionsReference(optionDefinitionsReference),
createFunction(createFunction),
updateFunction(0),
refreshFunction(0),
backgroundFunction(0),
translateFunction(0)
updateFunction(updateFunction),
refreshFunction(refreshFunction),
backgroundFunction(backgroundFunction),
translateFunction(translateFunction),
lvglLayout(lvglLayout),
path(filename)
{
path = path.substr(0, path.rfind("/") + 1);
translateOptions(widgetOptions);
}
LuaWidgetFactory::~LuaWidgetFactory() {
@@ -45,7 +53,7 @@ LuaWidgetFactory::~LuaWidgetFactory() {
delete displayName;
}
auto option = getOptions();
auto option = getDefaultOptions();
while (option && option->name != nullptr) {
if (option->displayName) {
delete option->displayName;
@@ -62,7 +70,6 @@ Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect,
initPersistentData(persistentData, init);
luaSetInstructionsLimit(lsWidgets, MAX_INSTRUCTIONS);
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, createFunction);
// Make 'zone' table for 'create' call
lua_newtable(lsWidgets);
@@ -75,8 +82,6 @@ Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect,
// Store the zone data in registry for later updates
int zoneRectDataRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
// Push stored zone for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, zoneRectDataRef);
// Create options table
lua_newtable(lsWidgets);
@@ -99,14 +104,8 @@ Widget* LuaWidgetFactory::create(Window* parent, const rect_t& rect,
// Store the options data in registry for later updates
int optionsDataRef = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
// Push stored options for 'create' call
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionsDataRef);
bool err = lua_pcall(lsWidgets, 2, 1, 0);
int widgetData = err ? LUA_NOREF : luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
LuaWidget* lw = new LuaWidget(this, parent, rect, persistentData, widgetData, zoneRectDataRef, optionsDataRef);
if (err) lw->setErrorMessage("create()");
return lw;
return new LuaWidget(this, parent, rect, persistentData, zoneRectDataRef, optionsDataRef, createFunction, path);
}
void LuaWidgetFactory::translateOptions(ZoneOption * options)
@@ -144,3 +143,207 @@ void LuaWidgetFactory::translateOptions(ZoneOption * options)
}
lua_pop(lsWidgets, 1);
}
static int switchValue()
{
int v = SWSRC_INVERT;
if (lua_istable(lsWidgets, -1)) {
// Find first available
int t = lua_gettop(lsWidgets);
for (lua_pushnil(lsWidgets); v == SWSRC_INVERT && lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
v = getSwitchIndex(luaL_checkstring(lsWidgets, -1), false);
}
lua_settop(lsWidgets, t);
} else if (lua_type(lsWidgets, -1) == LUA_TSTRING) {
v = getSwitchIndex(lua_tostring(lsWidgets, -1), true);
} else {
v = luaL_checkinteger(lsWidgets, -1);
}
if (v == SWSRC_INVERT) v = SWSRC_NONE;
return v;
}
static int sourceValue()
{
int v = -1;
if (lua_istable(lsWidgets, -1)) {
// Find first available
int t = lua_gettop(lsWidgets);
for (lua_pushnil(lsWidgets); v < 0 && lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
v = getSourceIndex(luaL_checkstring(lsWidgets, -1), false);
}
lua_settop(lsWidgets, t);
} else if (lua_type(lsWidgets, -1) == LUA_TSTRING) {
v = getSourceIndex(lua_tostring(lsWidgets, -1), true);
} else {
v = luaL_checkunsigned(lsWidgets, -1);
}
if (v == -1) v = MIXSRC_NONE;
return v;
}
// Parse the options table to get the default, min and max values
// Called when the widget settings dialog is opened to get values
// for current loaded model.
const void LuaWidgetFactory::parseOptionDefaults() const
{
if (optionDefinitionsReference == LUA_REFNIL) {
// TRACE("parseOptionDefaults() no options");
return;
}
PROTECT_LUA()
{
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, optionDefinitionsReference);
ZoneOption *option = (ZoneOption*)options;
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2), option->name;
lua_pop(lsWidgets, 1)) {
// TRACE("parsing option %d", count);
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++) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
switch (field) {
case 2:
if (option->type == ZoneOption::Switch) {
option->deflt.signedValue = switchValue();
} else if (option->type == ZoneOption::Source) {
option->deflt.unsignedValue = sourceValue();
} else if (option->type == ZoneOption::Integer) {
option->deflt.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Bool) {
option->deflt.boolValue = (luaL_checkunsigned(lsWidgets, -1) != 0);
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
strncpy(option->deflt.stringValue, luaL_checkstring(lsWidgets, -1),
LEN_ZONE_OPTION_STRING);
} else {
option->deflt.unsignedValue = luaL_checkunsigned(lsWidgets, -1);
}
break;
case 3:
if (option->type == ZoneOption::Switch) {
option->min.signedValue = switchValue();
} else if (option->type == ZoneOption::Source) {
option->min.unsignedValue = sourceValue();
} else if (option->type == ZoneOption::Integer || option->type == ZoneOption::Slider) {
option->min.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Choice) {
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is a table
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
option->choiceValues.push_back(luaL_checkstring(lsWidgets, -1));
}
} else if (option->type == ZoneOption::File) {
option->fileSelectPath = luaL_checkstring(lsWidgets, -1);
}
break;
case 4:
if (option->type == ZoneOption::Switch) {
option->max.signedValue = switchValue();
} else if (option->type == ZoneOption::Source) {
option->max.unsignedValue = sourceValue();
} else if (option->type == ZoneOption::Integer || option->type == ZoneOption::Slider) {
option->max.signedValue = luaL_checkinteger(lsWidgets, -1);
}
break;
default:
break;
}
}
option++;
}
}
else
{
TRACE("error in theme/widget options");
}
UNPROTECT_LUA();
return;
}
// Parse options table to get name and type values.
// Called on radio startup to build base data for all widgtes.
ZoneOption* LuaWidgetFactory::parseOptionDefinitions(int reference)
{
if (reference == LUA_REFNIL) {
// TRACE("parseOptionDefinitions() no options");
return NULL;
}
int count = 0;
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
count++;
}
// TRACE("we have %d options", count);
if (count > MAX_WIDGET_OPTIONS) {
count = MAX_WIDGET_OPTIONS;
// TRACE("limited to %d options", count);
}
ZoneOption *options = new ZoneOption[count + 1];
if (!options) {
return NULL;
}
PROTECT_LUA()
{
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
ZoneOption *option = options;
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2), count-- > 0;
lua_pop(lsWidgets, 1)) {
// TRACE("parsing option %d", count);
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++) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
switch (field) {
case 0:
option->name = luaL_checkstring(lsWidgets, -1);
option->displayName = nullptr;
// TRACE("name = %s", option->name);
break;
case 1:
option->type = (ZoneOption::Type)luaL_checkinteger(lsWidgets, -1);
option->deflt.unsignedValue = 0;
// set some sensible defaults
if (option->type == ZoneOption::Integer) {
option->min.signedValue = -100;
option->max.signedValue = 100;
} else if (option->type == ZoneOption::Switch) {
option->min.signedValue = SWSRC_FIRST;
option->max.signedValue = SWSRC_LAST;
} else if (option->type == ZoneOption::Timer) {
option->min.unsignedValue = 0;
option->max.unsignedValue = MAX_TIMERS - 1;
} else if (option->type == ZoneOption::TextSize) {
option->min.unsignedValue = FONT_STD_INDEX;
option->max.unsignedValue = FONTS_COUNT - 1;
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
option->deflt.stringValue[0] = 0;
} else if (option->type == ZoneOption::Slider) {
option->min.unsignedValue = 0;
option->max.unsignedValue = 9;
}
break;
default:
break;
}
}
option++;
}
option->name = NULL; // sentinel
}
else
{
TRACE("error in theme/widget options");
delete[] options;
return NULL;
}
UNPROTECT_LUA();
return options;
}
+9 -4
View File
@@ -25,12 +25,13 @@
class LuaWidgetFactory : public WidgetFactory
{
friend void luaLoadWidgetCallback();
friend class LuaWidget;
public:
LuaWidgetFactory(const char* name, ZoneOption* widgetOptions,
int createFunction);
LuaWidgetFactory(const char* name, ZoneOption* widgetOptions, int optionDefinitionsReference,
int createFunction, int updateFunction, int refreshFunction,
int backgroundFunction, int translateFunction, bool lvgllayout,
const char* filename);
~LuaWidgetFactory();
Widget* create(Window* parent, const rect_t& rect,
@@ -41,14 +42,18 @@ class LuaWidgetFactory : public WidgetFactory
bool useLvglLayout() const { return lvglLayout; }
static ZoneOption* parseOptionDefinitions(int reference);
const void parseOptionDefaults() const override;
protected:
void translateOptions(ZoneOption * options);
int optionDefinitionsReference;
int createFunction;
int updateFunction;
int refreshFunction;
int backgroundFunction;
int translateFunction;
int settingsFunction;
bool lvglLayout;
std::string path;
};
+13 -133
View File
@@ -98,123 +98,12 @@ void luaSetInstructionsLimit(lua_State * L, int count)
#endif
}
ZoneOption *createOptionsArray(int reference, uint8_t maxOptions)
{
if (reference == 0) {
// TRACE("createOptionsArray() no options");
return NULL;
}
int count = 0;
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
count++;
}
// TRACE("we have %d options", count);
if (count > maxOptions) {
count = maxOptions;
// TRACE("limited to %d options", count);
}
ZoneOption *options = new ZoneOption[count + 1];
if (!options) {
return NULL;
}
PROTECT_LUA()
{
lua_rawgeti(lsWidgets, LUA_REGISTRYINDEX, reference);
ZoneOption *option = options;
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2), count-- > 0;
lua_pop(lsWidgets, 1)) {
// TRACE("parsing option %d", count);
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++) {
luaL_checktype(lsWidgets, -2, LUA_TNUMBER); // key is number
switch (field) {
case 0:
option->name = luaL_checkstring(lsWidgets, -1);
option->displayName = nullptr;
// TRACE("name = %s", option->name);
break;
case 1:
option->type = (ZoneOption::Type)luaL_checkinteger(lsWidgets, -1);
option->deflt.unsignedValue = 0;
// set some sensible defaults
if (option->type == ZoneOption::Integer) {
option->min.signedValue = -100;
option->max.signedValue = 100;
} else if (option->type == ZoneOption::Switch) {
option->min.signedValue = SWSRC_FIRST;
option->max.signedValue = SWSRC_LAST;
} else if (option->type == ZoneOption::Timer) {
option->min.unsignedValue = 0;
option->max.unsignedValue = MAX_TIMERS - 1;
} else if (option->type == ZoneOption::TextSize) {
option->min.unsignedValue = FONT_STD_INDEX;
option->max.unsignedValue = FONTS_COUNT - 1;
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
option->deflt.stringValue[0] = 0;
} else if (option->type == ZoneOption::Slider) {
option->min.unsignedValue = 0;
option->max.unsignedValue = 9;
}
break;
case 2:
if (option->type == ZoneOption::Integer || option->type == ZoneOption::Switch) {
option->deflt.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Bool) {
option->deflt.boolValue = (luaL_checkunsigned(lsWidgets, -1) != 0);
} else if (option->type == ZoneOption::String || option->type == ZoneOption::File) {
strncpy(option->deflt.stringValue, luaL_checkstring(lsWidgets, -1),
LEN_ZONE_OPTION_STRING);
} else {
option->deflt.unsignedValue = luaL_checkunsigned(lsWidgets, -1);
}
break;
case 3:
if (option->type == ZoneOption::Integer || option->type == ZoneOption::Switch || option->type == ZoneOption::Slider) {
option->min.signedValue = luaL_checkinteger(lsWidgets, -1);
} else if (option->type == ZoneOption::Choice) {
luaL_checktype(lsWidgets, -1, LUA_TTABLE); // value is a table
for (lua_pushnil(lsWidgets); lua_next(lsWidgets, -2); lua_pop(lsWidgets, 1)) {
option->choiceValues.push_back(luaL_checkstring(lsWidgets, -1));
}
} else if (option->type == ZoneOption::File) {
option->fileSelectPath = luaL_checkstring(lsWidgets, -1);
}
break;
case 4:
if (option->type == ZoneOption::Integer || option->type == ZoneOption::Switch || option->type == ZoneOption::Slider) {
option->max.signedValue = luaL_checkinteger(lsWidgets, -1);
}
break;
}
}
option++;
}
option->name = NULL; // sentinel
}
else
{
TRACE("error in theme/widget options");
delete[] options;
return NULL;
}
UNPROTECT_LUA();
return options;
}
void luaLoadWidgetCallback()
void luaLoadWidgetCallback(const char* filename)
{
TRACE("luaLoadWidgetCallback()");
const char * name=NULL;
int widgetOptions = 0, createFunction = 0, updateFunction = 0, settingsFunction = 0,
int optionDefinitionsReference = LUA_REFNIL, createFunction = 0, updateFunction = 0,
refreshFunction = 0, backgroundFunction = 0, translateFunction = 0;
bool lvglLayout = false;
@@ -226,7 +115,7 @@ void luaLoadWidgetCallback()
name = luaL_checkstring(lsWidgets, -1);
}
else if (!strcmp(key, "options")) {
widgetOptions = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
optionDefinitionsReference = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcmp(key, "create")) {
@@ -249,34 +138,25 @@ void luaLoadWidgetCallback()
translateFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcmp(key, "settings")) {
settingsFunction = luaL_ref(lsWidgets, LUA_REGISTRYINDEX);
lua_pushnil(lsWidgets);
}
else if (!strcasecmp(key, "useLvgl")) {
lvglLayout = lua_toboolean(lsWidgets, -1);
}
}
if (name && createFunction) {
ZoneOption * options = createOptionsArray(widgetOptions, MAX_WIDGET_OPTIONS);
ZoneOption * options = LuaWidgetFactory::parseOptionDefinitions(optionDefinitionsReference);
if (options) {
LuaWidgetFactory * factory = new LuaWidgetFactory(name, options, createFunction);
factory->updateFunction = updateFunction;
factory->refreshFunction = refreshFunction;
factory->backgroundFunction = backgroundFunction;
factory->translateFunction = translateFunction;
factory->settingsFunction = settingsFunction;
factory->translateOptions(options);
factory->lvglLayout = lvglLayout;
new LuaWidgetFactory(name, options, optionDefinitionsReference,
createFunction, updateFunction, refreshFunction, backgroundFunction,
translateFunction, lvglLayout, filename);
TRACE("Loaded Lua widget %s", name);
}
}
}
void luaLoadFile(const char * filename, void (*callback)())
static void luaLoadFile(const char * filename, std::function<void()> callback)
{
if (lsWidgets == NULL || callback == NULL)
if (lsWidgets == NULL)
return;
TRACE("luaLoadFile(%s)", filename);
@@ -286,7 +166,7 @@ void luaLoadFile(const char * filename, void (*callback)())
PROTECT_LUA() {
if (luaLoadScriptFileToState(lsWidgets, filename, LUA_SCRIPT_LOAD_MODE) == SCRIPT_OK) {
if (lua_pcall(lsWidgets, 0, 1, 0) == LUA_OK && lua_istable(lsWidgets, -1)) {
(*callback)();
callback();
}
else {
TRACE("luaLoadFile(%s): Error parsing script: %s", filename, lua_tostring(lsWidgets, -1));
@@ -301,7 +181,7 @@ void luaLoadFile(const char * filename, void (*callback)())
UNPROTECT_LUA();
}
void luaLoadFiles(const char * directory, void (*callback)())
static void luaLoadFiles(const char * directory)
{
char path[LUA_FULLPATH_MAXLEN+1];
FILINFO fno;
@@ -324,7 +204,7 @@ void luaLoadFiles(const char * directory, void (*callback)())
strcpy(&path[pathlen], fno.fname);
strcat(&path[pathlen], LUA_WIDGET_FILENAME);
if (isFileAvailable(path)) {
luaLoadFile(path, callback);
luaLoadFile(path, [=]() { luaLoadWidgetCallback(path); });
}
}
}
@@ -374,7 +254,7 @@ void luaInitThemesAndWidgets()
}
UNPROTECT_LUA();
TRACE("lsWidgets %p", lsWidgets);
luaLoadFiles(WIDGETS_PATH, luaLoadWidgetCallback);
luaLoadFiles(WIDGETS_PATH);
luaDoGc(lsWidgets, true);
}
}
+102 -28
View File
@@ -427,9 +427,9 @@ char *getCustomSwitchesGroupName(char *dest, uint8_t idx)
return dest;
}
char *getSwitchName(char *dest, uint8_t idx)
char *getSwitchName(char *dest, uint8_t idx, bool defaultOnly)
{
if (switchHasCustomName(idx)) {
if (!defaultOnly && switchHasCustomName(idx)) {
dest = strAppend(dest, switchGetCustomName(idx), LEN_SWITCH_NAME);
} else {
dest = strAppend(dest, switchGetName(idx), LEN_SWITCH_NAME);
@@ -464,7 +464,7 @@ const char *getSwitchPositionSymbol(uint8_t pos)
return _switch_state_str[pos + 1];
}
char *getSwitchPositionName(char *dest, swsrc_t idx)
char *getSwitchPositionName(char *dest, swsrc_t idx, bool defaultOnly)
{
if (idx == SWSRC_NONE) {
return strcpy(dest, STR_EMPTY);
@@ -480,7 +480,7 @@ char *getSwitchPositionName(char *dest, swsrc_t idx)
if (idx <= SWSRC_LAST_SWITCH) {
div_t swinfo = switchInfo(idx);
s = getSwitchName(s, swinfo.quot);
s = getSwitchName(s, swinfo.quot, defaultOnly);
s = strAppend(s, getSwitchPositionSymbol(swinfo.rem), 2);
*s = '\0';
} else if (idx <= SWSRC_LAST_MULTIPOS_SWITCH) {
@@ -522,9 +522,42 @@ char *getSwitchPositionName(char *dest, swsrc_t idx)
return dest;
}
const char *getAnalogLabel(uint8_t type, uint8_t idx)
bool switchCanHaveCustomName(swsrc_t idx)
{
if (analogHasCustomLabel(type, idx)) return analogGetCustomLabel(type, idx);
return (idx >= SWSRC_FIRST_SWITCH && idx <= SWSRC_LAST_SWITCH);
}
int getSwitchIndex(const char* name, bool all)
{
bool negate = false;
if (name[0] == '!') {
name++;
negate = true;
}
for (swsrc_t idx = SWSRC_NONE; idx < SWSRC_COUNT; idx++) {
if (all || isSwitchAvailable(idx, ModelCustomFunctionsContext)) {
char* s;
if (switchCanHaveCustomName(idx)) {
// Check default name
s = getSwitchPositionName(idx, true);
if (!strcasecmp(s, name))
return negate ? -idx : idx;
}
s = getSwitchPositionName(idx);
if (!strcasecmp(s, name))
return negate ? -idx : idx;
}
}
return SWSRC_INVERT; // Not found
}
const char *getAnalogLabel(uint8_t type, uint8_t idx, bool defaultOnly)
{
if (!defaultOnly && analogHasCustomLabel(type, idx))
return analogGetCustomLabel(type, idx);
if (type == ADC_INPUT_MAIN) {
// main controls: translated label is stored in "short label"
@@ -566,15 +599,15 @@ const char *getAnalogShortLabel(uint8_t idx)
return "";
}
const char *getMainControlLabel(uint8_t idx)
const char *getMainControlLabel(uint8_t idx, bool defaultOnly)
{
return getAnalogLabel(ADC_INPUT_MAIN, idx);
return getAnalogLabel(ADC_INPUT_MAIN, idx, defaultOnly);
}
const char *getTrimLabel(uint8_t idx)
const char *getTrimLabel(uint8_t idx, bool defaultOnly)
{
if (idx < adcGetMaxInputs(ADC_INPUT_MAIN)) {
return getMainControlLabel(idx);
return getMainControlLabel(idx, defaultOnly);
}
// TODO: replace with string from HW def
@@ -595,15 +628,15 @@ const char *getTrimSourceLabel(uint16_t src_raw, int8_t trim_src)
}
}
const char *getPotLabel(uint8_t idx)
const char *getPotLabel(uint8_t idx, bool defaultOnly)
{
return getAnalogLabel(ADC_INPUT_FLEX, idx);
return getAnalogLabel(ADC_INPUT_FLEX, idx, defaultOnly);
}
// this should be declared in header, but it used so much foreign symbols that
// we declare it in cpp-file and pre-instantiate it for the uses
template <size_t L>
char *getSourceString(char (&destRef)[L], mixsrc_t idx)
char *getSourceString(char (&destRef)[L], mixsrc_t idx, bool defaultOnly)
{
size_t dest_len = L;
char* dest = destRef;
@@ -622,7 +655,7 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
static_assert(L > sizeof(STR_CHAR_INPUT) - 1, "dest string too small");
dest_len -= sizeof(STR_CHAR_INPUT) - 1;
char *pos = strAppend(dest, STR_CHAR_INPUT, sizeof(STR_CHAR_INPUT) - 1);
if (g_model.inputNames[idx][0] != '\0' &&
if (!defaultOnly && g_model.inputNames[idx][0] != '\0' &&
(dest_len > sizeof(g_model.inputNames[idx]))) {
memset(pos, 0, sizeof(g_model.inputNames[idx]) + 1);
size_t input_len =
@@ -669,7 +702,7 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
if (idx < MAX_STICKS) {
pos = strAppend(pos, STR_CHAR_STICK, sizeof(STR_CHAR_STICK) - 1);
dest_len -= sizeof(STR_CHAR_STICK) - 1;
name = getMainControlLabel(idx);
name = getMainControlLabel(idx, defaultOnly);
} else {
idx -= MAX_STICKS;
if (IS_SLIDER(idx)) {
@@ -680,7 +713,7 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
dest_len -= sizeof(STR_CHAR_POT) - 1;
}
// TODO: AXIS / SWITCH ???
name = getPotLabel(idx);
name = getPotLabel(idx, defaultOnly);
}
strncpy(pos, name, dest_len - 1);
pos[dest_len - 1] = '\0';
@@ -707,11 +740,11 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
} else if (idx <= MIXSRC_LAST_TRIM) {
idx -= MIXSRC_FIRST_TRIM;
char *pos = strAppend(dest, STR_CHAR_TRIM, sizeof(STR_CHAR_TRIM) - 1);
strAppend(pos, getTrimLabel(idx));
strAppend(pos, getTrimLabel(idx, defaultOnly));
} else if (idx <= MIXSRC_LAST_SWITCH) {
idx -= MIXSRC_FIRST_SWITCH;
char *pos = strAppend(dest, STR_CHAR_SWITCH, sizeof(STR_CHAR_SWITCH) - 1);
getSwitchName(pos, idx);
getSwitchName(pos, idx, defaultOnly);
#if defined(FUNCTION_SWITCHES)
} else if (idx <= MIXSRC_LAST_CUSTOMSWITCH_GROUP) {
idx -= MIXSRC_FIRST_CUSTOMSWITCH_GROUP;
@@ -719,15 +752,14 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
getCustomSwitchesGroupName(pos, idx);
#endif
} else if (idx <= MIXSRC_LAST_LOGICAL_SWITCH) {
// TODO: unnecessary, use the direct way instead
idx -= MIXSRC_FIRST_LOGICAL_SWITCH;
getSwitchPositionName(dest, idx + SWSRC_FIRST_LOGICAL_SWITCH);
getSwitchPositionName(dest, idx + SWSRC_FIRST_LOGICAL_SWITCH, defaultOnly);
} else if (idx <= MIXSRC_LAST_TRAINER) {
idx -= MIXSRC_FIRST_TRAINER;
strAppendStringWithIndex(dest, STR_PPM_TRAINER, idx + 1);
} else if (idx <= MIXSRC_LAST_CH) {
auto ch = idx - MIXSRC_FIRST_CH;
if (g_model.limitData[ch].name[0] != '\0') {
if (!defaultOnly && g_model.limitData[ch].name[0] != '\0') {
strAppend(dest, g_model.limitData[ch].name, LEN_CHANNEL_NAME);
} else {
strAppendStringWithIndex(dest, STR_CH, ch + 1);
@@ -736,7 +768,7 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
idx -= MIXSRC_FIRST_GVAR;
#if defined(LIBOPENUI)
char *s = strAppendStringWithIndex(dest, STR_GV, idx + 1);
if (g_model.gvars[idx].name[0]) {
if (!defaultOnly && g_model.gvars[idx].name[0]) {
s = strAppend(s, ":");
getGVarString(s, idx);
}
@@ -763,7 +795,7 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
strncpy(dest, src_str, dest_len - 1);
} else if (idx <= MIXSRC_LAST_TIMER) {
idx -= MIXSRC_FIRST_TIMER;
if (g_model.timers[idx].name[0] != '\0') {
if (!defaultOnly && g_model.timers[idx].name[0] != '\0') {
strAppend(dest, g_model.timers[idx].name, LEN_TIMER_NAME);
} else {
strAppendStringWithIndex(dest, STR_SRC_TIMER, idx + 1);
@@ -781,13 +813,53 @@ char *getSourceString(char (&destRef)[L], mixsrc_t idx)
return destRef;
}
bool sourceCanHaveCustomName(mixsrc_t idx)
{
return (idx >= MIXSRC_FIRST_INPUT && idx <= MIXSRC_LAST_INPUT) ||
(idx >= MIXSRC_FIRST_STICK && idx <= MIXSRC_LAST_STICK) ||
(idx >= MIXSRC_FIRST_POT && idx <= MIXSRC_LAST_POT) ||
(idx >= MIXSRC_FIRST_TRIM && idx <= MIXSRC_LAST_TRIM) ||
(idx >= MIXSRC_FIRST_SWITCH && idx <= MIXSRC_LAST_SWITCH) ||
(idx >= MIXSRC_FIRST_CH && idx <= MIXSRC_LAST_CH) ||
(idx >= MIXSRC_FIRST_GVAR && idx <= MIXSRC_LAST_GVAR) ||
(idx >= MIXSRC_FIRST_TIMER && idx <= MIXSRC_LAST_TIMER);
}
bool matchSource(const char* name, mixsrc_t idx, bool defaultOnly)
{
char *s = getSourceString(idx, defaultOnly);
if (strcasecmp(s, name) == 0)
return true;
// Check for names starting with CHAR_xxx symbol strings
if (s[0] == '\302' && (strcasecmp(s + 2, name) == 0))
return true;
return false;
}
int getSourceIndex(const char* name, bool all)
{
for (mixsrc_t idx = MIXSRC_NONE; idx <= MIXSRC_LAST_TELEM; idx++) {
if (all || isSourceAvailable(idx)) {
if (sourceCanHaveCustomName(idx)) {
// Check default name
if (matchSource(name, idx, true))
return idx;
}
if (matchSource(name, idx, false))
return idx;
}
}
return -1;
}
// pre-instantiate for use from external
// all other instantiations are done from this file
template char *getSourceString<16>(char (&dest)[16], mixsrc_t idx);
template char *getSourceString<16>(char (&dest)[16], mixsrc_t idx, bool defaultOnly);
char *getSourceString(mixsrc_t idx)
char *getSourceString(mixsrc_t idx, bool defaultOnly)
{
return getSourceString(_static_str_buffer, idx);
return getSourceString(_static_str_buffer, idx, defaultOnly);
}
char *getCurveString(int idx)
@@ -805,9 +877,9 @@ char *getTimerString(char *dest, int32_t tme, TimerOptions timerOptions)
return getFormattedTimerString(dest, tme, timerOptions);
}
char *getSwitchPositionName(swsrc_t idx)
char *getSwitchPositionName(swsrc_t idx, bool defaultOnly)
{
return getSwitchPositionName(_static_str_buffer, idx);
return getSwitchPositionName(_static_str_buffer, idx, defaultOnly);
}
char *getGVarString(int idx) { return getGVarString(_static_str_buffer, idx); }
@@ -1102,6 +1174,8 @@ char *strAppendSigned(char *dest, int32_t value, uint8_t digits, uint8_t radix)
char *strAppend(char *dest, const char *source, int len)
{
if (source == nullptr) { *dest = '\0'; return dest; }
while ((*dest++ = *source++)) {
if (--len == 0) {
*dest = '\0';
+16 -14
View File
@@ -110,9 +110,11 @@ char *strAppendStringWithIndex(char *dest, const char *s, int idx);
#define LEN_TIMER_STRING 10 // "-00:00:00"
char *getTimerString(char *dest, int32_t tme,
TimerOptions timerOptions = {.options = 0});
char *getTimerString(int32_t tme, TimerOptions timerOptions = {.options = 0});
char *getFormattedTimerString(char *dest, int32_t tme,
TimerOptions timerOptions);
char *getCurveString(char *dest, int idx);
char *getCurveString(int idx);
char *getGVarString(char *dest, int idx);
char *getGVarString(int idx);
char *getValueOrGVarString(char *dest, size_t len, gvar_t value, gvar_t vmin,
@@ -123,33 +125,33 @@ char *getValueOrSrcVarString(char *dest, size_t len, gvar_t value, gvar_t vmin,
const char *suffix = nullptr, gvar_t offset = 0, bool usePPMUnit = false);
const char *getSwitchWarnSymbol(uint8_t pos);
const char *getSwitchPositionSymbol(uint8_t pos);
char *getSwitchPositionName(char *dest, swsrc_t idx);
char *getSwitchName(char *dest, uint8_t idx);
char *getSwitchPositionName(char *dest, swsrc_t idx, bool defaultOnly = false);
char *getSwitchPositionName(swsrc_t idx, bool defaultOnly = false);
char *getSwitchName(char *dest, uint8_t idx, bool defaultOnly = false);
int getSwitchIndex(const char* name, bool all);
int getSourceIndex(const char* name, bool all);
const char *getAnalogLabel(uint8_t type, uint8_t idx);
const char *getAnalogLabel(uint8_t type, uint8_t idx, bool defaultOnly = false);
const char *getAnalogShortLabel(uint8_t idx);
const char *getMainControlLabel(uint8_t idx);
const char *getTrimLabel(uint8_t idx);
const char *getMainControlLabel(uint8_t idx, bool defaultOnly = false);
const char *getTrimLabel(uint8_t idx, bool defaultOnly = false);
const char *getTrimSourceLabel(uint16_t src_raw, int8_t trim_src);
const char *getPotLabel(uint8_t idx);
const char *getPotLabel(uint8_t idx, bool defaultOnly = false);
char *getCustomSwitchesGroupName(char *dest, uint8_t idx);
template <size_t L>
char *getSourceString(char (&dest)[L], mixsrc_t idx);
char *getSourceString(char (&dest)[L], mixsrc_t idx, bool defaultOnly = false);
char *getSourceString(mixsrc_t idx, bool defaultOnly = false);
template <size_t L>
char *getSourceCustomValueString(char (&dest)[L], mixsrc_t source, int32_t val,
LcdFlags flags);
#endif
char *getSourceCustomValueString(mixsrc_t source, int32_t val, LcdFlags flags);
char *getFlightModeString(char *dest, int8_t idx);
char *getSourceString(mixsrc_t idx);
char *getSourceCustomValueString(mixsrc_t source, int32_t val, LcdFlags flags);
char *getSwitchPositionName(swsrc_t idx);
char *getCurveString(int idx);
char *getTimerString(int32_t tme, TimerOptions timerOptions = {.options = 0});
#endif
void splitTimer(char *s0, char *s1, char *s2, char *s3, int tme,
bool bLowercase = true);
+2 -6
View File
@@ -311,12 +311,8 @@ void processCrossfireTelemetryFrame(uint8_t module, uint8_t* rxBuffer,
crossfireModuleStatus[module].queryCompleted = true;
}
if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(rxBufferCount - 2)) {
for (uint8_t i = 1; i < rxBufferCount - 1; i++) {
// destination address and CRC are skipped
luaInputTelemetryFifo->push(rxBuffer[i]);
}
}
// destination address and CRC are skipped
pushTelemetryDataToQueues(rxBuffer + 1, rxBufferCount - 2);
break;
#endif
}
+12 -22
View File
@@ -391,18 +391,12 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t module, uint8_t origin, const
}
else if (dataId >= DIY_STREAM_FIRST_ID && dataId <= DIY_STREAM_LAST_ID) {
#if defined(LUA)
if (luaInputTelemetryFifo &&
luaInputTelemetryFifo->hasSpace(sizeof(SportTelemetryPacket))) {
SportTelemetryPacket luaPacket;
luaPacket.physicalId = physicalId;
luaPacket.primId = primId;
luaPacket.dataId = dataId;
luaPacket.value = data;
for (uint8_t i=0; i<sizeof(SportTelemetryPacket); i++) {
luaInputTelemetryFifo->push(luaPacket.raw[i]);
}
}
SportTelemetryPacket luaPacket;
luaPacket.physicalId = physicalId;
luaPacket.primId = primId;
luaPacket.dataId = dataId;
luaPacket.value = data;
pushTelemetryDataToQueues(luaPacket.raw, sizeof(SportTelemetryPacket));
#endif
}
else if (dataId >= RB3040_CH1_2_FIRST_ID && dataId <= RB3040_CH7_8_LAST_ID) {
@@ -433,16 +427,12 @@ void sportProcessTelemetryPacketWithoutCrc(uint8_t module, uint8_t origin, const
}
#if defined(LUA)
else if (primId == 0x32) {
if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(sizeof(SportTelemetryPacket))) {
SportTelemetryPacket luaPacket;
luaPacket.physicalId = physicalId;
luaPacket.primId = primId;
luaPacket.dataId = dataId;
luaPacket.value = data;
for (uint8_t i=0; i<sizeof(SportTelemetryPacket); i++) {
luaInputTelemetryFifo->push(luaPacket.raw[i]);
}
}
SportTelemetryPacket luaPacket;
luaPacket.physicalId = physicalId;
luaPacket.primId = primId;
luaPacket.dataId = dataId;
luaPacket.value = data;
pushTelemetryDataToQueues(luaPacket.raw, sizeof(SportTelemetryPacket));
}
#endif
}
+1 -5
View File
@@ -315,11 +315,7 @@ void processGhostTelemetryFrame(uint8_t module, uint8_t* buffer, uint32_t length
#if defined(LUA)
default:
// destination address and CRC are skipped
if (luaInputTelemetryFifo && luaInputTelemetryFifo->hasSpace(length - 2) ) {
for (uint8_t i = 1; i < length - 1; i++) {
luaInputTelemetryFifo->push(buffer[i]);
}
}
pushTelemetryDataToQueues(buffer + 1, length - 2);
break;
#endif
}
+32 -1
View File
@@ -468,7 +468,38 @@ void logTelemetryWriteByte(uint8_t data)
OutputTelemetryBuffer outputTelemetryBuffer __DMA_NO_CACHE;
#if defined(LUA)
Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE> * luaInputTelemetryFifo = NULL;
TelemetryQueue* luaInputTelemetryFifo = nullptr;
#if defined(COLORLCD)
std::list<TelemetryQueue*> telemetryQueues;
void registerTelemetryQueue(TelemetryQueue* queue)
{
telemetryQueues.emplace_back(queue);
}
void deregisterTelemetryQueue(TelemetryQueue* queue)
{
telemetryQueues.remove(queue);
}
#endif
static void pushDataToQueue(TelemetryQueue* queue, uint8_t* data, int length)
{
if (queue && queue->hasSpace(length)) {
for (uint8_t i = 0; i < length; i += 1) {
queue->push(data[i]);
}
}
}
void pushTelemetryDataToQueues(uint8_t* data, int length)
{
#if defined(COLORLCD)
for (auto it = telemetryQueues.cbegin(); it != telemetryQueues.cend(); ++it)
pushDataToQueue(*it, data, length);
#endif
pushDataToQueue(luaInputTelemetryFifo, data, length);
}
#endif
#if defined(HARDWARE_INTERNAL_MODULE)
+5 -1
View File
@@ -236,7 +236,11 @@ extern OutputTelemetryBuffer outputTelemetryBuffer __DMA_NO_CACHE;
#if defined(LUA)
#include "fifo.h"
#define LUA_TELEMETRY_INPUT_FIFO_SIZE 256
extern Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE> * luaInputTelemetryFifo;
typedef Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE> TelemetryQueue;
extern TelemetryQueue* luaInputTelemetryFifo;
void registerTelemetryQueue(TelemetryQueue*);
void deregisterTelemetryQueue(TelemetryQueue*);
void pushTelemetryDataToQueues(uint8_t* data, int length);
#endif
void processPXX2Frame(uint8_t idx, const uint8_t* frame,
+1 -2
View File
@@ -61,8 +61,7 @@ struct crsf_frame_test {
{
ctx = CrossfireDriver.init(EXTERNAL_MODULE);
if (!luaInputTelemetryFifo) {
luaInputTelemetryFifo =
new Fifo<uint8_t, LUA_TELEMETRY_INPUT_FIFO_SIZE>();
luaInputTelemetryFifo = new TelemetryQueue();
assert(luaInputTelemetryFifo != nullptr);
} else {
luaInputTelemetryFifo->clear();