From 6c8be70eb9c7a3d03ebc6f2aa1368f0c53f06828 Mon Sep 17 00:00:00 2001 From: MaPaLo76 <72209721+MaPaLo76@users.noreply.github.com> Date: Fri, 6 Mar 2026 21:48:14 +0100 Subject: [PATCH] fix(display): FR-014 MAX7219 Re-Init + redraw() nach Relais-Umschaltung (v1.5.2) - DisplayManager::reinit() setzt nur Kontroll-Register (ohne clear()) - Neues State-Tracking: show*() speichert letzten Zustand intern - Neues redraw(): zeichnet alle Zonen nach reinit() sofort neu - LaserTracker::onSessionStart/onSessionEnd rufen display.reinit() auf --- include/display_manager.h | 17 ++++++++++++++++ src/display_manager.cpp | 43 +++++++++++++++++++++++++++++++++++++++ src/laser_tracker.cpp | 3 +++ 3 files changed, 63 insertions(+) diff --git a/include/display_manager.h b/include/display_manager.h index f00c18e..583a2d8 100644 --- a/include/display_manager.h +++ b/include/display_manager.h @@ -92,6 +92,11 @@ public: // 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() {} @@ -112,6 +117,18 @@ 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) diff --git a/src/display_manager.cpp b/src/display_manager.cpp index da46552..e0bf295 100644 --- a/src/display_manager.cpp +++ b/src/display_manager.cpp @@ -209,6 +209,39 @@ void DisplayManager::begin() { LOG_I("DISP", "DisplayManager initialisiert (GENERIC_HW, %d Module)", DISPLAY_MODULE_COUNT); } +// --------------------------------------------------------------------------- +// Nur Kontroll-Register neu setzen – ohne clear() (Digit-Daten bleiben) +// --------------------------------------------------------------------------- +static void reInitRegisters(MD_MAX72XX& mx, uint8_t brightness) { + mx.begin(); + mx.control(MD_MAX72XX::INTENSITY, brightness); + mx.control(MD_MAX72XX::TEST, MD_MAX72XX::OFF); +} + +// --------------------------------------------------------------------------- +// Leichter Re-Init nach EMV-Störung: Register neu + sofort neu zeichnen +// --------------------------------------------------------------------------- +void DisplayManager::reinit() { + reInitRegisters(_mx, DISPLAY_BRIGHTNESS); + redraw(); + LOG_I("DISP", "reinit() + redraw() nach Relais-Umschaltung"); +} + +// --------------------------------------------------------------------------- +// Letzten Zustand neu auf die Hardware schreiben +// --------------------------------------------------------------------------- +void DisplayManager::redraw() { + showLaserTime(_lastLaserMinutes); + switch (_lastBottomMode) { + case BottomMode::IDLE: showIdle(); break; + case BottomMode::COUNTDOWN: showCountdown(_lastBottomValue); break; + case BottomMode::RING: showSessionRing(_lastBottomValue); break; + case BottomMode::STATUS: showStatus(_lastStatusMsg); break; + } + showWifiError(_lastWifiError); + showMqttError(_lastMqttError); +} + // --------------------------------------------------------------------------- void DisplayManager::setBrightness(uint8_t level) { if (level > 15) level = 15; @@ -252,6 +285,7 @@ void DisplayManager::writeZone(uint8_t zone, const char* str) { // --------------------------------------------------------------------------- void DisplayManager::showLaserTime(float minutes) { if (minutes < 0.0f) minutes = 0.0f; + _lastLaserMinutes = minutes; int mins = (int)(minutes + 0.5f); // kaufmännisch runden char buf[4]; // 3 Zeichen + Nulltermin @@ -279,6 +313,8 @@ void DisplayManager::showLaserTime(float minutes) { // Modul 4 (MQTT-Fehler-Reservierung) wird NICHT verändert. // --------------------------------------------------------------------------- void DisplayManager::showCountdown(int seconds) { + _lastBottomMode = BottomMode::COUNTDOWN; + _lastBottomValue = seconds; if (seconds < 0) seconds = 0; char buf[4]; // 3 Zeichen + Nulltermin @@ -304,6 +340,7 @@ void DisplayManager::showCountdown(int seconds) { // Leerlauf-Anzeige unten (" --" auf Module 5–7) // --------------------------------------------------------------------------- void DisplayManager::showIdle() { + _lastBottomMode = BottomMode::IDLE; writeChar(5, 'A'); writeChar(6, 'U'); writeChar(7, 'S'); @@ -320,6 +357,8 @@ void DisplayManager::showIdle() { // Pos 54-59: links, col=0, row 6→1 // --------------------------------------------------------------------------- void DisplayManager::showSessionRing(int seconds) { + _lastBottomMode = BottomMode::RING; + _lastBottomValue = seconds; if (seconds < 1) seconds = 1; // Defensiv: Untergrenze if (seconds > 60) seconds = 60; // Defensiv: Obergrenze @@ -360,6 +399,8 @@ void DisplayManager::showSessionRing(int seconds) { // Statustext unten (max. 3 Zeichen auf Module 5–7) // --------------------------------------------------------------------------- void DisplayManager::showStatus(const char* msg) { + _lastBottomMode = BottomMode::STATUS; + strlcpy(_lastStatusMsg, msg, sizeof(_lastStatusMsg)); char buf[4] = " "; // 3 Leerzeichen als Vorlage size_t len = strlen(msg); if (len > 3) len = 3; @@ -374,6 +415,7 @@ void DisplayManager::showStatus(const char* msg) { // WiFi-Fehler-Indikator auf Modul 0 // --------------------------------------------------------------------------- void DisplayManager::showWifiError(bool error) { + _lastWifiError = error; writeChar(0, error ? 'W' : ' '); } @@ -381,6 +423,7 @@ void DisplayManager::showWifiError(bool error) { // MQTT-Fehler-Indikator auf Modul 4 // --------------------------------------------------------------------------- void DisplayManager::showMqttError(bool error) { + _lastMqttError = error; writeChar(4, error ? 'M' : ' '); } diff --git a/src/laser_tracker.cpp b/src/laser_tracker.cpp index 4be6b25..3c25d85 100644 --- a/src/laser_tracker.cpp +++ b/src/laser_tracker.cpp @@ -4,6 +4,7 @@ #include "laser_tracker.h" #include "config.h" +#include "display_manager.h" // Globale Instanz LaserTracker laserTracker; @@ -82,6 +83,7 @@ void LaserTracker::onSessionStart() { _sessionStartTime = time(nullptr); _netStartMs = 0; LOG_I("LASER", "SessionStart -> GRATIS"); + display.reinit(); // MAX7219 nach Relais-AN re-init (EMV-Schutz) } time_t LaserTracker::getSessionStartTime() const { @@ -91,6 +93,7 @@ time_t LaserTracker::getSessionStartTime() const { // --------------------------------------------------------------------------- // Ereignis: Laser AUS (nach Debounce) void LaserTracker::onSessionEnd() { + display.reinit(); // MAX7219 nach Relais-AUS re-init (EMV-Schutz) // Gesamte Session-Dauer (inkl. Gratiszeit) -> NVS int totalSessionSec = (int)((millis() - _sessionStartMs) / 1000);