Virtuelle serielle Schnittstelle für Linux

127

Ich muss eine Anwendung mit serieller Schnittstelle unter Linux testen. Mein Testcomputer verfügt jedoch nur über eine serielle Schnittstelle.

Gibt es eine Möglichkeit, Linux eine virtuelle serielle Schnittstelle hinzuzufügen und meine Anwendung zu testen, indem ein Gerät über eine Shell oder ein Skript emuliert wird?

Hinweis: Ich kann den Port nicht neu zuordnen, er ist auf ttys2 fest codiert und ich muss die Anwendung so testen, wie sie geschrieben ist.

JeffV
quelle

Antworten:

74

Sie können hierfür ein pty ("Pseudo-Teletyp", wobei eine serielle Schnittstelle ein "echter Teletyp" ist) verwenden. Öffnen Sie an einem Ende /dev/ptyp5Ihr Programm und hängen Sie es an /dev/ttyp5. ttyp5verhält sich wie eine serielle Schnittstelle, sendet / empfängt jedoch alles, was es tut, über / dev / ptyp5.

Wenn Sie es wirklich brauchen, um mit einer aufgerufenen Datei zu sprechen /dev/ttys2, schieben Sie einfach Ihr altes /dev/ttys2aus dem Weg und erstellen Sie einen Symlink von ptyp5zu ttys2.

Natürlich können Sie eine andere Nummer als verwenden ptyp5. Wählen Sie möglicherweise eine mit einer hohen Nummer aus, um Duplikate zu vermeiden, da alle Ihre Login-Terminals auch ptys verwenden.

Wikipedia hat mehr über ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

Apenwarr
quelle
8
Unter Linux können Sie die Systemaufrufe openpty / forkpty verwenden. Siehe Manpage
Matthew Smith
8
Wie erstelle ich ein virtuelles serielles Port-Paar mithilfe des Befehlszeilentools?
Linjunhalida
8
Beachten Sie, dass viele Parameter der seriellen Schnittstelle, z. B. Baudrate, Parität, Hardware-Flusskontrolle, Zeichengröße (?), nicht in pty implementiert sind. Daher ist es unmöglich, Ihre Anwendung auf serielle Übertragungsfehler zu testen.
Dima Tisnek
10
Dies ist hilfreich, beschreibt jedoch die BSD-Pseudo-Terminals im "alten Stil". Die UNIX 98-Pseudo-Terminals im "neuen Stil" funktionieren etwas anders - Einzelheiten finden Sie in der ptsManpage .
Craig McQueen
3
@ LaszloPapp Ich entschuldige mich, ich habe die ganze Zeit gelogen
Matthew Smith
160

Ergänzung der Antwort von @ slonik.

Sie können socat testen, um einen virtuellen seriellen Port zu erstellen, indem Sie das folgende Verfahren ausführen (getestet unter Ubuntu 12.04):

Öffnen Sie ein Terminal (nennen wir es Terminal 0) und führen Sie es aus:

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

Der obige Code gibt Folgendes zurück:

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]

Öffnen Sie ein anderes Terminal und schreiben Sie (Terminal 1):

cat < /dev/pts/2

Der Portname dieses Befehls kann je nach PC geändert werden. es hängt von der vorherigen Ausgabe ab.

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 

Sie sollten die im markierten Bereich verfügbare Nummer verwenden.

Öffnen Sie ein anderes Terminal und schreiben Sie (Terminal 2):

echo "Test" > /dev/pts/3

Nun zurück zu Terminal 1 und Sie sehen die Zeichenfolge "Test".

cantoni
quelle
Dies funktionierte für mich besser als die Antwort von slonik, da es virtuellen COM-Port-Dateien automatisch zugewiesen wird und kein Echo gibt.
Gbmhunter
7
Wenn Sie einen reproduzierbaren Dateinamen wünschen, verwenden Sie ihn link=/path/to/linknach jeder Gerätedeklaration (nach echo = 0). Es kann somit in automatisierten Tests verwendet werden. (wie Slonik in ihrer Antwort tut)
Patrick B.
Dies funktionierte genau wie erwähnt. Es hat mir geholfen, danke.
nim118
1
So erstellen Sie eine Pty, die mit einer echten seriellen Schnittstelle verbunden ist : socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng
Kann ich eine serielle Schnittstelle mit Namen wie /dev/ttyS0anstelle von erstellen /dev/pts/1?
Mrid
48

Verwenden Sie dazu socat:

Beispielsweise:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
slonik
quelle
Das hat bei mir gut funktioniert, mit Minicom getestet! Es scheint, als würde der Eingang eines Terminals an beide weitergegeben (so dass er auch am Eingangsanschluss wieder angezeigt wird).
Gbmhunter
1
Ich habe nicht das gleiche Echo-Verhalten ... minicom hat eine "lokales Echo" -Funktion ... aber wenn es deaktiviert ist, funktioniert es genau wie eine echte serielle Schnittstelle. Danke für den Tipp.
cptHammer
16

