diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5a4ff3e --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Python-Bytecode +__pycache__/ +*.py[cod] + +# Virtuelle Umgebungen +venv/ +.venv/ + +# Editor-/OS-Kram +.DS_Store diff --git a/README.md b/README.md index f3f6d74..2738469 100644 --- a/README.md +++ b/README.md @@ -85,14 +85,6 @@ selbst. ## Offene Punkte -- **Antworttelegramm-Pfad (RX) noch offen, absichtlich zurückgestellt.** - `WANT_RESPONSE = False` ist Default, der Normalbetrieb läuft ohne Rückkanal. - Diagnose 2026-07-15: Adapter-Loopback ok, aber über den MAX232 und am echten - Gerät kommt keine Antwort zurück → der Empfangszweig (Anzeige Pin 3 TxD → MAX232 - R_IN → R_OUT → Adapter RxD) leitet nicht. `loopback.py` hilft beim Eingrenzen. - Die Anzeige *antwortet* nachweislich (das alte MSP430-Programm nutzte die Antwort - als Handshake); es ist reine Verdrahtung. Wird der RX-Pfad fertig, `WANT_RESPONSE` - in `config.py` auf True stellen. - **Echte Montierungs-IP:** In `config.py` steht `MOUNT_HOST` noch als Platzhalter. Sobald die GM4000 im Netz erreichbar ist, dort die IP eintragen (Port 3490 ist Vorgabe). Bis dahin läuft alles gegen den Mock (`run_display.py --mock`). @@ -127,12 +119,30 @@ diese Zelle überschreibt. `CHARS_PER_LINE` aufgefüllt werden, sonst bricht das Füll-Leerzeichen um und beschädigt die andere Zeile. +## Antwortleitung (RX) + +Der Rückkanal ist verdrahtet und verifiziert (2026-07-16): Anzeige Pin 3 (TxD) → +MAX232-Empfängereingang (R_IN) → R_OUT → Adapter RxD. Die Anzeige quittiert jedes +Telegramm mit `02 80 81 80 30 03` (Fehlercode `0` = kein Fehler). `WANT_RESPONSE = True` +ist damit aktiv: Nach der Antwort darf sofort das nächste Telegramm folgen, der +Fehlercode wird ausgewertet. `resp_test.py` prüft den Rückweg (sendet mit Antwort- +Anforderung und zeigt die empfangenen Antworten). + +Wichtig: `SerialTransport.write` leert vor jedem Senden den Empfangspuffer, damit +`read_response` nur die frische Antwort sieht (sonst können Störbytes zwischen den +Telegrammen das Parsen stören). `run_display` fängt Anzeige-Fehler ab und zeichnet +beim nächsten Durchlauf neu, statt abzustürzen. + +Diagnose-Historie: Der Rückweg war anfangs falsch verdrahtet — Pin 3 lag an einem +MAX232-*Sender*ausgang statt einem Empfängereingang; zwei Ausgänge trieben +gegeneinander (verschliffener ~3-V-Pegel am Oszi). `loopback.py` grenzt so etwas ein. + ## Erledigt -- **Phase 1 + 2 am Gerät bestätigt (2026-07-15):** Koordinaten erscheinen korrekt, +- **Phase 1 + 2 am Gerät bestätigt (2026-07-15/16):** Koordinaten erscheinen korrekt, inkl. echtem Gradzeichen; im `run_display`-Betrieb aktualisieren beide Zeilen - laufend, sauber und ohne Flimmern. Protokoll, 19200 8E1, Zeichensatz und - Zeilengeometrie stimmen. + laufend, sauber und ohne Flimmern, mit Antwort-Handshake der Anzeige. Protokoll, + 19200 8E1, Zeichensatz und Zeilengeometrie stimmen. - Schrift: Sperrschrift (`ESC z`, `CHARSET_SPACED = True`), 10 Zeichen/Zeile. Die schmale `1` wirkt dadurch etwas luftig — Font-Eigenschaft, nur per eigenem Font (microSYST-PC-Software) änderbar. diff --git a/__pycache__/config.cpython-313.pyc b/__pycache__/config.cpython-313.pyc deleted file mode 100644 index e391fe8..0000000 Binary files a/__pycache__/config.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/coords.cpython-313.pyc b/__pycache__/coords.cpython-313.pyc deleted file mode 100644 index e790f71..0000000 Binary files a/__pycache__/coords.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/display.cpython-313.pyc b/__pycache__/display.cpython-313.pyc deleted file mode 100644 index f4b0c12..0000000 Binary files a/__pycache__/display.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/lx200.cpython-313.pyc b/__pycache__/lx200.cpython-313.pyc deleted file mode 100644 index b57eb15..0000000 Binary files a/__pycache__/lx200.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/migra.cpython-313.pyc b/__pycache__/migra.cpython-313.pyc deleted file mode 100644 index 29860ca..0000000 Binary files a/__pycache__/migra.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/mount_client.cpython-313.pyc b/__pycache__/mount_client.cpython-313.pyc deleted file mode 100644 index 99d4ff7..0000000 Binary files a/__pycache__/mount_client.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/mount_mock.cpython-313.pyc b/__pycache__/mount_mock.cpython-313.pyc deleted file mode 100644 index 68f5fcb..0000000 Binary files a/__pycache__/mount_mock.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/test_lx200.cpython-313.pyc b/__pycache__/test_lx200.cpython-313.pyc deleted file mode 100644 index 1fd1d4d..0000000 Binary files a/__pycache__/test_lx200.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/test_migra.cpython-313.pyc b/__pycache__/test_migra.cpython-313.pyc deleted file mode 100644 index 9529bd2..0000000 Binary files a/__pycache__/test_migra.cpython-313.pyc and /dev/null differ diff --git a/__pycache__/transport.cpython-313.pyc b/__pycache__/transport.cpython-313.pyc deleted file mode 100644 index a8574c1..0000000 Binary files a/__pycache__/transport.cpython-313.pyc and /dev/null differ diff --git a/config.py b/config.py index df0794b..c1f783a 100644 --- a/config.py +++ b/config.py @@ -5,7 +5,7 @@ import migra # -- Serielle Schnittstelle ----------------------------------------------- # Auslieferzustand der Anzeige laut Handbuch (Kap. 4.1) und identisch zur # UART-Init des alten MSP430-Programms: 19200 8E1. -PORT = "/dev/cu.usbserial-1120" # Mac; auf dem ESP32-C3 spaeter die UART-Nummer +PORT = "/dev/cu.usbserial-120" # Mac; auf dem ESP32-C3 spaeter die UART-Nummer BAUDRATE = 19200 PARITY = "E" BYTESIZE = 8 @@ -15,11 +15,10 @@ STOPBITS = 1 DISPLAY_ADDR = 1 # Zieladresse der Anzeige (DA = 0x81) HOST_ADDR = 0 # unsere Quelladresse (SA = 0x80) USE_CHECKSUM = False # das alte Programm fuhr ohne Pruefsumme -# Antworttelegramm als Flusskontrolle. Derzeit False, weil die RS232-Rueckleitung -# (Anzeige Pin 3 TxD -> Adapter RxD) noch nicht verdrahtet ist. Ist der RX-Pfad -# fertig, hier wieder auf True stellen -- dann wird der Fehlercode ausgewertet und -# ohne feste Pause gesendet. -WANT_RESPONSE = False +# Antworttelegramm als Flusskontrolle: Rueckweg verdrahtet und verifiziert +# (2026-07-16), Anzeige liefert 02 80 81 80 30 03. Nach Erhalt der Antwort darf +# sofort das naechste Telegramm folgen; der Fehlercode wird ausgewertet. +WANT_RESPONSE = True RESPONSE_TIMEOUT = 1.0 # Sekunden (nur relevant, wenn WANT_RESPONSE = True) QUIET_TIME = 0.4 # Pause zwischen Telegrammen, wenn ohne Antwort gefahren wird diff --git a/resp_test.py b/resp_test.py new file mode 100644 index 0000000..7bfb466 --- /dev/null +++ b/resp_test.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +"""Antwortleitung testen: Telegramme MIT Antwort-Anforderung senden. + +Sendet im 1-Sekunden-Takt ein festes Telegramm mit gesetztem Antwort-Bit +(FC = 0x81). Nach jedem Empfang muss die Anzeige auf Pin 3 ihr Antworttelegramm +senden (erwartet: 02 80 81 80 30 03). Bricht bei ausbleibender Antwort NICHT ab, +damit man am Oszi in Ruhe messen kann; liest eine evtl. eintreffende Antwort mit +und zeigt sie als Hex. + + python3 resp_test.py # 60 s, 1 s Takt + python3 resp_test.py --seconds 120 +""" + +import argparse +import sys +import time + +import config +import migra +from transport import SerialTransport + + +def main(argv=None): + p = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument("--seconds", type=float, default=60.0) + p.add_argument("--interval", type=float, default=1.0) + p.add_argument("--port", default=config.PORT) + args = p.parse_args(argv) + + du = migra.DataUnit().fill(config.BACKGROUND).charset(0, spaced=True) + du.cursor(0, 0); du.text("RESP TEST") + frame = migra.build_telegram(du, dest=config.DISPLAY_ADDR, src=config.HOST_ADDR, + checksum=False, response=True) # FC-Bit0 = 1 + + t = SerialTransport(port=args.port, baudrate=config.BAUDRATE, parity=config.PARITY, + bytesize=config.BYTESIZE, stopbits=config.STOPBITS, timeout=0.5) + + print("Port :", args.port) + print("TX (%d B): %s" % (len(frame), " ".join("%02X" % b for b in frame))) + print("FC : 0x%02X (Bit0=1 -> Antwort anfordern)" % frame[3]) + print("Erwartete Antwort auf Pin 3: 02 80 81 80 30 03") + print("Laufzeit %.0f s, Takt %.1f s. Abbruch mit Ctrl-C.\n" % (args.seconds, args.interval)) + + deadline = time.monotonic() + args.seconds + n = 0 + got = 0 + try: + while time.monotonic() < deadline: + n += 1 + t._port.reset_input_buffer() + t.write(frame) + # kurz auf eine Antwort lauschen (blockiert das Oszi nicht) + end = time.monotonic() + 0.4 + buf = bytearray() + while time.monotonic() < end: + c = t._port.read(1) + if c: + buf.extend(c) + if c[0] == migra.ETX: + break + elif buf: + break + if buf: + got += 1 + print("#%02d RX: %s" % (n, " ".join("%02X" % b for b in buf))) + else: + print("#%02d RX: (nichts empfangen)" % n) + # bis zum naechsten Sekundentakt warten + rest = args.interval - 0.4 + if rest > 0: + time.sleep(rest) + except KeyboardInterrupt: + print("\nabgebrochen") + finally: + t.close() + + print("\n%d Telegramme gesendet, %d Antworten empfangen." % (n, got)) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/run_display.py b/run_display.py index 6a33d8c..3acd8de 100644 --- a/run_display.py +++ b/run_display.py @@ -17,6 +17,7 @@ import time import config import coords +import migra from display import open_display from mount_client import MountClient, MountError @@ -72,6 +73,11 @@ def main(argv=None): last_shown = (ra_line, dec_line) print("RA %-11s DEC %-12s -> %s | %s" % (ra_raw, dec_raw, ra_line, dec_line)) + except migra.MigraError as e: + # Anzeige-/Antwortfehler (z.B. gestoerte Antwort): nicht abstuerzen, + # nur melden und beim naechsten Durchlauf neu zeichnen. + print("Anzeige: %s" % e, file=sys.stderr) + last_shown = None except (MountError, ValueError) as e: print("Montierung: %s" % e, file=sys.stderr) client.close() diff --git a/transport.py b/transport.py index d315c10..4577ef1 100644 --- a/transport.py +++ b/transport.py @@ -40,6 +40,10 @@ class SerialTransport: self._timeout = timeout def write(self, data): + # Empfangspuffer vor dem Senden leeren: eventuelle Stoerbytes zwischen + # den Telegrammen verwerfen, damit read_response nur die frische Antwort + # auf DIESES Telegramm sieht. + self._port.reset_input_buffer() self._port.write(data) self._port.flush()