#python #pyserial #hardware-interface
Вопрос:
Я использую pySerial 3.4 с Python 3.6.7 на компьютере с Windows 10 для взаимодействия с USB-устройствами. Таких устройств 12, и все они подключены к одному и тому же USB-концентратору. Взаимодействие с устройствами простое: отправьте на устройство конкретное сообщение с запросом, и оно отправит ответ после получения этого сообщения.
Проблема, которую я пытаюсь решить, заключается в том, что я периодически получаю сериальные исключения и теряю возможность общаться с одним или несколькими устройствами, если не выполняется какое-либо ручное вмешательство (например, включение питания USB-устройств). Конкретным исключением является:
SerialException("ClearCommError failed (PermissionError(13, 'Access is denied.', None, 5))",)
Это иногда, но не всегда, совпадает с системным предупреждением от Windows:
USB-устройство не распознано (последнее USB-устройство, которое вы подключили к этому компьютеру, вышло из строя, и Windows не распознает его.)
Кажется маловероятным, что это фактическая аппаратная неисправность самого USB-устройства, так как она не происходит постоянно на одном из устройств, но может периодически происходить с любым из 12 из них.
Моя общая логика взаимодействия с каждым из устройств через pySerial выглядит так:
# (Only done once, although serial port is closed and reinitialized like this after a SerialException occurring)
serial_port = serial.Serial(port=port, baudrate=19200, timeout=10.0, write_timeout=10.0)
serial_port.dtr = True
serial_port.rts = False
# (Done for every read)
# Open serial port if not already opened
if not serial_port.is_open:
serial_port.open()
# If any old/stale data pending, clear it out first
if serial_port.inWaiting() > 0:
serial_port.read(serial_port.inWaiting())
# Request measurement
serial_port.write(bytearray([0xC1, 0xD2, 0x21]))
# Wait for measurement
while ...: # logic for looping until timeout occurs
if serial_port.inWaiting() >= 3: # 3 bytes is expected return packet length
bytes_read = serial_port.read(serial_port.inWaiting())
break
# Cleanup and close port
serial_port.reset_input_buffer()
serial_port.reset_output_buffer()
serial_port.flush()
serial_port.close()
Я пробовал различные методы чтения, такие как асинхронное чтение со всех устройств одновременно по сравнению с синхронным чтением по одному за раз или закрытие последовательного порта после каждого чтения по сравнению с оставлением его открытым между чтениями. Синхронное чтение с закрытием порта после каждого чтения кажется, что у него самая низкая частота встречающихся исключений, но неясно, насколько это важно.
After the SerialException starts occurring, I’ve been unable to find anything on the software side or operating system side that can recover the device (but it would be very convenient if there was a way to recover it from this end!).
Notable actions that do typically resolve the SerialException (at least temporarily):
- Power-cycling the USB device that the SerialException is occurring on.
- Обмен проводами между USB-устройствами. Обратите внимание, что:
- Отсоединение провода от USB-устройства, а затем повторное подключение его обратно к тому же устройству не устраняет исключение (USB-устройство имеет внутреннюю батарею, поэтому отсоединение провода не выключает его)
- Однако замена проводов между одним из неисправных устройств и одним из исправных обычно устраняет исключение SerialException.
- Кроме того, после этого, при замене проводов на их первоначальные места, связь с устройствами по-прежнему остается хорошей.