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
This commit is contained in:
MaPaLo76 2026-03-06 21:48:14 +01:00
parent b6610dffc7
commit 6c8be70eb9
3 changed files with 63 additions and 0 deletions

View File

@ -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)

View File

@ -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 57)
// ---------------------------------------------------------------------------
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 57)
// ---------------------------------------------------------------------------
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' : ' ');
}

View File

@ -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);