【IT168技术】现在GPS应用必须足以在商业环境如汽车导航中使用,此外,该如何解释GPS数据的实际工作过程,在这三个部分组成的系列,我将介绍两个主题,在大多数行业工程有GPS设备的今天,增加你编写一个商业级GPS应用的技巧。
一个强大的语句
这系列中的第一部分的任务将探讨解析原始GPS数据。幸运的是,任务是简化国家海洋电子协会由于它采用了一种行业标准,现在使用绝大多数的GPS设备。为了给开发人员提供一个良好的开端,我选择使用一些Visual Studio。NET源代码来自我的“GPS.NET全球定位SDK的”组件。 (代码被剥离,如多线程和错误处理功能。)
NMEA数据发送以逗号分隔的“句子”,其中载有关于这句话的第一个字的信息。有超过50多种的句子,但翻译完成这项工作真只需要处理其中的一些。所有最常见的NMEA语句是一句是“Recommended Minimum”这一句,以“$GPRMC开头”。下面是一个例子:
代码:
这一个句子包含几乎所有的GPS应用程序需要:纬度,经度,速度,轴承,卫星获取的时间,固定的地位和磁性的变化。
解析器的核心
做NMEA翻译的第一步是写一个方法来做这两件事情:将每一句分离成单个字、审议第一个字,找出哪些信息是可以进一步提取。列表1-1显示了翻译类的开始。
代码片段:
2
3 '** Listing 1-1. The core of an NMEA interpreter
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Processes information from the GPS receiver
9 Public Function Parse(ByVal sentence As String) As Boolean
10 ' Divide the sentence into words
11 Dim Words() As String = GetWords(sentence)
12 ' Look at the first word to decide where to go next
13 Select Case Words(0)
14 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
15 ' Indicate that the sentence was recognized
16 Return True
17 Case Else
18 ' Indicate that the sentence was not recognized
19 Return False
20 End Select
21 End Function
22 ' Divides a sentence into individual words
23 Public Function GetWords(ByVal sentence As String) As String()
24 Return sentence.Split(","c)
25 End Function
26 End Class
27
下一步是执行实际信息的提取,首先是经度和纬度。纬度和经度以“DDD°MM’SS.S”的形式存储,其中D代表小时(也称为“度”),M代表分钟,S代表秒。坐标可以在速记上显示,如“DD°MM.M’” 甚至是 “DD°”。这句话的第四个单词“3939.7”,显示了当前的纬度为小时和分钟(39 ° 39.7')。前两个字符(39)代表小时,这个词其余部分(39.7)代表分钟。经度和纬度有相同的结构方式,除了前三个字符代表小时(105 ° 06.6')。关键词5和7表明“半球”,其中“N”是指“北”,“W”是指“西”等。半球附加到数字的末尾部分,做一个完整的测量。我发现 NMEA解析器 正像是事件驱动一样更容易协作。这是因为数据的到达没有特定的顺序。事件驱动类给应用程序的解析器最大的灵活性和响应能力。因此,我将设计解析器用来报告信息使用事件。第一个事件,PositionReceived,将会被凸起 只要目前的经度和纬度被收到。列表1-2扩大解析器用以记录目前的情况。
代码片段:
2
3 '** Listing 1-2. Extracting information from a sentence
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 ' Processes information from the GPS receiver
12 Public Function Parse(ByVal sentence As String) As Boolean
13 ' Look at the first word to decide where to go next
14 Select Case GetWords(sentence)(0)
15 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
16 Return ParseGPRMC(sentence)
17 Case Else
18 ' Indicate that the sentence was not recognized
19 Return False
20 End Select
21 End Function
22 ' Divides a sentence into individual words
23 Public Function GetWords(ByVal sentence As String) As String()
24 Return sentence.Split(","c)
25 End Function
26 ' Interprets a $GPRMC message
27 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
28 ' Divide the sentence into words
29 Dim Words() As String = GetWords(sentence)
30 ' Do we have enough values to describe our location?
31 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
32 Words(6) <> "" Then
33 ' Yes. Extract latitude and longitude
34 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
35 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
36 Latitude = Latitude & Words(4) ' Append the hemisphere
37 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
38 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
39 Longitude = Longitude & Words(6) ' Append the hemisphere
40 ' Notify the calling application of the change
41 RaiseEvent PositionReceived(Latitude, Longitude)
42 End If
43 ' Indicate that the sentence was recognized
44 Return True
45 End Function
46 End Class
47
这里值得注意的一个地方就是在没有获取到信息时,某些GPS设备将记录空值。因此,一个好主意就是在解析之前来测试每个单词的值。如果您需要输入度数符号(°),按住Alt键并键入数字键盘上的“0176”。
取出垃圾
校验和以美元符号和星号(但不包括)之间的XOR字节来计算。这个校验和然后与语句中的校验和进行比较。如果校验和不匹配,这句话通常被丢弃。这是正常的,因为这样做GPS设备往往每隔几秒钟重复相同的信息。有比较校验和的能力,解析器能够抛出任何带有无效的校验和的语句。列表1-3扩大解析器:
代码片段:
2
3 '** Listing 1-3. Detecting and handling NMEA errors
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 ' Processes information from the GPS receiver
12 Public Function Parse(ByVal sentence As String) As Boolean
13 ' Discard the sentence if its checksum does not match our calculated
14 'checksum
15 If Not IsValid(sentence) Then Return False
16 ' Look at the first word to decide where to go next
17 Select Case GetWords(sentence)(0)
18 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
19 Return ParseGPRMC(sentence)
20 Case Else
21 ' Indicate that the sentence was not recognized
22 Return False
23 End Select
24 End Function
25 ' Divides a sentence into individual words
26 Public Function GetWords(ByVal sentence As String) As String()
27 Return sentence.Split(","c)
28 End Function
29 ' Interprets a $GPRMC message
30 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
31 ' Divide the sentence into words
32 Dim Words() As String = GetWords(sentence)
33 ' Do we have enough values to describe our location?
34 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
35 Words(6) <> "" Then
36 ' Yes. Extract latitude and longitude
37 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
38 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
39 Latitude = Latitude & Words(4) ' Append the hemisphere
40 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
41 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
42 Longitude = Longitude & Words(6) ' Append the hemisphere
43 ' Notify the calling application of the change
44 RaiseEvent PositionReceived(Latitude, Longitude)
45 End If
46 ' Indicate that the sentence was recognized
47 Return True
48 End Function
49 ' Returns True if a sentence's checksum matches the calculated checksum
50 Public Function IsValid(ByVal sentence As String) As Boolean
51 ' Compare the characters after the asterisk to the calculation
52 Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
53 End Function
54 ' Calculates the checksum for a sentence
55 Public Function GetChecksum(ByVal sentence As String) As String
56 ' Loop through all chars to get a checksum
57 Dim Character As Char
58 Dim Checksum As Integer
59 For Each Character In sentence
60 Select Case Character
61 Case "$"c
62 ' Ignore the dollar sign
63 Case "*"c
64 ' Stop processing before the asterisk
65 Exit For
66 Case Else
67 ' Is this the first value for the checksum?
68 If Checksum = 0 Then
69 ' Yes. Set the checksum to the value
70 Checksum = Convert.ToByte(Character)
71 Else
72 ' No. XOR the checksum with this character's value
73 Checksum = Checksum Xor Convert.ToByte(Character)
74 End If
75 End Select
76 Next
77 ' Return the checksum formatted as a two-character hexadecimal
78 Return Checksum.ToString("X2")
79 End Function
80 End Class
81
无线原子时
时间是GPS技术的基石,因为距离以光速来测量。每个GPS卫星载有4个原子钟,它用来测定几纳秒内的无线传输。一个有趣的特点是只需几行代码,这些原子钟可用于同步电脑毫秒级精确度的时钟。$GPRMC语句的第二字,“040302.663”,以压缩格式包含卫星导出的时间。前两个字符代表时,紧接着两个字符代表分钟,再接着两个代表秒,小数点后的一切代表毫秒。因此,时间是上午4:03:02.663。然而,卫星报告的时间为通用时间(GMT +0),所以时间必须适应当地的时区。列表1-4增加了对卫星导出时间的支持,并使用DateTime.ToLocalTime方法将卫星时间转换为本地时区。
代码片段:
2
3 '** Listing 1-4. Add support for satellite-derived time
4
5 '********************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 Public Event DateTimeChanged(ByVal dateTime As DateTime)
12 ' Processes information from the GPS receiver
13 Public Function Parse(ByVal sentence As String) As Boolean
14 ' Discard the sentence if its checksum does not match our
15 ' calculated checksum
16 If Not IsValid(sentence) Then Return False
17 ' Look at the first word to decide where to go next
18 Select Case GetWords(sentence)(0)
19 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
20 Return ParseGPRMC(sentence)
21 Case Else
22 ' Indicate that the sentence was not recognized
23 Return False
24 End Select
25 End Function
26 ' Divides a sentence into individual words
27 Public Function GetWords(ByVal sentence As String) As String()
28 Return sentence.Split(","c)
29 End Function
30 ' Interprets a $GPRMC message
31 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
32 ' Divide the sentence into words
33 Dim Words() As String = GetWords(sentence)
34 ' Do we have enough values to describe our location?
35 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
36 Words(6) <> "" Then
37 ' Yes. Extract latitude and longitude
38 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
39 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
40 Latitude = Latitude & Words(4) ' Append the hemisphere
41 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
42 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
43 Longitude = Longitude & Words(6) ' Append the hemisphere
44 ' Notify the calling application of the change
45 RaiseEvent PositionReceived(Latitude, Longitude)
46 End If
47 ' Do we have enough values to parse satellite-derived time?
48 If Words(1) <> "" Then
49 ' Yes. Extract hours, minutes, seconds and milliseconds
50 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
51 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
52 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
53 Dim UtcMilliseconds As Integer
54 ' Extract milliseconds if it is available
55 If Words(1).Length > 7 Then
56 UtcMilliseconds = CType(Single.Parse(Words(1).Substring(6), _
57 CultureInfo.InvariantCulture) * 1000, Integer)
58 End If
59 ' Now build a DateTime object with all values
60 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
61 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
62 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
63 ' Notify of the new time, adjusted to the local time zone
64 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
65 End If
66 ' Indicate that the sentence was recognized
67 Return True
68 End Function
69 ' Returns True if a sentence's checksum matches the calculated checksum
70 Public Function IsValid(ByVal sentence As String) As Boolean
71 ' Compare the characters after the asterisk to the calculation
72 Return sentence.Substring(sentence.IndexOf("*") + 1) = _
73 GetChecksum(sentence)
74 End Function
75 ' Calculates the checksum for a sentence
76 Public Function GetChecksum(ByVal sentence As String) As String
77 ' Loop through all chars to get a checksum
78 Dim Character As Char
79 Dim Checksum As Integer
80 For Each Character In sentence
81 Select Case Character
82 Case "$"c
83 ' Ignore the dollar sign
84 Case "*"c
85 ' Stop processing before the asterisk
86 Exit For
87 Case Else
88 ' Is this the first value for the checksum?
89 If Checksum = 0 Then
90 ' Yes. Set the checksum to the value
91 Checksum = Convert.ToByte(Character)
92 Else
93 ' No. XOR the checksum with this character's value
94 Checksum = Checksum Xor Convert.ToByte(Character)
95 End If
96 End Select
97 Next
98 ' Return the checksum formatted as a two-character hexadecimal
99 Return Checksum.ToString("X2")
100 End Function
101 End Class
102
方向和速度提醒
GPS设备分析您的位置,随着时间的推移来计算速度和影响。在本文开头$ GPRMC语句也包括这些数据。速度在每个节点都是始终要记录的,轴承以“方位”来记录,从0 °到360 °顺时针其中0 °表示北, 90 °表示东等。因此在地平线上测量。要应用数学公式转换成英里每小时。全球定位系统的力量再一次证明了一行代码。表单1-5的数字,显示汽车是否超过时速限制。
代码片段:
2
3 '** Listing 1-5. Extracting speed and bearing
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 Public Event DateTimeChanged(ByVal dateTime As DateTime)
12 Public Event BearingReceived(ByVal bearing As Double)
13 Public Event SpeedReceived(ByVal speed As Double)
14 Public Event SpeedLimitReached()
15 ' Processes information from the GPS receiver
16 Public Function Parse(ByVal sentence As String) As Boolean
17 ' Discard the sentence if its checksum does not match our calculated
18 ' checksum
19 If Not IsValid(sentence) Then Return False
20 ' Look at the first word to decide where to go next
21 Select Case GetWords(sentence)(0)
22 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
23 Return ParseGPRMC(sentence)
24 Case Else
25 ' Indicate that the sentence was not recognized
26 Return False
27 End Select
28 End Function
29 ' Divides a sentence into individual words
30 Public Function GetWords(ByVal sentence As String) As String()
31 Return sentence.Split(","c)
32 End Function
33 ' Interprets a $GPRMC message
34 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
35 ' Divide the sentence into words
36 Dim Words() As String = GetWords(sentence)
37 ' Do we have enough values to describe our location?
38 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
39 Words(6) <> "" Then
40 ' Yes. Extract latitude and longitude
41 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
42 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
43 Latitude = Latitude & Words(4) ' Append the hemisphere
44 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
45 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
46 Longitude = Longitude & Words(6) ' Append the hemisphere
47 ' Notify the calling application of the change
48 RaiseEvent PositionReceived(Latitude, Longitude)
49 End If
50 ' Do we have enough values to parse satellite-derived time?
51 If Words(1) <> "" Then
52 ' Yes. Extract hours, minutes, seconds and milliseconds
53 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
54 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
55 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
56 Dim UtcMilliseconds As Integer
57 ' Extract milliseconds if it is available
58 If Words(1).Length > 7 Then UtcMilliseconds = _
59 CType(Single.Parse(Words(1).Substring(6), _
60 CultureInfo.InvariantCulture) * 1000, Integer)
61 ' Now build a DateTime object with all values
62 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
63 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
64 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
65 ' Notify of the new time, adjusted to the local time zone
66 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
67 End If
68 ' Do we have enough information to extract the current speed?
69 If Words(7) <> "" Then
70 ' Yes. Convert it into MPH
71 Dim Speed As Double = CType(Words(7), Double) * 1.150779
72 ' If we're over 55MPH then trigger a speed alarm!
73 If Speed > 55 Then RaiseEvent SpeedLimitReached()
74 ' Notify of the new speed
75 RaiseEvent SpeedReceived(Speed)
76 End If
77 ' Do we have enough information to extract bearing?
78 If Words(8) <> "" Then
79 ' Indicate that the sentence was recognized
80 Dim Bearing As Double = CType(Words(8), Double)
81 RaiseEvent BearingReceived(Bearing)
82 End If
83 ' Indicate that the sentence was recognized
84 Return True
85 End Function
86 ' Returns True if a sentence's checksum matches the calculated checksum
87 Public Function IsValid(ByVal sentence As String) As Boolean
88 ' Compare the characters after the asterisk to the calculation
89 Return sentence.Substring(sentence.IndexOf("*") + 1) = _
90 GetChecksum(sentence)
91 End Function
92 ' Calculates the checksum for a sentence
93 Public Function GetChecksum(ByVal sentence As String) As String
94 ' Loop through all chars to get a checksum
95 Dim Character As Char
96 Dim Checksum As Integer
97 For Each Character In sentence
98 Select Case Character
99 Case "$"c
100 ' Ignore the dollar sign
101 Case "*"c
102 ' Stop processing before the asterisk
103 Exit For
104 Case Else
105 ' Is this the first value for the checksum?
106 If Checksum = 0 Then
107 ' Yes. Set the checksum to the value
108 Checksum = Convert.ToByte(Character)
109 Else
110 ' No. XOR the checksum with this character's value
111 Checksum = Checksum Xor Convert.ToByte(Character)
112 End If
113 End Select
114 Next
115 ' Return the checksum formatted as a two-character hexadecimal
116 Return Checksum.ToString("X2")
117 End Function
118 End Class
119
目前是否有 Fix
$ GPRMC语句包含一个值,显示“Fix”是否已经获得。当至少三颗卫星的信号强度足以与计算您的位置有关一个修复程序时,Fix将会获得。如果至少有四颗卫星都参与,高度也成为众所周知的。$ GPRMC语句的第三个字是两个字母中的一个:“A”为“积极”,其中获得一个Fix,或“V”为“无效”目前没有Fix存在。列表1-6包括代码审查这一字母和修复情况的报告。
代码片段:
2
3 '** Listing 1-6. Extracting satellite fix status
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8
9 ' Raised when the current location has changed
10 Public Event PositionReceived(ByVal latitude As String, _
11 ByVal longitude As String)
12 Public Event DateTimeChanged(ByVal dateTime As DateTime)
13 Public Event BearingReceived(ByVal bearing As Double)
14 Public Event SpeedReceived(ByVal speed As Double)
15 Public Event SpeedLimitReached()
16 Public Event FixObtained()
17 Public Event FixLost()
18 ' Processes information from the GPS receiver
19 Public Function Parse(ByVal sentence As String) As Boolean
20 ' Discard the sentence if its checksum does not match our calculated
21 ' checksum
22 If Not IsValid(sentence) Then Return False
23 ' Look at the first word to decide where to go next
24 Select Case GetWords(sentence)(0)
25 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
26 Return ParseGPRMC(sentence)
27 Case Else
28 ' Indicate that the sentence was not recognized
29 Return False
30 End Select
31 End Function
32 ' Divides a sentence into individual words
33 Public Function GetWords(ByVal sentence As String) As String()
34 Return sentence.Split(","c)
35 End Function
36 ' Interprets a $GPRMC message
37 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
38 ' Divide the sentence into words
39 Dim Words() As String = GetWords(sentence)
40 ' Do we have enough values to describe our location?
41 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
42 Words(6) <> "" Then
43 ' Yes. Extract latitude and longitude
44 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
45 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
46 Latitude = Latitude & Words(4) ' Append the hemisphere
47 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
48 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
49 Longitude = Longitude & Words(6) ' Append the hemisphere
50 ' Notify the calling application of the change
51 RaiseEvent PositionReceived(Latitude, Longitude)
52 End If
53 ' Do we have enough values to parse satellite-derived time?
54 If Words(1) <> "" Then
55 ' Yes. Extract hours, minutes, seconds and milliseconds
56 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
57 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
58 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
59 Dim UtcMilliseconds As Integer
60 ' Extract milliseconds if it is available
61 If Words(1).Length > 7 Then UtcMilliseconds = _
62 CType(Single.Parse(Words(1).Substring(6), _
63 CultureInfo.InvariantCulture) * 1000, Integer)
64 ' Now build a DateTime object with all values
65 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
66 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
67 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
68 ' Notify of the new time, adjusted to the local time zone
69 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
70 End If
71 ' Do we have enough information to extract the current speed?
72 If Words(7) <> "" Then
73 ' Yes. Convert it into MPH
74 Dim Speed As Double = CType(Words(7), Double) * 1.150779
75 ' If we're over 55MPH then trigger a speed alarm!
76 If Speed > 55 Then RaiseEvent SpeedLimitReached()
77 ' Notify of the new speed
78 RaiseEvent SpeedReceived(Speed)
79 End If
80 ' Do we have enough information to extract bearing?
81 If Words(8) <> "" Then
82 ' Indicate that the sentence was recognized
83 Dim Bearing As Double = CType(Words(8), Double)
84 RaiseEvent BearingReceived(Bearing)
85 End If
86 ' Does the device currently have a satellite fix?
87 If Words(2) <> "" Then
88 Select Case Words(2)
89 Case "A"
90 RaiseEvent FixObtained()
91 Case "V"
92 RaiseEvent FixLost()
93 End Select
94 End If
95 ' Indicate that the sentence was recognized
96 Return True
97 End Function
98 ' Returns True if a sentence's checksum matches the calculated checksum
99 Public Function IsValid(ByVal sentence As String) As Boolean
100 ' Compare the characters after the asterisk to the calculation
101 Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
102 End Function
103 ' Calculates the checksum for a sentence
104 Public Function GetChecksum(ByVal sentence As String) As String
105 ' Loop through all chars to get a checksum
106 Dim Character As Char
107 Dim Checksum As Integer
108 For Each Character In sentence
109 Select Case Character
110 Case "$"c
111 ' Ignore the dollar sign
112 Case "*"c
113 ' Stop processing before the asterisk
114 Exit For
115 Case Else
116 ' Is this the first value for the checksum?
117 If Checksum = 0 Then
118 ' Yes. Set the checksum to the value
119 Checksum = Convert.ToByte(Character)
120 Else
121 ' No. XOR the checksum with this character's value
122 Checksum = Checksum Xor Convert.ToByte(Character)
123 End If
124 End Select
125 Next
126 ' Return the checksum formatted as a two-character hexadecimal
127 Return Checksum.ToString("X2")
128 End Function
129 End Class
130