Es gibt auch tty0tty http://sourceforge.net/projects/tty0tty/ , einen echten Nullmodem-Emulator für Linux.

Es ist ein einfaches Kernelmodul - eine kleine Quelldatei. Ich weiß nicht, warum es nur Daumen runter auf SourceForge hat, aber es funktioniert gut für mich. Das Beste daran ist, dass auch die Hardware-Pins (RTC / CTS DSR / DTR) emuliert werden. Es implementiert sogar die iotcl-Befehle TIOCMGET / TIOCMSET und TIOCMIWAIT!

Auf einem aktuellen Kernel können Kompilierungsfehler auftreten. Dies ist leicht zu beheben. Fügen Sie einfach ein paar Zeilen oben in die Quelle des Moduls / tty0tty.c ein (nach den Includes):

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

Wenn das Modul geladen wird, werden 4 Paare serieller Schnittstellen erstellt. Die Geräte sind / dev / tnt0 bis / dev / tnt7, wobei tnt0 mit tnt1, tnt2 mit tnt3 usw. verbunden ist. Möglicherweise müssen Sie die Dateiberechtigungen korrigieren, um die Geräte verwenden zu können.

bearbeiten:

Ich glaube, ich war ein bisschen schnell mit meiner Begeisterung. Der Fahrer sieht zwar vielversprechend aus, scheint aber instabil zu sein. Ich weiß es nicht genau, aber ich glaube, es hat eine Maschine in dem Büro, an dem ich von zu Hause aus gearbeitet habe, zum Absturz gebracht. Ich kann nicht nachsehen, bis ich am Montag wieder im Büro bin.

Das zweite ist, dass TIOCMIWAIT nicht funktioniert. Der Code scheint aus einem "winzigen tty" -Beispielcode kopiert worden zu sein. Die Behandlung von TIOCMIWAIT scheint vorhanden zu sein, wird jedoch nie aktiviert, da der entsprechende Aufruf von wake_up_interruptible () fehlt.

bearbeiten:

Der Absturz im Büro war wirklich die Schuld des Fahrers. Es fehlte eine Initialisierung, und der vollständig ungetestete TIOCMIWAIT-Code verursachte einen Absturz der Maschine.

Ich habe gestern und heute den Treiber neu geschrieben. Es gab viele Probleme, aber jetzt funktioniert es gut für mich. Es fehlt noch Code für die vom Treiber verwaltete Hardware-Flusskontrolle, aber ich brauche ihn nicht, da ich die Pins selbst mit TIOCMGET / TIOCMSET / TIOCMIWAIT aus dem Benutzermodus-Code verwalten werde.

Wenn jemand an meiner Version des Codes interessiert ist, senden Sie mir eine Nachricht und ich werde sie Ihnen senden.

Peter Remmers
quelle
2
Es würde mich interessieren, Ihren Code zu sehen. Können Sie es wieder in das tty0tty-Projekt einbringen? Ich würde es jedoch vorziehen, wenn Leute den Pseudo-Terminal-Code im Linux-Kernel verbessern. Fügen Sie beispielsweise Hardware-Handshake-Unterstützung und TIOCMIWAIT hinzu.
Craig McQueen
3
"Wenn jemand an meiner Version des Codes interessiert ist, sende mir eine Nachricht und ich sende sie dir." Ja, ich bin interessiert! Kannst du irgendwo darauf hinweisen, zB auf GitHub?
Craig McQueen
7
Ich habe den Treiber hochgeladen auf: github.com/pitti98/nullmodem Die Antwort hat leider so lange gedauert. Ich bin nicht sehr aktiv im Stackoverflow und habe Ihren Kommentar übersehen!
Peter Remmers
Nein, ich habe es geschrieben, weil ich es brauchte, und habe aufgehört, als es gut genug war, um das zu tun, was ich wollte. Jetzt, da es öffentlich ist, hoffe ich, dass es für jemand anderen nützlich ist und vielleicht jemand dort weitermacht, wo ich es gelassen habe.
Peter Remmers
8

Vielleicht möchten Sie sich Tibbo VSPDL ansehen, um eine virtuelle serielle Linux-Schnittstelle mit einem Kernel-Treiber zu erstellen - es scheint ziemlich neu zu sein und steht ab sofort zum Download zur Verfügung (Beta-Version). Sie sind sich zu diesem Zeitpunkt nicht sicher über die Lizenz oder ob sie nur in Zukunft kommerziell verfügbar sein soll.

Es gibt andere kommerzielle Alternativen wie http://www.ttyredirector.com/ .

In Open Source kann Remserial (GPL) auch mithilfe von Unix- PTYs das tun, was Sie möchten. Es überträgt die seriellen Daten in "Rohform" an einen Netzwerk-Socket; Die STTY-ähnliche Einrichtung der Terminalparameter muss beim Erstellen des Ports erfolgen. Eine spätere Änderung wie in RFC 2217 beschrieben scheint nicht unterstützt zu werden. Sie sollten in der Lage sein, zwei Remserialinstanzen auszuführen, um ein virtuelles Nullmodem wie com0com zu erstellen, außer dass Sie die Portgeschwindigkeit usw. im Voraus einrichten müssen.

