feat: Lua app firmware for the E32R40T display module

Boots to a launcher that lists /apps/<name>/main.lua on the SD card and runs
the selected app in a vendored Lua 5.4 with gui, input, fs, sys and log
bindings. Settings persist as a Lua table in /settings.lua, covering touch
calibration and screen rotation, with a settings app to edit both. Rotation is
applied after mapping raw touch into the panel's rotation-0 frame, so turning
the UI never invalidates a calibration.
This commit is contained in:
2026-07-31 21:28:11 -04:00
commit ad396d3f01
75 changed files with 29804 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
#include "settings.h"
#include <SD.h>
extern "C" {
#include <lauxlib.h>
#include <lua.h>
}
Settings settings;
static constexpr const char* PATH = "/settings.lua";
static int16_t fieldOr(lua_State* L, const char* key, int16_t fallback) {
lua_getfield(L, -1, key);
int16_t value = lua_isinteger(L, -1) ? lua_tointeger(L, -1) : fallback;
lua_pop(L, 1);
return value;
}
bool Settings::setRotation(int16_t degrees) {
if (degrees % 90 != 0 || degrees < 0 || degrees > 270) return false;
rotation = degrees;
return true;
}
bool Settings::load() {
File f = SD.open(PATH);
if (!f) return false;
String source = f.readString();
f.close();
lua_State* L = luaL_newstate();
if (!L) return false;
bool ok = luaL_loadbuffer(L, source.c_str(), source.length(), PATH) == LUA_OK &&
lua_pcall(L, 0, 1, 0) == LUA_OK && lua_istable(L, -1);
if (ok) {
rotation = fieldOr(L, "rotation", rotation);
lua_getfield(L, -1, "touch");
if (lua_istable(L, -1)) {
touchX0 = fieldOr(L, "x0", touchX0);
touchY0 = fieldOr(L, "y0", touchY0);
touchX1 = fieldOr(L, "x1", touchX1);
touchY1 = fieldOr(L, "y1", touchY1);
}
lua_pop(L, 1);
}
lua_close(L);
return ok;
}
bool Settings::save() const {
File f = SD.open(PATH, FILE_WRITE);
if (!f) return false;
char buf[200];
int len = snprintf(buf, sizeof(buf),
"return {\n rotation = %d,\n"
" touch = { x0 = %d, y0 = %d, x1 = %d, y1 = %d },\n}\n",
rotation, touchX0, touchY0, touchX1, touchY1);
bool ok = f.write(reinterpret_cast<const uint8_t*>(buf), len) == (size_t)len;
f.close();
return ok;
}