refactor(display): extract dashboard tile grid logic to DisplayManager
This commit is contained in:
46
.clangd
46
.clangd
@@ -1,36 +1,26 @@
|
|||||||
CompileFlags:
|
CompileFlags:
|
||||||
Add:
|
Add:
|
||||||
- "-std=c++17"
|
|
||||||
- "-DARDUINO=200"
|
|
||||||
- "-DESP32"
|
|
||||||
- "-DCORE_DEBUG_LEVEL=0"
|
|
||||||
- "-DBOARD_HAS_PSRAM"
|
|
||||||
- "-DLGFX_USE_V1"
|
|
||||||
- "-DDEBUG_MODE"
|
|
||||||
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/cores/esp32"
|
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/cores/esp32"
|
||||||
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/tools"
|
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/tools/sdk/esp32/include"
|
||||||
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries"
|
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/tools/sdk/esp32/include/esp_hw_support"
|
||||||
- "-I/home/david/.arduino15/packages/esp32/tools/esp32-libs/3.3.6/include"
|
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/WiFi/src"
|
||||||
- "-I/home/david/.arduino15/packages/esp32/tools/esp32-libs/3.3.6/include/freertos/FreeRTOS-Kernel/include"
|
- "-I/home/david/.arduino15/packages/esp32/hardware/esp32/3.3.6/libraries/EEPROM/src"
|
||||||
- "-I/home/david/.arduino15/packages/esp32/tools/esp32-libs/3.3.6/include/freertos/config/include/freertos"
|
- "-I/home/david/Arduino/sketches/doorbell-touch/vendor/esp32-s3-lcd-43/LovyanGFX/src"
|
||||||
- "-I/home/david/.arduino15/packages/esp32/tools/esp32-libs/3.3.6/include/freertos/config/include"
|
- "-I/home/david/Arduino/libraries/TFT_eSPI"
|
||||||
- "-I/home/david/.arduino15/packages/arduino/hardware/arduino/1.8.6/cores/arduino"
|
|
||||||
- "-I/home/david/.arduino15/packages/arduino/hardware/arduino/1.8.6/libraries/WiFi/src"
|
|
||||||
- "-I/home/david/Arduino/sketchbook/libraries/ArduinoJson/src"
|
|
||||||
- "-I/home/david/Arduino/sketchbook/libraries/NTPClient"
|
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/libraries/KlubhausCore/src"
|
- "-I/home/david/Arduino/sketches/doorbell-touch/libraries/KlubhausCore/src"
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/boards/esp32-s3-lcd-43"
|
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/vendor/esp32-s3-lcd-43/LovyanGFX/src/lgfx"
|
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/vendor/esp32-s3-lcd-43/LovyanGFX/src/lgfx/v0"
|
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/vendor/esp32-s3-lcd-43/LovyanGFX/src/lgfx/v0/platforms/esp32"
|
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/boards/esp32-32e"
|
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/boards/esp32-32e-4"
|
- "-I/home/david/Arduino/sketches/doorbell-touch/boards/esp32-32e-4"
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/vendor/esp32-32e/TFT_eSPI"
|
- "-DARDUINO=200"
|
||||||
- "-I/home/david/Arduino/sketches/doorbell-touch/vendor/esp32-32e-4/TFT_eSPI"
|
- "-DESC32"
|
||||||
- "-I/home/david/Arduino/sketchbook/libraries/XPT2046_Touchscreen"
|
- "-DESP_PLATFORM"
|
||||||
|
- "-Dcore_debug=0"
|
||||||
|
|
||||||
Diagnostics:
|
Diagnostics:
|
||||||
ClangTidy:
|
ClangTidy:
|
||||||
Remove: [readability-*, modernize-*, performance-*, bugprone-*]
|
Add:
|
||||||
Add: [clang-diagnostic-*, modernize-use-trailing-return-type]
|
- modernize-*
|
||||||
UnusedIncludes: Strict
|
- performance-*
|
||||||
|
- readability-*
|
||||||
|
- bugprone-*
|
||||||
|
Remove:
|
||||||
|
- modernize-use-trailing-return-type
|
||||||
|
- readability-magic-numbers
|
||||||
|
|||||||
@@ -123,28 +123,51 @@ void DisplayDriverTFT::drawAlert(const ScreenState& st) {
|
|||||||
|
|
||||||
void DisplayDriverTFT::drawDashboard(const ScreenState& st) {
|
void DisplayDriverTFT::drawDashboard(const ScreenState& st) {
|
||||||
_tft.fillScreen(TFT_BLACK);
|
_tft.fillScreen(TFT_BLACK);
|
||||||
_tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
|
||||||
|
|
||||||
|
// Header
|
||||||
|
_tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||||
_tft.setTextSize(1);
|
_tft.setTextSize(1);
|
||||||
_tft.setCursor(5, 5);
|
_tft.setCursor(5, 5);
|
||||||
_tft.printf("KLUBHAUS — %s", deviceStateStr(st.deviceState));
|
_tft.printf("KLUBHAUS");
|
||||||
|
|
||||||
int y = 30;
|
// WiFi indicator
|
||||||
_tft.setCursor(5, y);
|
_tft.setCursor(DISPLAY_WIDTH - 50, 5);
|
||||||
y += 18;
|
_tft.printf("WiFi:%s", st.wifiSsid.length() > 0 ? "ON" : "OFF");
|
||||||
_tft.printf("WiFi: %s %ddBm", st.wifiSsid.c_str(), st.wifiRssi);
|
|
||||||
|
|
||||||
_tft.setCursor(5, y);
|
// Render tiles via DisplayManager (abstracted to library)
|
||||||
y += 18;
|
// For now, draw directly using our tile implementation
|
||||||
_tft.printf("IP: %s", st.ipAddr.c_str());
|
constexpr int cols = 2;
|
||||||
|
constexpr int rows = 2;
|
||||||
|
constexpr int tileW = DISPLAY_WIDTH / cols;
|
||||||
|
constexpr int tileH = (DISPLAY_HEIGHT - 30) / rows;
|
||||||
|
constexpr int margin = 8;
|
||||||
|
|
||||||
_tft.setCursor(5, y);
|
const char* tileLabels[] = { "Alert", "Silent", "Status", "Reboot" };
|
||||||
y += 18;
|
const uint16_t tileColors[] = { 0x0280, 0x0400, 0x0440, 0x0100 };
|
||||||
_tft.printf("Up: %lus Heap: %d", st.uptimeMs / 1000, ESP.getFreeHeap());
|
|
||||||
|
|
||||||
_tft.setCursor(5, y);
|
for(int i = 0; i < 4; i++) {
|
||||||
y += 18;
|
int col = i % cols;
|
||||||
_tft.printf("Last poll: %lus ago", st.lastPollMs > 0 ? (millis() - st.lastPollMs) / 1000 : 0);
|
int row = i / cols;
|
||||||
|
|
||||||
|
int x = col * tileW + margin;
|
||||||
|
int y = 30 + row * tileH + margin;
|
||||||
|
int w = tileW - 2 * margin;
|
||||||
|
int h = tileH - 2 * margin;
|
||||||
|
|
||||||
|
// Tile background
|
||||||
|
_tft.fillRoundRect(x, y, w, h, 8, tileColors[i]);
|
||||||
|
|
||||||
|
// Tile border
|
||||||
|
_tft.drawRoundRect(x, y, w, h, 8, TFT_WHITE);
|
||||||
|
|
||||||
|
// Tile label
|
||||||
|
_tft.setTextColor(TFT_WHITE);
|
||||||
|
_tft.setTextSize(2);
|
||||||
|
int textLen = strlen(tileLabels[i]);
|
||||||
|
int textW = textLen * 12;
|
||||||
|
_tft.setCursor(x + w/2 - textW/2, y + h/2 - 10);
|
||||||
|
_tft.print(tileLabels[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Touch ───────────────────────────────────────────────────
|
// ── Touch ───────────────────────────────────────────────────
|
||||||
@@ -166,18 +189,27 @@ uint16_t DisplayDriverTFT::getRawTouchZ() {
|
|||||||
return _tft.getTouchRawZ();
|
return _tft.getTouchRawZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DisplayDriverTFT::dashboardTouch(int x, int y) {
|
void DisplayDriverTFT::transformTouch(int* x, int* y) {
|
||||||
// 2x2 grid, accounting for 30px header
|
// Resistive touch panel is rotated 90° vs display - swap coordinates
|
||||||
if(y < 30)
|
int temp = *x;
|
||||||
return -1;
|
*x = *y;
|
||||||
|
*y = temp;
|
||||||
|
}
|
||||||
|
|
||||||
int col = (x * 2) / DISPLAY_WIDTH; // 0 or 1
|
void DisplayDriverTFT::drawTileAt(int x, int y, int w, int h, const char* label, uint16_t bgColor) {
|
||||||
int row = ((y - 30) * 2) / (DISPLAY_HEIGHT - 30); // 0 or 1
|
// Tile background
|
||||||
|
_tft.fillRoundRect(x, y, w, h, 8, bgColor);
|
||||||
|
|
||||||
if(col < 0 || col > 1 || row < 0 || row > 1)
|
// Tile border
|
||||||
return -1;
|
_tft.drawRoundRect(x, y, w, h, 8, TFT_WHITE);
|
||||||
|
|
||||||
return row * 2 + col; // 0, 1, 2, or 3
|
// Tile label
|
||||||
|
_tft.setTextColor(TFT_WHITE);
|
||||||
|
_tft.setTextSize(2);
|
||||||
|
int textLen = strlen(label);
|
||||||
|
int textW = textLen * 12; // approx width
|
||||||
|
_tft.setCursor(x + w/2 - textW/2, y + h/2 - 10);
|
||||||
|
_tft.print(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
HoldState DisplayDriverTFT::updateHold(unsigned long holdMs) {
|
HoldState DisplayDriverTFT::updateHold(unsigned long holdMs) {
|
||||||
|
|||||||
@@ -12,12 +12,15 @@ public:
|
|||||||
void render(const ScreenState& state) override;
|
void render(const ScreenState& state) override;
|
||||||
TouchEvent readTouch() override;
|
TouchEvent readTouch() override;
|
||||||
uint16_t getRawTouchZ();
|
uint16_t getRawTouchZ();
|
||||||
int dashboardTouch(int x, int y) override;
|
|
||||||
HoldState updateHold(unsigned long holdMs) override;
|
HoldState updateHold(unsigned long holdMs) override;
|
||||||
void updateHint(int x, int y, bool active) override;
|
void updateHint(int x, int y, bool active) override;
|
||||||
int width() override { return DISPLAY_WIDTH; }
|
int width() override { return DISPLAY_WIDTH; }
|
||||||
int height() override { return DISPLAY_HEIGHT; }
|
int height() override { return DISPLAY_HEIGHT; }
|
||||||
|
|
||||||
|
// Dashboard tiles - library handles grid math, we just draw
|
||||||
|
void transformTouch(int* x, int* y) override;
|
||||||
|
void drawTileAt(int x, int y, int w, int h, const char* label, uint16_t bgColor) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void drawBoot(const ScreenState& st);
|
void drawBoot(const ScreenState& st);
|
||||||
void drawAlert(const ScreenState& st);
|
void drawAlert(const ScreenState& st);
|
||||||
|
|||||||
@@ -96,6 +96,22 @@ int DisplayDriverGFX::dashboardTouch(int x, int y) {
|
|||||||
return row * cols + col;
|
return row * cols + col;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayDriverGFX::drawTileAt(int x, int y, int w, int h, const char* label, uint16_t bgColor) {
|
||||||
|
// Tile background (use fillRect - LovyanGFX may not have fillRoundRect)
|
||||||
|
_gfx->fillRect(x, y, w, h, bgColor);
|
||||||
|
|
||||||
|
// Tile border
|
||||||
|
_gfx->drawRect(x, y, w, h, 0xFFFF);
|
||||||
|
|
||||||
|
// Tile label
|
||||||
|
_gfx->setTextColor(0xFFFF);
|
||||||
|
_gfx->setTextSize(2);
|
||||||
|
int textLen = strlen(label);
|
||||||
|
int textW = textLen * 12;
|
||||||
|
_gfx->setCursor(x + w/2 - textW/2, y + h/2 - 10);
|
||||||
|
_gfx->print(label);
|
||||||
|
}
|
||||||
|
|
||||||
HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) {
|
HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) {
|
||||||
HoldState state;
|
HoldState state;
|
||||||
|
|
||||||
|
|||||||
@@ -12,13 +12,15 @@ public:
|
|||||||
void render(const ScreenState& state) override;
|
void render(const ScreenState& state) override;
|
||||||
|
|
||||||
TouchEvent readTouch() override;
|
TouchEvent readTouch() override;
|
||||||
int dashboardTouch(int x, int y) override;
|
|
||||||
HoldState updateHold(unsigned long holdMs) override;
|
HoldState updateHold(unsigned long holdMs) override;
|
||||||
void updateHint(int x, int y, bool active) override;
|
void updateHint(int x, int y, bool active) override;
|
||||||
|
|
||||||
int width() override;
|
int width() override;
|
||||||
int height() override;
|
int height() override;
|
||||||
|
|
||||||
|
// Dashboard tiles - library handles grid math, we just draw
|
||||||
|
void drawTileAt(int x, int y, int w, int h, const char* label, uint16_t bgColor) override;
|
||||||
|
|
||||||
// ── Internal ──
|
// ── Internal ──
|
||||||
static DisplayDriverGFX& instance();
|
static DisplayDriverGFX& instance();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IDisplayDriver.h"
|
#include "IDisplayDriver.h"
|
||||||
|
#include "ScreenState.h"
|
||||||
|
|
||||||
class DisplayManager {
|
class DisplayManager {
|
||||||
public:
|
public:
|
||||||
@@ -24,8 +25,6 @@ public:
|
|||||||
|
|
||||||
TouchEvent readTouch() { return _drv ? _drv->readTouch() : TouchEvent {}; }
|
TouchEvent readTouch() { return _drv ? _drv->readTouch() : TouchEvent {}; }
|
||||||
|
|
||||||
int dashboardTouch(int x, int y) { return _drv ? _drv->dashboardTouch(x, y) : -1; }
|
|
||||||
|
|
||||||
HoldState updateHold(unsigned long ms) { return _drv ? _drv->updateHold(ms) : HoldState {}; }
|
HoldState updateHold(unsigned long ms) { return _drv ? _drv->updateHold(ms) : HoldState {}; }
|
||||||
|
|
||||||
void updateHint(int x, int y, bool active) {
|
void updateHint(int x, int y, bool active) {
|
||||||
@@ -34,9 +33,114 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int width() { return _drv ? _drv->width() : 0; }
|
int width() { return _drv ? _drv->width() : 0; }
|
||||||
|
|
||||||
int height() { return _drv ? _drv->height() : 0; }
|
int height() { return _drv ? _drv->height() : 0; }
|
||||||
|
|
||||||
|
/// Auto-calculate grid dimensions for dashboard tiles
|
||||||
|
/// Prefers landscape (more columns than rows) for wide displays
|
||||||
|
void getTileGrid(int tileCount, int* outRows, int* outCols) const {
|
||||||
|
if(tileCount <= 0) {
|
||||||
|
*outRows = *outCols = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Calculate cols: try to make it wider than tall
|
||||||
|
int cols = (int)sqrt(tileCount);
|
||||||
|
if(cols * cols < tileCount) cols++;
|
||||||
|
|
||||||
|
// Make cols >= rows for landscape preference
|
||||||
|
while(cols * ((tileCount + cols - 1) / cols) < tileCount) {
|
||||||
|
cols++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows = (tileCount + cols - 1) / cols;
|
||||||
|
|
||||||
|
// If display is wider, prefer more columns
|
||||||
|
if(_drv) {
|
||||||
|
int w = _drv->width();
|
||||||
|
int h = _drv->height();
|
||||||
|
if(w > h) {
|
||||||
|
// Landscape display - maximize columns
|
||||||
|
cols = tileCount;
|
||||||
|
rows = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*outRows = rows;
|
||||||
|
*outCols = cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render all dashboard tiles with auto-calculated grid
|
||||||
|
void renderDashboard(const ScreenState& st) {
|
||||||
|
if(!_drv) return;
|
||||||
|
|
||||||
|
int rows, cols;
|
||||||
|
getTileGrid(DASHBOARD_TILE_COUNT, &rows, &cols);
|
||||||
|
|
||||||
|
int dispW = _drv->width();
|
||||||
|
int dispH = _drv->height();
|
||||||
|
|
||||||
|
// Reserve space for header
|
||||||
|
int headerH = 30;
|
||||||
|
int contentH = dispH - headerH;
|
||||||
|
|
||||||
|
// Calculate tile sizes
|
||||||
|
int tileW = dispW / cols;
|
||||||
|
int tileH = contentH / rows;
|
||||||
|
int margin = 8;
|
||||||
|
|
||||||
|
for(int i = 0; i < DASHBOARD_TILE_COUNT; i++) {
|
||||||
|
int row = i / cols;
|
||||||
|
int col = i % cols;
|
||||||
|
|
||||||
|
int x = col * tileW + margin;
|
||||||
|
int y = headerH + row * tileH + margin;
|
||||||
|
int w = tileW - 2 * margin;
|
||||||
|
int h = tileH - 2 * margin;
|
||||||
|
|
||||||
|
_drv->drawTileAt(x, y, w, h, DASHBOARD_TILES[i].label, DASHBOARD_TILES[i].bgColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store grid for touch calculations
|
||||||
|
_gridRows = rows;
|
||||||
|
_gridCols = cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle dashboard touch - returns action for tapped tile, or NONE
|
||||||
|
TileAction handleDashboardTouch(int x, int y) const {
|
||||||
|
if(!_drv || _gridCols <= 0) return TileAction::NONE;
|
||||||
|
|
||||||
|
// Transform touch coordinates (handles rotated touch panels)
|
||||||
|
_drv->transformTouch(&x, &y);
|
||||||
|
|
||||||
|
int dispW = _drv->width();
|
||||||
|
int dispH = _drv->height();
|
||||||
|
int headerH = 30;
|
||||||
|
|
||||||
|
// Check if in header area
|
||||||
|
if(y < headerH) return TileAction::NONE;
|
||||||
|
|
||||||
|
// Calculate which tile was touched
|
||||||
|
int tileW = dispW / _gridCols;
|
||||||
|
int contentH = dispH - headerH;
|
||||||
|
int tileH = contentH / _gridRows;
|
||||||
|
|
||||||
|
int col = x / tileW;
|
||||||
|
int row = (y - headerH) / tileH;
|
||||||
|
|
||||||
|
// Bounds check
|
||||||
|
if(col < 0 || col >= _gridCols || row < 0 || row >= _gridRows) {
|
||||||
|
return TileAction::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = row * _gridCols + col;
|
||||||
|
if(index < 0 || index >= DASHBOARD_TILE_COUNT) {
|
||||||
|
return TileAction::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DASHBOARD_TILES[index].action;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IDisplayDriver* _drv;
|
IDisplayDriver* _drv;
|
||||||
|
mutable int _gridRows = 0;
|
||||||
|
mutable int _gridCols = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -323,11 +323,30 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(_state.screen == ScreenID::DASHBOARD) {
|
if(_state.screen == ScreenID::DASHBOARD) {
|
||||||
int tile = _display->dashboardTouch(evt.x, evt.y);
|
TileAction action = _display->handleDashboardTouch(evt.x, evt.y);
|
||||||
if(tile >= 0) {
|
if(action != TileAction::NONE) {
|
||||||
Serial.printf("[DASH] Tile %d tapped\n", tile);
|
Serial.printf("[DASH] Action: %d\n", (int)action);
|
||||||
|
switch(action) {
|
||||||
|
case TileAction::ALERT:
|
||||||
|
onAlert("Manual Alert", "Tile tap");
|
||||||
|
break;
|
||||||
|
case TileAction::SILENCE:
|
||||||
|
if(_state.deviceState == DeviceState::ALERTING)
|
||||||
|
silenceAlert();
|
||||||
|
break;
|
||||||
|
case TileAction::STATUS:
|
||||||
|
heartbeat();
|
||||||
|
break;
|
||||||
|
case TileAction::REBOOT:
|
||||||
|
flushStatus("REBOOT (tile)");
|
||||||
|
delay(500);
|
||||||
|
ESP.restart();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tile;
|
return (int)action;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_state.screen == ScreenID::ALERT) {
|
if(_state.screen == ScreenID::ALERT) {
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ public:
|
|||||||
|
|
||||||
// ── Touch ──
|
// ── Touch ──
|
||||||
virtual TouchEvent readTouch() = 0;
|
virtual TouchEvent readTouch() = 0;
|
||||||
/// Returns tile index at (x,y), or -1 if none.
|
|
||||||
virtual int dashboardTouch(int x, int y) = 0;
|
|
||||||
/// Track a long-press gesture; returns progress/completion.
|
/// Track a long-press gesture; returns progress/completion.
|
||||||
virtual HoldState updateHold(unsigned long holdMs) = 0;
|
virtual HoldState updateHold(unsigned long holdMs) = 0;
|
||||||
/// Idle hint animation (e.g. pulsing ring) while alert is showing.
|
/// Idle hint animation (e.g. pulsing ring) while alert is showing.
|
||||||
@@ -36,4 +34,10 @@ public:
|
|||||||
virtual void updateHint(int x, int y, bool active) = 0;
|
virtual void updateHint(int x, int y, bool active) = 0;
|
||||||
virtual int width() = 0;
|
virtual int width() = 0;
|
||||||
virtual int height() = 0;
|
virtual int height() = 0;
|
||||||
|
|
||||||
|
// ── Dashboard tiles ──
|
||||||
|
/// Transform raw touch coordinates (for rotated touch panels)
|
||||||
|
virtual void transformTouch(int* x, int* y) { /* default: no transform */ }
|
||||||
|
/// Draw a tile at specified position (library handles grid math)
|
||||||
|
virtual void drawTileAt(int x, int y, int w, int h, const char* label, uint16_t bgColor) = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,31 @@ enum class ScreenID { BOOT, OFF, ALERT, DASHBOARD };
|
|||||||
|
|
||||||
enum class BootStage { SPLASH, INIT_DISPLAY, INIT_NETWORK, CONNECTING_WIFI, READY, DONE };
|
enum class BootStage { SPLASH, INIT_DISPLAY, INIT_NETWORK, CONNECTING_WIFI, READY, DONE };
|
||||||
|
|
||||||
|
/// Dashboard tile action handlers
|
||||||
|
enum class TileAction {
|
||||||
|
NONE,
|
||||||
|
ALERT, // Trigger alert
|
||||||
|
SILENCE, // Silence alert
|
||||||
|
STATUS, // Send heartbeat/status
|
||||||
|
REBOOT, // Reboot device
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Dashboard tile definitions — shared across all boards
|
||||||
|
struct DashboardTile {
|
||||||
|
const char* label;
|
||||||
|
uint16_t bgColor; // RGB565
|
||||||
|
TileAction action;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Standard dashboard tiles (auto-gridded based on count)
|
||||||
|
static constexpr DashboardTile DASHBOARD_TILES[] = {
|
||||||
|
{ "Alert", 0x0280, TileAction::ALERT },
|
||||||
|
{ "Silent", 0x0400, TileAction::SILENCE },
|
||||||
|
{ "Status", 0x0440, TileAction::STATUS },
|
||||||
|
{ "Reboot", 0x0100, TileAction::REBOOT },
|
||||||
|
};
|
||||||
|
static constexpr int DASHBOARD_TILE_COUNT = sizeof(DASHBOARD_TILES) / sizeof(DASHBOARD_TILES[0]);
|
||||||
|
|
||||||
struct ScreenState {
|
struct ScreenState {
|
||||||
DeviceState deviceState = DeviceState::BOOTED;
|
DeviceState deviceState = DeviceState::BOOTED;
|
||||||
ScreenID screen = ScreenID::BOOT;
|
ScreenID screen = ScreenID::BOOT;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ def cmd_reader():
|
|||||||
if ready:
|
if ready:
|
||||||
cmd = fifo.read().strip()
|
cmd = fifo.read().strip()
|
||||||
if cmd:
|
if cmd:
|
||||||
ser.write((cmd + "\r").encode())
|
ser.write((cmd + "\n").encode())
|
||||||
print(f"[SENT] {cmd}")
|
print(f"[SENT] {cmd}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if cmd_running:
|
if cmd_running:
|
||||||
|
|||||||
Reference in New Issue
Block a user