refactor(display): split render into screen-specific draw methods
This commit is contained in:
@@ -1,20 +1,3 @@
|
|||||||
#include "LovyanPins.h"
|
|
||||||
#include "board_config.h"
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <ESP_IOExpander_Library.h>
|
|
||||||
|
|
||||||
// Global display instance
|
|
||||||
static LGFX* _gfx = nullptr;
|
|
||||||
static ESP_IOExpander* _expander = nullptr;
|
|
||||||
|
|
||||||
// Forward declarations
|
|
||||||
void initExpander();
|
|
||||||
void initDisplay();
|
|
||||||
|
|
||||||
// ── Expander initialization (from Westcott) ──
|
|
||||||
void initExpander()
|
|
||||||
{
|
|
||||||
Serial.println("IO expander init...");
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <ESP_IOExpander_Library.h>
|
#include <ESP_IOExpander_Library.h>
|
||||||
@@ -34,11 +17,11 @@ static void initDisplay();
|
|||||||
static constexpr int DISP_W = 800;
|
static constexpr int DISP_W = 800;
|
||||||
static constexpr int DISP_H = 480;
|
static constexpr int DISP_H = 480;
|
||||||
|
|
||||||
// ── Expander initialization ──
|
// ── Expander initialization (from Westcott) ──
|
||||||
static void initExpander() {
|
static void initExpander() {
|
||||||
Serial.println("IO expander init...");
|
Serial.println("IO expander init...");
|
||||||
|
|
||||||
// Initialize I2C for expander
|
// Initialize I2C for expander (port 0)
|
||||||
Wire.begin(TOUCH_SDA, TOUCH_SCL);
|
Wire.begin(TOUCH_SDA, TOUCH_SCL);
|
||||||
|
|
||||||
_expander = new ESP_IOExpander_CH422G(
|
_expander = new ESP_IOExpander_CH422G(
|
||||||
@@ -51,7 +34,7 @@ static void initExpander() {
|
|||||||
// Set all pins to output
|
// Set all pins to output
|
||||||
_expander->multiPinMode(TP_RST | LCD_BL | LCD_RST | SD_CS | USB_SEL, OUTPUT);
|
_expander->multiPinMode(TP_RST | LCD_BL | LCD_RST | SD_CS | USB_SEL, OUTPUT);
|
||||||
|
|
||||||
// Reset sequence
|
// Reset sequence for LCD
|
||||||
_expander->digitalWrite(LCD_RST, LOW);
|
_expander->digitalWrite(LCD_RST, LOW);
|
||||||
delay(50);
|
delay(50);
|
||||||
_expander->digitalWrite(LCD_RST, HIGH);
|
_expander->digitalWrite(LCD_RST, HIGH);
|
||||||
@@ -115,7 +98,7 @@ TouchEvent DisplayDriverGFX::readTouch() {
|
|||||||
evt.x = static_cast<int>(x);
|
evt.x = static_cast<int>(x);
|
||||||
evt.y = static_cast<int>(y);
|
evt.y = static_cast<int>(y);
|
||||||
|
|
||||||
// Track press start
|
// Track press start for hold detection
|
||||||
if (!_lastTouch.pressed) {
|
if (!_lastTouch.pressed) {
|
||||||
_pressStartMs = millis();
|
_pressStartMs = millis();
|
||||||
_isHolding = false;
|
_isHolding = false;
|
||||||
@@ -154,7 +137,6 @@ HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) {
|
|||||||
unsigned long elapsed = millis() - _pressStartMs;
|
unsigned long elapsed = millis() - _pressStartMs;
|
||||||
|
|
||||||
if (!_isHolding) {
|
if (!_isHolding) {
|
||||||
// Start tracking hold
|
|
||||||
_isHolding = true;
|
_isHolding = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,49 +156,111 @@ HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) {
|
|||||||
void DisplayDriverGFX::render(const ScreenState& state) {
|
void DisplayDriverGFX::render(const ScreenState& state) {
|
||||||
if (!_gfx) return;
|
if (!_gfx) return;
|
||||||
|
|
||||||
// Clear with background color
|
// Check if we need full redraw
|
||||||
_gfx->fillScreen(0x001030); // Dark blue
|
if (state.screen != _lastScreen) {
|
||||||
|
_needsRedraw = true;
|
||||||
if (!state.showDashboard) {
|
_lastScreen = state.screen;
|
||||||
// Show alert/message screen
|
|
||||||
renderAlert(state);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw dashboard tiles
|
switch (state.screen) {
|
||||||
|
case ScreenID::BOOT:
|
||||||
|
if (_needsRedraw) {
|
||||||
|
_gfx->fillScreen(0x000000);
|
||||||
|
_gfx->setTextColor(0xFFFF);
|
||||||
|
_gfx->setTextSize(2);
|
||||||
|
_gfx->setCursor(10, 10);
|
||||||
|
_gfx->print("KLUBHAUS BOOT");
|
||||||
|
_needsRedraw = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScreenID::OFF:
|
||||||
|
if (_needsRedraw) {
|
||||||
|
_gfx->fillScreen(0x000000);
|
||||||
|
_needsRedraw = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScreenID::ALERT:
|
||||||
|
drawAlert(state);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ScreenID::DASHBOARD:
|
||||||
|
if (_needsRedraw) {
|
||||||
|
drawDashboard(state);
|
||||||
|
_needsRedraw = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayDriverGFX::drawAlert(const ScreenState& state) {
|
||||||
|
uint32_t elapsed = millis() - state.alertStartMs;
|
||||||
|
uint8_t pulse = static_cast<uint8_t>(180.0f + 75.0f * sinf(elapsed / 300.0f));
|
||||||
|
uint16_t bg = _gfx->color565(pulse, 0, 0);
|
||||||
|
|
||||||
|
_gfx->fillScreen(bg);
|
||||||
|
_gfx->setTextColor(0xFFFF, bg);
|
||||||
|
|
||||||
|
_gfx->setTextSize(3);
|
||||||
|
_gfx->setCursor(10, 20);
|
||||||
|
_gfx->print(state.alertTitle.length() > 0 ? state.alertTitle.c_str() : "ALERT");
|
||||||
|
|
||||||
|
_gfx->setTextSize(2);
|
||||||
|
_gfx->setCursor(10, 80);
|
||||||
|
_gfx->print(state.alertBody);
|
||||||
|
|
||||||
|
_gfx->setTextSize(1);
|
||||||
|
_gfx->setCursor(10, DISP_H - 20);
|
||||||
|
_gfx->print("Hold to silence...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayDriverGFX::drawDashboard(const ScreenState& state) {
|
||||||
|
_gfx->fillScreen(0x001030); // Dark blue
|
||||||
|
|
||||||
|
// Header
|
||||||
|
_gfx->fillRect(0, 0, DISP_W, 30, 0x0220);
|
||||||
|
_gfx->setTextColor(0xFFFF);
|
||||||
|
_gfx->setTextSize(1);
|
||||||
|
_gfx->setCursor(5, 10);
|
||||||
|
_gfx->printf("KLUBHAUS");
|
||||||
|
|
||||||
|
// WiFi status
|
||||||
|
_gfx->setCursor(DISP_W - 100, 10);
|
||||||
|
_gfx->printf("WiFi:%s", state.wifiSsid.length() > 0 ? "ON" : "OFF");
|
||||||
|
|
||||||
|
|
||||||
|
// Tiles: 2 rows × 4 columns
|
||||||
constexpr int cols = 4;
|
constexpr int cols = 4;
|
||||||
constexpr int rows = 2;
|
constexpr int rows = 2;
|
||||||
constexpr int tileW = DISP_W / cols;
|
constexpr int tileW = DISP_W / cols;
|
||||||
constexpr int tileH = DISP_H / rows;
|
constexpr int tileH = (DISP_H - 30) / rows;
|
||||||
constexpr int margin = 8;
|
constexpr int margin = 8;
|
||||||
|
|
||||||
for (int i = 0; i < state.dashTiles.size(); i++) {
|
// Draw placeholder tiles (8 total for 2x4 grid)
|
||||||
|
const char* tileLabels[] = {"1", "2", "3", "4", "5", "6", "7", "8"};
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
int col = i % cols;
|
int col = i % cols;
|
||||||
int row = i / cols;
|
int row = i / cols;
|
||||||
|
|
||||||
int x = col * tileW + margin;
|
int x = col * tileW + margin;
|
||||||
int y = row * tileH + margin;
|
int y = 30 + row * tileH + margin;
|
||||||
int w = tileW - 2 * margin;
|
int w = tileW - 2 * margin;
|
||||||
int h = tileH - 2 * margin;
|
int h = tileH - 2 * margin;
|
||||||
|
|
||||||
// Tile background
|
// Tile background
|
||||||
uint16_t tileColor = state.dashTiles[i].active ? 0x04A0 : 0x0220;
|
_gfx->fillRoundRect(x, y, w, h, 8, 0x0220);
|
||||||
_gfx->fillRoundRect(x, y, w, h, 8, tileColor);
|
|
||||||
|
|
||||||
// Tile border
|
// Tile border
|
||||||
_gfx->drawRoundRect(x, y, w, h, 8, 0xFFFF);
|
_gfx->drawRoundRect(x, y, w, h, 8, 0xFFFF);
|
||||||
|
|
||||||
// Tile label
|
// Tile number
|
||||||
_gfx->setTextColor(0xFFFF);
|
_gfx->setTextColor(0xFFFF);
|
||||||
_gfx->setTextSize(2);
|
_gfx->setTextSize(2);
|
||||||
_gfx->setCursor(x + 10, y + 10);
|
_gfx->setCursor(x + w/2 - 10, y + h/2 - 10);
|
||||||
_gfx->print(state.dashTiles[i].label);
|
_gfx->print(tileLabels[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw WiFi status
|
|
||||||
_gfx->setTextSize(1);
|
|
||||||
_gfx->setCursor(DISP_W - 100, 10);
|
|
||||||
_gfx->printf("WiFi: %s", state.wifiConnected ? "ON" : "OFF");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayDriverGFX::updateHint() {
|
void DisplayDriverGFX::updateHint() {
|
||||||
@@ -233,12 +277,3 @@ void DisplayDriverGFX::updateHint() {
|
|||||||
|
|
||||||
_gfx->drawCircle(DISP_W / 2, DISP_H / 2, 50, col);
|
_gfx->drawCircle(DISP_W / 2, DISP_H / 2, 50, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper for alert rendering (implement as needed)
|
|
||||||
void DisplayDriverGFX::renderAlert(const ScreenState& state) {
|
|
||||||
// Placeholder - implement based on your ScreenState fields
|
|
||||||
_gfx->setTextColor(0xFFFF);
|
|
||||||
_gfx->setTextSize(3);
|
|
||||||
_gfx->setCursor(200, 200);
|
|
||||||
_gfx->print("Alert Mode");
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,21 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "ScreenState.h"
|
|
||||||
#include "IDisplayDriver.h"
|
#include "IDisplayDriver.h"
|
||||||
|
|
||||||
struct TouchEvent {
|
|
||||||
bool pressed = false;
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HoldState {
|
|
||||||
bool active = false;
|
|
||||||
bool completed = false;
|
|
||||||
float progress = 0.0f; // 0.0 – 1.0
|
|
||||||
};
|
|
||||||
|
|
||||||
class DisplayDriverGFX : public IDisplayDriver {
|
class DisplayDriverGFX : public IDisplayDriver {
|
||||||
public:
|
public:
|
||||||
// ── IDisplayDriver ──
|
// ── IDisplayDriver ──
|
||||||
@@ -35,8 +22,16 @@ public:
|
|||||||
static DisplayDriverGFX& instance();
|
static DisplayDriverGFX& instance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Helper rendering functions
|
||||||
|
void drawAlert(const ScreenState& state);
|
||||||
|
void drawDashboard(const ScreenState& state);
|
||||||
|
|
||||||
// Touch handling
|
// Touch handling
|
||||||
TouchEvent _lastTouch = {false, 0, 0};
|
TouchEvent _lastTouch = {false, 0, 0};
|
||||||
unsigned long _pressStartMs = 0;
|
unsigned long _pressStartMs = 0;
|
||||||
bool _isHolding = false;
|
bool _isHolding = false;
|
||||||
|
|
||||||
|
// Screen tracking
|
||||||
|
ScreenID _lastScreen = ScreenID::BOOT;
|
||||||
|
bool _needsRedraw = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,38 +17,50 @@ enum class ScreenID {
|
|||||||
|
|
||||||
struct ScreenState {
|
struct ScreenState {
|
||||||
DeviceState deviceState = DeviceState::BOOTED;
|
DeviceState deviceState = DeviceState::BOOTED;
|
||||||
ScreenID screen = ScreenID::BOOT;
|
ScreenID screen = ScreenID::BOOT;
|
||||||
|
|
||||||
String alertTitle;
|
String alertTitle;
|
||||||
String alertBody;
|
String alertBody;
|
||||||
uint32_t alertStartMs = 0;
|
uint32_t alertStartMs = 0;
|
||||||
uint32_t silenceStartMs = 0;
|
uint32_t silenceStartMs = 0;
|
||||||
|
|
||||||
bool backlightOn = false;
|
bool backlightOn = false;
|
||||||
int wifiRssi = 0;
|
int wifiRssi = 0;
|
||||||
String wifiSsid;
|
String wifiSsid;
|
||||||
String ipAddr;
|
String ipAddr;
|
||||||
uint32_t uptimeMs = 0;
|
uint32_t uptimeMs = 0;
|
||||||
uint32_t lastPollMs = 0;
|
uint32_t lastPollMs = 0;
|
||||||
uint32_t lastHeartbeatMs= 0;
|
uint32_t lastHeartbeatMs = 0;
|
||||||
|
|
||||||
|
bool showDashboard = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const char* deviceStateStr(DeviceState s) {
|
inline const char* deviceStateStr(DeviceState s)
|
||||||
|
{
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case DeviceState::BOOTED: return "BOOTED";
|
case DeviceState::BOOTED:
|
||||||
case DeviceState::SILENT: return "SILENT";
|
return "BOOTED";
|
||||||
case DeviceState::ALERTING: return "ALERTING";
|
case DeviceState::SILENT:
|
||||||
case DeviceState::SILENCED: return "SILENCED";
|
return "SILENT";
|
||||||
|
case DeviceState::ALERTING:
|
||||||
|
return "ALERTING";
|
||||||
|
case DeviceState::SILENCED:
|
||||||
|
return "SILENCED";
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char* screenIdStr(ScreenID s) {
|
inline const char* screenIdStr(ScreenID s)
|
||||||
|
{
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case ScreenID::BOOT: return "BOOT";
|
case ScreenID::BOOT:
|
||||||
case ScreenID::OFF: return "OFF";
|
return "BOOT";
|
||||||
case ScreenID::ALERT: return "ALERT";
|
case ScreenID::OFF:
|
||||||
case ScreenID::DASHBOARD: return "DASHBOARD";
|
return "OFF";
|
||||||
|
case ScreenID::ALERT:
|
||||||
|
return "ALERT";
|
||||||
|
case ScreenID::DASHBOARD:
|
||||||
|
return "DASHBOARD";
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|||||||
16
mise.toml
16
mise.toml
@@ -42,6 +42,22 @@ if [ ! -d "vendor/esp32-s3-lcd-43/LovyanGFX" ]; then
|
|||||||
else
|
else
|
||||||
echo "LovyanGFX already exists, skipping"
|
echo "LovyanGFX already exists, skipping"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Create library.properties for Arduino CLI
|
||||||
|
cat > vendor/esp32-s3-lcd-43/LovyanGFX/library.properties << 'EOF'
|
||||||
|
name=LovyanGFX
|
||||||
|
version=0.5.0
|
||||||
|
author=lovyan03
|
||||||
|
maintainer=lovyan03
|
||||||
|
sentence=GFX library for ESP32
|
||||||
|
paragraph=Display and touch driver for ESP32
|
||||||
|
category=Display
|
||||||
|
url=https://github.com/lovyan03/LovyanGFX
|
||||||
|
architectures=esp32
|
||||||
|
includes=LovyanGFX.hpp
|
||||||
|
src_core=src
|
||||||
|
EOF
|
||||||
|
|
||||||
echo "[OK] LovyanGFX vendored"
|
echo "[OK] LovyanGFX vendored"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user