I am trying to find checksum for NMEA sentence which is already calculated by GPS.
char GPRMCBuf[POS_BUFFER] = {0xA0, 0xA2, 0x00, 0x48, 0xDD,
0x24, 0x47, 0x50, 0x52, 0x4D, 0x43, 0x2C, 0x31, 0x35,
0x30, 0x35, 0x32, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2C,
0x41, 0x2C, 0x34, 0x31, 0x32, 0x31, 0x2E, 0x37, 0x39,
0x37, 0x37, 0x2C, 0x4E, 0x2C, 0x30, 0x30, 0x32, 0x31,
0x30, 0x2E, 0x39, 0x36, 0x36, 0x37, 0x2C, 0x45, 0x2C,
0x31, 0x2E, 0x35, 0x30, 0x2C, 0x35, 0x38, 0x2E, 0x32,
0x39, 0x2C, 0x32, 0x33, 0x30, 0x37, 0x31, 0x35, 0x2C,
0x2C, 0x2C, 0x41, 0x2A, 0x35, 0x38, 0x0D, 0x0A, 0x0F,
0x05, 0xB0, 0xB3};
hear last 3rd and 4th char are checksum that is 0F05 but we want to correct algorithm. Our algorithm which we used is as follows
Index = first,
checkSum = 0,
while index < msgLen,
checkSum = checkSum + message[index],
checkSum = checkSum AND (2^15-1).
increment index.
code we have written is as follows:
#include<stdio.h>
main()
{
unsigned char i;
unsigned short chk;
char test[]={ 0x47, 0x50, 0x52, 0x4D, 0x43, 0x2C, 0x31,
0x35, 0x30, 0x35, 0x32, 0x30, 0x2E, 0x30, 0x30,
0x30, 0x2C, 0x41, 0x2C, 0x34, 0x31, 0x32, 0x31,
0x2E, 0x37, 0x39, 0x37, 0x37, 0x2C, 0x4E, 0x2C,
0x30, 0x30, 0x32, 0x31, 0x30, 0x2E, 0x39, 0x36,
0x36, 0x37, 0x2C, 0x45, 0x2C, 0x31, 0x2E, 0x35,
0x30, 0x2C, 0x35, 0x38, 0x2E, 0x32, 0x39, 0x2C,
0x32, 0x33, 0x30, 0x37, 0x31, 0x35, 0x2C, 0x2C,
0x2C, 0x41,0x2A, 0x35, 0x38, 0x0D, 0x0A};
chk = 0;
for(i = 0; i < 70; i++)
{
chk = chk + test[i];
chk = chk & 32767;
}
printf("A=%hu\n", chk);
return 0;
}
problem is that we are getting 3588 but it should be 3845(0F05).
Please help us to solve this algorithm.
You've made a good attempt, but you've got a few things wrong. I think the following link is a good starting point for NMEA: http://www.gpsinformation.org/dale/nmea.htm
You'll see in the introduction that each command is self-contained, starts with a $
symbol and ends with a carriage return/line feed combination. The checksum, when present, is at the end of the message and preceded by an asterisk *
. You'll also see that the checksum is an XOR of all bytes between the $
and the *
, and the checksum, in hexadecimal, follows the *
in ASCII format.
Your input data also has some noise at the beginning and end, which you need to discard. Let me annotate your input:
char GPRMCBuf[POS_BUFFER] = {
0xA0, 0xA2, 0x00, 0x48, 0xDD, // these bytes are not part of the message
0x24, // this is the '$' character, so this is the message start byte
// checksum calculation starts with the next byte (0x47)
0x47, 0x50, 0x52, 0x4D, 0x43, 0x2C, 0x31, 0x35, // GPRMC,15
0x30, 0x35, 0x32, 0x30, 0x2E, 0x30, 0x30, 0x30, 0x2C, // 0520.000,
0x41, 0x2C, 0x34, 0x31, 0x32, 0x31, 0x2E, 0x37, 0x39, // A,4121.79
0x37, 0x37, 0x2C, 0x4E, 0x2C, 0x30, 0x30, 0x32, 0x31, // 77,N,0021
0x30, 0x2E, 0x39, 0x36, 0x36, 0x37, 0x2C, 0x45, 0x2C, // 0.9667,E,
0x31, 0x2E, 0x35, 0x30, 0x2C, 0x35, 0x38, 0x2E, 0x32, // 1.50,58.2
0x39, 0x2C, 0x32, 0x33, 0x30, 0x37, 0x31, 0x35, 0x2C, // 9,230715,
0x2C, 0x2C, 0x41, // ,,A
// checksum calculation ends here
0x2A, // The '*' character, i.e. message/checksum delimiter
0x35, 0x38, // The checksum, '5' and '8', so the checksum is 0x58
0x0D, 0x0A, // The CR/LF line terminator
0x0F, 0x05, 0xB0, 0xB3 // these bytes are not part of the message
};
So, the checksum calculation is:
chk = 0;
chk = chk ^ 0x47; // chk = 0x47
chk = chk ^ 0x50; // chk = 0x17
chk = chk ^ 0x52; // chk = 0x45
...
chk = chk ^ 0x41; // chk = 0x58
Note that you'll end up with 0x58
, which is in the message as 0x35 0x38
. So once you've correctly framed the message and adjusted the for loop to iterate over the checksummed bytes, the loop body simply becomes:
chk ^= test[i];
After the loop you then need to either convert the two nibbles of chk
into ASCII and compare with the signalled checksum, or convert the signalled checksum to a binary value and compare with chk
.