refactor: run apps on the shared esp32-lua-api runtime
Replaces the firmware's own lua_State, bindings, module loader, node tree and navigation history with lib/esp32-lua-api. What is left in src/host is the hardware behind the provider interfaces plus the chrome the firmware owns: the viewport, the status bar and touch polling. src/lua became src/host because src is on the include path, so a directory named lua shadowed the library's <lua/providers.h> and #pragma once then silently skipped it.
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
#include <Arduino.h>
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
#include "../net.h"
|
||||
#include "../settings.h"
|
||||
#include "lua_host.h"
|
||||
#include "providers.h"
|
||||
|
||||
namespace slate {
|
||||
|
||||
using esp32lua::Status;
|
||||
|
||||
void Log::write(esp32lua::LogLevel level, const std::string& message) {
|
||||
const char* tag = level == esp32lua::LogLevel::Error ? "error"
|
||||
: (level == esp32lua::LogLevel::Info ? "info" : "debug");
|
||||
Serial.printf("[lua] %s: %s\n", tag, message.c_str());
|
||||
}
|
||||
|
||||
int32_t Settings::rotation() const { return settings.rotation; }
|
||||
|
||||
// Applies the rotation itself, because a setter that needs a follow-up call is a bug in the
|
||||
// setter: the frame, the viewport and the bar all move together or not at all.
|
||||
Status Settings::setRotation(int32_t degrees) {
|
||||
if (!settings.setRotation(degrees)) return Status::failure("rotation must be 0, 90, 180 or 270");
|
||||
host.applyRotation();
|
||||
return settings.save() ? Status::success() : Status::failure("cannot save settings");
|
||||
}
|
||||
|
||||
std::string Settings::timezone() const { return settings.timezone.c_str(); }
|
||||
|
||||
Status Settings::setTimezone(const std::string& timezone) {
|
||||
if (timezone.empty() || timezone.size() > 48) return Status::failure("timezone must be 1 to 48 characters");
|
||||
settings.timezone = timezone.c_str();
|
||||
net::applyTimezone();
|
||||
return settings.save() ? Status::success() : Status::failure("cannot save settings");
|
||||
}
|
||||
|
||||
int32_t Sys::millis() const { return static_cast<int32_t>(::millis()); }
|
||||
|
||||
esp32lua::MemoryInfo Sys::memory() const {
|
||||
esp32lua::MemoryInfo info;
|
||||
info.freeBytes = static_cast<int32_t>(ESP.getFreeHeap());
|
||||
info.totalBytes = static_cast<int32_t>(ESP.getHeapSize());
|
||||
info.largestFreeBlock = static_cast<int32_t>(heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT));
|
||||
return info;
|
||||
}
|
||||
|
||||
bool Sys::isClockSynced() const { return net::clockSynced(); }
|
||||
|
||||
bool Touch::touch(int32_t& x, int32_t& y) const {
|
||||
if (!panel.touched()) return false;
|
||||
int16_t mappedX = 0, mappedY = 0;
|
||||
host.mapTouch(panel.getPoint(), mappedX, mappedY);
|
||||
x = mappedX;
|
||||
y = mappedY;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Touch::rawTouch(int32_t& x, int32_t& y) const {
|
||||
if (!panel.touched()) return false;
|
||||
const TS_Point point = panel.getPoint();
|
||||
// The controller's axes are swapped relative to the panel, which calibration undoes.
|
||||
x = point.y;
|
||||
y = point.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Touch::isTouched() const { return panel.touched(); }
|
||||
|
||||
Status Touch::setCalibration(int32_t x0, int32_t y0, int32_t x1, int32_t y1) {
|
||||
settings.touchX0 = x0;
|
||||
settings.touchY0 = y0;
|
||||
settings.touchX1 = x1;
|
||||
settings.touchY1 = y1;
|
||||
return settings.save() ? Status::success() : Status::failure("cannot save settings");
|
||||
}
|
||||
|
||||
// A fixed slot table rather than a heap list: the whole point of the arena elsewhere is that
|
||||
// a Lua app cannot fragment the heap, and timers are created from Lua.
|
||||
Status Timer::schedule(esp32lua::TimerId id, int32_t intervalMs, bool repeating) {
|
||||
for (int at = 0; at < SLOTS; at++) {
|
||||
if (slots[at].id != 0) continue;
|
||||
slots[at].id = id;
|
||||
slots[at].dueMs = ::millis() + intervalMs;
|
||||
slots[at].intervalMs = intervalMs;
|
||||
slots[at].repeating = repeating;
|
||||
return Status::success();
|
||||
}
|
||||
return Status::failure("no timer slot available");
|
||||
}
|
||||
|
||||
void Timer::cancel(esp32lua::TimerId id) {
|
||||
for (int at = 0; at < SLOTS; at++) {
|
||||
if (slots[at].id == id) slots[at] = Slot();
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::collectDue(uint32_t nowMs, std::vector<esp32lua::TimerId>& due) {
|
||||
for (int at = 0; at < SLOTS; at++) {
|
||||
if (slots[at].id == 0) continue;
|
||||
// Signed comparison, so a deadline still pending across the millis() wrap is not "due".
|
||||
if (static_cast<int32_t>(nowMs - slots[at].dueMs) < 0) continue;
|
||||
due.push_back(slots[at].id);
|
||||
if (slots[at].repeating) {
|
||||
slots[at].dueMs = nowMs + slots[at].intervalMs;
|
||||
} else {
|
||||
slots[at] = Slot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace slate
|
||||
Reference in New Issue
Block a user