web-dev-qa-db-fra.com

En utilisant PySerial, est-il possible d'attendre des données?

J'ai un programme python qui lit les données d'un port série via le module PySerial. Les deux conditions que je dois garder à l'esprit sont les suivantes: je ne sais pas quelle quantité de données va être générée et je ne sais pas quand attendre des données.

Sur cette base, je suis arrivé avec les extraits de code suivants:

#Code from main loop, spawning thread and waiting for data
s = serial.Serial(5, timeout=5)  # Open COM5, 5 second timeout
s.baudrate = 19200

#Code from thread reading serial data
while 1:
  tdata = s.read(500)    # Read 500 characters or 5 seconds

  if(tdata.__len__() > 0):        #If we got data
    if(self.flag_got_data is 0):  #If it's the first data we recieved, store it
      self.data = tdata        
    else:                         #if it's not the first, append the data
      self.data += tdata
      self.flag_got_data = 1

Donc, ce code restera en boucle pour obtenir des données du port série. Nous aurons jusqu'à 500 caractères pour stocker les données, puis alerterons la boucle principale en définissant un drapeau. Si aucune donnée n'est présente, nous allons simplement nous rendormir et attendre.

Le code fonctionne, mais je n'aime pas le délai d'attente de 5 secondes. J'en ai besoin parce que je ne sais pas combien de données attendre, mais je n'aime pas que cela se réveille toutes les 5 secondes, même en l'absence de données. 

Existe-t-il un moyen de vérifier quand les données deviennent disponibles avant de faire la variable read? Je pense à quelque chose comme la commande select sous Linux.

MODIFIER:
Je pensais juste que j’ai remarqué que j’avais trouvé la méthode inWaiting(), mais cela semble vraiment changer mon "sommeil" en un sondage, donc ce n’est pas ce que je veux ici. Je veux juste dormir jusqu'à l'arrivée des données, puis aller les chercher.

16
Mike

Ok, j'ai en fait quelque chose que j'aime bien pour ça. Utilisation d'une combinaison de read() sans délai d'expiration et de la méthode inWaiting():

#Modified code from main loop: 
s = serial.Serial(5)

#Modified code from thread reading the serial port
while 1:
  tdata = s.read()           # Wait forever for anything
  time.sleep(1)              # Sleep (or inWaiting() doesn't give the correct value)
  data_left = s.inWaiting()  # Get the number of characters ready to be read
  tdata += s.read(data_left) # Do the read and combine it with the first character

  ... #Rest of the code

Cela semble donner les résultats que je voulais, je suppose que ce type de fonctionnalité n'existe pas en tant que méthode unique en Python

17
Mike

Vous pouvez définir timeout = None, puis l'appel read sera bloqué jusqu'à ce que le nombre d'octets demandé soit atteint. Si vous voulez attendre que les données arrivent, faites simplement une read(1) avec timeout None. Si vous souhaitez vérifier des données sans bloquer, effectuez une opération read(1) avec timeout zéro et vérifiez si elle renvoie des données.

(voir documentation http://pyserial.sourceforge.net/pyserial_api.html )

11
TJD
def cmd(cmd,serial):
    out='';prev='101001011'
    serial.flushInput();serial.flushOutput()
    serial.write(cmd+'\r');
    while True:
        out+= str(serial.read(1))
        if prev == out: return out
        prev=out
    return out

appelez ça comme ça:

cmd('ATZ',serial.Serial('/dev/ttyUSB0', timeout=1, baudrate=115000))
0
user5509884