Port série virtuel pour Linux

128

J'ai besoin de tester une application de port série sur Linux, cependant, ma machine de test n'a qu'un seul port série.

Existe-t-il un moyen d'ajouter un port série virtuel à Linux et de tester mon application en émulant un périphérique via un shell ou un script?

Remarque: je ne peux pas remapper le port, il est codé en dur sur ttys2 et je dois tester l'application telle qu'elle est écrite.

JeffV
la source

Réponses:

75

Vous pouvez utiliser un pty ("pseudo-télétype", où un port série est un "vrai télétype") pour cela. D'un côté, ouvrez /dev/ptyp5et attachez votre programme à /dev/ttyp5; ttyp5agira comme un port série, mais enverra / recevra tout ce qu'il fait via / dev / ptyp5.

Si vous en avez vraiment besoin pour parler à un fichier appelé /dev/ttys2, déplacez simplement votre ancien /dev/ttys2et créez un lien symbolique de ptyp5vers ttys2.

Bien sûr, vous pouvez utiliser un nombre autre que ptyp5. Peut-être en choisir un avec un nombre élevé pour éviter les doublons, car tous vos terminaux de connexion utiliseront également ptys.

Wikipédia en a plus sur ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

Apenwarr
la source
8
Sous Linux, vous pouvez utiliser les appels système openpty / forkpty. Voir la page de manuel
Matthew Smith
8
comment créer une paire de ports série virtuels à l'aide de l'outil de ligne de commande?
linjunhalida
8
notez que de nombreux paramètres du port série, par exemple le débit en bauds, la parité, le contrôle de flux matériel, la taille des caractères (?) ne sont pas implémentés dans pty, il est donc impossible de tester votre application en présence d'erreurs de transmission série.
Dima Tisnek le
10
C'est utile, mais cela décrit les pseudo-terminaux BSD «à l'ancienne». Les pseudo-terminaux UNIX 98 «nouveau style» fonctionnent un peu différemment - voir la ptspage de manuel pour plus de détails.
Craig McQueen
3
@LaszloPapp Je m'excuse, je mentais tout le temps
Matthew Smith
160

Complétant la réponse de @ slonik.

Vous pouvez tester socat pour créer un port série virtuel en suivant la procédure suivante (testée sur Ubuntu 12.04):

Ouvrez un terminal (appelons-le Terminal 0) et exécutez-le:

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

Le code ci-dessus renvoie:

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/2
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/3
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs [3,3] and [5,5]

Ouvrez un autre terminal et écrivez (Terminal 1):

cat < /dev/pts/2

Le nom de port de cette commande peut être modifié en fonction du PC. cela dépend de la sortie précédente.

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**2**
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**3**
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs 

vous devez utiliser le numéro disponible sur la zone en surbrillance.

Ouvrez un autre terminal et écrivez (Terminal 2):

echo "Test" > /dev/pts/3

Revenez maintenant au terminal 1 et vous verrez la chaîne "Test".

cantoni
la source
Cela a mieux fonctionné pour moi que la réponse de slonik, car il est automatiquement assigné aux fichiers de port COM virtuels et ne fait pas écho.
gbmhunter
7
Si vous souhaitez utiliser un nom de fichier reproductible link=/path/to/linkaprès chaque déclaration de périphérique (après echo = 0). Il peut ainsi être utilisé dans des tests automatisés. (comme le fait slonik dans leur réponse)
Patrick B.
Cela a fonctionné exactement comme mentionné. Cela m'a aidé grâce.
nim118
1
Pour créer un pty que les liens vers un port série réel: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng
puis-je créer un port série avec des noms comme /dev/ttyS0au lieu de /dev/pts/1?
mrid
48

Utilisez socat pour cela:

