Используя PySerial, можно ли ждать данных?

У меня есть программа Python, которая читает данные из последовательного порта черезPySerial модуль. Два условия, которые я должен иметь в виду: я не знаю, сколько данных получит, и я не знаю, когда ожидать данные.

Исходя из этого, я придумал следующие фрагменты кода:

#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

Таким образом, этот код будет зацикливаться на получение данных от последовательного порта. Мы получим до 500 символов для хранения данных, а затем оповестим основной цикл, установив флаг. Если данных нет, мы просто вернемся спать и будем ждать.

Код работает, но мне не нравится время ожидания 5 с. Мне это нужно, потому что я не знаю, сколько данных ожидать, но мне не нравится, что он просыпается каждые 5 секунд, даже если данных нет.

Есть ли способ проверить, когда данные становятся доступными, прежде чем делатьread? Я думаю что-то вродеselect Команда в Linux.

РЕДАКТИРОВАТЬ:
Просто подумал, что заметил, что нашелinWaiting() метод, но на самом деле это, кажется, просто меняет мой «сон» на опрос, так что это не то, что я хочу здесь. Я просто хочу поспать, пока данные не придут, а потом иди за ними.

Ответы на вопрос(3)

timeout = Noneтогдаread Вызов будет заблокирован, пока не будет запрошенное количество байтов. Если вы хотите дождаться прибытия данных, просто выполнитеread(1) с таймаутомNone, Если вы хотите проверить данные без блокировки, сделайтеread(1) с нулевым временем ожидания, и проверьте, возвращает ли он какие-либо данные.

(см. документациюhttp://pyserial.sourceforge.net/pyserial_api.html)

 Marcel21 мар. 2016 г., 18:13
На мой взгляд, лучшее решение (по крайней мере, для моих нужд). Спасибо, что поделился.
 Mike22 окт. 2012 г., 21:21
Спасибо за информацию, я видел прочитанную документацию, просто не мог понять, как заставить ее делать то, что я хотел. Я согласен, что цикл с тайм-аутом не слишком дорогостоящий на настольном компьютере, но (исходя из встроенного фона) мне так неправильно опрашивать
 TJD22 окт. 2012 г., 21:11
Но я также думаю, что нет ничего плохого в использовании тайм-аута 5 с и его пробуждении и немедленном возвращении к чтению. Это очень просто и не будет иметь измеримых накладных расходов.
Решение Вопроса

я действительно собрал что-то, что мне нравится для этого. Используя комбинациюread() без тайм-аута и тому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

Кажется, это дает желаемые результаты, я полагаю, что этот тип функциональности не существует как отдельный метод в Python

 TJD22 окт. 2012 г., 21:28
time.sleep(1) кажется довольно уродливым взломом, который добавляет кучу задержек для получения ваших данных.
 Mike22 окт. 2012 г., 21:32
@ TJD - Там нет никаких аргументов, кажется, что это работает и без сна, ноdata_left становится очень ненадежным (строка из 19 символов зацикливается на 3, затем на 10, затем на 6 «банков»). Так что я все еще не доволен этим, но это ближе к тому, о чем я думал. Сон до данных, затем прочитайте данные, затем вернитесь ко сну.
 TJD22 окт. 2012 г., 22:20
Я не вижу, как это "ненадежно". Именно так поступают байты, когда вы их читаете. Вы можете использоватьinterCharTimeout, который позволяет определить, когда получатель перестал видеть новые байты.
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

Назовите это так:

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

Ваш ответ на вопрос