10 Zeichen pro Zeile: Zellenbreite am Geraet gemessen, Zeilen zentriert
Die RS232-Strecke ESP32 -> MAX3232 -> Anzeige ist am Geraet bestaetigt; damit war "probe.py pitch" moeglich und hat die offene Zeichenbreiten-Frage geklaert. Das Ergebnis korrigiert eine Annahme: Bisher stand CHARS_PER_LINE = 9, abgezaehlt am Zeilenumbruch. Gemessen wurde damit aber der Auto-Vorschub der Sperrschrift (7 px), nicht die Zeichenbreite. Die Zeichenmatrix ist 6 px breit -- zehn Ziffern, einzeln auf x = i*6 gesetzt, stehen sauber getrennt nebeneinander. - display._emit_line positioniert jedes Zeichen selbst, statt den Auto-Vorschub laufen zu lassen. CHARS_PER_LINE = 10, CELL_WIDTH = 6. - Die Deklination passt dadurch in voller Form: +38°47'01" statt +38°47'01. - show_lines sendet ein Telegramm je Zeile. Mit Einzelpositionierung kaemen beide zusammen auf 224 der erlaubten 230 Bytes -- zu wenig Reserve fuer den Dauerbetrieb. Die Reihenfolge bleibt unten vor oben (Home-Zelle). - Zeilen werden zentriert (CENTER_LINES, LINE_X). Der Zeichenblock bleibt dabei gleich breit und an derselben Stelle, damit keine Reste stehen bleiben. - probe.py kommt mit aufs Geraet: Die Anzeige haengt jetzt am ESP32, nur von dort laesst sich die Geometrie noch ausmessen. Die Tests pruefen nicht mehr auf zusammenhaengenden Text im Telegramm -- den gibt es nicht mehr -- sondern rechnen ueber die Cursor-Sequenzen zurueck, was wirklich auf welcher Zelle landet. 97 Tests gruen, Kette am Geraet im Sekundentakt bestaetigt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+46
-22
@@ -6,6 +6,7 @@
|
||||
|
||||
import unittest
|
||||
|
||||
import config
|
||||
import coords
|
||||
import migra
|
||||
from display import Display
|
||||
@@ -146,30 +147,44 @@ class TestKoordinaten(unittest.TestCase):
|
||||
|
||||
class TestDisplay(unittest.TestCase):
|
||||
|
||||
def test_zeilen_ergeben_ein_telegramm(self):
|
||||
def test_je_zeile_ein_telegramm(self):
|
||||
"""Eine Zeile je Telegramm, jeweils sauber gerahmt.
|
||||
|
||||
Frueher war beides ein Telegramm. Seit jedes Zeichen einzeln
|
||||
positioniert wird (10 statt 9 Zeichen), waeren beide Zeilen zusammen zu
|
||||
dicht an migra.MAX_DATA_UNIT -- siehe display.show_lines.
|
||||
"""
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12:34:56", "+45:12:30", clear=True)
|
||||
|
||||
self.assertEqual(len(t.frames), 1)
|
||||
frame = t.frames[0]
|
||||
self.assertEqual(frame[:4], bytes([0x02, 0x81, 0x80, 0x81]))
|
||||
self.assertEqual(frame[-1], 0x03)
|
||||
self.assertEqual(len(t.frames), 2)
|
||||
for frame in t.frames:
|
||||
self.assertEqual(frame[:4], bytes([0x02, 0x81, 0x80, 0x81]))
|
||||
self.assertEqual(frame[-1], 0x03)
|
||||
self.assertLessEqual(len(frame), migra.MAX_DATA_UNIT)
|
||||
|
||||
data = frame[4:-1]
|
||||
self.assertIn(b"\x1bF0", data) # mit clear=True: vorher loeschen
|
||||
self.assertIn(b"\x1bC000000\x1f12:34:56", data) # Zeile 1 bei y=0
|
||||
self.assertIn(b"\x1bC000009\x1f+45:12:30", data) # Zeile 2 bei y=9
|
||||
unten, oben = t.frames # untere Zeile zuerst
|
||||
self.assertIn(b"\x1bF0", unten) # mit clear=True: einmal loeschen
|
||||
self.assertNotIn(b"\x1bF0", oben)
|
||||
|
||||
# Jedes Zeichen sitzt auf seiner eigenen Zelle: x = LINE_X + i*CELL_WIDTH.
|
||||
def zelle(i, y):
|
||||
return b"\x1bC%03d%03d" % (config.LINE_X + i * config.CELL_WIDTH, y)
|
||||
|
||||
# "12:34:56" hat 8 Zeichen und wird in 10 Zellen mittig gesetzt (ab Zelle 1),
|
||||
# "+45:12:30" hat 9 und beginnt daher schon bei Zelle 0.
|
||||
self.assertIn(zelle(1, 0) + b"\x1f1", oben)
|
||||
self.assertIn(zelle(2, 0) + b"\x1f2", oben)
|
||||
self.assertIn(zelle(0, 9) + b"\x1f+", unten)
|
||||
|
||||
def test_ohne_clear_kein_fill_aber_aufgefuellt(self):
|
||||
"""Standard (clear=False): kein Vollbild-Loeschen, Zeilen auf volle Breite."""
|
||||
from test_display import zeile, zentriert
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12:34:56", clear=False)
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertNotIn(b"\x1bF0", data)
|
||||
# auf CHARS_PER_LINE mit Leerzeichen aufgefuellt
|
||||
import config
|
||||
padded = "12:34:56".ljust(config.CHARS_PER_LINE).encode()
|
||||
self.assertIn(padded, data)
|
||||
self.assertNotIn(b"\x1bF0", t.frames[0])
|
||||
# auf CHARS_PER_LINE mit Leerzeichen aufgefuellt (mittig, siehe CENTER_LINES)
|
||||
self.assertEqual(zeile(t.frames, 0), zentriert("12:34:56"))
|
||||
|
||||
def test_gradzeichen_via_zeichensatz(self):
|
||||
"""Gradzeichen wird durch kurzen Wechsel auf Zeichensatz 1 erzeugt."""
|
||||
@@ -180,11 +195,20 @@ class TestDisplay(unittest.TestCase):
|
||||
self.assertIn(b"\x1bz01\x1f/\x1bz00", data)
|
||||
|
||||
def test_oberste_zeile_wird_zuletzt_gezeichnet(self):
|
||||
"""Wegen der Home-Zellen-Stoerung muss y=0 nach y=9 im Telegramm stehen."""
|
||||
"""Wegen der Home-Zellen-Stoerung muss y=0 nach y=9 gesendet werden.
|
||||
|
||||
Seit es ein Telegramm je Zeile gibt, entscheidet die Reihenfolge der
|
||||
Telegramme statt der Reihenfolge innerhalb eines Telegramms.
|
||||
"""
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_lines("12h34m56s", "+45°12'30\"")
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertLess(data.index(b"C000009"), data.index(b"C000000"))
|
||||
from test_display import zellen
|
||||
self.assertEqual(len(t.frames), 2)
|
||||
# Auf die y-Koordinaten schauen, nicht auf feste Cursor-Bytes.
|
||||
y_zuerst = set(y for _, y in zellen(t.frames[:1]))
|
||||
y_zuletzt = set(y for _, y in zellen(t.frames[1:]))
|
||||
self.assertEqual(y_zuerst, {config.LINE_Y[1]}) # untere Zeile zuerst
|
||||
self.assertEqual(y_zuletzt, {config.LINE_Y[0]}) # oberste Zeile zuletzt
|
||||
|
||||
def test_gradzeichen_fallback_ohne_zeichensatz(self):
|
||||
"""Ist DEGREE_CHARSET None, wird der Fallbacktext statt der Umschaltung genutzt."""
|
||||
@@ -208,12 +232,12 @@ class TestDisplay(unittest.TestCase):
|
||||
|
||||
def test_show_line_nur_eine_zeile(self):
|
||||
"""show_line schreibt nur die angegebene Zeile, ohne Vollbild-Loeschen."""
|
||||
from test_display import zellen
|
||||
t = FakeTransport(echo=False)
|
||||
Display(t, response=True).show_line(0, "18h36m56s")
|
||||
data = t.frames[0][4:-1]
|
||||
self.assertNotIn(b"\x1bF0", data) # kein Loeschen
|
||||
self.assertIn(b"\x1bC000000", data) # Cursor auf Zeile 1 (y=0)
|
||||
self.assertNotIn(b"C000009", data) # Zeile 2 unberuehrt
|
||||
self.assertNotIn(b"\x1bF0", t.frames[0]) # kein Loeschen
|
||||
y_werte = set(y for _, y in zellen(t.frames))
|
||||
self.assertEqual(y_werte, {config.LINE_Y[0]}) # nur Zeile 1, Zeile 2 unberuehrt
|
||||
|
||||
def test_show_line_ungueltiger_index(self):
|
||||
t = FakeTransport(echo=False)
|
||||
|
||||
Reference in New Issue
Block a user