Par exemple:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
Slonik
la source
Cela a bien fonctionné pour moi, testé avec minicom! Il semble que l'entrée d'un terminal soit renvoyée aux deux (donc elle réapparaîtra également sur la borne d'entrée).
gbmhunter
1
Je n'ai pas le même comportement d'écho ... minicom a une fonction "écho local" ... mais quand il est désactivé, il fonctionne exactement comme un vrai port série. Merci pour le conseil.
cptHammer
16

Il existe également tty0tty http://sourceforge.net/projects/tty0tty/ qui est un véritable émulateur de modem nul pour Linux.

C'est un simple module de noyau - un petit fichier source. Je ne sais pas pourquoi il n'a eu que des pouces vers le bas sur sourceforge, mais cela fonctionne bien pour moi. La meilleure chose à ce sujet est qu'il émule également les broches matérielles (RTC / CTS DSR / DTR). Il implémente même les commandes TIOCMGET / TIOCMSET et TIOCMIWAIT iotcl!

Sur un noyau récent, vous pouvez obtenir des erreurs de compilation. C'est facile à réparer. Insérez simplement quelques lignes en haut du module / tty0tty.c source (après les includes):

#ifndef init_MUTEX
#define init_MUTEX(x) sema_init((x),1)
#endif

Lorsque le module est chargé, il crée 4 paires de ports série. Les périphériques sont / dev / tnt0 à / dev / tnt7 où tnt0 est connecté à tnt1, tnt2 est connecté à tnt3, etc. Vous devrez peut-être corriger les autorisations de fichier pour pouvoir utiliser les périphériques.

Éditer:

Je suppose que j'ai été un peu rapide avec mon enthousiasme. Bien que le pilote semble prometteur, il semble instable. Je ne sais pas avec certitude, mais je pense que cela a fait planter une machine dans le bureau sur lequel je travaillais depuis chez moi. Je ne peux pas vérifier jusqu'à ce que je sois de retour au bureau lundi.

La deuxième chose est que TIOCMIWAIT ne fonctionne pas. Le code semble être copié à partir d'un exemple de code "minuscule tty". La gestion de TIOCMIWAIT semble en place, mais elle ne se réveille jamais car l'appel correspondant à wake_up_interruptible () est manquant.

Éditer:

L'accident dans le bureau était vraiment la faute du chauffeur. Il manquait une initialisation et le code TIOCMIWAIT complètement non testé a provoqué un crash de la machine.

J'ai passé hier et aujourd'hui à réécrire le pilote. Il y avait beaucoup de problèmes, mais maintenant cela fonctionne bien pour moi. Il manque encore du code pour le contrôle de flux matériel géré par le pilote, mais je n'en ai pas besoin car je gérerai les broches moi-même en utilisant TIOCMGET / TIOCMSET / TIOCMIWAIT à partir du code du mode utilisateur.

Si quelqu'un est intéressé par ma version du code, envoyez-moi un message et je vous l'enverrai.

Peter Remmers
la source
2
Je serais intéressé de voir votre code. Pouvez-vous contribuer au projet tty0tty? Cependant, je préférerais voir les gens améliorer le code du pseudo-terminal dans le noyau Linux. Par exemple, ajoutez la prise en charge de la connexion matérielle et TIOCMIWAIT.
Craig McQueen
3
"Si quelqu'un est intéressé par ma version du code, envoyez-moi un message et je vous l'enverrai." Oui, ça m'intéresse! Pouvez-vous le pointer quelque part, par exemple sur GitHub?
Craig McQueen
7
J'ai téléchargé le pilote sur: github.com/pitti98/nullmodem Désolé, il a fallu si longtemps pour répondre. Je ne suis pas très actif sur stackoverflow et j'ai oublié votre commentaire!
Peter Remmers
Non, je l'ai écrit parce que j'en avais besoin et je me suis arrêté une fois que c'était assez bon pour faire ce que je voulais. Maintenant que c'est public, j'espère que c'est utile pour quelqu'un d'autre, et peut-être que quelqu'un reprend là où je l'ai laissé.
Peter Remmers
8

Vous voudrez peut-être regarder Tibbo VSPDL pour créer un port série virtuel Linux à l'aide d'un pilote de noyau - cela semble assez nouveau et est disponible au téléchargement dès maintenant (version bêta). Je ne suis pas sûr de la licence à ce stade, ou s'ils souhaitent la rendre disponible dans le commerce uniquement à l'avenir.

Il existe d'autres alternatives commerciales, telles que http://www.ttyredirector.com/ .

En Open Source, Remserial (GPL) peut également faire ce que vous voulez, en utilisant Unix PTY. Il transmet les données série sous "forme brute" à une prise réseau; La configuration de type STTY des paramètres de terminal doit être effectuée lors de la création du port, les modifier ultérieurement comme décrit dans la RFC 2217 ne semble pas être pris en charge. Vous devriez pouvoir exécuter deux instances remserial pour créer un nullmodem virtuel comme com0com, sauf que vous devrez configurer la vitesse du port, etc. à l'avance.

Socat (également GPL) est comme une variante étendue de Remserial avec beaucoup plus d'options, y compris une méthode "PTY" pour rediriger le PTY vers autre chose, qui peut être une autre instance de Socat. Pour les tets unitaires, socat est probablement plus agréable que remserial car vous pouvez directement cat des fichiers dans le PTY. Voir l' exemple PTY sur la page de manuel. Un correctif existe sous "contrib" pour fournir le support RFC2217 pour la négociation des paramètres de ligne série.


la source
6

En utilisant les liens postés dans les réponses précédentes, j'ai codé un petit exemple en C ++ en utilisant un port série virtuel. J'ai poussé le code dans GitHub: https://github.com/cymait/virtual-serial-port-example .

Le code est assez explicite. Tout d'abord, vous créez le processus maître en exécutant ./main master et il s'imprimera sur stderr que le périphérique utilise. Ensuite, vous appelez le périphérique esclave ./main, où périphérique est le périphérique imprimé dans la première commande.

Et c'est tout. Vous avez un lien bidirectionnel entre les deux processus.

En utilisant cet exemple, vous pouvez tester l'application en envoyant toutes sortes de données et voir si cela fonctionne correctement.

De plus, vous pouvez toujours créer un lien symbolique sur le périphérique, vous n'avez donc pas besoin de recompiler l'application que vous testez.

Mauro Ciancio
la source
1
while (read (fd, & inputbyte, 1) == 1) {...} read n'est pas défini dans votre code. l'écriture n'est pas définie. close n'est pas défini.
Mattis Asp
4

Seriez-vous capable d'utiliser un adaptateur USB-> RS232? J'en ai quelques-uns, et ils utilisent simplement le pilote FTDI. Ensuite, vous devriez pouvoir renommer / dev / ttyUSB0 (ou tout ce qui est créé) en / dev / ttyS2.

Hurleur
la source
4

Je peux penser à trois options:

Mettre en œuvre la RFC 2217

La RFC 2217 couvre un port com à la norme TCP / IP qui permet à un client sur un système d'émuler un port série vers les programmes locaux, tout en envoyant et recevant de manière transparente des données et des signaux de contrôle à un serveur sur un autre système qui possède en fait le port série. Voici un aperçu de haut niveau .

Ce que vous feriez est de trouver ou d'implémenter un pilote de port com client qui implémenterait le côté client du système sur votre PC - semblant être un véritable port série mais en réalité, tout transférer vers un serveur. Vous pourrez peut-être obtenir ce pilote gratuitement auprès de Digi, Lantronix, etc. pour prendre en charge leurs véritables serveurs de port série autonomes.

Vous implémenteriez ensuite le côté serveur de la connexion localement dans un autre programme - permettant au client de se connecter et d'émettre les données et les commandes de contrôle si nécessaire.

Ce n'est probablement pas trivial, mais le RFC existe et vous pourrez peut-être trouver un projet open source qui implémente un ou les deux côtés de la connexion.

Modifier le pilote du port série Linux

Alternativement, la source du pilote de port série pour Linux est facilement disponible. Prenez cela, débarrassez-vous des éléments de contrôle matériels et demandez à ce pilote d'exécuter deux ports / dev / ttySx, comme un simple bouclage. Ensuite, connectez votre programme réel au ttyS2 et votre simulateur à l'autre ttySx.

Utilisez deux câbles USB <--> série en boucle

Mais la chose la plus simple à faire maintenant? Dépensez 40 $ sur deux périphériques USB à port série, connectez-les ensemble (modem nul) et disposez en fait de deux ports série réels - un pour le programme que vous testez, un pour votre simulateur.

-Adam

Adam Davis
la source
1
En fait, les câbles USB UART null modem me semblent une solution assez élégante car ils prennent en charge à la fois les tests locaux (obtenez un concentrateur USB si vous manquez de ports) et le débogage à distance.
Maxthon Chan
Je n'ai pas revu sa qualité, mais ttynvt implémente RFC 2217 via Linux FUSE
Daniel Santos