#pragma once // ============================================================================= // display_manager.h – Dot-Matrix-Display Ausgabe (8× GYMAX7219, 4×2 Layout) // Projekt: MQTT-Display LaserCutter // // Implementierung mit rohem MD_MAX72XX (kein MD_Parola), damit die physische // 90°-CW Verdrehung der Module per Software (rotateCCW) zuverlässig kompensiert // werden kann – ohne dass MD_Parola Zonenlogik interferiert. // // Modul-Aufteilung (oben links = Index 0): // Modul 0 : WiFi-Fehler-Indikator (showWifiError) // Modul 1–3 (oben) : Laserzeit in ganzen Minuten, 3 Stellen rechtsbündig // Modul 4 : MQTT-Fehler-Indikator (showMqttError) // Modul 5–7 (unten) : Countdown-Sekunden, 3 Stellen rechtsbündig / showIdle // // Verwendung: // display.begin(); // einmalig in setup() // display.showLaserTime(42.5f); // Modul 1-3 // display.showCountdown(18); // Modul 5-7 // display.showIdle(); // Modul 5-7 // display.showWifiError(true); // Modul 0 // display.showMqttError(true); // Modul 4 // display.update(); // in loop() aufrufen (Pflicht) // ============================================================================= #include #include #include #include "config.h" // --------------------------------------------------------------------------- // Maximale Textlänge je Zone (= Anzahl Module pro Zone) // --------------------------------------------------------------------------- #define DISP_CHARS_PER_ZONE DISPLAY_MODULES_PER_ZONE // 4 class DisplayManager { public: DisplayManager(); // Initialisierung (einmalig in setup()) void begin(); // Helligkeit setzen 0–15 void setBrightness(uint8_t level); // ---- Anzeige-Methoden --------------------------------------------------- // Modul 1–3 (oben): Laserzeit in ganzen Minuten, 3 Stellen rechtsbündig // 0–9 → " x" z.B. " 7" // 10–99 → " xx" z.B. " 42" // 100–999 → "xxx" z.B. "123" // ≥ 1000 → "!!!" (Überlauf, wird laut Anforderung nie erreicht) // Modul 0 bleibt unberührt. void showLaserTime(float minutes); // Modul 5–7 (unten): Countdown-Sekunden, 3 Stellen rechtsbündig // 0–9 → " x" // 10–99 → " xx" // 100–999 → "xxx" // ≥ 1000 → "!!!" // Modul 4 bleibt unberührt. void showCountdown(int seconds); // Modul 5–7 (unten): Leerlauf-Anzeige (" --") // Modul 4 bleibt unberührt. void showIdle(); // Modul 5–7 (unten): Sekunden-Kreisanzeige (wie analoge Uhr) // seconds = 0–60: Rand der 3 Module wird sekündlich befüllt // 60 LEDs = Perimeter des 24×8-Feldes (24 oben + 6 rechts + 24 unten + 6 links) // Richtung: Uhrzeigersinn, Start oben-links // seconds = 0 → alle LEDs aus (= Idle) // seconds ≥ 60 → alle 60 Rand-LEDs an // Modul 4 bleibt unberührt. void showSessionRing(int seconds); // Modul 5–7 (unten): Statustext (max. 3 Zeichen, wird abgeschnitten / aufgefüllt) // Modul 4 bleibt unberührt. void showStatus(const char* msg); // Modul 0 (oben links): WiFi-Fehler-Indikator // error=true → 'W' Symbol // error=false → leer void showWifiError(bool error); // Modul 4 (unten links): MQTT-Fehler-Indikator // error=true → 'M' Symbol // error=false → leer void showMqttError(bool error); // Beide Zonen löschen void clear(); // MAX7219 neu initialisieren (einmaliges initMx, kein Delay) // Aufrufen nach Relais-Umschaltung um durch EMV-Störungen korrumpierte // MAX7219-Register (Decode-Mode, Scan-Limit) zurückzusetzen void reinit(); // Muss in loop() aufgerufen werden (reserviert für zukünftige Scroll-Animation) void update() {} // Alle LEDs ein / aus (Testfunktion) void allLedsOn(); void allLedsOff(); // Display ein-/ausschalten (SHUTDOWN-Modus des MAX7219) // setEnabled(false) → alle LEDs aus (MAX7219 Shutdown) // setEnabled(true) → normaler Betrieb void setEnabled(bool enabled); bool isEnabled() const { return _enabled; } // Debug-Ausgabe auf Serial void printToSerial() const; private: MD_MAX72XX _mx; bool _enabled = true; // ---- Letzter angezeigter Zustand (für redraw nach reinit) ---------------- enum class BottomMode : uint8_t { IDLE, COUNTDOWN, RING, STATUS }; float _lastLaserMinutes = 0.0f; BottomMode _lastBottomMode = BottomMode::IDLE; int _lastBottomValue = 0; char _lastStatusMsg[4] = {' ', ' ', ' ', '\0'}; bool _lastWifiError = false; bool _lastMqttError = false; // Zeichnet den zuletzt gespeicherten Zustand neu auf die Hardware void redraw(); // Schreibt genau DISP_CHARS_PER_ZONE Zeichen auf eine Zone // zone 0 → Module 0..3 (oben) // zone 1 → Module 4..7 (unten) // str muss exakt DISP_CHARS_PER_ZONE Zeichen enthalten (kein Null-Terminator nötig) void writeZone(uint8_t zone, const char* str); // Schreibt ein Zeichen auf ein einzelnes Modul void writeChar(uint8_t moduleIdx, char c); // 90° CCW Rotation – kompensiert physische 90° CW Verdrehung der Module static void rotateCCW(const uint8_t src[8], uint8_t dst[8]); // Gibt Zeiger auf 8-Byte-Bitmap für ASCII-Zeichen zurück // Unterstützt: '0'–'9', ' ', '-', '.', '!', 'E', 'r', 'o', 'n', 'A', 'P' static const uint8_t* charBitmap(char c); }; // Globale Instanz extern DisplayManager display;