Hallo zusammen, ich bin absoluter Einsteiger in Python und mache da nach einem kurzen Einsteierlehrgang meine ersten Schritte. Was möchte ich probieren: Ziel ist die Kommunikation mit einem externen Gerät über eine serielle Schnittstelle. Das Gerät antwortet auf Anfragen und kann auch unabhängig von Anfragen selbst Meldungen absetzen, auf die ich reagieren sollte. Die Kommunikation findet über Binärdaten mit 8N1 statt. Die Daten mit einem Frame aus 2 Bytes und können in der Länge variabel sein. Es muss geprüft werden, ob die empfangenen Daten korrekt (xor CRC) und vollständig sind. Dazu möchte ich einen eigenen Thread laufen lassen, der genau das macht und nur dann, wenn die Daten als korrekt erkannt wurden, diese dem Hauptprozess zur Verfügung stellt. Das ist derzeit über eine Queue geplant. Was habe ich: Ich habe eine Klasse implementiert, die die serielle Schnittstelle initialisiert, alle Zeichen entgegennimmt, prüft und in eine Queue stellt (sowie zu Testzwecken ausgibt). Funktioniert einwandfrei. Das Senden der Daten läuft derzeit direkt aus der main(), funktioniert auch. Wo ist das Problem: 1. Da die empfangenen Daten schon geprüft sind, würde ich gerne nur die Nutzdaten an den Hauptprozess weitergeben. Auf Grund der variablen Länge brauche ich da aber wieder Framekennzeichen und Länge. Kann ich die Queue auf eine Liste umstellen, der ich dann wieder je Datensatz eine Liste übergebe? Damit würde ich im Hauptprogramm mit einem Zugriff wieder alle Daten eines Datensatzes zur Verfügung haben. Wäre schön, aber welche Nebenwirkungen hat das? 2. Kann ich die Senderoutine mit in die Klasse class lzv_sst(threading.Thread): aufnehmen, damit alles zusammen bleibt oder ist diese Klasse ausschließlich für den Empfangsthread da? Die Initialisierung liegt ja auch dort, aber im Moment sende ich die Daten mit einem direkten Aufruf - geht, aber ist nicht sauber. Hier blicke ich das Konzept nicht. Bringe ich das Senden als Methode in die Klasse, funktioniert zwar das Senden, es gibt aber keinen Empfang mehr. Danke für alle Hinweise (und bitte nicht gleich draufhauen, ich weiß, dass ich da viele Lücken habe) Thomas
Punkt 2 hat sich gerade beim Aufbereiten des Codes zum hier Einstellen erledigt, ich habe eine Umwandlung ".to_bytes" vergessen. Zum Senden nimmt es die Routine, aber das falsche Format bewirkt, dass es keine Antwort gibt. zu Punkt 1: Weiß jetzt nicht, was das Coding hier helfen könnte. Ich empfange Daten im Format [Frame_1][Frame_2][Kommando+Länge]...[Data_i][CRC]. In der Empfangsroutine wird der Datensatz geprüft und in eine Queue gestellt, da nicht sicher ist, ob vor der Verarbeitung im main nicht schon neue Daten eingetroffen sind. Der komplette empfangene Datensatz steht in "incoming_data": for i in incoming_data: self.queue.put(i) Jetzt kann ich das im main wieder aus der Queue holen und verarbeiten, also schauen, dass die Framedaten passen (Synchronisation), dann die Länge aus dem dritten Zeichen ermitteln und danach die restlichen Bytes einlesen. CRC kann entfallen, die Prüfung ist ja schon erfolgt. Ziel wäre jetzt, den gesamten Datensatz unabhängig von seiner Länge als ein Objekt zu übergeben und genauso im main wieder zu empfangen. Das würde mir die Framebytes sparen und es gäbe trotzdem keine Synchronisationsprobleme. Thomas
1) in Queue kannst du alles reinpacken - hinten kommt es so wieder raus. Also pack deinen Datensatz in ein Array oder ein Objekt und so bleibt alles zusammen was zusammen gehört. 2) zeig mal den Code Sascha
Thomas P. schrieb: > Ziel wäre jetzt, den gesamten Datensatz unabhängig von seiner Länge als > ein Objekt zu übergeben und genauso im main wieder zu empfangen Ja dann mache das doch so. Was soll ich jetzt ohne Code hier sagen?
Moin, anbei mal den derzeitigen Stand des proof-of-concept mit zahlreichen Debug-Ausgaben. Prinzipiell scheint das zu funktionieren, wenn nach dem Senden einer Anfrage
1 | zentrale.write([33, 33]) |
2 | while zentrale.status < 2: |
3 | pass |
4 | #sleep(0.05) |
5 | myData = zentrale.read() |
6 | print("Main", myData) |
und warten auf zentrale.status > 1 die Daten sofort abgeholt werden. Gibt es eine kleine Pause (hier: sleep(0.05)), liefert die Ausgabe nur einen leeren Datensatz. Soweit ich das mit meinem Anfängerwissen eingrenzen konnte, liegt das Problem in der Klassendefinition, offensichtlich wird die Funktion self.read() auch aufgerufen und damit ist die Queue leer. Aber sollte nicht nur run(self) ständig laufen? Oder können Threads und Funktionen nicht in eine Klasse gepackt werden? Frage: Wie baut man die Klasse richtig auf? Thomas
Ich mache dann mal die Ingrid: Die Klassendefinition ist unschuldig. Das Schreiben und Lesen von Listen über die Queue funktioniert problemlos; danke für den Hinweis. Der oben beschriebene Fehler liess sich da lokalisieren:
1 | elif sm == 3: # Telegrammkörper |
2 | incoming_data.append(lzv_data) |
3 | crc = crc ^ lzv_data # CRC bilden |
4 | anz = anz - 1 |
5 | if anz == 0: # alles da? |
6 | if crc == 0: # und CRC ok |
7 | sm = 0 |
8 | # ganzen Satz in die Queue stellen |
9 | self.queue.put(incoming_data) |
10 | if self.status == 1: |
11 | self.status = 2 # Antwort auf Anfrage |
12 | elif self.status == 0: |
13 | self.status = 3 # ungefragte Daten |
14 | #print("Daten da:", incoming_data) |
15 | #sleep(0.1) |
16 | #del incoming_data[:] |
17 | incoming_data = [] |
Am Ende der Sequenz wird nach dem Übergeben der Daten an die Queue die Liste "incoming_data" mit den eingegangenen Daten mit "del incoming_data[:] gelöscht. Das funktioniert nur in Verbindung mit dem vorhergehenden sleep, fehlt das, werden im main leere Daten aus der Queue gelesen. Ersetzt man beides durch "incoming_data = []", funktioniert die Übergabe an die main einwandfrei. Dass ein "incoming_data = []" eine neue Liste erzeugt und an den "alten" Namen bindet, weiß ich - warum "del incoming_data[:]" ohne "sleep" irgendwie den Schreibprozess in die Queue abschießt, leider nicht. Thomas
i.d.R. werden Objekte nicht als Kopie übergeben sondern nur als Zeiger auf das Objekt. Ich könnte mir daher vorstellen das in Queue.put, asyncron zum aufrufenden Thread erst eine Kopie des Objekts erstellt und an die Queue angehangen wird. Löschst du im Hauptthread das Objekt bevor die Kopie erstellt wurde sind sie Daten halt weg. Müsste man sich mal die Implementierung anschauen. Zur Not kannst du auch selbst eine Kopie an Queue.put übergeben. Sascha
Die Implementierung zu untersuchen übersteigt meine Fähigkeiten. Du hast aber recht, übergibt man die Daten an die Queue mit "queue.put(list(incoming_data))" dann funktioniert auch "del incoming_data[:]" ohne "sleep". Ist irgendwie blöd, wenn ich aufeinanderfolgende Anweisungen schreibe, dann gehe ich doch davon aus, dass bei Ausführung der 2. Anweisung die 1. Anweisung vollständig abgearbeitet ist. Böse Falle... Thomas
Beitrag #6554415 wurde von einem Moderator gelöscht.
Beitrag #6554417 wurde von einem Moderator gelöscht.
Beitrag #6554418 wurde von einem Moderator gelöscht.
Thomas P. schrieb: > Ist irgendwie blöd, wenn ich aufeinanderfolgende Anweisungen schreibe, > dann gehe ich doch davon aus, dass bei Ausführung der 2. Anweisung die > 1. Anweisung vollständig abgearbeitet ist. Ist sie ja auch. Das Problem ist eher, dass du anscheinend nicht weißt, wie Objekte in Python funktionieren. In Python ist alles pass-by-reference.
Ja, das ist bei mir ein Anfängerproblem, dass das zwar bei der Druckbetankung mal erwähnt wurde, aber die Konsequenzen erst am konkreten Beispiel sichtbar werden. Merkt man sich nach so einer Pleite aber besser... Thomas
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.