Forum: PC-Programmierung mehrere serielle Schnittstellen verwalten


von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hey Leute,
mein Vorhaben ist es mehrere (zwei) Geräte, die an einem Rechner (auf 
dem Linux läuft) via USB -> seriell angeschlossen sind, zu steuern.

Mein bisheriges Vorgehen:
Schaffen eines neuen Prozesses:
Child -> Schreiben auf den Seriellen Schnittstellen
Parent -> Lesen von den seriellen Schnittstellen

Im Parent:
Mit select an den zwei Schnittstellen hören.

Im Child: (bisher)
am Ende des eingegebenen Strings muss entweder eine '1' oder '2' stehen:
1 -> String wird auf Schnittstelle 1 geschrieben
2 -> String wird auf Schnittstelle 2 geschrieben


Zwei Sachen:
 - das schreiben funktioniert nicht, wenn mit select an den 
Schnittstellen gelauscht wird.
Generell hat es mit zwei Prozessen funktioniert, wenn nur eine 
Schnittstelle benutzt wurde.
Ich habe auch versucht mit select nicht nur zu überprüfen, ob die 
Schnittstellen bereit sind, dass man von ihnen lesen kann,
sondern auch zu überprüfen, ob sie bereit sind, dass man auf sie 
schreiben kann. -> keine Verbesserung.

 - Gibt es eine bessere Möglichkeit mein Vorhaben zu realisieren?
z.B.: Vier Prozesse -> zwei zum Schreiben auf und zwei zum Lesen von den 
zwei seriellen Schnittstellen

Gruß
Michael

von Michael (Gast)


Lesenswert?

Erster Fehler gefunden:

Vielleicht sollte man die seriellen Schnittstellen nicht mit O_RDONLY 
öffnen, wenn man auch auf sie auch schreiben möchte...


Funktioniert aber immer noch nicht wie es soll
-> beide Fragen sind noch aktuell

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Hat es einen tieferen Sinn, daß Du das Lesen und Beschreiben ein und der 
selben seriellen Schnittstelle in unterschiedlichen Prozessen 
stattfinden lässt?

Mir scheint dieses Softwaredesign kaputt zu sein.

von Tom M. (tomm) Benutzerseite


Lesenswert?

> write(0, buf, n); // 0 : handle für stdin/keyboard

Was versuchst du hier zu tun?

von Michael (Gast)


Lesenswert?

@ Tom:
sollte wohl eher
1
write(1, &buf, n);
 heißen? Hat aber trotzdem irgendwie funktioniert.

@ Rufus:
Die Prozesse waren zur Aufteilung von Lesen und Schreiben gedacht. 
(Nicht zur Aufteilung der seriellen Schnittstellen)

Rufus t. Firefly schrieb:
> Mir scheint dieses Softwaredesign kaputt zu sein.

Könntest du bitte ein besserers Vorschlagen? (wieviel Prozesse, was in 
diese Prozesse, wo select, ...)

Grüße

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Michael schrieb:
> Die Prozesse waren zur Aufteilung von Lesen und Schreiben gedacht.

Eben. Genau diese Trennung scheint mir ein kaputtes Design zu sein - 
stell' Dir einfach mal vor, ein serielles Protokoll zu implementieren, 
bei dem die Gegenstelle auf bestimmte Telegramme auf eine bestimmte Art 
und Weise antwortet. Da müsste der Lese-Prozess vom Schreib-Prozess 
mitgeteilt bekommen, was das letzte angeforderte Telegramm war ... und 
gegebenenfalls der Leseprozess dem Schreibprozess mitteilen, daß er ein 
fehlerhaftes Telegramm erneut anfordern soll.

Das ist nicht nur umständlich, sondern auch noch ineffizient und 
fehlerträchtig.

von Michael (Gast)


Lesenswert?

mhm jo verständlich. Ich hab mir dieses Design von miniterm 
abgeschaut...

Ein Versuch war dann noch mit Hilfe von select() auf die 
Schreibbereitschaft zu warten:
1
  while (loop)  {
2
    FD_SET(fd1, &readfs);  /* set testing for source 1 */
3
    FD_SET(fd2, &readfs);  /* set testing for source 2 */
4
    FD_SET(fd1, &writefs); 
5
    /* block until input becomes available */
6
    select(maxfd, &readfs, &writefs, NULL, NULL);
7
    if (FD_ISSET(fd1, &readfs))  {        /* input from source 1 available */
8
      int n = read(fd1, &buf, sizeof (buf));
9
      if (n < 0) {
10
        fprintf(stderr, "read fd1 failed: %s", strerror(errno));
11
        break;
12
      }
13
      write(1, &buf, n);
14
    }
15
    if (FD_ISSET(fd2, &readfs))  {       /* input from source 2 available */
16
      int n = read(fd2, &buf, sizeof (buf));
17
      if (n < 0) {
18
        fprintf(stderr, "read fd2 failed: %s", strerror(errno));
19
        break;
20
      }
21
      write(1, &buf, n);
22
    }
23
    if (FD_ISSET(fd1, &writefs))  {
24
      for (c = getchar() ; c!=2 ; c = getchar()) write(fd1,&c,1);      
25
    }
26
  }

Das funktioniert aber auch nicht so richtig.
Wenn ich etwas von einem Gerät empfange muss ich erst eine Taste 
drücken, damit die "write-Schleife" unterbrochen wird.
Wenn ich etwas senden will sehe ich nicht, was ich tippe und es kommt 
auch nichts am Gerät an.


