2012-10-22 7 views
14

Ho un programma Python che sta leggendo i dati da una porta seriale tramite il modulo PySerial. Le due condizioni che devo tenere a mente sono: non so quanti dati saranno disponibili e non so quando prevedere i dati.Utilizzando PySerial è possibile attendere i dati?

Sulla base di questo ho si avvicinò con le snipets CODICE:

#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 

Quindi questo codice esegue un loop infinito ottenere i dati fuori la porta seriale. Otterremo fino a 500 caratteri per memorizzare i dati, quindi avvisare il ciclo principale impostando un flag. Se non ci sono dati, torneremo a dormire e aspettiamo.

Il codice funziona ma non mi piace il timeout 5s. Ne ho bisogno perché non so quanti dati aspettarsi, ma non mi piace che si svegli ogni 5 secondi anche quando non ci sono dati presenti.

C'è un modo per verificare quando i dati diventano disponibili prima di effettuare il read? Sto pensando a qualcosa come il comando select in Linux.

EDIT:
Ho pensato di notare che ho trovato il metodo inWaiting(), ma in realtà sembra che solo cambiare la mia "sonno" per un sondaggio, in modo che non è quello che voglio qui. Voglio solo dormire finché i dati non arrivano, quindi vai a prenderlo.

risposta

15

Ok, ho effettivamente avuto qualcosa insieme che mi piace per questo. Usando una combinazione di read() senza timeout e il metodo 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 

Questo sembra dare i risultati che volevo, credo che questo tipo di funzionalità non esiste come un unico metodo in Python

+1

'time.sleep (1)' sembra un trucco piuttosto brutto che aggiunge un po 'di ritardo nel far uscire i tuoi dati. – TJD

+0

@TJD - Non ci sono argomenti, sembra che funzioni anche senza sleep, ma 'data_left' diventa molto inaffidabile (una stringa di 19 caratteri esegue il loop come 3, quindi 10, poi 6" bank "entrano). Quindi non sono ancora soddisfatto, ma è più vicino a ciò a cui stavo pensando. Dormire fino a quando i dati, quindi leggere i dati, quindi tornare a dormire. – Mike

+0

Non vedo come sia "inaffidabile". È esattamente come arrivano i byte mentre li stai leggendo.Si potrebbe voler usare 'interCharTimeout', che consente di rilevare quando il ricevitore ha smesso di vedere nuovi byte. – TJD

10

È possibile impostare timeout = None, quindi la chiamata read verrà bloccata fino a quando il numero di byte richiesto non sarà disponibile. Se si desidera attendere fino a quando i dati arrivano, è sufficiente eseguire uno read(1) con timeout None. Se si desidera verificare i dati senza bloccare, eseguire uno read(1) con timeout zero e controllare se restituisce dati.

(vedi documentazione http://pyserial.sourceforge.net/pyserial_api.html)

+1

ma penso anche che non c'è assolutamente niente di sbagliato con l'utilizzo di un timeout 5s e averlo Wakeup e subito tornare a leggere. È molto semplice e non avrà overhead misurabili. – TJD

+0

Grazie per le informazioni, ho visto che la documentazione di lettura non riusciva a capire come farlo fare ciò che volevo. Sono d'accordo che avere un ciclo con un timeout non è terribilmente costoso su una macchina desktop, ma (proveniente da uno sfondo incorporato) mi sembra così sbagliato sondare – Mike

+0

Soluzione migliore secondo me (almeno per i miei bisogni). Grazie per la condivisione. – Marcel

0
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 

chiamare in questo modo:

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