Serieller Port-Loopback / Duplex-Test, in Bash oder C? (Prozesssubstitution)

8

Ich habe ein serielles Gerät als Loopback eingerichtet (das bedeutet, es wird einfach jedes empfangene Zeichen zurückgeben), und ich möchte die effektive Durchsatzgeschwindigkeit messen. Dafür hoffte ich, dass ich time verwenden konnte, wie in

%Vor%

wobei ' ... ' ein Befehl wäre, den ich ausführen könnte.

Nun, das erste Problem ist, dass ich das Gerät mit 2000000 bps verwenden möchte, also kann ich ttylog nicht verwenden oder Bildschirm (beide scheinen nur bis zu 115200 bps zu gehen). Die Arbeit mit /dev/ttyUSB0 als Datei (mit Dateiumleitung und cat ) scheint jedoch gut zu funktionieren:

%Vor%

Nun möchte ich etwas Ähnliches tun - ich möchte cat eine Datei an eine serielle Schnittstelle anschließen und die serielle Schnittstelle zurücklesen lassen - aber von einem einzigen Terminalbefehl (so könnte ich es als verwenden Argument für time ).

Ich dachte, ich könnte eine Bash-Prozess-Substitution verwenden, um den "schreibenden" und den "lesenden" Teil gewissermaßen "parallel" gehen zu lassen - wenn ich es mit Named Pipes versuche, funktioniert es:

%Vor%

Da oben verwende ich comm nicht für irgendeinen anderen Zweck, als die beiden Prozesse zu einem einzigen Befehl zusammenzufassen (ich denke, ich hätte stattdessen auch echo verwenden können).

Leider scheint dieser Trick nicht mit einer seriellen Schnittstelle zu funktionieren, denn wenn ich es versuche, bekomme ich manchmal:

%Vor%

... aber normalerweise bekomme ich überhaupt keine Ausgabe. Das sagt mir: Entweder gibt es keine Kontrolle darüber, welcher Prozess zuerst gestartet wird, und so kann cat mit dem Lesen beginnen, bevor der Port fertig ist (dies scheint jedoch im ersten Beispiel kein Problem zu sein); oder in Linux / Bash kann man nicht gleichzeitig auf einen seriellen Port lesen und schreiben, und so würde " Invalid argument " in den Momenten auftreten, in denen sowohl Lesen als auch Schreiben zur gleichen Zeit passieren.

Meine Fragen sind also:

  • Gibt es eine Möglichkeit, so etwas zu machen ( cat eine Datei an einen als Loopback konfigurierten seriellen Port; lese es zurück und sehe, wie lange es dauert), nur in Bash, ohne auf ein dediziertes C-Programm zurückgreifen zu müssen?
  • Wenn ich ein dediziertes C-Programm benötige, könnten irgendwelche Quellenbeispiele dort im Netz verwendet werden?

Vielen Dank für die Antworten,

Prost!

BEARBEITEN: Ich bin mir bewusst, dass die oben beschriebene while -Schleife nicht beendet wird; Diese Befehlszeile diente zum Testen, und ich unterbreche sie mit Ctrl-C. ( Ich könnte es im Prinzip mit etwas wie timeout -9 0.1 bash -c 'while (true) do echo AA ; done' unterbrechen, aber das würde den Zweck von time zunichte machen, dann:) )

Der Grund dafür, dass while vorhanden ist, besteht darin, dass das Lesen über cat vom Gerät momentan sofort beendet wird; manchmal habe ich das Gerät eingerichtet, so dass, wenn cat ausgegeben wird, es tatsächlich blockiert und auf eingehende Daten wartet; aber ich kann noch nicht absehen, was vor sich geht (und teilweise suche ich deshalb nach einer Möglichkeit, von der Kommandozeile aus zu testen).

Falls ich while nicht verwendet habe, stelle ich mir zum Timing etwas vor:

time bash -c 'comm <(echo "1234567890" > /dev/ttyUSB0) <(cat -A /dev/ttyUSB0)'

... aber damit dies funktioniert, nimmt man an, dass cat -A /dev/ttyUSB0 zuerst startet und blockiert; dann schreibt die echo in den seriellen Port (und beendet); und dann gibt cat -A aus, was auch immer es von der seriellen Schnittstelle gelesen hat - und dann beendet. ( Und ich bin mir auch nicht wirklich sicher, ob sich ein serieller Port überhaupt so verhalten kann, oder ob cat zum Blockieren und Beenden beliebig gemacht werden kann ).

Die genaue Methode spielt wirklich keine Rolle; wenn es mir möglich ist, möchte ich nur vermeiden, mein eigenes C-Programm zu programmieren, um diese Art von Tests zu machen - weshalb mein Hauptinteresse darin besteht, ob es irgendwie möglich ist, einen solchen "Vollduplex-Test" mit Basic Bash / Linux (zB coreutils ); ( und wenn nicht, wenn es einen vorgefertigten Code gibt, den ich für so etwas verwenden kann ).

EDIT2: Auch möglicherweise relevant:

sdaau 13.09.2010, 15:38
quelle

2 Antworten

4

Nun, es ist mir gelungen, writeread.c in eine Thread-Version mit pthread zu setzen ( Code ist darunter - ich glaube nicht, dass serial.h sich stark verändert hat; in der thread-Version wird es sowieso nicht so oft verwendet) / em>). Ich habe auch die Geschwindigkeit auf 115200 gesenkt, und jetzt kann ich diese Messungen mit dem Gerät bestätigen, in der folgenden Beispiel-Befehlszeilen-Sitzung:

