245 lines
5.8 KiB
C++
245 lines
5.8 KiB
C++
#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");
|
||
}
|