Linux serial input per bash verarbeiten

Liebe/-r Experte/-in,

ich möchte gern Eingaben an einem seriellen Port per bash script verarbeiten. An der seriellen Schnittstelle meines Linux PC (VIA C7 epia board 800 MHz mit reinem Konsolen linux EISFair) hängt ein Gerät, welches Textinformationen sendet. Die Übertragung erfolgt mit 9600 baud ohne Flusskontrolle.

Wenn ich minicom benutze, sieht der Datenstrom etwa wie folgt aus:

tdi ($110f $3102 $01) $00
tdi ($110f $3602 $00) $00
tdi (01.01.001 11/05/000 $03) $75 $07 $00
tdi (01.01.039 06/01/010 $01) $00
tdi (01.01.039 06/06/013 $00) $00
tdi (01.01.011 06/03/002 $02) $18 $F6

…usw.

Jede Zeile endet mit einem LFCR bzw. mit 0x0A 0x0D.
Nun möchte ich diesen Input zeilenweise per bash script verarbeiten. Dazu lese ich den Input in eine Variable ein. Der Scriptschnipsel sieht wie folgt aus:

#!/bin/bash
comdevice="/dev/ttyS0"
stty -F $comdevice 9600 -echo
while :
 do
 inputvar=`head $comdevice --lines=1`
 echo $inputvar
done;

Das Ergebnis auf der Konsole sieht leider etwas verkrüppelt aus:
tdi ($110f $3102 $01) $00
$110f $3602 $00) $00
tdi (01.01.001 11/05/000 $03) $75 $07 $00
tdi (01.01.039 06/01/010 $01) $00
01.01.039 06/06/013 $00) $00
i (01.01.011 06/03/002 $02) $18 $F6

Es sieht so aus, als ob irgendwie Zeichen verloren gehen.
Ich habe auch schon versucht, die Zeichen mit dem Befehl

inputvar=`dd if=$comdevice count=1 2\>\>/dev/null`

einzulesen. Das Ergebnis war gleich.
Ich vermute, dass hier irgendwelche Parameter beim stty oder beim setserial für ein Besserung sorgen könnten, bin aber leider nicht wirklich durch die manpage durchgestiegen. Kannst Du mir vieleicht weiterhelfen?

Ich bin für jeden Hinweis dankbar, der es mir ermöglicht, die Zeile komplett in die Variable zu bekommen.

Vielen Dank im Voraus!

Sorry, da kann ich nicht helfen. Ist nicht mein Thema.

Ronald

Hallo,

Jede Zeile endet mit einem LFCR bzw. mit 0x0A
0x0D
.
Nun möchte ich diesen Input zeilenweise per bash script
verarbeiten.

Zeilen würde ich in der bash einfach mit „read“ lesen:

comdevice="/dev/ttyS0"
stty -F $comdevice 9600 -echo |
while read inputvar
do
echo $inputvar
done

Was das eigentliche Problem angeht, könnte es vielleicht an der Kommunikationsgeschwindigkeit liegen. Zur Erklärung siehe hier:
http://linux.about.com/od/srl_howto/a/hwtsrl18t21.htm

Eine Lösung z.B. hier:
http://forums.fedoraforum.org/showthread.php?t=176658

Kenne mich selbst nicht besonders gut mit den Besonderheiten des seriellen Ports aus, aber ich denke, das zitierte Howto enthält alles, was Du brauchen könntest (da werden auch Diagnose- und sonstige Hilfsprogramme aufgeführt).

Hellow,

vermutlich ist das Zeilenende genau dein Problem. Die Shell bzw. ‚head‘ brauchen nur ein Zeichen für das Zeilenende, nämlich LF, das CR ist über und müßte eigentlich rausgeworfen werden. Minicom verarbeitet den Datenstrom entsprechend den minicom-Einstellungen, alle Shellkommandos, die direkt auf die serielle Schnitte zugreifen, nicht! Von daher muß stty alles einstellen und die eingegangenen Zeichen interpretieren.
stty bietet also diverse spezielle Eingangszeichenbehandlung an, die du entsprechend einstellen mußt. Ich habe z. B. gerade in der man-Page zu stty folgendes gefunden:

Input settings:
 [-]icrnl translate carriage return to newline
**[-]igncr ignore carriage return**
 [-]inlcr translate newline to carriage return

Ich vermute mal, ein

\> stty -F $comdevice 9600 **-igncr** -echo 

könnte dein Problem lösen.

Es kann aber auch weiter noch möglich sein, daß dir die Flußkontrolle dazwischenfunkt, also explizit XON/XOFF ausschalten, auch RTS/CTS. Dann noch aufpassen, was es mit Input buffer flushing „auffe Hakken“ hat, gerade dann, wenn jetzt mal eine Zeile nicht vollständig rüberkommt, daß nach einer bestimmten Zeit der Empfangsbuffer ausgegeben wird bzw. auch geleert wird, sonst Datenchaos.

