GPS Auslesen - String als Blocks
-
Du hast mehrere Probleme, neben dem anfängerhaften Beispielprogramm auch noch:
- fread/read kennen keine C-Strings, d.h. du musst für die '\0'-Terminierung selbst sorgen
- für die Library musst du zusätzlich für die "\r\n" Terminierung sorgen
- fread/read sollte immer in einer Schleife verwendet werden, da gerade bei externen Schnittstellen nicht gesichert ist, dass ein Aufruf alle anstehenden Daten liest- '\0' Terminierung geht mit direkter Zuweisung von '\0' an die gewünschte Bytestelle
- ist die C-String Terminierung sichergestellt, kann z.B. strcat(str,"\r\n") erfolgenDer erste Punkt war mir nicht klar - Vielen Dank!
Die anderen beiden Punkte hatte ich auch bereits als Problem auf der Liste. Das Auslesen des Ports läuft inner While Schleife mit manueller AbbruchbedingungVielen Dank für die Antwort - ich probiere mich mal eben an der Terminierung
€Edit
Ich sollte zu allerst checken mit welcher Terminierung die Strings überhaupt bei mir ankommen bevor ich da einfach was dran hänge.
-
Marco1990 schrieb:
Ich bin mir nicht sicher, aber ich denke sie sollten immer auf \r\n enden. Was sie wohl bei mir nicht tun.
Das war jetzt nicht die Frage, was sie sollten.
Wenn die Zeilen genau 100 Zeichen lang sind , kannst du fread bzw read nehmen.
Wenn du aber bis zu einem '\n' lesen musst, ist fgets besser.
Das Posix*-Gegenstück dazu kenn ich nicht. Evtl. musst du Zeichenweise lesen.Hast du die Schnittstelle auch im Binary-modus (bzw. nicht Textmodus) geöffnet?
*open und read gehören zum Posix-Standard.
-
Ich verwende diesen Code Canonical Input Processing http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html
Ich vermute mal ich hab sie als Txt modul geöffnetCREAD : enable receiving characters
.
Das mit den genau 100 Zeichen lang prüfe ich mal eben ... Aber zwischen den einzelnen Strings die vom GPS kommen ist immer eine 1 Zeichen lange zeile.
€dit
Ja es scheinen immer 100 Zeichen zu sein. Habe mir die Size aus dem Beispielprogramm der Lib printen lassen und das Logfile mit GPS Daten von mir gefüllt. Die Size war immer 100 bis auf die letzte ... die war bei 14- wohl wegen keiner neuen Zeile oder so
Das printen von res zeigt mir, dass fread und read unterschiedliche Längen zurückgeben. res ist steht wirklich so lang wie der String Zeichen hat. Size ist halt wie beschrieben stets 100 lang.ich habe per
if (buf[res-2]=='\r' ) { printf("JASJDJASJD"); } if (buf[res-1]=='\n' ) { printf("asdasdasd"); }
getestet welche Terminierung wohl mein String hat und es ist nur \n
-
So nach einigen Stunden tüffteln wiederhole ich nochmal die neusten Infos:
- Ich weiss noch immer nicht ob ich den Port als Text oder Binär öffne
while (STOP==FALSE) { /* loop until we have a terminating condition */ /* read blocks program execution until a line terminating character is input, even if more than 255 chars are input. If the number of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars. res will be set to the actual number of characters actually read */ res = read(fd,buf,100); strcat(buf,"\r"); buf[res]=0; /* set end of string, so we can printf */ if(buf[res-2]=='\r') { printf("Ende richtig\n"); } if(buf[res-1]=='\n') { printf("Ende2 richtig\n"); } printf(buf+res);
Der Code sagt mir nur das Ende2 richtig gesetzt ist aber das
strcat(buf,"\r");
nicht klappt scheinbar.
- Res hat nicht die gleiche Größe wie als wenn ich die gleichen Daten als Log file speicher und diese über fread einlese und mit der Größe von Size vergleiche.Momentan weiß ich nicht an welcher Baustelle ich zuerst arbeiten sollte.
-
Wie unterscheiden sich denn die Größen von read und fread?
Sind die immer konstant, weit auseinander, wirr?Hast du mal die Zeilen mit
strlen
überprüft?
-
Erklär mal, was du mit den Zeilen bezweckst:
res = read(fd,buf,100); strcat(buf,"\r"); buf[res]=0; /* set end of string, so we can printf */ ... printf(buf+res);
Zeig doch mal die ganze Lesefunktion. Wo kommt z.B. das STOP her?
-
DirkB schrieb:
Wie unterscheiden sich denn die Größen von read und fread?
Sind die immer konstant, weit auseinander, wirr?Hast du mal die Zeilen mit
strlen
überprüft?Also:
GPS Daten aus Log file + fread:printf("\nSIZE: %d\n",size); printf("\nZ: %d \n",strlen(buff));
SIZE: 100
Z: 2068
wobei ich die 2068 nicht verstehe, da
char buff[2048];
SeriellenPort + read:
res = read(fd,buf,100); strcat(buf,"\r"); buf[res]=0; /* set end of string, so we can printf */ int z=strlen(buf); printf("Z:%d\n",z); printf("res:%d \n",res);
res:1
Z:75
res:75
Z:1
res:1
Z:69
res:69also das read scheint mir die genaue Zeichenlänge des Strings zugeben - hingegen macht fread blöcke von 100 zeichen
DirkB schrieb:
Erklär mal, was du mit den Zeilen bezweckst:
res = read(fd,buf,100); strcat(buf,"\r"); buf[res]=0; /* set end of string, so we can printf */ ... printf(buf+res);
Zeig doch mal die ganze Lesefunktion. Wo kommt z.B. das STOP her?
/* * Serialverbindung.c */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <pthread.h> #include <string.h> #include "Serialverbindung.h" #include "nmea/nmea.h" #ifdef NMEA_WIN #include <io.h> #endif /* baudrate settings are defined in <asm/termbits.h>, which is included by <termios.h> */ #define BAUDRATE B38400 /* change this definition for the correct port */ #define MODEMDEVICE "/dev/ttyO3" #define _POSIX_SOURCE 1 /* POSIX compliant source */ #define FALSE 0 #define TRUE 1 volatile int STOP=FALSE; pthread_t gpsthread,gpsauslesen; nmeaINFO info; nmeaPARSER parser; nmeaPOS dpos; void trace(const char *str, int str_size) { printf("Trace: "); write(1, str, str_size); printf("\n"); } void error(const char *str, int str_size) { printf("Error: "); write(1, str, str_size); printf("\n"); } void* GibDatenaus(void * args) { printf("Daten sollen ausgegeben werden\n"); while(STOP==FALSE) { sleep(5); printf("x: %d y:%d %d %d\n",dpos.lat, dpos.lon, info.sig, info.fix); } printf("STOPPE 5 sekunden taktung\n"); pthread_exit(gpsauslesen); } void* StartenGps(void * args) { int fd,c, res; struct termios oldtio,newtio; char buf[2048]; /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. O_RDWR */ fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); if (fd <0) {perror(MODEMDEVICE); exit(-1); } tcgetattr(fd,&oldtio); /* save current serial port settings */ bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */ /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity,1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters */ newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) */ newtio.c_iflag = IGNPAR | ICRNL; /* Raw output. */ newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program */ newtio.c_lflag = ICANON; /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here */ newtio.c_cc[VINTR] = 0; /* Ctrl-c */ newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */ newtio.c_cc[VERASE] = 0; /* del */ newtio.c_cc[VKILL] = 0; /* @ */ newtio.c_cc[VEOF] = 4; /* Ctrl-d */ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */ newtio.c_cc[VSWTC] = 0; /* '\0' */ newtio.c_cc[VSTART] = 0; /* Ctrl-q */ newtio.c_cc[VSTOP] = 0; /* Ctrl-s */ newtio.c_cc[VSUSP] = 0; /* Ctrl-z */ newtio.c_cc[VEOL] = 0; /* '\0' */ newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */ newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */ newtio.c_cc[VWERASE] = 0; /* Ctrl-w */ newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */ newtio.c_cc[VEOL2] = 0; /* '\0' */ /* now clean the modem line and activate the settings for the port */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); int it = 0; nmea_property()->trace_func = &trace; nmea_property()->error_func = &error; nmea_zero_INFO(&info); nmea_parser_init(&parser); /* terminal settings done, now handle input In this example, inputting a 'z' at the beginning of a line will exit the program. */ //pthread_create(&gpsauslesen,NULL,GibDatenaus,NULL); while (STOP==FALSE) { /* loop until we have a terminating condition */ /* read blocks program execution until a line terminating character is input, even if more than 255 chars are input. If the number of characters read is smaller than the number of chars available, subsequent reads will return the remaining chars. res will be set to the actual number of characters actually read */ res = read(fd,buf,100); strcat(buf,"\r"); buf[res]=0; /* set end of string, so we can printf */ int z=strlen(buf); printf("Z:%d\n",z); // printf("%s ", buf); printf("res:%d \n",res); nmea_parse(&parser, &buf[0], res, &info); nmea_info2pos(&info, &dpos); /* printf( "%03d, Lat: %f, Lon: %f, Sig: %d, Fix: %d\n", it++, dpos.lat, dpos.lon, info.sig, info.fix );*/ } /* restore the old port settings */ tcsetattr(fd,TCSANOW,&oldtio); nmea_parser_destroy(&parser); pthread_exit(gpsthread); } void stoppit() { STOP=TRUE; } int startegps() { int errorthread= pthread_create(&gpsthread,NULL,StartenGps,NULL); if (errorthread != 0) { printf("aFEHLER Threaderstellung \n"); return 0; } return 1; }
Was habe ich damit vor?
res = read(fd,buf,100); strcat(buf,"\r"); buf[res]=0; /* set end of string, so we can printf */ int z=strlen(buf); printf("Z:%d\n",z); // printf("%s ", buf); printf("res:%d \n",res);
ich will an das Ende des Strings ein \r\n erzeugen da die Lib nur damit arbeiten kann.
-
strcat, strlen
und auch %s vonprintf
arbeiten mit C-Strings.
C-Strings werden durch ein '\0' beendet.
strlen
zählt so lange, bis die '\0 gefunden wird.
strcat
sucht die '\0' und schreibt ab der Stelle die neuen Zeichen und packt eine '\0' dahinter.
printf
mit %s gibt solange Zeichen aus, bis die '\0' gefunden wird.
Und keine der Funktionen interessiert sich dafür, wie groß der Puffer ist in dem die Daten stehen, weil sie die Größe gar nicht feststellen können.fread
undread
lesen nur das, was auch in der Datei ist. Die packen keine '\0' ans Ende.Du solltest nochmal die Reihenfolge deiner Zeilen überdenken.
- Kann das strcat schon das Ende erkennen?
- Was bewirkt dasbuf[res]=0;
danach?Hast du dir mal angesehn, was das
ICRNL
-Flag bewirkt?
-
DirkB schrieb:
strcat, strlen
und auch %s vonprintf
arbeiten mit C-Strings.
C-Strings werden durch ein '\0' beendet.
strlen
zählt so lange, bis die '\0 gefunden wird.
strcat
sucht die '\0' und schreibt ab der Stelle die neuen Zeichen und packt eine '\0' dahinter.
printf
mit %s gibt solange Zeichen aus, bis die '\0' gefunden wird.
Und keine der Funktionen interessiert sich dafür, wie groß der Puffer ist in dem die Daten stehen, weil sie die Größe gar nicht feststellen können.fread
undread
lesen nur das, was auch in der Datei ist. Die packen keine '\0' ans Ende.Du solltest nochmal die Reihenfolge deiner Zeilen überdenken.
- Kann das strcat schon das Ende erkennen?
- Was bewirkt dasbuf[res]=0;
danach?Hast du dir mal angesehn, was das
ICRNL
-Flag bewirkt?Okay Okay
Ich glaub ich habe wohl einen ziemlichen Bock in meiner Source/* Raw output. */ newtio.c_oflag = 0;
http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_16.html#SEC277
Das müsste wohl eher OPOST heißen. so wie ich das jetzt alles verstanden habe muss ich aber dennoch einbuf[res]=0;
setzen. richtig?
-
Marco1990 schrieb:
so wie ich das jetzt alles verstanden habe muss ich aber dennoch ein
buf[res]=0;
setzen. richtig?Ja.
Aber nicht irgendwo, sondern an der richtigen Stelle.
Und read kann im Fehlerfall auch etwas anderes zurück geben.OPOST ist für die Ausgabe an das Device. Die Einstellung mag richtig sein, aber im Augenblick liest doch vpm Device.
Ich würde, wenn das nötig ist, das \r\n selber senden.
-
Bevor ich jetzt weiter rumspiele - glaube ich ich muss erstmal das auslesen des Ports als RS232 sauber aufbauen ... Dann sollte das \r\n vllt sogar automatisch richtig mitgeliefert werden....
->schreibe neue OpenPort Funktion
-
Diese CR LF Sache ist ziemlich verwirrend, da die verschiedenen Betriebssysteme darauf unterschiedlich reagieren.
http://de.wikipedia.org/wiki/Zeilenumbruch#Codierung_des_ZeilenumbruchsViel I/O-Funktionen können die Zeichen auch auf das jeweilige System umsetzen.
Im Programm hat man dann aber nur mit dem /n zu tun.Viele Geräte auch darauf einstellen was sie senden und als Endekennung akzeptieren.
Eine Software sollte mit allen Einstellungen klar kommen.