Виртуальное последовательное устройство в Python?

Я знаю, что могу использовать, например, pySerial, чтобы общаться с последовательными устройствами, но что, если у меня сейчас нет устройства, но мне все еще нужно написать для него клиент? Как я могу написать «виртуальное последовательное устройство» на Python и заставить pySerial разговаривать с ним, как я бы, скажем, запустил локальный веб-сервер? Возможно, я просто плохо ищу, но мне не удалось найти никакой информации по этой теме.


person tdavis    schedule 18.02.2010    source источник


Ответы (6)


это то, что я сделал и разработал для себя до сих пор:

import os, pty, serial

master, slave = pty.openpty()
s_name = os.ttyname(slave)

ser = serial.Serial(s_name)

# To Write to the device
ser.write('Your text')

# To read from the device
os.read(master,1000)

Если вы создадите больше виртуальных портов, у вас не будет проблем, так как разные мастера получают разные файловые дескрипторы, даже если у них одинаковое имя.

person Aquiles    schedule 26.02.2013
comment
Это именно тот ответ, который я искал. У меня это работает в Mac OS X. - person DrRobotNinja; 01.07.2014
comment
Это не будет работать в Windows, в которой отсутствует модуль termios, необходимый для pty. - person OYRM; 12.12.2014
comment
Кажется, я могу нормально читать с поддельного устройства (т.е. у меня есть другая программа, записывающая на устройство в конечной точке s_name), но всякий раз, когда я выдаю ser.write("..."), этот текст просто возвращается эхом в следующий раз, когда я os.read(master,1000), независимо от того, есть ли что-нибудь подключен к порту, а другой конец порта, похоже, не получает данные. - person Ponkadoodle; 23.07.2015
comment
Когда я запускаю ваш код в Ubuntu 14.04, я получаю следующую ошибку: File "<stdin>", line 1, in <module> File "/usr/local/lib/python2.7/dist-packages/serial/serialutil.py", line 180, in __init__ self.open() File "/usr/local/lib/python2.7/dist-packages/serial/serialposix.py", line 311, in open self._update_dtr_state() File "/usr/local/lib/python2.7/dist-packages/serial/serialposix.py", line 605, in _update_dtr_state fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) IOError: [Errno 22] Invalid argument - person Samuel Góngora; 10.03.2016
comment
Извини, Самуэль, у меня сейчас все работает отлично. Но я уже давно перестал работать над этим проектом, поэтому на данный момент у меня не так много материалов, которые я мог бы вам дать. - person Aquiles; 10.03.2016
comment
@OYRM у вас есть предложения для Windows, я создал вопрос здесь stackoverflow.com/questions/36115831/ - person Ivan Borshchov; 20.03.2016
comment
@ SamuelGóngora, я получал ту же ошибку, убедитесь, что у вас есть разрешения на доступ к файлу /dev/tty, запустив python с помощью sudo или сменив владельца файла на вас. - person Patrick Steadman; 26.05.2016
comment
@ SamuelGóngora См. Также следующее: stackoverflow.com/questions/34831131/, я думаю, что это, вероятно, более точная причина проблемы. - person Patrick Steadman; 26.05.2016
comment
Модульные тесты pyserial содержат хороший набор примеров: github.com/pyserial pyserial / blob / - person Matt; 16.03.2017

Мне удалось сымитировать произвольный последовательный порт ./foo, используя этот код:

SerialEmulator.py

import os, subprocess, serial, time

# this script lets you emulate a serial device
# the client program should use the serial port file specifed by client_port

# if the port is a location that the user can't access (ex: /dev/ttyUSB0 often),
# sudo is required

class SerialEmulator(object):
    def __init__(self, device_port='./ttydevice', client_port='./ttyclient'):
        self.device_port = device_port
        self.client_port = client_port
        cmd=['/usr/bin/socat','-d','-d','PTY,link=%s,raw,echo=0' %
                self.device_port, 'PTY,link=%s,raw,echo=0' % self.client_port]
        self.proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        time.sleep(1)
        self.serial = serial.Serial(self.device_port, 9600, rtscts=True, dsrdtr=True)
        self.err = ''
        self.out = ''

    def write(self, out):
        self.serial.write(out)

    def read(self):
        line = ''
        while self.serial.inWaiting() > 0:
            line += self.serial.read(1)
        print line

    def __del__(self):
        self.stop()

    def stop(self):
        self.proc.kill()
        self.out, self.err = self.proc.communicate()

