serielle Schnittstellen-Parameter werden durch open() verändert (Linux)

OP #4202778
Lesenswert?
• ▲
▼
Um die zwischen zwei Maschinen seriell (genauer: Per RS-422) 
ausgetauschten Nachrichten aufzuzeichnen habe ich die Schnittstellen an 
einem Messrechner entsprechend konfiguriert, aber schon bei nur einer 
Schnittstelle zeigt sich das Problem das sich das die Parameter (Baud 
Rate etc.) unmittelbar nach dem Start vom Programmm, z. B. jpnevulator, 
verändert sind, so das ich nichts oder nur Müll empfange.

Deshalb musste ich das verwendete Skript um eine Hintergrund-Funktion 
ergänzen, die die Parameter eine Sekunde nach dem Start vom Programm 
nochmals setzt und damit geht es:
1
#!/bin/bash
2
# With the serial port $DEVICE: Sniff.
3

4
# no unset variables
5
set -u
6

7
# serial port type, e. g. ttyS0, ttyUSB0, ...
8
DEVICE=/dev/$1
9

10

11
# Set the configuration a second time just after the start of jpnevulator because some adapters, e. g. an USB
12
# adapter with a FT232, do lose some parameters like parenb or the baud rate although the program does not
13
# change the parameters. I could see this under
14
# 3.19.0-22-lowlatency #22-Ubuntu SMP PREEMPT Tue Jun 16 17:47:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
15
# and the resuls is no input with a changed baud rate and ghost bytes of type 0xFF at unset parenb.
16
backgroundfunction ()
17
{
18
  sleep 1
19
  stty 19200 -parodd cs8 parenb -cstopb -crtscts -ixon -clocal -echo cread -F $DEVICE
20
}
21

22
# configure: 19200 baud, 8 bits/byte, even parity, one stop bit, no RTS/CTS handshaking,
23
# no XON/XOFF flow control, no modem control signals, no echo, open device /dev/$DEVICE
24
#stty 19200 -parodd cs8 parenb -cstopb -crtscts -ixon -clocal -echo cread -cdtrdsr -F $DEVICE
25
stty 19200 -parodd cs8 parenb -cstopb -crtscts -ixon -clocal -echo cread -F $DEVICE
26

27
# sniffing: only reading, print a line with the current time and device before the bytes,
28
# print up 99 bytes per line, extra column with the current index number of the byte in the output,
29
# first device $DEVICE0 with alias Nr1, and copy the output to the log file
30
backgroundfunction &
31
echo starting jpnevulator ...
32
jpnevulator --read --timing-print --width=99 --byte-count --tty $DEVICE:Nr1 2>&1 | tee log_single_x25_`date +%F_%H.%M.%S`.txt
33

34
exit 0

Ohne diesen Workaroung zeigt sich beispielsweise, am USB-RS-422-Adapter 
von Delock, der Fehler das der Parameter parenb fehlte (geändert zu 
-parenb). Das verursachte verlorene Daten-Bytes und Geister-Bytes vom 
Typ 0xff, also Datenmüll.
Mit einem anderen, auch nur lesenden Programm (multithreaded_logger), 
zeigt sich das die Baudrate geändert ist von 19200 auf 9600, mit dem 
Resultat das nichts empfangen wurde.
Von einer anderen Konsole zeigte sich diese Verstellung mittels

stty -a -F $DEVICE

und lsof zeigte keinen anderen Prozess der auf die Schnittstelle 
zugriff.

Woher kommt dieses verdeckte Verstellen der Parameter?

In den Kernel-Nachrichten steht nichts dazu und auf dem Messrechner 
läuft Ubuntu Server ohne GUI.
Gast #4202792
Lesenswert?
• ▲
▼
Würde ich erst mal schauen, ob der jpnevulator die Parameter absichtlich 
verändert. Eingebauter Default, wenn du den Parameter weg lässt.

Wenn sich in Doku oder Quelltext nichts finden lässt, halt mit strace 
trace=ioctl
Gast #4203022
Lesenswert?
• ▲
▼
Lange Nachtschicht...

