help with strtok()

I am working with a GPS and working to parse the NMEA data myself. I am aware of libraries such as TinyGPS but I prefer to learn and do it myself. I am 95% done in being able to grab all the information I need and what I have works great. I need pieces of data from 3 separate lines in order to store the data I want and here is an example of what I get.

$GPRMC,044159.000,A,3903.1262,N,07729.0495,W,0.00,40.30,061212,,,A*4D
$GPGGA,044200.000,3903.1262,N,07729.0497,W,1,08,1.0,83.7,M,-33.4,M,,0000*5F                     
$GPGSA,A,3,30,31,32,16,20,23,29,14,,,,,2.1,1.0,1.8*33

In the $GPRMC and $GPGGA data I can easily grab any piece of data that I want such as latitude and longitude using strtok() using the comma as a delimiter. This part is working perfectly.

Where I struggle is grabbing the data from the $GPGSA line since many of the comma delimited fields have no data and the data I want is at the end. In the example data I need to be able to grab the 2.1, 1.0 and 1.8 at the end. fixType (in the code below) works reliably since it is in a fixed position within the data, but PDOP is the 2.1 and it has a variable number of blank spaces before it. I cant seem to keep a fixed number here because the number of blank data can be different from one second to the next. For example $GPGSA could have 8 blank fields instead of 4 and could easily look like this instead $GPGSA,A,3,30,31,32,16,,,,,,,,,2.1,1.0,1.8*33. How should I handle data like this?

Here is a sample of how I break the data apart and store it as separate variables.

void GPGSA(){
  valPosition = strtok(GPGSAC, delimiters);
  i = 0;
  while(valPosition != NULL && i < 18){
    i++;
    valPosition = strtok(NULL, delimiters);
    if (i ==2){
      fixType = atoi(valPosition);
      Serial.print(F("fixType = "));
      Serial.println(fixType);
    }
    if (i ==15){
      PDOP = atof(valPosition);
      Serial.print(F("PDOP = "));
      Serial.println(PDOP);
    }
  }
}

Looks like strtok() is known to not work with empty fields.

Options:
strsep(); // Finding Tokens in a String (The GNU C Library)
strchr(); // find the next comma

Hello,

I suggest you make your own function, similar to strtok but that it skips blocks of ",,"..Something like that:

http://codepad.org/5rWaj2iA

I have been working your suggestions and I don't think strsep() will work. Reading the documentation suggests that if multiple delimiters are in a row it it will count 2 of them as one. Since the instance of multiple delimiters can change I don't think this will work. I need the data that is between the 15th and 16th delimiter. So I tried using strchr() to find where the 15th delimiters starts and use the 16th delimiter as a end marker. I used some code from an example I found and I it works to get the start/end points. Now I am not clear on how I grab the data from between those points?

void GPGSA(){
  pch=strchr(GPGSAC,',');
  i = 0;
  while (pch!=NULL)
  {
    i++;
    Serial.print("found at comma at ");
    Serial.println(pch-GPGSAC+1);
    pch=strchr(pch+1,',');
  }

Since atoi() and atof() will stop when they hit a comma or * I don't think you need to isolate the end of each value:

void GPGSA(){
  pch=strchr(GPGSAC,',');
  i = 0;
  while (pch!=NULL)
  {
    i++;
    if (i ==2){
      fixType = atoi(pch+1);
      Serial.print(F("fixType = "));
      Serial.println(fixType);
    }
    if (i==15) {
        PDOP = atof(pch+1);
        Serial.print(F("PDOP = "));
        Serial.println(PDOP);
    }
    pch=strchr(pch+1,',');
  }

I knew there had to be an easy way. It works perfectly now, thanks so much for the help!

Hello,
I have exactly the same problem with the GPGSA as described in post 1. Could you please explain me the solution in more details since i know very little about programing and it is very hard for me to understand it.
Thank You.

HellasT:
I have exactly the same problem with the GPGSA as described in post 1. Could you please explain me the solution in more details since i know very little about programing and it is very hard for me to understand it.

The original author said that they wanted to ignore the existing libraries and do the parsing themselves. Since you say that you are not a programmer, you should probably use one of the existing GPS libraries. Select "Tools -> Manage Libraries..." and type NeoGPS into the 'Filter your search' box. Then just click on the Install button. Select File -> Examples -> NeoGPS to see the list of examples that come with the library. Follow one of those examples.

Thank you sir for your fast response
Like in the first post , i am also writing my own code based on suggestions and guidance so in this case i would appreciate some explanation if possible. ThankYou!

Here is the function with comments. Is there any part you still don't understand?

void GPGSA()
{
  pch = strchr(GPGSAC, ',');  // Return a pointer to the next ',' in the GPGSAC buffer.
  i = 0;  
  while (pch != NULL)  // We found a comma
  {
    i++;


    if (i == 2)  // Comma 2 is just before the integer "fix type" field.
    {
      fixType = atoi(pch + 1);  // Starting after the comma, read an integer.
      Serial.print(F("fixType = "));
      Serial.println(fixType);
    }


    if (i == 15)  // Comma 15 is just before the float "PDOP" field.
    {
      PDOP = atof(pch + 1);  // Starting after the comma, read a float.
      Serial.print(F("PDOP = "));
      Serial.println(PDOP);
    }


    pch = strchr(pch + 1, ','); // Now go to the next comma
  }

is (pch) a pointer? char *pch=;

is (i) an integer? int i =0;

I am not sure i fully understand it. Specially how the while statement keeps "going on".
I will have to try the code and see...

I have tested the code and it seems to work okay. If it is okay with you, will let you know if i need help.

Thank you very much sir