socat необходимо установить (sudo apt-get install socat), а также pyserial пакет python (pip install pyserial).

Откройте интерпретатор Python и импортируйте SerialEmulator:

>>> from SerialEmulator import SerialEmulator
>>> emulator = SerialEmulator('./ttydevice','./ttyclient') 
>>> emulator.write('foo')
>>> emulator.read()

Затем ваша клиентская программа может обернуть ./ttyclient pyserial, создав виртуальный последовательный порт. Вы также можете сделать client_port /dev/ttyUSB0 или аналогичный, если вы не можете изменить код клиента, но может потребоваться sudo.

Также помните об этой проблеме: Pyserial плохо работает с виртуальным портом < / а>

person Patrick Steadman    schedule 26.05.2016
comment
У вас есть этот код где-нибудь на GitHub? Зачем мне нужны ttydevice и ttyclient? Я хочу иметь программу Python (эмулятор устройства), которую я буду запускать как отдельный процесс. он создаст './ttymydevice' и ответит на мои последовательные команды, поскольку это действительно устройство. - person Valentyn; 23.09.2019

Может быть проще использовать что-то вроде com0com (если вы работаете в Windows) для настройки виртуального последовательного порта. , и развивайтесь на этом.

person mtrw    schedule 18.02.2010
comment
есть ли бесплатная com0com альтернатива (с API), которую я могу использовать в своем коммерческом программном обеспечении as it is? Мне просто нужно, чтобы у пользователя были виртуальные последовательные порты - person mrid; 12.05.2020

Если вы используете Linux, вы можете использовать для этого команду socat, например:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

Когда команда запустится, она сообщит вам, какие последовательные порты были созданы. На моей машине это выглядит так:

2014/04/23 15:47:49 socat[31711] N PTY is /dev/pts/12
2014/04/23 15:47:49 socat[31711] N PTY is /dev/pts/13
2014/04/23 15:47:49 socat[31711] N starting data transfer loop with FDs [3,3] and [5,5]

Теперь я могу писать на /dev/pts/13 и получать на /dev/pts/12, и наоборот.

person Richard    schedule 23.04.2014

Возможно, петлевое устройство выполнит эту работу, если вам нужно протестировать приложение без доступа к устройству. Он включен в pySerial 2.5 https://pythonhosted.org/pyserial/url_handlers.html#loop

person steko    schedule 18.02.2011

Это немного зависит от того, чего вы сейчас пытаетесь достичь ...

Вы можете обернуть доступ к последовательному порту в класс и написать реализацию для использования ввода-вывода сокетов или файлового ввода-вывода. Затем напишите свой класс последовательного ввода-вывода для использования того же интерфейса и подключите его, когда устройство будет доступно. (На самом деле это хороший дизайн для тестирования функциональности без использования внешнего оборудования.)

Или, если вы собираетесь использовать последовательный порт для интерфейса командной строки, вы можете использовать stdin / stdout.

Или есть другой ответ о виртуальных последовательных устройствах для Linux.

person Dave Bacher    schedule 18.02.2010
comment
Да, напишите класс виртуального последовательного устройства, который дублирует интерфейс pySerial. Тогда ваш код может взаимозаменяемо использовать либо класс вашего виртуального устройства, либо реальный интерфейс pySerial. - person Craig McQueen; 19.02.2010
comment
Это хорошая реализация, поскольку ее довольно легко реализовать, и она будет работать на всех платформах! - person Pithikos; 22.01.2015
comment
Извините за обновление этого старого сообщения, но не могли бы вы рассказать немного подробнее? Это было бы очень полезно для меня. Спасибо - person rowman; 14.01.2018