Kannst du mir einen Designvorschlag machen?

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

So,

im Anhang ist mein derzeitiges Programm.
Ich habe jetzt bei select stdin->0 als weiteren "file descriptor" 
hinzugefügt, an dem gelauscht werden soll. Wenn ich dann etwas eintippe, 
wird es auch an das erste Gerät übertragen.

Funktioniert soweit auch ganz gut.
Problem ist, dass ich nur eines der beiden Geräte ansprechen kann. Wie 
könnte ich dieses Problem lösen?


Wie man sieht habe ich auch noch zwei logfiles kreiert, in denen ich das 
Empfangene der beiden Geräte speichern will.
Nun möchte ich aber den String, den ich empfange, noch vorher 
bearbeiten. Wie mache ich das am besten? (welche Funktionen?) (immer 
noch unter Linux!)
Kann ich da fseek,...
bzw.  strcat,...
benutzen? (wegen POSIX , ANSI C)

Ich hatte auch mal mit
1
 lseek(fd, 10, SET_CUR);
 probiert das Empfangene der beiden Geräte in zwei Spalten einer Datei 
zu schreiben. Das hat aber nicht funktioniert. Ich konnte danach die 
Log-Datei nicht öffnen... Woran liegt das? Springe ich mit dem Befehl an 
irgendeine Stelle im Speicher nach dem File, so dass es unlesbar wird? 
Wie kann ich das verhindern?


Viele Fragen ...
Ich hoffe auf Antworten : - )

So long
Michael

von Tom M. (tomm) Benutzerseite


Lesenswert?

Michael schrieb:
> Wie man sieht habe ich auch noch zwei logfiles kreiert, in denen ich das
> Empfangene der beiden Geräte speichern will.
> Nun möchte ich aber den String, den ich empfange, noch vorher
> bearbeiten. Wie mache ich das am besten? (welche Funktionen?) (immer
> noch unter Linux!)
> Kann ich da fseek,...
> bzw.  strcat,...
> benutzen? (wegen POSIX , ANSI C)

Kommt drauf an, wie wild du bearbeiten willst. Im einfachsten Fall 
reicht dir fprintf(), allenfalls strtok(), als Wollmilchsau bietet sich 
dann die regex library an: regcomp() etc. Auf meiner Kiste (BSD) ist 
diese Bestandteil der libc, ist POSIX konform, hat aber Erweiterungen 
gegenüber POSIX. Steht alles im manual.

> Ich hatte auch mal mit lseek(fd, 10, SET_CUR);  probiert das Empfangene der 
beiden Geräte in zwei Spalten einer Datei
> zu schreiben. Das hat aber nicht funktioniert.

lseek() liefert einen off_t Datentyp, zusätzlich wird errno gesetzt. 
Hast du diese ausgewertet?

> Ich konnte danach die
> Log-Datei nicht öffnen... Woran liegt das

Kann nicht sein. ;) Wie wolltest du sie öffnen? Fehlermeldung/-nummer?

von Michael (Gast)


Lesenswert?

Hey,
also zum zweiten "Problem":
ich habe mir jetzt den Rückgabewert angeschaut, und der passt. Es werden 
immer sinnvolle Werte größer 0 ausgegeben.

Zuerst habe ich versucht die Datei mit Gedit zu öffnen. Das hat nicht 
funktioniert. Fehlermeldung:
"Die Zeichenkodierung konnte nicht festgestellt werden."
Dann habe ich es mit emacs probiert, und siehe da, es geht.
Das komisch ist jetzt, dass in jedem übersprungenem Byte/Zeichen ein ^@ 
steht. Ist das normal? Wie bekomme ich es hin, dass dort nichts steht?
Wie bekomme ich es hin, dass ich die Datei auch mit Gedit öffnen kann?



Zum ersten Thema:
Es soll ein String, dessen Anfang und Ende jeweils mit einem 
unterschiedlichen Zeichen gekennzeichnet und dessen Inhaltsstücke durch 
Kommas getrennt ist, aufgespalten werden.
Ich möchte nämlich mit den Inhaltsstücken weiter arbeiten.
Da scheint mir strtok() recht gut zu passen. Werde mir aber auch REGEX 
anschauen. Wird auch als "wildcards on steroids" beschrieben :)
Oder gibts gleich eine bessere Möglichkeit?


Gibts noch Ideen, wie ich das "Terminalprogramm" geschickt aufbauen 
könnte?


vG
Michael

von Michael (Gast)


Lesenswert?

und weiter gehts:

Ich lese die seriellen Schnittstellen ja mit Hilfe des select-Befehls 
aus.
Jetzt kann es ja vorkommen, dass bei einem einzelnen read Vorgang nur 
bis zwischen zwei Kommas, also innerhalb eines Inhaltsstücks eingelesen 
wird. Wenn ich dann strtok ausführe gibt er mir an dieser Stelle anstatt 
eines kompletten Inhaltsstücks zwei Inhaltsteile aus.
Bsp:

buf[] = ",Inhalt,Inhalt,Inhalt,"
hier kann ich strtok gut anwenden:
Inhalt
Inhalt
Inhalt


buf[] = ",Inhalt,Inha"
buf[] = "lt,Inhalt,"
hier funktioniert strtok nicht so gut:
Inhalt
Inha
lt
Inhalt

Wie könnte ich das verhindern? (ohne das restliche Programm zu stark zu 
blockieren)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.