web-dev-qa-db-fra.com

Périphérique série virtuel en Python?

Je sais que je peux utiliser par exemple pySerial pour parler aux périphériques série, mais que se passe-t-il si je n'ai pas de périphérique en ce moment mais que je dois encore écrire un client pour cela? Comment puis-je écrire un "périphérique série virtuel" dans Python et avoir pySerial lui parler, comme je le ferais, disons, exécuter un serveur Web local? Peut-être que je ne cherche pas bien, mais Je n'ai pas pu trouver d'informations sur ce sujet.

41
tdavis

c'est quelque chose que j'ai fait et travaillé 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 car les différents maîtres obtiennent des descripteurs de fichiers différents même s'ils ont le même nom.

39
Aquiles

Il peut être plus facile d'utiliser quelque chose comme com0com (si vous êtes sous Windows) pour configurer un port série virtuel et développer cela.

6
mtrw

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 package pyserial python (pip install pyserial).

Ouvrez l'interpréteur python et importez SerialEmulator:

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

Votre programme client peut ensuite envelopper ./ttyclient avec pyserial, créant le port série virtuel. Vous pouvez également créer client_port /dev/ttyUSB0 ou similaire si vous ne pouvez pas modifier le code client, mais que vous pourriez avoir besoin de Sudo.

Soyez également conscient de ce problème: Pyserial ne joue pas bien avec le port virtuel

5
Patrick Steadman

Cela dépend un peu de ce que vous essayez d'accomplir maintenant ...

Vous pouvez encapsuler l'accès au port série dans une classe et écrire une implémentation pour utiliser les E/S de socket ou les E/S de fichiers. Ensuite, écrivez votre classe d'E/S série pour utiliser la même interface et branchez-la lorsque le périphérique est disponible. (Il s'agit en fait d'une bonne conception pour tester les fonctionnalités sans nécessiter de matériel externe.)

Ou, si vous allez utiliser le port série pour une interface de ligne de commande, vous pouvez utiliser stdin/stdout.

Ou, il y a cette autre réponse à propos de périphériques série virtuels pour linux .

4
Dave Bacher

Peut-être qu'un périphérique en boucle fera le travail si vous avez besoin de tester votre application sans accéder à un périphérique. Il est inclus dans pySerial 2.5 https://pythonhosted.org/pyserial/url_handlers.html#loop

3
steko

Si vous utilisez Linux, vous pouvez utiliser la commande socat pour cela, comme ceci:

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 recevez le /dev/pts/12, et vice versa.

3
Richard