SparkFun Forums 

Where electronics enthusiasts find answers.

Tips and questions relating to the GPS modules from SFE
By seulater
#42489
I would like to perform the checksum calculations on my received GPS data. Before i go re invent the wheel has anyone else done this already in C and would not mind posting or private e-mailing the snippet for that ?
By frank26080115
#42497
have a static checksum variable inside your serial receive interrupt, every time the interrupt is called, check if the received data is "$" or "*", if it's "$", clear the checksum variable to 0, if it's "*", do not XOR the checksum, if the data is anything else, XOR it against the checksum variable.
By mg
#42534
Code: Select all
static unsigned char gps_fromhexchr (const char ch)
{
        return (ch >= '0' && ch <= '9') ? (unsigned char) (ch - '0') : (unsigned char) ((UTIL_TOUPPER (ch) - 'A') + (char) 10);
}

static boolean gps_nmea_decode_verify_checksum (/*@notnull@*/ const char * str_ptr)
{
        unsigned char csum = (unsigned char) 0;

        assert (str_ptr != NULL);

        while (*str_ptr != '\0' && *str_ptr != '$')
                str_ptr++;
        if (*str_ptr == '\0')
                return FALSE;
        str_ptr++;

        while (*str_ptr != '\0' && *str_ptr != '*')
                csum ^= (unsigned char) *str_ptr++;
        if (*str_ptr == '\0')
                return FALSE;
        str_ptr++;

/*@-evalorderuncon@*/
        return ((gps_fromhexchr (str_ptr [0]) << 4) | (gps_fromhexchr (str_ptr [1]))) == csum ? TRUE : FALSE;
/*@=evalorderuncon@*/
}
By seulater
#42535
thanks, i wound up using the following for mine.

char checkSum(char *to)
{
unsigned char check = 0;
int c;

// iterate over the string, XOR each byte with the total sum:
for (c = 1; c < strlen(to); c++)
{
if(to[c]=='*')
{
break;
}

check = (check ^ to[c]);
}
// return the result
return check;
}
By mg
#42536
two main problems with that code:
(a) strlen may be called on each iteration of the loop, you should break it out (e.g. int n = strlen (to); and then c < n);
(b) if you reach end of string but haven't seen a '*' you should return false - the current code may return positive if by chance (reasonably likely) the partially built checksum matches
By seulater
#42537
i have already done "a",
as far a "b" goes. that is taken care of in my serial receive routine.
thanks for pointing them out though.

i should have noted that that routine is for my use and not for some global usage for others. you see my IRQ routine takes care of the formatting of the string. when i get the "$" its clears the pointer counter to 0, if i dont receive the *, 0x0d, 0x0a before 120 chars gets received it chucks the whole sentence out.
By septer012
#42579
{ 2007 11 20 }
XOR calculation for NMEA checksums (GPS protocol)

If you’ve ever seen the serial output of a GPS reader, you’ve seen a mystery string at the end like this:

That’s the checksum of the whole string. NMEA data structure for Global Positioning (GPS) readers has a checksum on the end of each sentence. The checksum is the XOR of all the bytes between the $ and the * in the sentence. For example, if the sentence is this:

$GPRMC,155123.000,A,4043.8432,N,07359.7653,W,0.15,83.25,200407,,*28

then you run a checksum on this:

GPRMC,155123.000,A,4043.8432,N,07359.7653,W,0.15,83.25,200407,,

Here’s a Processing method to calculate the checksum, given the string between the $ and the *:

Technorati Tags: GPS, NMEA
Code: Select all
char checkSum(String theseChars) {
  char check = 0;
  // iterate over the string, XOR each byte with the total sum:
  for (int c = 0; c < theseChars.length(); c++) {
    check = char(check ^ theseChars.charAt(c));
  }
  // return the result
  return check;
}
And here’s a whole program to use the checksum with an Etek EB-85A reader:
Code: Select all
/*
  ETEK EB-85A GPS reader test.

 This program reads NMEA data in from a GPS reader at 4800 bps.
 The ETEK EB-85A reader has a proprietary command protocol that
 requires the calculation of the checksum of each command you send.
 The checksum is the XOR of all the bytes between the $
 and the * in the command string. The checkSum() routine
 does that calculation.

 created 20 Nov. 2007
 by Tom Igoe and Kristin O'Friel

 */

import processing.serial.*;

Serial myPort;

void setup(){
  // get the serial list:
  String[] thisPort = Serial.list();
  println(thisPort);
  // open the port:
  myPort = new Serial(this,thisPort[0] , 4800);
}

void draw() {

}

void keyReleased() {
  // command to turn on WAAS:
  String cmd = "PMTK501,2";
  // turn off all byt the RMC sentence:
  // String cmd = "PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0";
  // cold reset:
  //String cmd = "PMTK104";
  // test packet:
  //String cmd = "PMTK000";
  // calculate the checksum, convert it to a 2-byte hex string:
  String checkSum = hex(checkSum(cmd),2);
  // add the $, the *, the checksum, the CR and LF:
  cmd = "$" + cmd + "*" + checkSum + "\r\n";
  // print it for debugging:
  println("\r\n\r\n");
  println(cmd);
  println("\r\n\r\n");
  // send it out the serial port:
  myPort.write(cmd);
}
// print anything that comes in the serial port:
void serialEvent(Serial myPort) {
  char inByte = char(myPort.read());
  print (inByte);
}

// calculate the checksum:
char checkSum(String theseChars) {
  char check = 0;
  // iterate over the string, XOR each byte with the total sum:
  for (int c = 0; c < theseChars.length(); c++) {
    check = char(check ^ theseChars.charAt(c));
  }
  // return the result
  return check;
}
By septer012
#42581
Now who wants to do it like a man and help me do it in Assembly?!
sorry for the 3 post...