Page 1 of 1
NMEA Checksum Code
Posted: 09 October 2006, 11:13 AM
by mdown
The NMEA checksum is the 8-bit exclusive OR (no start or stop bits) of all characters in the sentence, including the "," delimiters, between -- but not including -- the "$" and "*" delimiters.
The hexadecimal value of the most significant and least significant 4 bits of the result are converted to two ASCII characters (0-9, A-F) for transmission. The most significant character is transmitted first.
Code: Select all
Function NMEA_Checksum(sentence as String) As String
Dim i as integer
dim sum as integer
sum=0
For i = 2 To Len(trim(sentence)) - 2
sum = sum Xor cint(Asc(Mid(sentence, i, 1)))
Next i
NMEA_Checksum = mid(cstrHex(sum),3,2)
End Function
This seems to be correct, am I missing anything?
-Mike
Posted: 09 October 2006, 11:33 AM
by stevech
You might want to use a byte for the checksum since the standard specifies this. I don't think it would change your results, just the efficiency
Posted: 09 October 2006, 13:09 PM
by dkinzer
The code below incorporates Steve's suggestion and additional changes.
Firstly, since
sentence is passed by reference in your code that precludes calling the function with a constant string parameter. That may or may not be an important limitation.
Secondly, the upper limit of the For loop was computed as the length of the trimmed input string but the bytes being added to the checksum were being retrieved from the untrimmed input string. This would only be important if the input string had leading space characters.
Thirdly, the optional second parameter to the Asc() function can be used to eliminate the need to generate intermediate 1-byte strings.
Another issue that is not addressed is the assumption that the input string has the correct format. If the caller checks the format before calling this function then that is not an issue.
Code: Select all
Function NMEA_Checksum(ByVal sentence as String) As String
Dim s as String
Dim i as Integer
Dim sum as Byte
s = Trim(sentence)
sum=0
For i = 2 To Len(s) - 2
sum = sum Xor Asc(s, i)
Next i
NMEA_Checksum = CStrHex(sum)
End Function
As a side note, one characteristic of the Xor function is that performing the operation a second time with the same value reverses the effect of the initial operation, i.e. A Xor B Xor A equals B. The operation is commutative so the order of operations is unimportant. The upshot of this is that you needn't skip the first and last characters if you initialize the checksum to the Xor of those two characters. The inner code block would then be:
Code: Select all
sum = Asc("$") Xor Asc("*") ' negate the effect of the first and last characters
For i = 1 To Len(s)
sum = sum Xor Asc(s, i)
Next i
Posted: 27 February 2010, 12:46 PM
by FFMan
I've used the code in this post to check my nmea checksum and the received checksum and the calculated one agree when the checksum does ot include letters. When it does, the received one is uppercase, the calculated on lower case - can anyone suggest a reason why ?
$GPGLL,5153.4516,N,00111.4612,W,204149.400,A,A*41
Calc=41
Mine=41
Valid
Count=51
$GPGLL,5153.4520,N,00111.4609,W,204149.600,A,A*4C
Calc=4c
Mine=4C
Bad Checksum
Posted: 27 February 2010, 13:47 PM
by spamiam
you are returning a STRING that has the characters "4" and "C". It is being compared to the characters "4" and "c". Since the "C" characters are not identical, the comparison is untrue.
You can convert the case of one all upper or the other to all lower, them make the comparison.
Alternatively, you can return the actual numerical value of the checksum as a byte, and compare that to the the value of the checksum in the sentence.
-Tony
Posted: 27 February 2010, 14:02 PM
by dkinzer
FFMan wrote:[T]he calculated on lower case - can anyone suggest a reason why ?
Both A-F and a-f are valid hexadecimal characters in most contexts; alphabetic case is usually a matter of preference. The function CStrHex() happens to produce lower case characters. If you need upper case, use this modified version of the checksum function:
Code: Select all
Function NMEA_Checksum(ByVal sentence as String, ByVal upper as Boolean = True) As String
Dim s as String
Dim i as Integer
Dim sum as Byte
s = Trim(sentence)
sum=0
For i = 2 To Len(s) - 2
sum = sum Xor Asc(s, i)
Next i
NMEA_Checksum = CStrHex(sum)
If (upper) Then
NMEA_Checksum = UCase(NMEA_Checksum)
End If
End Function
Posted: 27 February 2010, 14:52 PM
by FFMan
ok - i thought the print of the checksum was the actual checksum but you're saying its the value printed as hex and therefore 4c=4C naturally.
It all working now thanks