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
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
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.
> write(0, buf, n); // 0 : handle für stdin/keyboard
Was versuchst du hier zu tun?
@ 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
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.
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?
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
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?
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.