www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik strtok-Funktion mag keine leeren token


Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo
Fange gerade an mit C zu spielen und bin gleich mal über folgendes 
Problem gestolpert:
Wenn ich mit strtok(String, delimiter); folgenden String zerteilen 
möchte

"$PFLAU,0,1,1,1,0,,0,,*63";

stolpert die Funktion über den leeren Token vor "*63".
Die anderen Felder werden richtig getrennt.

Gibt es da eine bessere Möglichkeit, solche Strings zu teilen ?
Muss ich diese Fälle von Hand abfangen ?

Danke
Torsten

Autor: Peter II (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die frage ist strtok stolperst oder du - aber ohne code ist das schwer 
zu sagen.

Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wollte die Welt nicht mit Anfänger Code langweilen, aber hier ...

Das struct wird bis zum ersten "leeren" Token erwartungsgemäß mit den 
Daten gefüttert.
Die leeren werden dann übersprungen.

Autor: Torsten B. (torty)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
sorry falsche Version hochgeladen

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist normal. strsep ist dasselbe wie strtok ohne den Bug.

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist kein Bug, sondern Feature. Die Entwickler haben wahrscheinlich 
hauptsächlich an Whitespace als Delimiter gedacht. Und bei fast allem, 
was man parsen kann (z.B. C), ist ja "int  count" äquivalent zu "int 
count".

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es ist ein Bug. Auch bei Whitespace passiert dir dasselbe, daß man eine
Null bei zwei aufeinanderfolgenden Spaces zurückbekommt und infolge 
dessen
die Zeile nicht parsen kann einfach weil ein Feld leer ist.

HISTORY
     The strsep() function is intended as a replacement for the strtok() 
func-
     tion.  While the strtok() function should be preferred for 
portability
     reasons (it conforms to ANSI X3.159-1989 (``ANSI C89'')) it is 
unable to
     handle empty fields, i.e., detect fields delimited by two adjacent 
delim-
     iter characters, or to be used for more than a single string at a 
time.

Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Aha, danke
Wird die Funktion auf die gleich Art und Weise genutzt und kennt sie die 
aktuelle string.h auch ?
Hab gerade mal im Quelltext einfach die "strtok" durch "strsep" ersetzt 
und der Simulator im Studio 4.18 hat sich gleich mal aufgehängt.
Was muss man da beachten ?

Danke Torsten

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, leicht unterschiedlich.
Bei strsep musst du ein Pointer auf einen String übergeben, also mit
dem & operator. Hier die Definition:

char *   strsep (char **, const char *)
char *   strtok (char *, const char *)

Beispiel:

for(i=0,str=line;str&&s=strsep(&str," \t");i++)


Wenn str als Funktionsargument übergeben wird, und du es später nicht 
mehr
brauchst, dann kannst du es auch direkt benutzen und brauchst keine 
temporaren Stringpointer, da der ja von der Funktion verändert wird und 
zum
Schluss Null zugewiesen bekommt. Hier wird einfach auf die Gültigkeit 
von str
geprüft, da das ja von einer vorherigen Funktion auf null gesetzt werden 
kann, es ist immer gut sowas abzufangen, bei generischem code.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Chris schrieb:
> Es ist ein Bug.

Naja, als Bug würde ich das nicht bezeichnen, denn die Funktion verhält
sich genau wie im C99-Standard spezifiziert:
  A sequence of calls to the strtok function breaks the string pointed
  to by s1 into a sequence of tokens, each of which is delimited by a
  character from the string pointed to by s2. The first call in the
  sequence has a non-null first argument; subsequent calls in the
  sequence have a null first argument. The separator string pointed to
  by s2 may be different from call to call.

  The first call in the sequence searches the string pointed to by s1
  for the first character that is not contained in the current separator
  string pointed to by s2. If no such character is found, then there are
  no tokens in the string pointed to by s1 and the strtok function
  returns a null pointer. If such a character is found, it is the start
  of the first token.
  
  The strtok function then searches from there for a character that is
  contained in the current separator string. If no such character is
  found, the current token extends to the end of the string pointed to
  by s1, and subsequent searches for a token will return a null pointer.
  If such a character is found, it is overwritten by a null character,
  which terminates the current token. The strtok function saves a
  pointer to the following character, from which the next search for a
  token will start.

  Each subsequent call, with a null pointer as the value of the first
  argument, starts searching from the saved pointer and behaves as
  described above.

  The implementation shall behave as if no library function calls the
  strtok function.

Allein schon der Funktionsname (ausgeschrieben "string tokenize")
impliziert, dass keine Leerstrings als Resultat geliefert werden, da
Tokens im üblichen Computerjargon immer nichtleere Zeichenketten sind.

Oft ist dieses Verhalten von strtok tatsächlich erwünscht (s. Beitrag
vom mechatroniker). Wenn nicht, muss man eben strsep als Ersatz nehmen
(sofern verfügbar, denn strsep ist nicht im C99-Standard), oder selber
etwas zusammenbasteln.

Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Auskünfte, aber wenn ich ehrlich bin, habe ich noch nicht 
verstanden, wie ich die Funktionen nun in meinem Fall austauschen kann.
in halt nicht sehr erfahren ..
Hat noch einmal jemand die Muse, mir das anfängertauglich zu erklären ?

Danke
Torsten

Autor: Vlad Tepesch (vlad_tepesch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Yalu X. schrieb:
> A sequence of calls to the strtok function breaks the string pointed
>   to by s1 into a sequence of tokens, each of which is delimited by a
>   character from the string pointed to by s2. The first call in the
>   sequence has a non-null first argument; subsequent calls in the
>   sequence have a null first argument. The separator string pointed to
>   by s2 may be different from call to call.

wobei das schon ziemlich starker Tobak ist.
von Reentrance keine Spur

Autor: U.R. Schmitt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vlad Tepesch schrieb:
> wobei das schon ziemlich starker Tobak ist.
> von Reentrance keine Spur
na ja, als das designt wurde hat man in Unix eigentlich kein (oder 
zumindest kaum) Multithreading sondern nur Multitasking gemacht. Und das 
bedeutete, daß jeder Prozess seinen eigenen Adressraum hatte, also sein 
eigenes strtok.
Insofern gab es da kein Problem.

Autor: Torsten B. (torty)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Möchte die Expertendiskussion ja nicht weiter stören, aber ich habe es 
jetzt mal so geschrieben und ich dachte, dass es funktioniertals keine 
leeren Token in dem String waren.
Wenn ich jedoch eine Zahl aus dem String lösche und damit einen leeren 
Token erzeuge, werden von dem ersten Token schon die ersten 2 Zeichen 
nicht richtig übertragen und alle weiteren Zeichen sind entsprechend 
verschoben.
Kann jemand helfen ?

Danke
Torsten

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bin warscheinlich schon zu alt, aber bei der Ansi Normierung gab es 
intendet usage for strtok und die gingen nicht (c89), klar daß man die 
dann bei der nächsten Revision berichtigt hat. Das war alles noch vor 
Google und somit
heutzutage nicht mehr auffindbar, und meine Emails von damals habe ich 
auch
gelöscht.

Zum eigentlichen Thema:

org source:

       ptr = strtok(Sentence,delimiter);
    strcpy(S_DATA.Name,ptr);

    while(ptr != NULL)
      {
        ptr = strtok(NULL, delimiter);

new source:
es braucht zusätzlich eine neue variable "char*str" als Beispiel

    strcpy(S_DATA.Name,str=Sentence);

    while(ptr=strsep(&str,delimiter))
      {

Noch zwei Anmerkungen

Es kann sein, daß du ein buffer-overflow produzierst, da die 
Null-Terminierung des Strings überschrieben werden kann.
Das einfachste in deinem Code wäre sizeof(Sequence)-1 zu schreiben.
Normalerweise löst man das so, daß man die betreffende Variable als 
static
declariert und ein Define mit SENTENCE_LEN oder so macht, sowie bei der
declaration Sentence[SENTENCE_LEN+1] macht. Wenn man es nicht als static
declariert, dann inizialisiert man das Feld mit NULL, es gibt aber auch
noch andere Denkschulen, das soll hier nur als eine Möglichkeit gesehen
werden.

Wengen Multitrhreading, es gibt auch strtok_s sowie strtok_e .
Dasselbe gibt es für strsep. Die korrekte Implementierung von
strtok/strsep laut ansi-c (Annex K) hat sich leider nicht durchgesetzt.

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sorry, war unterbrochen worden, die
  strcpy(S_DATA.Name,str=Sentence);
stimmt nicht, so wie du es gemacht hast ist richtig.

Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Chris

Danke für Deine Antwort!

wie gesagt...

für einen String: $PFLAU,1,2,3,4,5,6,7,8,*63
klappt alles wunderbar
-->

S_DATA.Name == '$'  ,  'P'  ,  'F'  ,  'L'  ,  'A'  ,  'U'
S_DATA.RX == '1'
S_DATA.TX == '2'
....

wenn der String jedoch so aussieht: $PFLAU,,2,3,4,5,6,7,8,*63
kommt es zu

S_DATA.Name == 'F'  ,  'L'  ,  'A'  ,  'U'  ,  ''  ,  '2'
S_DATA.RX == '3'
S_DATA.TX == '4'
....

hast Du dafür eine Erklärung ?

Wie geht denn der Profi mit Leeren Feldern in RS232 Datensätzen um ?
Es kann doch nicht sein, dass ich der erste Mensch bin, der das machen 
muss.

Autor: klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Torsten B. schrieb:
> Gibt es da eine bessere Möglichkeit, solche Strings zu teilen ?
> Muss ich diese Fälle von Hand abfangen ?

Torsten B. schrieb:
> Wie geht denn der Profi mit Leeren Feldern in RS232 Datensätzen um ?
> Es kann doch nicht sein, dass ich der erste Mensch bin, der das machen
> muss

Solches Parsing (gerade wenn es komplexer wird) kann man mit 
Zustandsmaschinen machen. Da muss man natürlich mehr selbst 
implementieren, allerdings ist dieser Ansatz dem "händischen 
Stringzerpflücken" weit überlegen und übersichtlicher.

Man geht dabei grob gesagt so vor, dass man zyklisch je ein Zeichen aus 
dem Zeichenstrom entnimmt und der Zustandsmaschine zuführt. Abhängig vom 
Zeichen werden dann Aktionen und Zustandsübergänge ausgelöst.

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kurz wieder hier,
Nein, habe keine Erklärung, auch das Fehlen des `$` ist unerklärlich.

Ich nehme an, der Code ist der den du zuletzt gepostet hast.
Abgesehen davon, daß der Code unbrauchbar ist, aber das hat jetzt nichts
zur Sache.

Punkt eins, ändere folgendes, was ich schon sagte:

 while(ptr != NULL)
      {
        ptr = strsep(&running,delimiter);

=>

 while(ptr = strsep(&running,delimiter))
      {
      printf("%d:<%s>\t<%s>\n",i,ptr,running?:"(NULL)");

Dann kannst du nachvollziehen, was passiert.

PS, bei der AVR-Lib gibt es einen bug bezüglich strsep, es könnte auch 
sein, daß das damit was zu tun hat. Ansonsten würde man sowas anders 
machen, aber dazu eventuell später.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Chris schrieb:

> PS, bei der AVR-Lib gibt es einen bug bezüglich strsep

Falls du damit die avr-libc meinst: welchen bitte?  Wo ist der
Bugreport?

Autor: Chris (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Der ist alt, von 2004, [bugs #10078]
Habe deine Datei getestet, funktioniert einwandfrei (auf dem PC).
Als output habe ich folgendes:

$PFLAU,1,89,3,4,5,6,7,8,*63
1:<$PFLAU>      <1,89,3,4,5,6,7,8,*63>
2:<1>   <89,3,4,5,6,7,8,*63>
3:<89>  <3,4,5,6,7,8,*63>
4:<3>   <4,5,6,7,8,*63>
5:<4>   <5,6,7,8,*63>
6:<5>   <6,7,8,*63>
7:<6>   <7,8,*63>
8:<7>   <8,*63>
9:<8>   <*63>
10:<*63>        <(null)>
$PFLAU,,89,3,4,5,6,7,8,*63
1:<$PFLAU>      <,89,3,4,5,6,7,8,*63>
2:<>    <89,3,4,5,6,7,8,*63>
3:<89>  <3,4,5,6,7,8,*63>
4:<3>   <4,5,6,7,8,*63>
5:<4>   <5,6,7,8,*63>
6:<5>   <6,7,8,*63>
7:<6>   <7,8,*63>
8:<7>   <8,*63>
9:<8>   <*63>
10:<*63>        <(null)>

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und hier noch einer mit zwei fehlenden Feldern,
$PFLAU,,,3,4,5,6,7,8,*63
1:<$PFLAU>      <,,3,4,5,6,7,8,*63>
2:<>    <,3,4,5,6,7,8,*63>
3:<>    <3,4,5,6,7,8,*63>
4:<3>   <4,5,6,7,8,*63>
5:<4>   <5,6,7,8,*63>
6:<5>   <6,7,8,*63>
7:<6>   <7,8,*63>
8:<7>   <8,*63>
9:<8>   <*63>
10:<*63>        <(null)>

Wie man normalerweise solche Felder parst, gleich mit strtol , das hier 
ist einfach, aber es geht auch so.

Andere Anmerkungen.
Normalerweise würde ich den String direkt nehmen, ohne strdup.
Als Alternative einen buffer nehmen, indem du die Sequenz reinkopierst,
aber Sequence dürfte bereits ein buffer sein, nehme mal an strdup ist 
nur
jetzt vorhanden und wird später eliminiert.

Du solltest das Format auf gültigkeit prüfen, wie z.B
if (*running!='$') running=strchr(running,'$'); // ein simpler Vorschlag
for(i=0,ptr=running;ptr&&*ptr&&*++ptr!='*';ptr++) i^=*++ptr;
if(ptr&&*ptr=='*') i^=strtol(ptr+1,&ptr,16); else i|=0x100;
if(i) nema_error++; /*auch nur ein simpler Vorschlag*/ else /*parse 
nema*/

Was aber der Grund ist, daß der Code nicht funktioniert ist folgender:
Dein Struct. Ein Beispiel.
      char RX[1];
      char TX[1];
      char GPS[1];
Da passt nur der Nullterminator von strcpy rein, und natürlich erzeugst 
du
buffer overflow, strncpy wäre ein nicht ernst gemeinter Vorschlag.
Normalerweise würde man aber eher die Daten parsen mittels strtol oder 
equivalent bzw mit einer eigenen Funktion welche auch 'N', 'W' usw 
entsprechend einliest und in eine Zahl (Enum) umwandelt.

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier ist natürlich bullshit.
for(i=0,ptr=running;ptr&&*ptr&&*++ptr!='*';ptr++) i^=*++ptr
es sollte sowas sein:
for(i=0,ptr=running;ptr&&*ptr&&*++ptr!='*';i^=*ptr);

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Chris schrieb:
> Der ist alt, von 2004, [bugs #10078]

Ach, das ist ja hornalt.  Meinst du wirklich, dass noch jemand mit
einer avr-libc < 1.0 arbeitet? ;-)

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ach, das ist ja hornalt.  Meinst du wirklich, dass noch jemand mit
> einer avr-libc < 1.0 arbeitet? ;-)

Nein.

Das hatte ich erst nachher rausgefunden, daß der so alt war.
Laut meinem drüberschauen dürfte es den Fehler nicht haben,
deshalt hattei ich auch den Code ausprobiert
 und bei mir lief er einwandfrei, auch wenn nur am PC.

Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen
zunächst erst mal vielen Dank für Eure Hilfe und besonders an Chris für 
seine ausführlichen Beiträge:

Chris schrieb:
> while(ptr = strsep(&running,delimiter))
>       {
>       printf("%d:<%s>\t<%s>\n",i,ptr,running?:"(NULL)");
>
> Dann kannst du nachvollziehen, was passiert.

Wahrscheinlich liegt es an meiner Unerfahrenheit, aber wieso kann ich 
das jetzt besser nachvollziehen ?
Ich fange gerade an, mich mit C zu beschäftigen und habe vorher nur mit 
Assembler gebastelt. Was macht die printf-Zeile hier ?

Chris schrieb:
> Der ist alt, von 2004, [bugs #10078]
> Habe deine Datei getestet, funktioniert einwandfrei (auf dem PC).
> Als output habe ich folgendes:

Hast Du den Code auch im AVR Studio getestet ?
Ich habe die Version 4.18
Was mich hierbei am meisten verwundert, ist die Tatsache, dass ich bei 
einer ersten Compilierung (STRG+F7) 3 Warnings bekomme und bei einer 
zweiten Compilierung (1 Sekunde später, ohne Änderungen am Quellcode) 
keine Warnings mehr bekomme.
Ist das ein Bug im Studio, oder lieg das Problem hier auch zwischen 
meinen Ohren ?

Chris schrieb:
> Normalerweise würde ich den String direkt nehmen, ohne strdup.
> Als Alternative einen buffer nehmen, indem du die Sequenz reinkopierst,
> aber Sequence dürfte bereits ein buffer sein, nehme mal an strdup ist
> nur
> jetzt vorhanden und wird später eliminiert.

Das mit strdup habe ich aus einer reference zu strdup im Internet.
Habe versucht, es ohne zu machen, aber dann hat gar nichts mehr 
funktioniert.

Chris schrieb:
> Du solltest das Format auf gültigkeit prüfen, wie z.B
> if (*running!='$') running=strchr(running,'$'); // ein simpler Vorschlag
> for(i=0,ptr=running;ptr&&*ptr&&*++ptr!='*';ptr++) i^=*++ptr;
> if(ptr&&*ptr=='*') i^=strtol(ptr+1,&ptr,16); else i|=0x100;
> if(i) nema_error++; /*auch nur ein simpler Vorschlag*/ else /*parse
> nema*/

OK
Leider habe ich keine Ahnung, was das bedueten könnte. Ich werde mich 
wahrscheinlich erst mal ein paar Jahre mit einem C Buch im Wald 
verstecken müssen, bi ich das drauf habe ;-)

Bin im Augenblick auf Dienstreise und kann daher den Code auch nicht auf 
einem Prozessor ausprobieren.

Ich wollte dieses Projekt eigentlich für den Einstieg nehmen. Vielleicht 
habe ich mich übernommen.
Wenn jamand die Muse und die Zeit hat, mir die printf und die kryptische 
for-Schleife zu erklären, wäre das toll, aber ich erwarte es nicht 
wirklich. :-)

Danke für Eure Hilfe
Torsten

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das printf generiert (printed) dir den Output raus,
wenn du hapsim oder equivalent installiert hast, dann bekommst du den 
output wie oben gepostet. Und nein, ich benutze AVR Studio nicht, 
deshalb kann
ich dir nicht sagen ob es damit läuft, auf simavr geht es zumindest.
Printf gibt Daten auf die Serielle oder dem LCD Display aus.
In simavr wird es auf der Console ausgegeben.
> printf("%d:<%s>\t<%s>\n",i,ptr,running?:"(NULL)");
Das obige printf gibt den Inhalt der Variablen i,ptr,running aus und
gleichzeitig fängt es den Fall ab, wenn running Null ist, dann zeigt
es das an. Das ?: ist eine GCC erweiterung und kein portables C,
ansonsten müsste es running?running:"(NULL)" heissen, in diesem Falle.

Die For Schleife ist dasselbe wie deine do mit den Zeilen zuvor/danach.
Die wurde hauptsächlich gemacht, wegen des mehrmals erwähnten Falles,
dass beim Code von dir ein Nullpointer sein könnte. Z.B. bei diesem
$PGRMIE*56
oder auch nur einer simplen leeren Zeile oder abgebrochenen Message.
dann würde bei deinem Code zwar die while Schleife durchlaufen werden
aber ptr würde den Wert 0 haben.

> OK
> Leider habe ich keine Ahnung, was das bedueten könnte. Ich werde mich

>> if (*running!='$') running=strchr(running,'$'); // ein simpler Vorschlag
Die GPS daten beginnen alle mit dem Dollarzeichen, und wenn am Anfang
kein Dollarzeichen ist, dann überspringe alles bis zu einem 
Dollarzeichen.
Weiters haben GPS Daten eine sogenannte Checksum, um die Richtigkeit der
Daten zu überprüfen. Auch die sollte zuerst überprüft werden bevor mit
dem Datensatz gearbeitet wird.
Dieses for macht ein Xor über alle zeichen bis zum Checksum 
Trennzeichen,
wie es in dem NEMA Standard definiert ist.
>> for(i=0,ptr=running;ptr&&*ptr&&*++ptr!='*';i^=*ptr);
Als Resultat enthält i jezt das Resultat aller Zeichen zwischen '$' und 
'*' welche mittels Xor Operator miteinander aufsummiert wurden, wenn man
das so nennen kann.
>> if(ptr&&*ptr=='*') i^=strtol(ptr+1,&ptr,16); else i|=0x100;
Hier wird zuerst geprüft ob der Checksumoperator vorhanden ist, wenn 
nicht
wird zur Checksum der Wert 0x100 aufsummiert, sodaß das Resultat auch 
erhalten bleibt, für eine eventuelle Fehleranalyse.
Sollte jedoch eine Checksum vorhanden sein, dann wird sie eingelesen, 
mittels Xor mit i verknüpft und der ptr (string) wird zum Ende der 
Checksum aktualisiert. Wenn die Checksum richtig ist, enthält i Null,
ansonsten einen Wert ungleich Null, was dann in der nächsten Zeile auch
verwendet wird, um dann ev. die Nema-Zeile zu parsen.
>> if(i) nema_error++; /*auch nur ein simpler Vorschlag*/ else /*parse
>> nema*/
>
> wahrscheinlich erst mal ein paar Jahre mit einem C Buch im Wald
> verstecken müssen, bi ich das drauf habe ;-)

Autor: Torsten B. (torty)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Öhh, danke !!!!
Ich gehe dann mal meine Hausaufgaben machen und melde mich wieder, wenn 
ich weitergekommen bin, bzw. vor dem nächsten Berg stehe.
Hoffe, Du hast dann auch noch so viel Zeit für mich.

Danke und Gruß
Torsten

Autor: Chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ein Auszug aus meinem GPS parsing, ist aber sehr Zeitoptimiert und
speziell , keine generisches parsing.

#define nmea2i(x) (nmea_sep(msg,1),strtol(x,&x,10))
#define nmea_valid(msg,x) 
(nmea_sep(msg,x)?nmea_skip(strchr("AD",*msg)?1:0):1)

if ((*(uint16_t*)msg=='GP'&&(msg+=2)) {   // GPS message
  if(*(uint32_t*)msg=='RMC,'&&(msg+=3)) { // RMC Recommended Minimum 
sentence C
    nmea2i(msg);  // fix taken at utc
    if(!nmea_valid(msg,1)) return NEMA_INVALID;
    a=nmea2lat(msg);  // lat
    b=nmea2lat(msg);  // lon
    c=fixmul(nmea2f(msg),ktof(0,514444444)); // speed [m/s]
    d=nmea2f(msg);    // true heading
    nmea2i(msg);  // date
    e=nmea2lat(msg);  // magnetic variation
    if(!nmea_valid(msg,0)) return NEMA_INVALID;
    gps[old]->lat=a;
    gps[old]->lon=b;
    gps[old]->spd=c;
    gps[old]->thd=d;
    gps[old]->mag=e;
    return NEMA_UPDATE;
  } else
  if(*(uint32_t*)msg=='GGA,'&&(msg+=3)) { // GGA Global Position Fix 
Data
    nmea2i(msg);    // fix taken at utc
    a=nmea2lat(msg);  // lat
    b=nmea2lat(msg);  // lon
    c=nmea2i(msg);    // fix quality
    d=nmea2i(msg);    // number of satellites
    e=nmea2f(msg);    // horizontal dilution of pos
    f=nmea2f16(msg);  // altitude
    nmea_sep(msg,1),nmea_skip(0); // M
    g=nmea2f16(msg);  // geoid msl diff
    nmea2i(msg);    // dgps age in seconds
    nmea2i(msg);    // dgps id
    if(!nmea_valid(msg,0)) return NEMA_INVALID;
    if(!c) return NEMA_INVALID
    gps[old]->lat=a;
    gps[old]->lon=b;
    gps[old]->mod=c;
    gps[old]->sat=d;
    gps[old]->hdp=e;
    gps[old]->alt=f;
    gps[old]->msl=g;
    return NEMA_UPDATE;
  }
// ...
  else return NEMA_IGNORE;
}

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.