1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package triptracker.client.gps.core;
21
22 /***
23 * Parser for the GPS NMEA-0183 (National Marine Electronics Association) data
24 * protocol. NMEA-0183 data is sent at 4800 baud and the max. length of a
25 * sentence is 80 ASCII characters including the leading '$' and the trailing
26 * CR LF control characters.
27 */
28 public class NMEASentence {
29
30
31
32
33 public static final char DELIMITER = ',';
34 public static final char START = '$';
35 public static final char CHECKSUM = '*';
36 public static final int MAXLENGTH = 82;
37 public static final String CRLF = "\r\n";
38
39 private String checksum;
40 private String sentence;
41 private String[] fields;
42 private NMEATalkerID talkerID;
43 private NMEASentenceID sentenceID;
44 private NMEAManufacturerID manufacturerID;
45 private boolean ignoreChecksum = false;
46 private boolean proprietary = false;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 public NMEASentence() { }
66
67 public NMEASentence(String sentence) {
68 parseSentence(sentence);
69 }
70
71 /***
72 * Parses the NMEA-0183 sentence. Fields can then be read from
73 * {@link #getField(int)}.
74 *
75 * @param sentence NMEA-0183 formatted sentence
76 * @throws IllegalArgumentException on malformed sentence
77 * @see #getField(int)
78 */
79 public void parseSentence(String sentence) throws IllegalArgumentException {
80
81 this.sentence = sentence.split(CRLF)[0];
82
83
84 if (sentence.charAt(0) == START) {
85 this.sentence = this.sentence.substring(1);
86 } else {
87
88
89 }
90
91 fields = this.sentence.split(DELIMITER + "");
92
93
94 String csField = fields[fields.length - 1];
95 if (this.sentence.matches(".*//*[0-9a-fA-F]{2}$")) {
96 checksum = csField.substring(csField.length() - 2);
97 fields[fields.length - 1]
98 = csField.substring(0, csField.length() - 3);
99 } else {
100 checksum = null;
101 }
102
103 validateSentence();
104
105
106 if (fields[0].substring(0, 1).equals(NMEATalkerID.P.name())) {
107 proprietary = true;
108 talkerID = NMEATalkerID.P;
109 } else {
110 proprietary = false;
111 talkerID = NMEATalkerID.valueOf(fields[0].substring(0, 2));
112 }
113
114
115 if (proprietary) {
116 sentenceID = NMEASentenceID.valueOf(fields[0].substring(1,5));
117 } else {
118 sentenceID = NMEASentenceID.valueOf(fields[0].substring(2,5));
119 }
120
121 }
122
123 private void validateSentence() throws IllegalArgumentException {
124
125 if (sentence.length() > (MAXLENGTH - CRLF.length() - 1))
126
127
128
129
130 if (fields[0].length() != 5)
131
132
133
134
135 if (fields.length < 2)
136
137
138
139
140
141
142 if (!sentence.matches("^[//x20-//x7E]+$"))
143
144
145
146
147
148
149
150
151
152
153
154 if (checksum != null && !ignoreChecksum) {
155 int csCalc = 0x00;
156 int csReal;
157
158
159 csReal = Integer.valueOf(checksum, 16);
160
161
162
163
164
165
166 for (int i = 0; i < sentence.length() - 3; i++) {
167 csCalc ^= sentence.charAt(i);
168 }
169
170 if (csCalc != csReal) {
171
172
173 }
174 }
175
176
177 }
178
179 public String getField(int index) {
180 return fields[index];
181 }
182
183 public String getField(String fieldName) {
184 return null;
185 }
186
187 public int getFieldCount() {
188 return fields.length;
189 }
190
191 public NMEATalkerID getTalkerID() {
192 return talkerID;
193 }
194
195 public NMEASentenceID getSentenceID() {
196 return sentenceID;
197 }
198
199 public NMEAManufacturerID getManufacturerID() {
200 return manufacturerID;
201 }
202
203 public String getSentence() {
204 return sentence;
205 }
206
207 public boolean isChecksumPresent() {
208 return (checksum != null);
209 }
210
211 public boolean isIgnoreChecksum() {
212 return ignoreChecksum;
213 }
214
215 public void setIgnoreChecksum(boolean ignoreChecksum) {
216 this.ignoreChecksum = ignoreChecksum;
217 }
218
219 public boolean isProprietary() {
220 return proprietary;
221 }
222
223 }