Socat (auch GPL) ist wie eine erweiterte Variante von Remserial mit vielen weiteren Optionen, einschließlich einer "PTY" -Methode zum Umleiten des PTY zu etwas anderem, das eine weitere Instanz von Socat sein kann. Für Unit-Tets ist socat wahrscheinlich besser als remserial, da Sie Dateien direkt in das PTY einfügen können. Siehe das PTY-Beispiel auf der Manpage. Unter "Contrib" befindet sich ein Patch , der RFC2217-Unterstützung für das Aushandeln von Einstellungen für serielle Leitungen bietet.


quelle
6

Unter Verwendung der in den vorherigen Antworten angegebenen Links habe ich ein kleines Beispiel in C ++ mithilfe einer virtuellen seriellen Schnittstelle codiert. Ich habe den Code in GitHub verschoben: https://github.com/cymait/virtual-serial-port-example .

Der Code ist ziemlich selbsterklärend. Zuerst erstellen Sie den Master-Prozess, indem Sie ./main master ausführen, und er druckt auf stderr, das das Gerät verwendet. Danach rufen Sie ./main Slave-Gerät auf, wobei Gerät das Gerät ist, das im ersten Befehl gedruckt wurde.

Und das ist es. Sie haben eine bidirektionale Verbindung zwischen den beiden Prozessen.

Anhand dieses Beispiels können Sie die Anwendung testen, indem Sie alle Arten von Daten senden und prüfen, ob sie ordnungsgemäß funktionieren.

Außerdem können Sie das Gerät jederzeit mit Symlinks verknüpfen, sodass Sie die zu testende Anwendung nicht erneut kompilieren müssen.

Mauro Ciancio
quelle
1
while (read (fd, & inputbyte, 1) == 1) {...} read ist in Ihrem Code undefiniert. Schreiben ist undefiniert. close ist undefiniert.
Mattis Asp
4

Könnten Sie einen USB-> RS232-Adapter verwenden? Ich habe einige, und sie verwenden nur den FTDI-Treiber. Dann sollten Sie in der Lage sein, / dev / ttyUSB0 (oder was auch immer erstellt wird) in / dev / ttyS2 umzubenennen.

Heuler
quelle
4

Ich kann mir drei Möglichkeiten vorstellen:

Implementieren Sie RFC 2217

RFC 2217 deckt einen COM-Port zum TCP / IP-Standard ab, der es einem Client auf einem System ermöglicht, einen seriellen Port für die lokalen Programme zu emulieren, während Daten und Steuersignale transparent an einen Server auf einem anderen System gesendet und empfangen werden, der tatsächlich über den seriellen Port verfügt. Hier ist eine allgemeine Übersicht .

Sie würden einen Client-COM-Port-Treiber finden oder implementieren, der die Client-Seite des Systems auf Ihrem PC implementiert. Dies scheint eine echte serielle Schnittstelle zu sein, in Wirklichkeit wird jedoch alles auf einen Server übertragen. Möglicherweise können Sie diesen Treiber kostenlos von Digi, Lantronix usw. erhalten, um die echten eigenständigen seriellen Serverserver zu unterstützen.

Sie würden dann die Serverseite der Verbindung lokal in einem anderen Programm implementieren, sodass der Client nach Bedarf eine Verbindung herstellen und die Daten- und Steuerbefehle ausgeben kann.

Es ist wahrscheinlich nicht trivial, aber der RFC ist da draußen, und Sie können möglicherweise ein Open Source-Projekt finden, das eine oder beide Seiten der Verbindung implementiert.

Ändern Sie den Treiber für die serielle Linux-Schnittstelle

Alternativ ist die Treiberquelle für die serielle Schnittstelle für Linux verfügbar. Nehmen Sie das, nehmen Sie die Hardware-Steuerelemente aus und lassen Sie diesen einen Treiber zwei / dev / ttySx-Ports als einfachen Loopback ausführen. Verbinden Sie dann Ihr reales Programm mit dem ttyS2 und Ihren Simulator mit dem anderen ttySx.

Verwenden Sie zwei serielle USB-Kabel in einem Loopback

Aber das Einfachste, was Sie jetzt tun können? Geben Sie 40 US-Dollar für zwei USB-Geräte mit serieller Schnittstelle aus, verbinden Sie sie miteinander (Nullmodem) und verfügen Sie über zwei echte serielle Schnittstellen - eine für das Programm, das Sie testen, eine für Ihren Simulator.

-Adam

Adam Davis
quelle
1
Tatsächlich scheinen mir die USB-UART-Kabel des Nullmodems eine recht elegante Lösung zu sein, da sie sowohl lokale Tests (einen USB-Hub erhalten, wenn die Ports knapp sind) als auch Remote-Debugging unterstützen.
Maxthon Chan
Ich habe die Qualität nicht überprüft, aber ttynvt implementiert RFC 2217 über Linux FUSE
Daniel Santos