#include "settings.h" #include extern "C" { #include #include } Settings settings; static constexpr const char* PATH = "/settings.lua"; static constexpr const char* TEMP_PATH = "/settings.tmp"; static constexpr const char* BACKUP_PATH = "/settings.bak"; 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; } static String stringFieldOr(lua_State* L, const char* key, const String& fallback) { lua_getfield(L, -1, key); String value = lua_isstring(L, -1) ? lua_tostring(L, -1) : fallback; lua_pop(L, 1); return value; } static String luaString(const String& value) { String out = "\""; for (size_t i = 0; i < value.length(); i++) { unsigned char c = value[i]; if (c == '\\' || c == '\"') { out += '\\'; out += (char)c; } else if (c >= 32 && c < 127) { out += (char)c; } else { char escaped[5]; snprintf(escaped, sizeof(escaped), "\\%03u", c); out += escaped; } } out += '\"'; return out; } 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); timezone = stringFieldOr(L, "timezone", timezone); theme = stringFieldOr(L, "theme", theme); 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_getfield(L, -1, "wifi"); if (lua_istable(L, -1)) { wifiSsid = stringFieldOr(L, "ssid", wifiSsid); wifiPassword = stringFieldOr(L, "password", wifiPassword); } lua_pop(L, 1); } lua_close(L); return ok; } bool Settings::save() const { String source = "return {\n rotation = " + String(rotation) + ",\n"; source += " timezone = " + luaString(timezone) + ",\n"; source += " theme = " + luaString(theme) + ",\n"; source += " touch = { x0 = " + String(touchX0) + ", y0 = " + String(touchY0) + ", x1 = " + String(touchX1) + ", y1 = " + String(touchY1) + " },\n"; source += " wifi = { ssid = " + luaString(wifiSsid) + ", password = " + luaString(wifiPassword) + " },\n}\n"; if (SD.exists(TEMP_PATH)) SD.remove(TEMP_PATH); File f = SD.open(TEMP_PATH, FILE_WRITE); if (!f) return false; bool ok = f.write(reinterpret_cast(source.c_str()), source.length()) == source.length(); f.close(); if (!ok) { SD.remove(TEMP_PATH); return false; } if (SD.exists(BACKUP_PATH)) SD.remove(BACKUP_PATH); bool hadSettings = SD.exists(PATH); if (hadSettings && !SD.rename(PATH, BACKUP_PATH)) return false; if (SD.rename(TEMP_PATH, PATH)) { if (hadSettings) SD.remove(BACKUP_PATH); return true; } if (hadSettings) SD.rename(BACKUP_PATH, PATH); return false; }