Alles mal durchprobieren, was strace beim logger ausgibt.
So was in der Art.
1
#include <fcntl.h>
2
main(int argc, char*argv[]) {
3
  system("stty -a -F /dev/ttyACM0");
4
  fopen("/dev/ttyACM0", "r");
5
  open("/dev/ttyACM0", O_RDONLY);
6
  system("stty -a -F /dev/ttyACM0");
7
}
Gast #4203023
Lesenswert?
• ▲
▼
Aus dem Source von jpnevaluator:
1
static int ttyOpen(char *name,int length) {
2
        int fd;
3
        struct termios options;
4
        fd=open(name,O_RDWR);
5
        if(fd!=-1) {
6
                /* Make sure we send to a raw serial interface! */
7
                fcntl(fd,F_SETFL,0);
8
                tcgetattr(fd,&options);
9
                cfmakeraw(&options);
10
                tcsetattr(fd,TCSANOW,&options);
11
        }
12
        return(fd);
13
}

Der relevante Aufruf ist cfmakeraw (ne alte BSD-Funktion).  Aus dessen 
man-Page:
1
       cfmakeraw()  sets  the terminal to something like the "raw" mode of the
2
       old Version 7 terminal driver: input is available character by  charac‐
3
       ter,  echoing is disabled, and all special processing of terminal input
4
       and output characters is disabled.  The terminal attributes are set  as
5
       follows:
6

7
           termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
8
                           | INLCR | IGNCR | ICRNL | IXON);
9
           termios_p->c_oflag &= ~OPOST;
10
           termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
11
           termios_p->c_cflag &= ~(CSIZE | PARENB);
12
           termios_p->c_cflag |= CS8;

Hier geht also deine Parity flöten.  Das einfachste dürfte das Ändern 
vom Source sein.  Alterntiv über LD_PRELOAD ein eigenes cfmakeraw 
reinpatchen.
Gast #4203025
Lesenswert?
• ▲
▼
Au Mist.
Ich hatte so ein Problem schon mal vor ein paar Jahren auf einem 
Suse-System beim sniffen auf der RS232.

Ich erinnere mich leider nicht mehr so recht, was die Ursache war.

Ich muss morgen mal schauen ob ich meine Notizen dazu noch finde. Sorry. 
Heute wird das vermutlich nichts mehr.
Gast #4203029
Lesenswert?
• ▲
▼
Wenn ich mich jetzt so daran erinnere, fällt mir nur ein, dass ich 
ziemlich lange (so 2 Stunden oder so) die man page mit den Parametern 
gelesen habe und einige (hoffentlich) intelligente Veränderungen 
vorgenommen habe.

Tut mir leid. Mehr fällt mir gerade nicht ein.
OP #4203202
Lesenswert?
• ▲
▼
asdfasd schrieb:
...
> Der relevante Aufruf ist cfmakeraw (ne alte BSD-Funktion).  Aus dessen
> man-Page:
...
> Hier geht also deine Parity flöten.  Das einfachste dürfte das Ändern
> vom Source sein.  Alterntiv über LD_PRELOAD ein eigenes cfmakeraw
> reinpatchen.

Aha, danke.
Der Autor von dem jpnevulator hat nie ein Problem gehabt, offenbar weil 
der immer ohne parenb gearbeitet hat.

Gegen den Workaround eine Sekunde nach dem Programmstart die Parameter 
erneut zu setzen spricht ja nichts, oder?
Gast #4203215
Lesenswert?
• ▲
▼
Erwin M. schrieb:

> Gegen den Workaround eine Sekunde nach dem Programmstart die Parameter
> erneut zu setzen spricht ja nichts, oder?

"Nichts" würde ich nicht sagen. Die Vorgehensweise ist "unsauber", was 
hier ganz klar als "ein Parameter wird gesetzt und dann verändert" 
beschrieben werden kann. Du brätst ja auch kein Schnitzel um unmittelbar 
danach daraus eine Schwarzwälder Kirschtorte zu machen. :-)

Für eine einmalige Sache, würde ich das so lassen. Auf Dauer aber einen 
Sniffer nehmen, der solche "Hacks" überflüssig macht.
Gast #4203543
Lesenswert?
• ▲
▼
> Gegen den Workaround eine Sekunde nach dem Programmstart die Parameter
> erneut zu setzen spricht ja nichts, oder?

Die sinnvolle Methode wäre, den Source so zu ändern, dass nur auf 
raw-Modus umgeschaltet wird und die Leitungsparameter (c_cflag) 
unangetastet bleiben, und dann das als Patch zum Author schicken ...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren