Files
klubhaus-doorbell/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp

245 lines
5.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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 <Wire.h>
#include <ESP_IOExpander_Library.h>
#include "LovyanPins.h"
#include "board_config.h"
#include "DisplayDriverGFX.h"
// ── Globals ──
static LGFX* _gfx = nullptr;
static ESP_IOExpander* _expander = nullptr;
// ── Forward declarations ──
static void initExpander();
static void initDisplay();
// ── Dimensions ──
static constexpr int DISP_W = 800;
static constexpr int DISP_H = 480;
// ── Expander initialization ──
static void initExpander() {
Serial.println("IO expander init...");
// Initialize I2C for expander
Wire.begin(TOUCH_SDA, TOUCH_SCL);
_expander = new ESP_IOExpander_CH422G(
(i2c_port_t)I2C_NUM_0,
ESP_IO_EXPANDER_I2C_CH422G_ADDRESS
);
_expander->init();
_expander->begin();
// Set all pins to output
_expander->multiPinMode(TP_RST | LCD_BL | LCD_RST | SD_CS | USB_SEL, OUTPUT);
// Reset sequence
_expander->digitalWrite(LCD_RST, LOW);
delay(50);
_expander->digitalWrite(LCD_RST, HIGH);
delay(150);
// Turn on backlight
_expander->digitalWrite(LCD_BL, HIGH);
Serial.println("IO expander ready");
}
// ── Display initialization ──
static void initDisplay() {
Serial.println("LovyanGFX init...");
_gfx = new LGFX();
_gfx->init();
_gfx->setRotation(1); // Landscape
_gfx->fillScreen(0x000000);
Serial.println("Display ready");
}
// ── Singleton ──
DisplayDriverGFX& DisplayDriverGFX::instance() {
static DisplayDriverGFX inst;
return inst;
}
// ── IDisplayDriver implementation ──
void DisplayDriverGFX::begin() {
initExpander();
initDisplay();
}
void DisplayDriverGFX::setBacklight(bool on) {
if (_expander) {
_expander->digitalWrite(LCD_BL, on ? HIGH : LOW);
}
}
int DisplayDriverGFX::width() {
return DISP_W;
}
int DisplayDriverGFX::height() {
return DISP_H;
}
// ── Touch handling ──
TouchEvent DisplayDriverGFX::readTouch() {
TouchEvent evt;
if (!_gfx) return evt;
int32_t x, y;
if (_gfx->getTouch(&x, &y)) {
evt.pressed = true;
evt.x = static_cast<int>(x);
evt.y = static_cast<int>(y);
// Track press start
if (!_lastTouch.pressed) {
_pressStartMs = millis();
_isHolding = false;
}
}
_lastTouch = evt;
return evt;
}
int DisplayDriverGFX::dashboardTouch(int x, int y) {
// Dashboard tiles: 2 rows × 4 columns
constexpr int cols = 4;
constexpr int rows = 2;
constexpr int tileW = DISP_W / cols;
constexpr int tileH = DISP_H / rows;
if (x < 0 || x >= DISP_W || y < 0 || y >= DISP_H) {
return -1;
}
int col = x / tileW;
int row = y / tileH;
return row * cols + col;
}
HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) {
HoldState state;
if (!_lastTouch.pressed) {
_isHolding = false;
return state;
}
unsigned long elapsed = millis() - _pressStartMs;
if (!_isHolding) {
// Start tracking hold
_isHolding = true;
}
state.active = true;
state.progress = static_cast<float>(elapsed) / static_cast<float>(holdMs);
if (state.progress >= 1.0f) {
state.progress = 1.0f;
state.completed = true;
}
return state;
}
// ── Rendering ──
void DisplayDriverGFX::render(const ScreenState& state) {
if (!_gfx) return;
// Clear with background color
_gfx->fillScreen(0x001030); // Dark blue
if (!state.showDashboard) {
// Show alert/message screen
renderAlert(state);
return;
}
// Draw dashboard tiles
constexpr int cols = 4;
constexpr int rows = 2;
constexpr int tileW = DISP_W / cols;
constexpr int tileH = DISP_H / rows;
constexpr int margin = 8;
for (int i = 0; i < state.dashTiles.size(); i++) {
int col = i % cols;
int row = i / cols;
int x = col * tileW + margin;
int y = row * tileH + margin;
int w = tileW - 2 * margin;
int h = tileH - 2 * margin;
// Tile background
uint16_t tileColor = state.dashTiles[i].active ? 0x04A0 : 0x0220;
_gfx->fillRoundRect(x, y, w, h, 8, tileColor);
// Tile border
_gfx->drawRoundRect(x, y, w, h, 8, 0xFFFF);
// Tile label
_gfx->setTextColor(0xFFFF);
_gfx->setTextSize(2);
_gfx->setCursor(x + 10, y + 10);
_gfx->print(state.dashTiles[i].label);
}
// Draw WiFi status
_gfx->setTextSize(1);
_gfx->setCursor(DISP_W - 100, 10);
_gfx->printf("WiFi: %s", state.wifiConnected ? "ON" : "OFF");
}
void DisplayDriverGFX::updateHint() {
if (!_gfx) return;
static uint32_t lastTime = 0;
uint32_t now = millis();
if (now - lastTime < 50) return;
lastTime = now;
float t = (now % 2000) / 2000.0f;
uint8_t v = static_cast<uint8_t>(30.0f + 30.0f * sinf(t * 2 * 3.14159f));
uint16_t col = ((v >> 3) << 11) | ((v >> 2) << 5) | (v >> 3);
_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");
}