NMEA Checksum Code

Discussion about the ZBasic language including the System Library. If you're not sure where to post your message, do it here. However, do not make test posts here; that's the purpose of the Sandbox.
Post Reply
mdown
Posts: 62
Joined: 03 February 2006, 5:46 AM
Location: Dallas, Texas
Contact:

NMEA Checksum Code

Post 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
stevech
Posts: 715
Joined: 22 February 2006, 20:56 PM

Post 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
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post 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 
- Don Kinzer
FFMan
Posts: 502
Joined: 09 January 2010, 12:52 PM

Post 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
spamiam
Posts: 739
Joined: 13 November 2005, 6:39 AM

Post 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
dkinzer
Site Admin
Posts: 3120
Joined: 03 September 2005, 13:53 PM
Location: Portland, OR

Post 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
- Don Kinzer
FFMan
Posts: 502
Joined: 09 January 2010, 12:52 PM

Post 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
Post Reply