Un périphérique série virtuel en Python?
je sais que je peux utiliser, par exemple, pySerial de parler à des périphériques série, mais si je n'ai pas d'appareil pour l'instant, mais encore le besoin d'écrire un client? Comment puis-je écrire un "périphérique série virtuel" en Python et demander à pySerial de lui parler, comme je voudrais, disons, lancer un serveur web local? Peut-être que je ne cherche pas bien, mais j'ai été incapable de trouver des informations sur ce sujet.
6 réponses
c'est quelque chose que j'ai fait et a fonctionné pour moi jusqu'à présent:
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)
si vous créez plus de ports virtuels, vous n'aurez aucun problème puisque les différents maîtres obtiennent des descripteurs de fichier différents même s'ils ont le même nom.
Ça dépend un peu de ce que vous essayez d'accomplir maintenant...
vous pouvez envelopper l'accès au port série dans une classe et écrire une implémentation pour utiliser les entrées/sorties de socket ou les entrées/sorties de fichier.ensuite, écrivez votre classe d'entrées/sorties de série pour utiliser la même interface et la brancher lorsque le périphérique est disponible. (C'est effectivement une bonne conception pour tester la fonctionnalité sans nécessiter de matériel externe.)
Ou, si vous allez utiliser le port série pour une commande interface de ligne, vous pouvez utiliser stdin / stdout.
ou, il y a cette autre réponse sur les périphériques série virtuels pour linux .
j'ai pu émuler un port série arbitraire ./foo
en utilisant ce code:
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
doit être installé ( sudo apt-get install socat
), ainsi que le paquet pyserial
python ( pip install pyserial
).
ouvrir l'interpréteur python et importer SerialEmulator:
>>> from SerialEmulator import SerialEmulator
>>> emulator = SerialEmulator('./ttydevice','./ttyclient')
>>> emulator.write('foo')
>>> emulator.read()
votre programme client peut alors envelopper ./ttyclient
avec pyserial, créant le port série virtuel. Vous pouvez aussi faire client_port /dev/ttyUSB0
ou similaire si vous ne pouvez pas modifier le code client, mais vous pourriez avoir besoin de sudo
.
soyez également conscient de cette question: Pyserial ne joue pas bien avec le port virtuel
si vous utilisez Linux, vous pouvez utiliser la commande socat comme suit:
socat -d -d pty,raw,echo=0 pty,raw,echo=0
lorsque la commande s'exécute, elle vous informe des ports série qu'elle a créés. Sur ma machine cela ressemble à:
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]
maintenant je peux écrire à /dev/pts/13
et recevoir sur /dev/pts/12
, et vice versa.
Peut-être une boucle appareil fera le travail si vous avez besoin de tester votre application sans accès à un périphérique. Il est inclus dans pySerial 2.5 https://pythonhosted.org/pyserial/url_handlers.html#loop