stty bietet nen ganzen Haufen an Einstellmöglichkeiten, ist manchmal echt schwierig, das alles so hinzukriegen. Vor ein paar Jahren habe ich mal ein urmelaltes Text-Only schwarz/weiß Terminal an die serielle Schnitte gehangen und per getty das Login machen lassen, sodaß das Ding voll funktionsfähig war. Die Parameterliste für getty bzw. stty ging so über 2 Zeilen mit je ca. 80 Zeichen. Ok, war keine 8N1 Übertragung, sondern 7E1 und dann mußten die ausgegebenen Zeichen und die ankommenden Zeichen speziell verarbeitet werden. Um dies ganzes zusammensuchen zu sparen, kukk dir mal in der man-Page den Abschnitt „Combination settings:“ an. Da kann man dann mit einem Parameter gleich ne ganze Menge Parameter abhaken, wie bei dem Parameter „sane“

\> stty sane

ist also gleich wie

\> stty cread -ignbrk brkint -inlcr -igncr icrnl -iutf8 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke

Parameter, die mit i anfangen wie „inlcr“ bearbeiten den eingehenden Datenstrom (Input), die mit o anfangen wie „ofill“ behandel die ausgehenden Daten (Output).

Viel Spaß noch beim schrauben, sowas kann dauern :smile:)
kann, muß nicht!

Nachtrag, hab mich evtl. vertan.

Statt des

\> stty -F $comdevice 9600 **-igncr** -echo

versuch mal

\> stty -F $comdevice 9600 **igncr** -echo

Ich glaube, das Minus vor dem igncr (ignore CR) schaltet das ignore CR ab, soll aber eingeschaltet werden, also ohne Minus.

Hallo Alex,

dieses Problem ist recht spezifisch, für mich mangels Hardware nicht nachvollziehbar. Ich habe allerdings eine Vermutung: bestimmte RS232 Bausteine bereiten setserial Probleme und hier ist bekannt, dass diese Probleme bedeuten, dass Zeichen verschluckt werden.
Im Normalfall wird auf aktuellen Systemen ein 16550 UART angenommen (und konfiguriert) auch wenn tatsächlich ein 16450 drin steckt.
Da ich nicht genau weiss, was für ein Board Du nutzt, kann ich diesen Verdacht erstmal nicht bestätigen. Gib mir doch mal bitte die genaue Boardbezeichnung oder checke selber ab, was für ein Baustein auf dem Board vorhanden ist. Falls es ein 16450 ist, gib setserial den Parameter ‚uart 16450‘ mit.
Falls das Dein Problem nicht löst, melde Dich einfach nochmal, dann schau ich gerne weiter. Ansonsten bin ich auch über eine positive Rückmeldung froh.

Schöne Grüße,
Markus Schmidt-Pauly

Leider kenn ich mich mit dem Arbeiten mit der seriellen Schnittstelle nicht so aus, darum kann ich nichts zu sttycat /dev/ttyS0 >/tmp/tty.out) und versuche, Dein Skript auf der Transcript-Datei arbeiten zu lassen (z.B. über eine named pipe). Wenn es damit auch nicht klappt, hast Du ein Problem mit dem Datenformat. (Mir sind die CRLF-Zeilenenden ein bißchen verdächtig; ich kann mir aber nicht erklären, wie die zu der „Textverkrüppelung“ führen könnten.)

Allerdings ist mir grad aufgefallen, daß es nicht ganz simpel ist, Dein Skript mit einer Datei zu testen; evtl. könnte es mit einer Named Pipe (mkfifo) gehen, in die Du das Transscript reinschiebst und das Skript rausliest.

Ich würde das Skript dewegen auch ein bißchen anders aufziehen. Die klassische Bauform für das zeilenweise Abarbeiten ist:

while read LINE
do
 irgenwas mit $LINE machen
done

Hat den Vorteil, daß man in das Skript alles per Stdin reinschieben kann:

./dein-skript 

genauso wie



    ./dein-skript 
    
    (Ggf. mußt Du Dich noch um das CR kümmern; vielleicht mit sed oder awk abschneiden.)
    
    
    Klappt mit dem Transcript alles super, aber direkt mit der Schnittstelle nicht, dann mußt Du wohl jemand anderes finden, der sich mit der Schnittstellensteuerung auskennt.

Hallo,

tut mir Leid, ich denke nicht dass ich Dir da weiterhelfen kann.

Da minicom funktioniert, solltest Du Dir da noch einmal alle Einstellungen anschauen.

Bist Du auch sicher, dass die Schleife in deinem Script schnell genug ist und nichts verschluckt?
Schreib doch mal alles was von der Schnittstelle kommt in eine Datei und schau dir das Ergebnis an.

Viele Grüße

Marcus

Vielen Dank an alle die mir mit Rat zur Seite standen.

Viele Versuche mit den Schnittstelleneinstellungen zu Flusskontrolle, Zeichenübersetzung u.a. haben leider nichts gebracht.

Ich habe das Problem gelöst, indem ich die Datenrate auf beiden Seiten von 9600 auf 1200 Baud reduziert habe. Es scheint wohl doch an der Verarbeitungsgeschwindigkeit meines Bash scripts zu liegen…

Viele Grüße
/Alex