scuberula
scuberula

Reputation: 35

GPS parser function doesn't work with new receiver

I'm using an old device (2006 - extremely trimmed embedded Linux) to get GPS latitude and longitude from an external receiver. GPS coordinates are displayed on device's LCD display. It used to work fine until the original GPS receiver failed. They replaced it with a new receiver but now it doesn't work anymore, all I see on LCD is: Latitude: - / Longitude: -.

I tried to see if the new GPS receiver is operational. And it seems the GPGGA packets are there. The old device expects GPGGA packets for parsing/processing.

char GPSLatBuf[12], GPSLonBuf[12];

int parseGPSData(char * gpsBuffer)
{
  char * p;
  char gpsQuality = '0';

  if((p = strstr(gpsBuffer, "$GPGGA")) == NULL)
     return -1;

  memset(GPSLatBuf, 0, sizeof(GPSLatBuf));
  memset(GPSLonBuf, 0, sizeof(GPSLonBuf));

  p += 7; // UTC time
  if(*p != ',') 
  {
     p += 10; // Latitude
     if(*p != ',') 
     {
        memcpy(&GPSLatBuf[1], p, 9);
        p += 10; // N/S Hemisphere
        if(*p != ',') 
        {
           GPSLatBuf[0] = (*p == 'N') ? '+' : '-';
           p += 2; // Longitude
           if(*p != ',') 
           {
              memcpy(&GPSLonBuf[1], p, 10);
              p += 11; // E/W Hemisphere
              if(*p != ',') 
              {
                 GPSLonBuf[0] = (*p == 'E') ? '+' : '-';
                 p += 2; // GPS quality
                 if(*p != ',')
                    gpsQuality = *p;
              }
           }
        }
     }
  }
  if(gpsQuality == '0')
     return -1;

  return 0;
}

Expected to see non-void fields like before: +4916.4600 / -12311.1200 (just an example as I see nothing on display right now).

Upvotes: 0

Views: 147

Answers (1)

סטנלי גרונן
סטנלי גרונן

Reputation: 2997

Hope this is not too late.
The idea is: the number of decimal digits of data inside GPGGA message* is somehow specific to GPS module.
Hence, your code has an issue here, as it uses fixed offsets to search for latitude, longitude, etc.
It is easy to fix that: instead of using fixed offsets, you should search for the delimiter ("," in this case) using strstr() function.
Here's the corrected code:

int parseGPSData(char * gpsBuffer)
{
  char * p;
  char gpsQuality = '0';

  if((p = strstr(gpsBuffer, "$GPGGA")) == NULL)
     return -1;

  memset(GPSLatBuf, 0, sizeof(GPSLatBuf));
  memset(GPSLonBuf, 0, sizeof(GPSLonBuf));

  if((p = strstr(p, ",")) != NULL)
  {
      p++; // there is UTC time
      if((p = strstr(p, ",")) != NULL)
      {
          p++; // Latitude
          memcpy(&GPSLatBuf[1], p, 9);
          if((p = strstr(p, ",")) != NULL)
          {
              p++; // N/S Hemisphere
              GPSLatBuf[0] = (*p == 'N') ? '+' : '-';
              if((p = strstr(p, ",")) != NULL)
              {
                  p++; // Longitude
                  memcpy(&GPSLonBuf[1], p, 10);
                  if((p = strstr(p, ",")) != NULL)
                  {
                      p++; // E/W Hemisphere
                      GPSLonBuf[0] = (*p == 'E') ? '+' : '-';
                      if((p = strstr(p, ",")) != NULL)
                          gpsQuality = p[1];
                  }
              }
          }
      }
  }

  if(gpsQuality == '0')
     return -1;

  return 0;
}  

I'm pretty sure this will solve your issue :)


*EDIT:
Here's how NMEA GGA message looks like - an example:

$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47

where:  
##     GGA          Global Positioning System Fix Data  
##     123519       Fix taken at 12:35:19 UTC  
##     4807.038,N   Latitude 48 deg 07.038' N  
##     01131.000,E  Longitude 11 deg 31.000' E  
##     ...  

More useful information you can find here: https://www.gpsinformation.org/dale/nmea.htm#GGA

Upvotes: 1

Related Questions