|
如何开发一个GPS应用程序(2)
|
|
|
作者:Jon Person 发布时间:2006-9-22 16:08:23 | 【字体: 大 中 小】
|
Taking out the Garbage
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
Wireless Atomic Time
Time is the cornerstone of GPS technology because distances are measured at the speed of light. Each GPS satellite contains four atomic clocks which it uses to time its radio transmissions within a few nanoseconds. One fascinating feature is that with just a few lines of code, these atomic clocks can be used to synchronize a computer’s clock with millisecond accuracy. The second word of the $GPRMC sentence, “040302.663,” contains satellite-derived time in a compressed format. The first two characters represent hours, the next two represent minutes, the next two represent seconds, and everything after the decimal place is milliseconds. So, the time is 4:03:02.663 AM. However, satellites report time in universal time (GMT+0), so the time must to be adjusted to the local time zone. Listing 1-4 adds support for satellite-derived time and uses the DateTime.ToLocalTime method to convert satellite time to the local time zone.
Listing 1-4: This class can now use atomic clocks to synchronize your computer’s clock wirelessly.
'******************************************************** '** Listing 1-4. Add support for satellite-derived time '******************************************************** Public Class NmeaInterpreter ' Raised when the current location has changed Public Event PositionReceived(ByVal latitude As String, _ ByVal longitude As String) Public Event DateTimeChanged(ByVal dateTime As DateTime) ' 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 ' Do we have enough values to parse satellite-derived time? If Words(1) <> "" Then ' Yes. Extract hours, minutes, seconds and milliseconds Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer) Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer) Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer) Dim UtcMilliseconds As Integer ' Extract milliseconds if it is available If Words(1).Length > 7 Then UtcMilliseconds = CType(Words(1).Substring(7), Integer) End If ' Now build a DateTime object with all values Dim Today As DateTime = System.DateTime.Now.ToUniversalTime Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _ Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds) ' Notify of the new time, adjusted to the local time zone RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime) 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
Direction & Speed Alerts
GPS devices analyze your position over time to calculate speed and bearing. The $GPRMC sentence at the beginning of this article also includes these readings. Speed is always reported in knots and bearing is reported as an “azimuth,” a measurement around the horizon measured clockwise from 0° to 360° where 0° represents north, 90° means east, and etc. A little math is applied to convert knots into miles per hour. The power of GPS is again demonstrated with one line of code in listing 1-5 which figures out if a car is over the speed limit.
(Listing 1-5: This class can now tell you which direction you're going and help prevent a speeding ticket.)
'** Listing 1-5. Extracting speed and bearing '******************************************************* Public Class NmeaInterpreter ' Raised when the current location has changed Public Event PositionReceived(ByVal latitude As String, _ ByVal longitude As String) Public Event DateTimeChanged(ByVal dateTime As DateTime) Public Event BearingReceived(ByVal bearing As Double) Public Event SpeedReceived(ByVal speed As Double) Public Event SpeedLimitReached() ' 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 ' Do we have enough values to parse satellite-derived time? If Words(1) <> "" Then ' Yes. Extract hours, minutes, seconds and milliseconds Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer) Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer) Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer) Dim UtcMilliseconds As Integer ' Extract milliseconds if it is available If Words(1).Length > 7 Then UtcMilliseconds = _ CType(Words(1).Substring(7), Integer) ' Now build a DateTime object with all values Dim Today As DateTime = System.DateTime.Now.ToUniversalTime Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _ Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds) ' Notify of the new time, adjusted to the local time zone RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime) End If ' Do we have enough information to extract the current speed? If Words(7) <> "" Then ' Yes. Convert it into MPH Dim Speed As Double = CType(Words(7), Double) * 1.150779 ' If we're over 55MPH then trigger a speed alarm! If Speed > 55 Then RaiseEvent SpeedLimitReached() ' Notify of the new speed RaiseEvent SpeedReceived(Speed) End If ' Do we have enough information to extract bearing? If Words(8) <> "" Then ' Indicate that the sentence was recognized Dim Bearing As Double = CType(Words(8), Double) RaiseEvent BearingReceived(Bearing) 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
|
|
文章来源:developerfusion
|
|
|
·Jon Person教你如何用.NET/.NETCF写GPS应用程序 ·如何开发一个GPS应用程序(3) ·如何开发一个GPS应用程序(1) ·基于Windows Mobile 5.0的GPS应用程序开发 ·用C#读取GPS数据的基类
|