Почему последовательное чтение (1) продолжает ждать до истечения времени ожидания после получения символа? - PullRequest
1 голос
/ 14 мая 2019

Следующий код связывается с оборудованием через последовательный интерфейс.Связь успешна (аппаратные средства активируются и сообщаются правильные положения), за исключением того, что команда чтения всегда занимает примерно s.timeout секунд, почти независимо от значения параметра s.timeout (s.timeout должно быть не менее ~ 3 с).

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

import serial # installed as pyserial
import time, io

try:
    # Best guesses for an undocumented serial device
    s = serial.Serial()
    s.port = 'COM1'
    s.baudrate = 9600
    s.timeout = 5
    s.open()

    # Device begins 18s init routine when serial communication established
    sio = io.TextIOWrapper(io.BufferedRWPair(s,s))
    time.sleep(18)
    start = time.time()
    dat = sio.read(1)
    print('Initial position is %s (%0.3fs reply)' % (dat, time.time()-start))

    # Move device from initial position to Position 2
    sio.write('2')
    sio.flush()
    start = time.time()
    dat = sio.read(1)
    print('New position is %s (%0.3fs reply)' % (dat, time.time()-start))

finally:
    del sio
    s.close()

Вывод:

Initial position is 0 (5.008s reply)
Moved to position 2 (5.003s reply)

Ответы [ 2 ]

1 голос
/ 14 мая 2019

В этом коде есть две вещи, которые кажутся мне странными.

  1. Последовательный порт упакован в буфер, но если вы хотите управлять оборудованием на символьной основе, это может быть не то, что вам нужно.
  2. BufferedRWPair следует использовать для логического объединения двух симплексных потоков в дуплексный поток. Однако класс Serial уже является дуплексным.

Я бы попытался полностью удалить TextIOWrapper и BufferedRWPair и напрямую вызвать методы чтения и записи класса Serial.

0 голосов
/ 14 мая 2019

Я могу получить ожидаемое поведение от read (1), когда я использую последовательный объект напрямую, а не через TextIOWrapper, как показано в коде ниже. time.sleep () больше не нужен, но я сохранил его, чтобы вывод кода можно было сравнить с выводом исходного сообщения.

Я использую Python 3.7.3 и документацию для io.TextIOWrapper , которая наследуется от io.TextIOBase , явно не говорится, что чтение (N) прекращается блокировка после чтения N символов, хотя я думаю, что разумно предположить, что так и должно быть. На самом деле, документы, похоже, предполагают, что read (size = 1) является правильной реализацией, хотя вызов read таким способом вызывает ошибку «read () не принимает аргументов ключевого слова».

Я доволен непосредственным использованием последовательного объекта, но, надеюсь, кто-то может ответить на N-символьный вопрос для тех, кому может понадобиться TextIOWrapper.

import time, serial

try:
    s = serial.Serial()
    s.port = 'COM1'
    s.baudrate = 9600
    s.timeout = 20
    s.open()

    time.sleep(18)
    start = time.time()
    dat = s.read(1)
    print('Initial position is %s (%0.3fs reply)' % \
          (dat.decode('utf-8'), time.time()-start))

    s.write('2'.encode())
    s.flush()
    start = time.time()
    dat = s.read(1)
    print('New position is %s (%0.3fs reply)' % \
          (dat.decode('utf-8'), time.time()-start))

finally:
    s.close()

Выход:

Initial position is 0 (0.000s reply)
New position is 2 (2.887s reply)
...