%Vor%

Nun, Messungen melden jetzt bis zu 99% der erwarteten Baudrate, also denke ich, dass der Profilierungsaspekt dieses Programms funktionieren sollte. Hinweis:

  • Bei diesem Gerät wird write in einem einzelnen Chunk ausgeführt (, da der PC in der Lage sein sollte, die Sequenzierung von Paketen zu übernehmen, falls erforderlich ),
  • während der read in kleineren Blöcken weitergeht ( bedeutet wahrscheinlich, dass das Gerät nicht auf den gesamten Chunk wartet), stattdessen sendet es kleinere Chunks zurück, sobald es genug )

Nun, ich denke, das ist das, was ich ursprünglich brauchte; Ich denke auch, es ist wahrscheinlich nicht möglich, cat und echo über die Prozesssubstitution anzuordnen, um dies auszuführen, nennen wir es "threaded", Weise :) ( Nun, ich habe ein Problem damit, dasselbe zu tun bei 2000000 Baud, aber das deutet auf ein Problem mit der Programmierung des Gerätes hin.

Prost!

writreead.c - threaded-Version

%Vor%     
sdaau 14.09.2010, 11:28
quelle
5

Nun, hier ist so etwas wie eine Teilantwort - obwohl die Frage nach dem Einsatz von bash noch offen ist. Ich habe versucht, ein wenig in C-Code-Lösungen zu suchen - und das scheint auch nicht trivial zu sein! :)

Sehen wir zuerst, was möglicherweise nicht für diesen Fall funktioniert - unten ist ein Beispiel von " zwischen schreiben und lesen: serielle Schnittstelle. - C ":

%Vor%

Das Problem mit dem obigen Code besteht darin, dass der serielle Port nicht explizit für Zeichenoperationen ("raw") initialisiert wird; Je nachdem, wie der Port zuvor eingestellt wurde, sieht eine Sitzung möglicherweise so aus:

%Vor%

... mit anderen Worten, es gibt kein Echo der Eingabedaten. Wenn der serielle Port jedoch richtig eingerichtet ist, können wir eine Sitzung wie folgt erhalten:

%Vor%

... (, aber selbst dann fällt dieser sertest -Code bei Eingabewörtern mit mehr als 3 Zeichen aus. )

Schließlich, durch einige Online-Grabungen, habe ich es geschafft, " zu finden (Gelöst) Serielle Programmierung, Schreib-Lese-Problem ", das ein writeread.cpp -Beispiel anbietet. Für diesen byteweisen "Duplex" -Fall reichte jedoch nicht einmal das aus, nämlich " Serielle Programmierung HOWTO " Anmerkungen: " Canonical Input Processing ... ist der normale Verarbeitungsmodus für Terminals ... was bedeutet, dass ein Lesen nur eine vollständige Zeile der Eingabe zurückgibt Zeile wird standardmäßig mit einem NL (ASCII LF) beendet ... "; und deshalb müssen wir explizit den seriellen Port in unserem Code auf "nicht-kanonischen" (oder "rohen") Modus setzen über ICANON ( mit anderen Worten, nur O_NONBLOCK setzen via open ist nicht genug ) - ein Beispiel dafür ist unter " 3.2 Wie kann ich einzelne Zeichen vom Terminal lesen? - Unix-Programmierung Häufig gestellte Fragen - 3. Terminal I / O ". Sobald dies geschehen ist, wird der Aufruf von writeread auch den seriellen Port für das serport -Beispiel (oben) "korrekt" setzen.

Also habe ich etwas von diesem writeread -Code zurück in C geändert, die benötigten Initialisierungskram hinzugefügt, sowie Zeitmessung, Möglichkeit, Strings oder Dateien zu senden, und zusätzlichen Ausgabestrom ( für 'piping') serielle Daten in eine separate Datei ). Der Code ist unten als writeread.c und serial.h , und damit kann ich etwas wie in der folgenden Bash-Sitzung tun:

%Vor%

Nun:

  • Erste Überraschung - es geht schneller, wenn ich in eine Datei schreibe, als wenn ich an /dev/null ! weiterleiten würde!
  • Auch, um 1000 Bps zu bekommen - während das Gerät anscheinend auf 200000 BPS eingestellt ist !!

An dieser Stelle denke ich, dass die Verlangsamung ist, weil wir nach jedem geschriebenen Byte in writeread.c darauf warten, dass ein Flag durch den Lese-Interrupt gelöscht wird, bevor wir fortfahren, den seriellen Puffer zu lesen. Möglicherweise, wenn das Lesen und Schreiben separate Threads waren, dann könnte sowohl das Lesen als auch das Schreiben versuchen, größere Blöcke von Bytes in einzelnen read oder write Aufrufen zu verwenden, und so würde die Bandbreite besser genutzt werden? ( Oder, vielleicht funktioniert der Interrupt-Handler in gewisser Weise wie ein "Thread", der parallel läuft - also könnte etwas ähnliches erreicht werden, indem alle lesebezogenen Funktionen an den Interrupt-Handler übergeben werden?! )

Nun gut, ich bin zu diesem Zeitpunkt sehr offen für Vorschläge / Links für bestehenden Code wie writeread.c , aber Multithread :) Und natürlich für alle möglichen anderen Linux-Tools oder möglicherweise Bash-Methoden (obwohl es scheint Bash wird diese Kontrolle nicht ausüben können ...)

Prost!

writeread.c :

%Vor%

serial.h :

%Vor%     
sdaau 14.09.2010 00:30
quelle

Tags und Links