Python read(3) nur wenn genug Daten in Datei vorhanden, sonst 0 zurück geben?

[o.0]

Lt. Commander
Registriert
Apr. 2008
Beiträge
1.056
Hallo zusammen,

was Programmieren angeht, bin ich zwar alles andere als unerfahren, allerdings habe ich gerade zum ersten Mal das Vergnügen mit Python.. man möge mir die vermutlich triviale Frage also verzeihen ;)

Es geht um ein Programm, welches nacheinander die verschiedenen Sensoren eines eingebetteten Systems (Modellauto) auslesen und auf der Bash des darauf laufenden Linux ausgeben soll. Das klappt auch soweit gut, auf Basis der Beispielprogramme des Herstellers hab ich mir schon was lauffähiges zusammengebastelt - bis auf das Auslesen der Maus, was noch Probleme macht.

Solange die Maus, welche die Bewegung des Autos erfassen soll, eine Bewegung registriert, werden vom Treiber/Betriebssystem Daten in /dev/input/mice' geschrieben. Das Script verarbeitet diese, läuft wie gewünscht durch und liefert eine Ausgabe wie folgende:
Code:
time:  946696715.787
a [x, y, z]:  [3600, 608, -16416]
c [x, y, z]:  [120, 745, 88]
g [x, y, z]:  [3, 41, -16]
adc [0, 1, 2, 3, 5, 6, 7]:  [0, 1285, 354, 1444, 482, 1450, 350]
mouse [dx, dy]:  [8, -2]

(und danach die nächste Runde, etc, pp)

Steht das Auto allerdings und liefert die Maus somit keine Daten mehr, bleibt das Programm in Zeile 26 solange hängen, bis die Maus wieder eine Bewegung registriert und somit wieder Daten in /dev/input/mice vorhanden sind.
Das ist so natürlich dämlich, auch wenn das Auto nicht fährt, ist der Zustand der restlichen Sensoren ja interessant. Ich hätte also gerne, dass, wenn die Maus keine Bewegung registriert, dx und dy null gesetzt wird. Somit würde das Script "mouse [dx, dy]: [0, 0]" zurück geben.

Der relevante Teil des Codes sieht so aus:

Code:
[...]

# Maus
mouse = file('/dev/input/mice')

[...]

try:
  while True:
    print "time: ",
    print time.time()

    # Accelerometer
    [...]
	
    # Kompass	
    [...]
	
    # Gyrometer
    [...]
  
    # ADCs
    [...]
	
    # Maus	
    status, dx, dy = tuple(ord(c) for c in mouse.read(3))  
    print "mouse [dx, dy]: ",
    print [
	  to_signed(dx),
	  to_signed(dy)
    ]

except KeyboardInterrupt:
  exit(0)

Naiv wie ich bin hab ich versucht mit try/catch (aka except) das irgendwie zu retten, was aber auch nicht funktioniert:

Code:
try:
  buffer = mouse.read(3)
  dx = ord(buffer[1])
  dy = ord(buffer[2])
  #status, dx, dy = tuple(ord(c) for c in mouse.read(3))
except:
  dx = 0
  dy = 0

Kann mir jemand auf die Schnelle einen Tip geben wie ich das Problem lösen kann? Etwas wie "wenn drei Byte gelesen werden können/die geöffnete Datei drei Byte hergibt, nimm diese als status, dy und dy, falls nicht, setze sie null" würde völlig ausreichen.

Viele Grüße
 
Kannst du nicht einfach nach dem read()-Aufruf die Länge von buffer prüfen?
 
Nee, eben nicht. Wenn ich den Code so verändere:

Code:
      [...]
      print "1"
      buffer = mouse.read(3)
      print "2"
      [...]

Gibt das Programm noch '1' aus und hängt dann in der Zeile mit 'read', bis ich die Maus bewege. Ich komme also gar nicht dazu, zu überprüfen was ich eingelesen habe.
 
Ah, verstehe. Dann brauchst du non-blocking I/O. Ich müßte mich jetzt selbst erst aufschlauen, wie man das in Python bewerkstelligt, aber der Suchbegriff python + non-blocking I/O sollte dich schon weiterbringen.
 
Ah, danke für das Stichwort, hab es jetzt hinbekommen. Gibt da anscheinend sogar einige Möglichkeiten unter Python, allerdings sind die meisten viel zu aufwändig für so einen simplen Fall.

Falls es jemanden jetzt oder in Zukunft interessiert:

Code:
# Für Non-Blocking I/O
import fcntl
import os

[...]

# Maus
mouse = file('/dev/input/mice')
fl = fcntl.fcntl(mouse, fcntl.F_GETFL)                # Non-Blocking I/O
fcntl.fcntl(mouse, fcntl.F_SETFL, fl | os.O_NONBLOCK) #

[...]

# Maus
try:
  buffer = mouse.read(3)
  dx = ord(buffer[1])
  dy = ord(buffer[2])
except:
  dx = 0
  dy = 0
	
  print "mouse [dx, dy]: ",
  print [
    to_signed(dx),
    to_signed(dy)
  ]
 
Zurück
Oben