A checksum is calculated as the XOR
of bytes between (but not including) the dollar sign and asterisk. This checksum is then compared with the checksum from the sentence. If the checksums do not match, the sentence is typically discarded. This is okay to do because the GPS devices tend to repeat the same information every few seconds. With the ability to compare checksums, the interpreter is able to throw out any sentence with an invalid checksum. Listing 1-3 expands the interpreter to do this.
Listing 1-3: The interpreter can now detect errors and parse only error-free NMEA data.
'** Listing 1-3. Detecting and handling NMEA errors
'*******************************************************
Public Class NmeaInterpreter
' Raised when the current location has changed
Public Event PositionReceived(ByVal latitude As String, _
ByVal longitude As String)
' Processes information from the GPS receiver
Public Function Parse(ByVal sentence As String) As Boolean
' Discard the sentence if its checksum does not match our calculated 'checksum
If Not IsValid(sentence) Then Return False
' Look at the first word to decide where to go next
Select Case GetWords(sentence)(0)
Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
Return ParseGPRMC(sentence)
Case Else
' Indicate that the sentence was not recognized
Return False
End Select
End Function
' Divides a sentence into individual words
Public Function GetWords(ByVal sentence As String) As String()
Return sentence.Split(","c)
End Function
' Interprets a $GPRMC message
Public Function ParseGPRMC(ByVal sentence As String) As Boolean
' Divide the sentence into words
Dim Words() As String = GetWords(sentence)
' Do we have enough values to describe our location?
If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
Words(6) <> "" Then
' Yes. Extract latitude and longitude
Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
Latitude = Latitude & Words(4) ' Append the hemisphere
Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
Longitude = Longitude & Words(6) ' Append the hemisphere
' Notify the calling application of the change
RaiseEvent PositionReceived(Latitude, Longitude)
End If
' Indicate that the sentence was recognized
Return True
End Function
' Returns True if a sentence's checksum matches the calculated checksum
Public Function IsValid(ByVal sentence As String) As Boolean
' Compare the characters after the asterisk to the calculation
Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
End Function
' Calculates the checksum for a sentence
Public Function GetChecksum(ByVal sentence As String) As String
' Loop through all chars to get a checksum
Dim Character As Char
Dim Checksum As Integer
For Each Character In sentence
Select Case Character
Case "$"c
' Ignore the dollar sign
Case "*"c
' Stop processing before the asterisk
Exit For
Case Else
' Is this the first value for the checksum?
If Checksum = 0 Then
' Yes. Set the checksum to the value
Checksum = Convert.ToByte(Character)
Else
' No. XOR the checksum with this character's value
Checksum = Checksum Xor Convert.ToByte(Character)
End If
End Select
Next
' Return the checksum formatted as a two-character hexadecimal
Return Checksum.ToString("X2")
End Function
End Class
Comments