eec9b692c6
Adds a wifi binding over the Arduino API and a settings flow that scans, picks the strongest AP per SSID, takes a password from an on-screen keyboard, and reports connection state. Credentials join /settings.lua and reconnect at boot. Settings are now written through a temp file and rename, and strings are Lua-escaped, so a password cannot corrupt the file the firmware parses at boot.
84 lines
2.1 KiB
C++
84 lines
2.1 KiB
C++
#include <SD.h>
|
|
#include <SPI.h>
|
|
#include <TFT_eSPI.h>
|
|
#include <WiFi.h>
|
|
#include <XPT2046_Touchscreen.h>
|
|
|
|
#include "lua/lua_app.h"
|
|
#include "settings.h"
|
|
|
|
// SD card is on a separate bus from the display/touch (board schematic)
|
|
static constexpr int SD_CS = 5;
|
|
static constexpr int SD_SCK = 18;
|
|
static constexpr int SD_MOSI = 23;
|
|
static constexpr int SD_MISO = 19;
|
|
static constexpr int TOUCH_CS = 33;
|
|
|
|
static const char* LAUNCHER = "/apps/launcher/main.lua";
|
|
|
|
TFT_eSPI tft;
|
|
SPIClass touchSpi(HSPI);
|
|
SPIClass& sdSpi = SPI;
|
|
XPT2046_Touchscreen touch(TOUCH_CS);
|
|
LuaApp app(tft, touch);
|
|
|
|
bool halted = false;
|
|
String nextApp;
|
|
|
|
// Last resort only: the UI lives in Lua, so this exists purely to explain why
|
|
// nothing else could run.
|
|
void fallbackScreen(const char* message) {
|
|
tft.setRotation(0);
|
|
tft.fillScreen(TFT_WHITE);
|
|
tft.setTextColor(TFT_RED, TFT_WHITE);
|
|
tft.drawString(message, 10, 10);
|
|
tft.setTextColor(TFT_BLACK, TFT_WHITE);
|
|
tft.drawString("expected /apps/launcher/main.lua", 10, 30);
|
|
Serial.printf("halted: %s\n", message);
|
|
halted = true;
|
|
}
|
|
|
|
void startApp(const String& path) {
|
|
tft.setRotation(settings.rotationIndex()); // apps may have rotated the frame
|
|
Serial.printf("launching %s\n", path.c_str());
|
|
if (app.load(path.c_str())) return;
|
|
if (path == LAUNCHER) fallbackScreen("launcher failed to start");
|
|
}
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
tft.begin();
|
|
tft.setRotation(0);
|
|
tft.fillScreen(TFT_WHITE);
|
|
touchSpi.begin(14, 12, 13, TOUCH_CS);
|
|
touch.begin(touchSpi);
|
|
|
|
sdSpi.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
|
|
if (!SD.begin(SD_CS, sdSpi)) {
|
|
fallbackScreen("SD card mount failed");
|
|
return;
|
|
}
|
|
settings.load(); // absent file keeps the built-in defaults
|
|
WiFi.persistent(false);
|
|
if (settings.wifiSsid.length()) {
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.begin(settings.wifiSsid.c_str(), settings.wifiPassword.c_str());
|
|
}
|
|
startApp(LAUNCHER);
|
|
}
|
|
|
|
void loop() {
|
|
if (halted) return;
|
|
|
|
if (app.running()) {
|
|
app.loop();
|
|
if (!app.running()) nextApp = app.takePendingLaunch();
|
|
return;
|
|
}
|
|
|
|
String path = nextApp.length() > 0 ? nextApp : String(LAUNCHER);
|
|
nextApp = "";
|
|
startApp(path);
|
|
delay(10);
|
|
}
|