GTK Problem??
-
Ja, da hätte ich auch vorher dran denken sollen, dass der Quellcode gebraucht wird
Bitte nicht an meinem Programmierstil aufhängen, ich bin nämlich noch blutiger Anfänger. Bitte das zu berücksichtigen.Hier der relevante Auszug aus der callback.c. Von hier aus wird per Button der neue Thread gestartet:
ifdef HAVE_CONFIG_H #include <config.h> #endif #include <gnome.h> // Globale Deklarationen zur Interaktion zw. callbacks.c und terminal.h GtkWidget *image1; GtkWidget *image2; GtkWidget *stat_kolben_ein; GtkWidget *stat_kolben_aus; GtkWidget *stat_druck_ein; GtkWidget *stat_druck_aus; GtkWidget *stat_pruef_ein; GtkWidget *stat_pruef_aus; GtkWidget *stat_menge_ein; GtkWidget *stat_menge_aus; GtkWidget *stat_pumpe_ein; GtkWidget *stat_pumpe_aus; GtkWidget *textfeld_kontrollwert; GtkWidget *textfeld_bestimmungswert; GtkWidget *textfeld_zeit; GtkWidget *textfeld_weg; GtkWidget *textfeld_kraft; GtkWidget *textfeld_status_pumpe; GtkWidget *label20; int shmem_id; char status; int fd,old_flags, i; ssize_t length; fd_set input_fdset; # include <termios.h> struct termios term_attr; char ready_to_send; #include <include/terminal.h> #include "rs232_send.c" // Global Vars ende # include <sys/shm.h> # include <sys/ipc.h> # include <sys/wait.h> #include "callbacks.h" #include "interface.h" #include "support.h" #include "fifo.h" #include "csv_lesen.h" #include <mysql/mysql.h> #include <stdio.h> #include <unistd.h> #include <sys/stat.h> #include <sched.h> #include <signal.h> #define STSZ (4096*1024) /*********************************************************** * GLOBALE VARIABLEN (werden von mysql_fktn() beschrieben) * ***********************************************************/ char rs232_toggle=0; char v1_toggle=0; char v2_toggle=0; char v3_toggle=0; char pumpe_toggle=0; char modus_toggle=0; char mengenregler_toggle=0; MYSQL_ROW inhalt; /* Typensicheres Byte-Array mit Feldinhalten */ char inhalt2[6][100]; //beinhaltet die aus der DB gelesenen Pruefparameter #include "src/mysql_func.h" /* . . [UNWICHTIGES AUSGELASSEN] . . */ void on_rs232_to_fifo_clicked (GtkButton *button, gpointer user_data) { int x; char *stack; stack=(char *)malloc(STSZ); image1 = lookup_widget(GTK_WIDGET (button), "image1"); image2 = lookup_widget(GTK_WIDGET (button), "image2"); stat_kolben_ein = lookup_widget(GTK_WIDGET (button), "stat_kolben_ein"); stat_kolben_aus = lookup_widget(GTK_WIDGET (button), "stat_kolben_aus"); stat_druck_ein = lookup_widget(GTK_WIDGET (button), "stat_druck_ein"); stat_druck_aus = lookup_widget(GTK_WIDGET (button), "stat_druck_aus"); stat_pruef_ein = lookup_widget(GTK_WIDGET (button), "stat_pruef_ein"); stat_pruef_aus = lookup_widget(GTK_WIDGET (button), "stat_pruef_aus"); stat_menge_ein = lookup_widget(GTK_WIDGET (button), "stat_menge_ein"); stat_menge_aus = lookup_widget(GTK_WIDGET (button), "stat_menge_aus"); stat_pumpe_ein = lookup_widget(GTK_WIDGET (button), "stat_pumpe_ein"); stat_pumpe_aus = lookup_widget(GTK_WIDGET (button), "stat_pumpe_aus"); textfeld_kontrollwert = lookup_widget(GTK_WIDGET (button), "textfeld_kontrollwert"); textfeld_bestimmungswert = lookup_widget(GTK_WIDGET (button), "textfeld_bestimmungswert"); textfeld_zeit = lookup_widget(GTK_WIDGET (button), "textfeld_zeit"); textfeld_weg = lookup_widget(GTK_WIDGET (button), "textfeld_weg"); textfeld_kraft = lookup_widget(GTK_WIDGET (button), "textfeld_kraft"); label20 = lookup_widget(GTK_WIDGET (button), "label20"); if(rs232_toggle==0) rs232_toggle=1; if (rs232_toggle==1) { clone(&terminal_test,stack+STSZ-1,CLONE_VM | SIGCHLD | CLONE_FILES | CLONE_FS,NULL); //x=terminal_test(); gtk_widget_hide(button); } }
Nun folgt die Datei terminal.h, welche die Abfrage der seriellen Schnittstelle übernimmt und die eintreffenden Daten Analysiert und in die entsprechenden Felder einträgt.
Entscheidend für das Problem sind die CASES, welche gtk_entry_set_text() aufrufen:/* terminal.c - Ein- und Ausgabe ueber die serielle Schnittstelle und abspeichern in eine Statische und eine FIFO Datei */ # include <stdio.h> # include <unistd.h> # include <fcntl.h> # include <termios.h> /*# include "include/dat_schreiben.h"*/ # include <unistd.h> # include <sys/stat.h> #include <sched.h> # define TERM_DEVICE "/dev/ttyUSB0" /* = COM1 */ # define TERM_SPEED B19200 /* Bit/Sek */ #include <gnome.h> #include <gtk/gtk.h> #include <glib.h> #include <pthread.h> char receive; void *terminal_test() { char buffer[16]; gchar wert[16]; int rc,x; /* //int old_flags, i; //fd, //ssize_t length; //char buffer[1600]; //struct termios term_attr; //fd_set input_fdset; */ FILE *out; /* FIFO Datei initialisieren, in welche Die Messdaten abgelegt werden */ FILE *stream; /* if (mkfifo("/home/psi/Projects/my_fifo", 0777) != 0) { perror("fifo: mkfifo() fehlgeschlagen"); return(1); } */ /* FIFO initialisieren (ende) */ /* lokale Datei öffnen um empfangene Daten darin abzulegen Datei darf hierbei nicht existieren! */ /*/out=open("/home/psi/Projects/test.cvs", O_RDWR|O_CREAT|S_IREAD|S_IWRITE|S_IRWXU);*/ /* alternatives öffnen der Datei (fehlerbehaftet) */ /*/out = fopen("/home/psi/Projects/test.c" , "w");*/ if ((fd = open(TERM_DEVICE, O_RDWR)) == -1) { perror("terminal: Can't open device " TERM_DEVICE); return(1); } /* RS232 konfigurieren */ if (tcgetattr(fd, &term_attr) != 0) { perror("terminal: tcgetattr() failed"); return(1); } term_attr.c_cflag = TERM_SPEED | CS8 | CLOCAL | CREAD; //CRTSCTS | term_attr.c_iflag = 0; term_attr.c_oflag = OPOST | ONLCR; term_attr.c_lflag = 0; if (tcsetattr(fd, TCSAFLUSH, &term_attr) != 0) perror("terminal: tcsetattr() failed"); /* Std.-Eingabe anpassen */ if (tcgetattr(STDIN_FILENO, &term_attr) != 0) { perror("terminal: tcgetattr() failed"); return(1); } /* alte Einst. sichern */ old_flags = term_attr.c_lflag; term_attr.c_lflag &= ~(ICANON | ECHO); if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_attr)!= 0) perror("terminal: tcsetattr() failed"); while (1) { FD_ZERO(&input_fdset); FD_SET(STDIN_FILENO, &input_fdset); FD_SET(fd, &input_fdset); if (select(fd+1, &input_fdset, NULL, NULL, NULL) == -1) perror("terminal: select() failed"); if (FD_ISSET(STDIN_FILENO, &input_fdset)) { if ((length = read(STDIN_FILENO, buffer, 15))== -1) perror("terminal: read() failed"); else { if (buffer[0] == '\33') /*/ Abbruch mit ESC (Tastatur)*/ break; else { write(fd, buffer, length); } } } if (FD_ISSET(fd, &input_fdset)) { if ((length = read(fd, buffer, 15)) == -1) perror("terminal: Lesen von RS232 fehlgeschlagen!"); else if (buffer[0] == 7) /* Abbruch mit BEL */ receive=0; else { if(buffer[0]==8) /*/wenn Steuerzeichen erfüllt, dann Daten empfangen*/ receive=1; if(buffer[0]==1) /*/wenn erfüllt, dann dürfen daten empfangen werden*/ { buffer[0]=7; write(fd, buffer, length); ready_to_send=1; gtk_widget_show(image2); gtk_widget_hide(image1); /*/write(STDOUT_FILENO, buffer, length);*/ buffer[0]=1; } if(buffer[0]==9) /*/wenn erfüllt, dürfen keine daten empfangen werden*/ { ready_to_send=0; /*/buffer[0]="";*/ gtk_widget_show(image1); gtk_widget_hide(image2); /*/write(STDOUT_FILENO, buffer, length);*/ } if (receive==1 ) /*&& buffer[0]!=8*/ { for(x=0;x<=15;x++) wert[x]=0; x=2; switch(buffer[1]) { case 'K': while(buffer[x]!=7) { wert[x-2]=buffer[x]; x++; } gtk_entry_set_text (GTK_ENTRY(textfeld_kontrollwert),wert); break; case 'B': while(buffer[x]!=7) { wert[x-2]=buffer[x]; x++; } wert[x-2]=0x00; gtk_label_set_text(GTK_LABEL(label20),wert); break; case 'T': while(buffer[x]!=7) { wert[x-2]=buffer[x]; x++; } wert[x-2]=0x00; gtk_entry_set_text (GTK_ENTRY(textfeld_zeit),wert); break; case 'S': while(buffer[x]!=7) { wert[x-2]=buffer[x]; x++; } gtk_entry_set_text (GTK_ENTRY(textfeld_weg),wert); break; case 'F': while(buffer[x]!=7) { wert[x-2]=buffer[x]; x++; } gtk_entry_set_text (GTK_ENTRY(textfeld_kraft),wert); break; case 'H': switch(buffer[2]) { case 'V': if(buffer[3]=='1') { if(buffer[4]=='1') { gtk_widget_show(stat_kolben_ein); gtk_widget_hide(stat_kolben_aus); } if(buffer[4]=='0') { gtk_widget_show(stat_kolben_aus); gtk_widget_hide(stat_kolben_ein); } } if(buffer[3]=='2') { if(buffer[4]=='1') { gtk_widget_show(stat_druck_ein); gtk_widget_hide(stat_druck_aus); } if(buffer[4]=='0') { gtk_widget_show(stat_druck_aus); gtk_widget_hide(stat_druck_ein); } } if(buffer[3]=='3') { if(buffer[4]=='1') { gtk_widget_show(stat_pruef_ein); gtk_widget_hide(stat_pruef_aus); } if(buffer[4]=='0') { gtk_widget_show(stat_pruef_aus); gtk_widget_hide(stat_pruef_ein); } } break; case 'P': if(buffer[4]=='1') { gtk_widget_show(stat_pumpe_ein); gtk_widget_hide(stat_pumpe_aus); } if(buffer[4]=='0') { gtk_widget_show(stat_pumpe_aus); gtk_widget_hide(stat_pumpe_ein); } break; case 'M': if(buffer[4]=='1') { gtk_widget_show(stat_menge_ein); gtk_widget_hide(stat_menge_aus); } if(buffer[4]=='0') { gtk_widget_show(stat_menge_aus); gtk_widget_hide(stat_menge_ein); } break; /*default: event_senden("no_inner_case");*/ } break; /*default: //event_senden("no outer case");*/ } /* Ausgabe der empfangenen Daten auf dem Terminal */ //write(STDOUT_FILENO, buffer, length); /* Ausgabe der empfangenen Daten in eine CSV Datei */ //write(out,buffer,length); /* Ausgabe der relevanten Messdaten in die FIFO Datei */ /*if (fork() == 0) { if ((stream = fopen("/home/psi/Projects/my_fifo", "w")) == NULL) perror("fifo: Kann FIFO zum schreiben nicht öffnen!"); else { fprintf(stream, buffer); fclose(stream); } }*/ //for(x=0;x<=30;x++) buffer[x]=0; } /* Daten in FIFO schreiben (ende) */ } } for(i=1;i<=15;i++) buffer[i]=0; } /* Std.-Eingabe wie vorher */ term_attr.c_lflag = old_flags; if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_attr)!= 0) perror("terminal: Datenempfang abgeschlossen!"); printf("Aborted.\n"); remove("my_fifo"); remove("test.cvs"); }
-
Ohne den Code gelesen zu haben, vermute ich, dass dein Problem auf den Threads basiert. Du musst in deiner Anwendung die GLib Threads aktivieren (g_thread_init). Dann ist die einfachste Möglichkeit, die du hast, die Funktion, die die Zahlen eintragen soll, im Hauptthread mit g_idle_add aufzurufen.
-
Ohne den Code gelesen zu haben, vermute ich, dass dein Problem auf den Threads basiert. Du musst in deiner Anwendung die GLib Threads aktivieren (g_thread_init). Dann ist die einfachste Möglichkeit, die du hast, die Funktion, die die Zahlen eintragen soll, im Hauptthread mit g_idle_add aufzurufen.
-
Ich sehe da nichts was direkt falsch ist und warum das jetzt einfrieren soll kann ich nicht sagen, momentan sehe ich einfach nichts was das eindeutig verursachen könnte (ausführen kann ich das programm auch nicht).
Ich sehe da nur ein paar Sachen die ich nicht so gemacht hätte:
1. Ich würde anstatt colne() würde ich hier gtk_timeout_add() verwenden.2. Anstatt dieser ganzen globalen Variablen würde ich sie zu einem Datentyp zusammenfassen (z.B struct appdata{ ...}) dann mit g_object_set_data an das Hauptfenster binden und wo es gebraucht wird mit g_object_get_data sich den pointer holen.
3. Das ganze RS232 Teil hast wohl aus dem Buch "C und Linux" übernomen ohne es sonderlich gut zu verstehen was da vorsich geht (oder war das doch Absicht ?), aber hier ist es doch unnötig standart ein/ausgabe auf serielle Schnittstele um zuleiten.
Du willst ja nur Daten empfangen, also man braucht die serielle Schnittstelle nur zu öffen, konfigurieren, Daten empfangen und schliessen.
Ich habe mir extra Funktionen für solchen Zweck geschrieben (send_byte,reciv_byte u.ä.), ich kann sie später posten.Alles im allen würde ich also einige Änderungen am desing des Programm vornehmen.
Wenn du Fragen hast , dann poste sie.
Sollte ich doch etwas in deinem Code entdecken das poste ich es.
-
Hallo!
Erstmal vielen Dank für die spontane Hilfe!
Ich habe jetzt als erstes mal damit bekonnen, clone zu ersetzen, da auch ich schon vermutet habe, dass es an den threads liegt.
Ich habe also
clone(&terminal_test,stack+STSZ-1,CLONE_VM | SIGCHLD | CLONE_FILES | CLONE_FS,NULL);
durch
gtk_timeout_add(50,(GtkFunction)terminal_test,0);
ersetzt.
Danach konnte ich das Prog zwar starten, jedoch reagiert die GUI jetzt gar nicht mehr.
Gleiches Ergebnis liefert g_idle_add();@marcin:
Ja, habe die RS232 Funktion aus dem Buch, da es für mich als Anfänger erstmal die einfachste Lösung darstellte und auch ihren Zweck erfüllt. Muß nebenbei mit anderen Funktionen auch noch auf die RS232 schreiben.
-
jedoch reagiert die GUI jetzt gar nicht mehr.
Das erhärtet den Verdacht das es an der konfiguration der seriellen Schitstelle liegt, oder die kommunikation mit dem externe Gerät klapt nicht so richtig.
Es bleibt höstwahrscheinlich an irgendeinem Aaufruf von read() oder select() hängen.erstmal die einfachste Lösung darstellte und auch ihren Zweck erfüllt.
Naja wie du siehst eben nicht.
Schau ob dien Programm immer noch hängt wenn du alle read()und select() aufrufe auskommentierts.
-
Ich habe da noch ein kleines logisches Problem.
Das Programm funtioniert ja soweit. Erst ab einem bestimmten Zeitpunkt, nachdem es beispielsweise 50 mal einen Wert von der RS232 bekommen hat, friert es ein. Allerdings läuft der thread mit der RS232 abfrage weiter.
Weiterhin kann ich meiner Meinung nach das Problem genau auf den Aufruf der Funktion gtk_entry_set_text() eingrenzen.
Wenn ich nämlich hergehe und in den entsprechenden CASES der terminal.h die Aufrufe von gtk_entry_set_text() auskommentiere (und nur diese), dann läuft das Programm stundenlang ohne einzufrieren. Dabei springt es ja auch in den jeweiligen CASE und bereitet das array WERT[] auf, nur wird es diesmal nicht ins entry geschrieben.
Also muß es doch zwangsläufig daran liegen, oder sehe ich das falsch?
-
Bist du dir sicher das das was du hier
gtk_entry_set_text (GTK_ENTRY(textfeld_kraft),wert);
ein C-String ist (endet mit null 0).
Ich sehe nämlich nirgendwo das in wert 0 geschrieben wird.
Das würde zwar nicht erklären warum das Programm hängt, aber das darf auch nicht sein.
-
Ja, da gebe ich dir Recht, habe ich in der geposteten Version nicht gemacht, habe es aber vorher mal manuell eingefügt mit wert[15]=0.
hat aber leider auch nichts geändert.
-
Wenn du willst kannst mir das ganze Programm per Email zu schicken (also am besten das ganze Verzeichnis vom Anjuta-Pojekt), ich kann nichts versprechen aber so was wie Daten über rs232 empfangen und anzeigen habe ich schon x-mal gemacht, ist eigentlich nicht schwierig. Nur aus Quellcode-Fetzen zu erraten was da nicht funktioniert ist mir schwierig.
Meine EMai: marc.in@kielnet.net
-
Email ist auf dem Weg...