fix(display): redesign module layout - integer minutes, dedicated error slots
New module assignment: Module 0 : WiFi error indicator (showWifiError) - 'W' / blank Module 1-3 : laser time in full minutes, 3-digit right-aligned Module 4 : MQTT error indicator (showMqttError) - 'M' / blank Module 5-7 : countdown seconds / idle / status, 3-digit right-aligned Changes in display_manager.h: - Update zone layout comments - showLaserTime: integer minutes only, writes modules 1-3 (module 0 untouched) - showCountdown: writes modules 5-7 only (module 4 untouched) - showIdle: ' --' on modules 5-7 - showStatus: 3-char string on modules 5-7 - Add showWifiError(bool): module 0 - Add showMqttError(bool): module 4 Changes in display_manager.cpp: - Add BMP_M character bitmap - Add 'M' case in charBitmap() - Rewrite showLaserTime() - round to int, 3 chars, modules 1-3 - Rewrite showCountdown() - 3 chars, modules 5-7 - Rewrite showIdle() - ' --' on modules 5-7 - Rewrite showStatus() - 3 chars, modules 5-7 - Add showWifiError() / showMqttError() implementations - Update printToSerial() log output Changes in test_sketch: - 9 test steps covering all new methods incl. combination test - Tested on hardware: all steps passed
This commit is contained in:
parent
4349b37f05
commit
26a4e9b95c
263
doc/Front.svg
Normal file
263
doc/Front.svg
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="297mm"
|
||||
height="420mm"
|
||||
viewBox="0 0 297 420"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4.2 (f4327f4, 2025-05-13)"
|
||||
sodipodi:docname="Front.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:zoom="0.71891835"
|
||||
inkscape:cx="755.99684"
|
||||
inkscape:cy="710.09455"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1009"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer3" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<rect
|
||||
x="570.3012"
|
||||
y="984.81281"
|
||||
width="239.24831"
|
||||
height="91.804584"
|
||||
id="rect4" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Rahmen"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#000000;stroke:#ff0000;stroke-width:0.2;stroke-linejoin:bevel"
|
||||
id="rect1"
|
||||
width="253"
|
||||
height="253"
|
||||
x="22"
|
||||
y="83.5" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#ff0000;stroke-width:0.2;stroke-linejoin:bevel"
|
||||
id="rect2"
|
||||
width="217"
|
||||
height="217"
|
||||
x="40"
|
||||
y="101.5" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="DotMatrixDisplay"
|
||||
transform="translate(5.921936,55.427505)"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="75.078072"
|
||||
y="154.57249" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-8"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="75.078072"
|
||||
y="121.07249" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-1"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="108.82807"
|
||||
y="121.07248" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-1-2"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="108.82807"
|
||||
y="154.57249" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-2"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="142.57806"
|
||||
y="154.57249" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-8-3"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="142.57806"
|
||||
y="121.07248" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-1-22"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="176.32806"
|
||||
y="121.07246" />
|
||||
<rect
|
||||
style="fill:#cccccc;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
id="rect3-1-2-1"
|
||||
width="33.75"
|
||||
height="33.5"
|
||||
x="176.32806"
|
||||
y="154.57249" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Beschriftung">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="204.76865"
|
||||
y="256.40359"
|
||||
id="text4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4"
|
||||
style="fill:#000000;stroke-width:0.2"
|
||||
x="204.76865"
|
||||
y="256.40359">Freie Testzeit</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="fill:#000000;stroke-width:0.2"
|
||||
x="204.76865"
|
||||
y="256.40359"
|
||||
id="tspan5" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="203.7793"
|
||||
y="265.51187"
|
||||
id="text6"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6"
|
||||
style="fill:#000000;stroke-width:0.2"
|
||||
x="203.7793"
|
||||
y="265.51187">in Sekunden</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="191.73494"
|
||||
y="162.06888"
|
||||
id="text4-6"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4-1"
|
||||
style="fill:#000000;stroke-width:0.2"
|
||||
x="191.73494"
|
||||
y="162.06888">kostenpflichtige</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="fill:#000000;stroke-width:0.2"
|
||||
x="191.73494"
|
||||
y="162.06888"
|
||||
id="tspan5-8" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-size:14.8167px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="241.88585"
|
||||
y="126.91018"
|
||||
id="text4-6-2"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7"
|
||||
x="241.88585"
|
||||
y="126.91018">Laser Cutter Zeiterfassung</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan8"
|
||||
x="241.88585"
|
||||
y="126.91018"></tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;stroke:#241212;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="199.64789"
|
||||
y="171.17715"
|
||||
id="text6-9"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6-2"
|
||||
style="fill:#000000;stroke-width:0.2"
|
||||
x="199.64789"
|
||||
y="171.17715">Laserzeit in Minuten</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#ff0000;stroke:#ff0000;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="103.04314"
|
||||
y="163.84862"
|
||||
id="text4-6-4"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4-1-1"
|
||||
style="fill:#ff0000;stroke-width:0.2;stroke:#ff0000"
|
||||
x="103.04314"
|
||||
y="163.84862">Wifi</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="fill:#ff0000;stroke-width:0.2;stroke:#ff0000"
|
||||
x="103.04314"
|
||||
y="163.84862"
|
||||
id="tspan5-8-1" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#ff0000;stroke:#ff0000;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="104.63658"
|
||||
y="171.17715"
|
||||
id="text6-9-3"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6-2-8"
|
||||
style="fill:#ff0000;stroke-width:0.2;stroke:#ff0000"
|
||||
x="104.63658"
|
||||
y="171.17715">Error</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#ff0000;stroke:#ff0000;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="106.06905"
|
||||
y="255.2171"
|
||||
id="text4-6-4-7"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4-1-1-9"
|
||||
style="fill:#ff0000;stroke-width:0.2;stroke:#ff0000"
|
||||
x="106.06905"
|
||||
y="255.2171">MQTT</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
style="fill:#ff0000;stroke-width:0.2;stroke:#ff0000"
|
||||
x="106.06905"
|
||||
y="255.2171"
|
||||
id="tspan5-8-1-3" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-weight:600;font-size:7.40833px;line-height:0;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Semi-Bold';text-align:end;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#ff0000;stroke:#ff0000;stroke-width:0.2;stroke-linejoin:bevel;stroke-opacity:1"
|
||||
x="104.63658"
|
||||
y="265.51187"
|
||||
id="text6-9-3-1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan6-2-8-9"
|
||||
style="fill:#ff0000;stroke-width:0.2;stroke:#ff0000"
|
||||
x="104.63658"
|
||||
y="265.51187">Error</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#241212;stroke-width:0.6;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 115.50744,249.24178 -0.27313,21.36127 101.41239,-0.15245 -0.0612,-23.82776"
|
||||
id="path6"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#241212;stroke-width:0.6;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 216,172.81966 -0.13385,-22.4101 -101.04619,-0.15132 0.11406,22.56145"
|
||||
id="path6-3"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
|
|
@ -8,16 +8,20 @@
|
|||
// 90°-CW Verdrehung der Module per Software (rotateCCW) zuverlässig kompensiert
|
||||
// werden kann – ohne dass MD_Parola Zonenlogik interferiert.
|
||||
//
|
||||
// Zone-Aufteilung:
|
||||
// Zone 0 (top): Module 0–3 → akkumulierte Laserzeit (Float, Minuten)
|
||||
// Zone 1 (bottom): Module 4–7 → Countdown / Status
|
||||
// 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);
|
||||
// display.showCountdown(18);
|
||||
// display.showIdle();
|
||||
// display.update(); // in loop() aufrufen (Pflicht)
|
||||
// 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 <Arduino.h>
|
||||
|
|
@ -42,24 +46,40 @@ public:
|
|||
|
||||
// ---- Anzeige-Methoden ---------------------------------------------------
|
||||
|
||||
// Obere Zone: Laserzeit in Minuten
|
||||
// < 10 → " x.x" z.B. " 9.5"
|
||||
// < 100 → "xx.x" z.B. "42.5"
|
||||
// < 1000 → " xxx" z.B. " 123"
|
||||
// < 10000 → "xxxx" z.B. "1234"
|
||||
// >= 10000 → "!!!!" (Überlauf)
|
||||
// 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);
|
||||
|
||||
// Untere Zone: Countdown-Sekunden (rechtsbündig)
|
||||
// 0–999s werden dargestellt, > 999 → " !!!"
|
||||
// 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);
|
||||
|
||||
// Untere Zone: Leerlauf-Anzeige (" --")
|
||||
// Modul 5–7 (unten): Leerlauf-Anzeige (" --")
|
||||
// Modul 4 bleibt unberührt.
|
||||
void showIdle();
|
||||
|
||||
// Untere Zone: Statustext (max. 4 Zeichen, wird abgeschnitten / aufgefüllt)
|
||||
// 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();
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,10 @@ static const uint8_t BMP_F[8] = {
|
|||
0b01111110, 0b01000000, 0b01000000, 0b01111100,
|
||||
0b01000000, 0b01000000, 0b01000000, 0b00000000
|
||||
};
|
||||
static const uint8_t BMP_M[8] = {
|
||||
0b01000001, 0b01100011, 0b01010101, 0b01001001,
|
||||
0b01000001, 0b01000001, 0b01000001, 0b00000000
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lookup: ASCII-Zeichen → Bitmap-Zeiger
|
||||
|
|
@ -139,6 +143,7 @@ const uint8_t* DisplayManager::charBitmap(char c) {
|
|||
case 'W': return BMP_W;
|
||||
case 'i': return BMP_i;
|
||||
case 'F': return BMP_F;
|
||||
case 'M': return BMP_M;
|
||||
default: return BMP_SPACE;
|
||||
}
|
||||
}
|
||||
|
|
@ -213,85 +218,94 @@ void DisplayManager::writeZone(uint8_t zone, const char* str) {
|
|||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Laserzeit oben anzeigen (Zone 0)
|
||||
// Laserzeit oben anzeigen (Module 1–3, ganze Minuten, 3-stellig rechtsbündig)
|
||||
// Modul 0 (WiFi-Fehler-Reservierung) wird NICHT verändert.
|
||||
// ---------------------------------------------------------------------------
|
||||
void DisplayManager::showLaserTime(float minutes) {
|
||||
char buf[DISP_CHARS_PER_ZONE + 1];
|
||||
|
||||
if (minutes < 0.0f) minutes = 0.0f;
|
||||
int mins = (int)(minutes + 0.5f); // kaufmännisch runden
|
||||
|
||||
if (minutes < 10.0f) {
|
||||
// " x.x" → Trennzeichen in Position 2
|
||||
int whole = (int)minutes;
|
||||
int frac = (int)((minutes - whole) * 10.0f + 0.5f);
|
||||
if (frac >= 10) { whole++; frac = 0; }
|
||||
snprintf(buf, sizeof(buf), " %d.%d", whole, frac);
|
||||
} else if (minutes < 100.0f) {
|
||||
// "xx.x"
|
||||
int whole = (int)minutes;
|
||||
int frac = (int)((minutes - whole) * 10.0f + 0.5f);
|
||||
if (frac >= 10) { whole++; frac = 0; }
|
||||
snprintf(buf, sizeof(buf), "%2d.%d", whole, frac);
|
||||
} else if (minutes < 1000.0f) {
|
||||
// " xxx"
|
||||
snprintf(buf, sizeof(buf), "%4d", (int)(minutes + 0.5f));
|
||||
} else if (minutes < 10000.0f) {
|
||||
// "xxxx"
|
||||
snprintf(buf, sizeof(buf), "%4d", (int)(minutes + 0.5f));
|
||||
char buf[4]; // 3 Zeichen + Nulltermin
|
||||
if (mins < 10) {
|
||||
snprintf(buf, sizeof(buf), " %d", mins);
|
||||
} else if (mins < 100) {
|
||||
snprintf(buf, sizeof(buf), " %d", mins);
|
||||
} else if (mins < 1000) {
|
||||
snprintf(buf, sizeof(buf), "%d", mins);
|
||||
} else {
|
||||
strlcpy(buf, "!!!!", sizeof(buf));
|
||||
strlcpy(buf, "!!!", sizeof(buf));
|
||||
}
|
||||
|
||||
// snprintf kann Länge > 4 produzieren wenn Rounding unerwartet → absichern
|
||||
if (strlen(buf) != DISP_CHARS_PER_ZONE) {
|
||||
strlcpy(buf, "!!!!", sizeof(buf));
|
||||
}
|
||||
// Absicherung: genau 3 Zeichen garantieren
|
||||
if (strlen(buf) != 3) strlcpy(buf, "!!!", sizeof(buf));
|
||||
|
||||
writeZone(DISPLAY_ZONE_TOP, buf);
|
||||
// Nur Module 1, 2, 3 schreiben – Modul 0 bleibt unberührt
|
||||
writeChar(1, buf[0]);
|
||||
writeChar(2, buf[1]);
|
||||
writeChar(3, buf[2]);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Countdown-Sekunden unten anzeigen (Zone 1), rechtsbündig
|
||||
// Countdown-Sekunden unten anzeigen (Module 5–7, 3-stellig rechtsbündig)
|
||||
// Modul 4 (MQTT-Fehler-Reservierung) wird NICHT verändert.
|
||||
// ---------------------------------------------------------------------------
|
||||
void DisplayManager::showCountdown(int seconds) {
|
||||
char buf[DISP_CHARS_PER_ZONE + 1];
|
||||
|
||||
if (seconds < 0) seconds = 0;
|
||||
|
||||
char buf[4]; // 3 Zeichen + Nulltermin
|
||||
if (seconds < 10) {
|
||||
snprintf(buf, sizeof(buf), " %d", seconds);
|
||||
} else if (seconds < 100) {
|
||||
snprintf(buf, sizeof(buf), " %d", seconds);
|
||||
} else if (seconds < 1000) {
|
||||
} else if (seconds < 100) {
|
||||
snprintf(buf, sizeof(buf), " %d", seconds);
|
||||
} else if (seconds < 1000) {
|
||||
snprintf(buf, sizeof(buf), "%d", seconds);
|
||||
} else {
|
||||
strlcpy(buf, " !!!", sizeof(buf));
|
||||
strlcpy(buf, "!!!", sizeof(buf));
|
||||
}
|
||||
|
||||
if (strlen(buf) != DISP_CHARS_PER_ZONE) {
|
||||
strlcpy(buf, " !!!", sizeof(buf));
|
||||
}
|
||||
if (strlen(buf) != 3) strlcpy(buf, "!!!", sizeof(buf));
|
||||
|
||||
writeZone(DISPLAY_ZONE_BOTTOM, buf);
|
||||
// Nur Module 5, 6, 7 schreiben – Modul 4 bleibt unberührt
|
||||
writeChar(5, buf[0]);
|
||||
writeChar(6, buf[1]);
|
||||
writeChar(7, buf[2]);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Leerlauf-Anzeige unten (" --")
|
||||
// Leerlauf-Anzeige unten (" --" auf Module 5–7)
|
||||
// ---------------------------------------------------------------------------
|
||||
void DisplayManager::showIdle() {
|
||||
writeZone(DISPLAY_ZONE_BOTTOM, " --");
|
||||
writeChar(5, ' ');
|
||||
writeChar(6, '-');
|
||||
writeChar(7, '-');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Statustext unten (max. 4 Zeichen)
|
||||
// Statustext unten (max. 3 Zeichen auf Module 5–7)
|
||||
// ---------------------------------------------------------------------------
|
||||
void DisplayManager::showStatus(const char* msg) {
|
||||
char buf[DISP_CHARS_PER_ZONE + 1] = " "; // mit Leerzeichen vorbelegen
|
||||
char buf[4] = " "; // 3 Leerzeichen als Vorlage
|
||||
size_t len = strlen(msg);
|
||||
if (len > DISP_CHARS_PER_ZONE) len = DISP_CHARS_PER_ZONE;
|
||||
if (len > 3) len = 3;
|
||||
memcpy(buf, msg, len);
|
||||
buf[DISP_CHARS_PER_ZONE] = '\0';
|
||||
writeZone(DISPLAY_ZONE_BOTTOM, buf);
|
||||
buf[3] = '\0';
|
||||
writeChar(5, buf[0]);
|
||||
writeChar(6, buf[1]);
|
||||
writeChar(7, buf[2]);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// WiFi-Fehler-Indikator auf Modul 0
|
||||
// ---------------------------------------------------------------------------
|
||||
void DisplayManager::showWifiError(bool error) {
|
||||
writeChar(0, error ? 'W' : ' ');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MQTT-Fehler-Indikator auf Modul 4
|
||||
// ---------------------------------------------------------------------------
|
||||
void DisplayManager::showMqttError(bool error) {
|
||||
writeChar(4, error ? 'M' : ' ');
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -323,8 +337,8 @@ void DisplayManager::allLedsOff() {
|
|||
void DisplayManager::printToSerial() const {
|
||||
LOG_I("DISP", "DisplayManager: %d Module, HW: GENERIC_HW, CS: GPIO%d",
|
||||
DISPLAY_MODULE_COUNT, DISPLAY_CS_PIN);
|
||||
LOG_I("DISP", "Zone 0 (oben): Module 0-%d = Laserzeit",
|
||||
DISPLAY_MODULES_PER_ZONE - 1);
|
||||
LOG_I("DISP", "Zone 1 (unten): Module %d-%d = Countdown/Status",
|
||||
DISPLAY_MODULES_PER_ZONE, DISPLAY_MODULE_COUNT - 1);
|
||||
LOG_I("DISP", "Modul 0 : WiFi-Fehler (showWifiError)");
|
||||
LOG_I("DISP", "Module 1-3 : Laserzeit in ganzen Minuten");
|
||||
LOG_I("DISP", "Modul 4 : MQTT-Fehler (showMqttError)");
|
||||
LOG_I("DISP", "Module 5-7 : Countdown/Status");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,31 @@
|
|||
/**
|
||||
* TEST SKETCH 4.3 – DisplayManager Verifikation
|
||||
/**
|
||||
* TEST SKETCH 4.3 - DisplayManager Verifikation (angepasstes Layout)
|
||||
*
|
||||
* Testet alle Methoden des DisplayManagers:
|
||||
* Modul-Aufteilung:
|
||||
* Modul 0 : WiFi-Fehler-Indikator (showWifiError)
|
||||
* Module 1-3 : Laserzeit in ganzen Minuten, 3-stellig rechtsbuendig
|
||||
* Modul 4 : MQTT-Fehler-Indikator (showMqttError)
|
||||
* Module 5-7 : Countdown-Sekunden / Idle / Status, 3-stellig rechtsbuendig
|
||||
*
|
||||
* Testet:
|
||||
* 1. Alle LEDs EIN/AUS (Modul-Check)
|
||||
* 2. showLaserTime() mit verschiedenen Werten (Grenzwerttest)
|
||||
* 3. showCountdown() hochzählend
|
||||
* 4. showIdle()
|
||||
* 5. showStatus() mit "Err", "AP", "WiFi"
|
||||
* 6. Realistischer Loop: laufende Laserzeit + Countdown simuliert
|
||||
* 2. WiFi-Fehler EIN/AUS (Modul 0)
|
||||
* 3. MQTT-Fehler EIN/AUS (Modul 4)
|
||||
* 4. showLaserTime() Grenzwerte: ganze Minuten, Module 1-3
|
||||
* 5. showCountdown() Grenzwerte: Module 5-7
|
||||
* 6. showIdle()
|
||||
* 7. showStatus() mit 3-Zeichen-Strings
|
||||
* 8. Kombinations-Test: WiFi+MQTT Fehler gleichzeitig mit Laserzeit+Countdown
|
||||
* 9. Realistischer Loop
|
||||
*
|
||||
* Flash: pio run -e test-display-mgr --target upload
|
||||
* Flash: pio run -e test-display-mgr --target upload
|
||||
* Monitor: pio device monitor -e test-display-mgr
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "display_manager.h"
|
||||
|
||||
// Pause zwischen Testschritten
|
||||
#define STEP_MS 2000
|
||||
#define STEP_MS 1500
|
||||
|
||||
static void step(const char* desc) {
|
||||
Serial.printf("[STEP] %s\n", desc);
|
||||
|
|
@ -30,92 +38,136 @@ void setup() {
|
|||
delay(500);
|
||||
|
||||
Serial.println("\n========================================");
|
||||
Serial.println(" TEST 4.3 – DisplayManager");
|
||||
Serial.println(" TEST 4.3 - DisplayManager (neues Layout)");
|
||||
Serial.println("========================================");
|
||||
|
||||
display.begin();
|
||||
display.printToSerial();
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 1. Alle LEDs EIN → alle 8 Module müssen leuchten
|
||||
// 1. Alle LEDs EIN -> alle 8 Module muessen leuchten
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[1] Alle LEDs EIN (2s) – alle 8 Module pruefen");
|
||||
Serial.println("\n[1] Alle LEDs EIN (2s) - alle 8 Module pruefen");
|
||||
display.allLedsOn();
|
||||
delay(2000);
|
||||
display.allLedsOff();
|
||||
delay(500);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 2. showLaserTime() – Grenzwerttests
|
||||
// 2. WiFi-Fehler Modul 0
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[2] showLaserTime() Grenzwerte:");
|
||||
Serial.println("\n[2] WiFi-Fehler Modul 0:");
|
||||
Serial.println(" EIN: Modul 0 zeigt 'W'");
|
||||
display.showWifiError(true);
|
||||
step("Erwarte: Modul 0 = 'W', Rest leer");
|
||||
Serial.println(" AUS: Modul 0 leer");
|
||||
display.showWifiError(false);
|
||||
step("Erwarte: Modul 0 = leer");
|
||||
|
||||
float testTimes[] = { 0.0f, 0.5f, 1.0f, 9.9f, 10.0f, 42.5f, 99.9f,
|
||||
100.0f, 123.0f, 999.0f, 1000.0f, 9999.0f };
|
||||
for (float t : testTimes) {
|
||||
Serial.printf(" %.1f min → oben\n", t);
|
||||
display.showLaserTime(t);
|
||||
delay(1500);
|
||||
// ------------------------------------------------------------------
|
||||
// 3. MQTT-Fehler Modul 4
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[3] MQTT-Fehler Modul 4:");
|
||||
Serial.println(" EIN: Modul 4 zeigt 'M'");
|
||||
display.showMqttError(true);
|
||||
step("Erwarte: Modul 4 = 'M', Rest leer");
|
||||
Serial.println(" AUS: Modul 4 leer");
|
||||
display.showMqttError(false);
|
||||
step("Erwarte: Modul 4 = leer");
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 4. showLaserTime() - ganze Minuten, Module 1-3
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[4] showLaserTime() Grenzwerte (Module 1-3, ganze Minuten):");
|
||||
int testMins[] = { 0, 1, 9, 10, 42, 99, 100, 123, 999 };
|
||||
for (int m : testMins) {
|
||||
Serial.printf(" %d min\n", m);
|
||||
display.showLaserTime((float)m);
|
||||
delay(1200);
|
||||
}
|
||||
display.clear();
|
||||
delay(500);
|
||||
delay(300);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 3. showCountdown() von 120 → 0 (jede Sekunde)
|
||||
// 5. showCountdown() - Module 5-7
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[3] showCountdown() 5..0:");
|
||||
for (int s = 5; s >= 0; s--) {
|
||||
Serial.println("\n[5] showCountdown() 9..0 (Module 5-7):");
|
||||
for (int s = 9; s >= 0; s--) {
|
||||
Serial.printf(" %d s\n", s);
|
||||
display.showCountdown(s);
|
||||
delay(1000);
|
||||
delay(700);
|
||||
}
|
||||
delay(500);
|
||||
Serial.println(" 120 s");
|
||||
display.showCountdown(120);
|
||||
delay(STEP_MS);
|
||||
display.clear();
|
||||
delay(300);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 4. showIdle()
|
||||
// 6. showIdle() - Module 5-7
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[4] showIdle() (2s)");
|
||||
Serial.println("\n[6] showIdle() (Module 5-7)");
|
||||
display.showIdle();
|
||||
step("Erwarte ' --' auf unterer Reihe");
|
||||
step("Erwarte: Module 5-7 = ' --', Modul 4 leer");
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 5. showStatus() mit verschiedenen Strings
|
||||
// 7. showStatus() mit 3-Zeichen-Strings
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[5] showStatus() Tests:");
|
||||
const char* statMsgs[] = { "Err ", "AP ", "WiFi", " oF" };
|
||||
for (const char* m : statMsgs) {
|
||||
Serial.println("\n[7] showStatus() Tests (Module 5-7):");
|
||||
const char* msgs[] = { "Err", "AP ", "oFF", " " };
|
||||
for (const char* m : msgs) {
|
||||
Serial.printf(" '%s'\n", m);
|
||||
display.showStatus(m);
|
||||
delay(STEP_MS);
|
||||
}
|
||||
display.clear();
|
||||
delay(500);
|
||||
delay(300);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 6. Realistischer Betrieb: Laserzeit wächst, Countdown läuft
|
||||
// 8. Kombinations-Test: WiFi+MQTT Fehler + Laserzeit + Countdown
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[6] Realistischer Betrieb (30s): Laserzeit + Countdown");
|
||||
Serial.println(" Erwarte: oben steigt, unten zaehlt runter, dann '--'");
|
||||
Serial.println("\n[8] Kombinations-Test:");
|
||||
Serial.println(" Modul 0='W', 1-3=042, Modul 4='M', 5-7= 20");
|
||||
display.showWifiError(true);
|
||||
display.showLaserTime(42.0f);
|
||||
display.showMqttError(true);
|
||||
display.showCountdown(20);
|
||||
step("Erwarte: W | 042 | M | 20");
|
||||
|
||||
Serial.println(" Fehler weg: Modul 0 und 4 leer");
|
||||
display.showWifiError(false);
|
||||
display.showMqttError(false);
|
||||
step("Erwarte: leer | 042 | leer | 20");
|
||||
|
||||
display.clear();
|
||||
delay(300);
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// 9. Realistischer Betrieb
|
||||
// ------------------------------------------------------------------
|
||||
Serial.println("\n[9] Realistischer Betrieb: Laserzeit steigt, Countdown->Idle");
|
||||
display.showWifiError(false);
|
||||
display.showMqttError(false);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
void loop() {
|
||||
static float totalMin = 42.3f;
|
||||
static int countdown = 20;
|
||||
static bool counting = true;
|
||||
static uint32_t lastSec = 0;
|
||||
static uint32_t lastTenth = 0;
|
||||
static float totalMin = 42.0f;
|
||||
static int countdown = 20;
|
||||
static bool counting = true;
|
||||
static uint32_t lastSec = 0;
|
||||
static uint32_t lastTenth = 0;
|
||||
|
||||
uint32_t now = millis();
|
||||
|
||||
// Jede 100ms: Laserzeit um ~0.001 min erhöhen (0.06 min/min = 1x Normal)
|
||||
// Alle 100ms: Laserzeit um ~0.001 min erhoehen
|
||||
if (now - lastTenth >= 100) {
|
||||
lastTenth = now;
|
||||
totalMin += 0.001f;
|
||||
display.showLaserTime(totalMin);
|
||||
}
|
||||
|
||||
// Jede Sekunde: Countdown herunterzählen
|
||||
// Jede Sekunde: Countdown herunterzaehlen
|
||||
if (now - lastSec >= 1000) {
|
||||
lastSec = now;
|
||||
if (counting && countdown > 0) {
|
||||
|
|
@ -124,8 +176,8 @@ void loop() {
|
|||
} else if (counting && countdown == 0) {
|
||||
counting = false;
|
||||
display.showIdle();
|
||||
Serial.println("[LIVE] Countdown abgelaufen → Idle");
|
||||
Serial.println("[LIVE] Countdown abgelaufen -> Idle");
|
||||
}
|
||||
Serial.printf("[LIVE] %.2f min, countdown=%d\n", totalMin, countdown);
|
||||
Serial.printf("[LIVE] %d min, countdown=%d\n", (int)(totalMin + 0.5f), countdown);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user