unbekannte menge daten empfangen mit pyserial

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Ich brauche eine Strategie zum Empfangen von mehreren Kilobyte Daten über die serielle Schnittstelle.

Ich versuche es mit

Code: Alles auswählen

		ser.timeout = 2

		print ser
		time.sleep(1)   # wait a bit for data

		while ser.inWaiting() > 0:
			out += ser.read(1)
			rxbytes += 1
			sys.stdout.write(str(rxbytes))
			#time.sleep(0.2)
aber dabei reißt das Auslesen ab weil der Buffer leer wird.

Man müsste es so hinbekommen, dass im Mittel genausoviele Bytes gelesen werden, wie hineinkommen, und das am Ende der Buffer komplett ausgelesen wird.

Vielleicht hat da jemand eine Idee oder kann mich auf bestehende Codebeispiele verweisen? Danke schonmal.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Habe in http://www.python-forum.de/topic-11144. ... t=pyserial was gefunden, aber das läuft mit Threads (keine Ahnung von) und ich bräuchte nur die einfachste Lösung - in der Zeit der Datenübertragung kann ich sowieso nichts anderes machen.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Also um es nochmal in einem Satz zu sagen:

Ich möchte etwa 50kB Daten, die über die serielle Schnittstelle eintreffen, in einen String zur Weiterverarbeitung, bzw. direkt in eine neue Datei schreiben.
D.h. das Script sollte in etwa mit der seriellen Baudrate den Füllstand des Puffers konstant halten, wenn keine neuen Daten ankommen leert sich der Puffer und wird bis einschließlich des letzten Bytes ausgelesen.
Die Daten sind als Strom ohne Steuerzeichen zu betrachten, also zeilenweises auslesen scheidet damit wohl aus (?).
Dann muss festgestellt werden, dass nichts mehr im Puffer ist (Timeout?) und die Empfangsroutine ist beendet.

Eigentlich kann das blockierend laufen. Es wäre allerdings schön, wenn die empfangene Datenmenge regelmäßig ausgegeben wird.

Das Ganze versuche ich unter WinXP.

(Wie groß ist eigentlich so ein Puffer?)

Gute Nacht.
BlackJack

Mir ist irgendwie nicht ganz klar, wie Du das Ende der Daten von einer langsamen Übertragung unterscheiden willst. Du könntest die Zeitüberschreitung so hoch einstellen, dass sie auf "jeden Fall" das Ende der Daten anzeigt. Das ist aber nicht so besonders sicher. In der Regel hat man ein Protokoll, dass entweder am Anfang die Anzahl der Bytes überträgt oder irgend wie das Datenende kennzeichnet.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Hallo,

ja, das Ende der Daten muss mit einer Art Timeout erkannt werden, die Baudrate ist bekannt und konstant. 2 Sekunden reichen locker.
Leider weiss ich nicht so ganz, was das timeout bei pyserial bewirkt - heisst das, die pyserial.readxx Funktionen blocken solange, bis sie n Bytes/eine Zeile gelesen haben oder aber die Zeit um ist?
Wird das Timeout mit jedem Byte zurückgesetzt?
BlackJack

Die Zeitüberschreitung gilt natürlich für jeden Leseaufruf neu. Ansonsten gibt's ja auch Dokumentation:

Code: Alles auswählen

In [151]: serial.Serial.read?
Type:           instancemethod
Base Class:     <type 'instancemethod'>
String Form:    <unbound method Serial.read>
Namespace:      Interactive
File:           /usr/lib/python2.5/site-packages/serial/serialposix.py
Definition:     serial.Serial.read(self, size=1)
Docstring:
    Read size bytes from the serial port. If a timeout is set it may
    return less characters as requested. With no timeout it will block
    until the requested number of bytes is read.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Ah, sowas habe ich auf den ersten Blick nicht gefunden.
Da ist nix:
http://sourceforge.net/docman/?group_id=46487
Da auch nix:
http://www.google.de/search?q=pyserial+documentation

Ist mein erstes Mal mit python.. ich vermute es gibt ein eingebautes doc system?

Jedenfalls ist es also anders, als ich angenommen hatte, es wird nicht nach dem letzten Byte für timeout gewartet.

D.h. ich muss periodisch mit Timeout einlesen, und feststellen ob es ein Timeout gegeben hat.

Wie kann ich prüfen, ob es ein Timeout gegeben hat?
BlackJack

Naja, dann sind weniger Daten gelesen worden, als Du angefordert hast. Wenn Du ein Byte lesen willst, aber 0 bekommst…
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Danke, damit kann ich was anfangen..
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Habe es jetzt mal so versucht, aber toll ist das nicht:

Code: Alles auswählen

		ser.timeout = 1
		done = 0
                time.sleep(1)   # wait a bit for data
                
                while not done :
                        temp = ser.read(128)
                        if len(temp) < 128:
                                done = 1
                        out += temp
                        rxbytes += 128
Es läuft besser als vorher, aber die Übertragung reisst irgendwann ab, weil das Programm nicht gebremst wird. Ich möchte aber ungerne time.sleep() benutzen, weil das vermutlich nicht genau genug ist, und auch von der baudrate abhängt.
Man könnte natürlich die Wartezeit berechnen, aber ich denke dass es noch einfacher gehen muss. Ich komme nur nicht drauf ;-(

Vielleicht ist ja jemand so nett und greift mir etwas unter die Arme.
BlackJack

Vielleicht ist es keine so gute Idee auf <128 zu testen sondern besser darauf, ob in der gesamten Timeout-Zeit *gar keine* Daten angekommen sind. So hörst Du ja schon auf, wenn "nur" 127 Bytes in der Sekunde empfangen wurden.

`done` kannst Du Dir übrigens sparen wenn Du eine "Endlosschleife" (``while True:``) nimmst und die an der entspechenden Stelle mit ``break`` verlässt. Falls Du `done` behalten möchtest, sind `True` und `False` etwas aussagekräftiger als 1 und 0.
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Danke für deine Hilfe, leider habe ich erstmal keine Zeit weiterzumachen. Mit false und true habe ich es schon probiert, kannte er nicht. Dann wohl False und True. Wieder was gelernt!
Ich werde deine Tipps bei der nächsten Gelegenheit ausprobieren, mal sehen, ob ich das hinbekomme!
arghargh
User
Beiträge: 81
Registriert: Donnerstag 4. September 2008, 22:26

Habe es gerade nochmal laufen lassen, anscheinend funktioniert das Ganze jetzt:

Code: Alles auswählen

                while True:
                        temp = ser.read(128)
                        if len(temp) == 0:
                                break
                        out += temp
                        rxbytes += len(temp)
Danke für die Hilfe! (ich komme wieder ;-)
Antworten