|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 |
|
17 |
|
18 // INCLUDE FILES |
|
19 #include <e32std.h> |
|
20 |
|
21 #include "BTGPSNmeaParser.h" |
|
22 #include "BTGPSMessageDef.h" |
|
23 #include "BTGPSPanic.h" |
|
24 |
|
25 // EXTERNAL DATA STRUCTURES |
|
26 |
|
27 // EXTERNAL FUNCTION PROTOTYPES |
|
28 |
|
29 // CONSTANTS |
|
30 //NMEA sentence field delimiter |
|
31 const TUint8 KNmeaFieldDelimiter = ','; |
|
32 |
|
33 //NMEA sentecne checksum delimiter |
|
34 const TUint8 KNmeaChecksumDelimiter = '*'; |
|
35 |
|
36 //Data start postion of NMEA sentence |
|
37 const TInt KNmeaDataStartPos = 1; |
|
38 |
|
39 //Minimum length of NMEA sentence(starter and check sum) |
|
40 const TInt KNmeaMininumLength = 4; |
|
41 |
|
42 //Checksum field length |
|
43 const TInt KNmeaChecksumFieldLength = 2; |
|
44 |
|
45 //Maximum length of address field length |
|
46 const TInt KNmeaMaxAddressFieldLength = 32; |
|
47 |
|
48 //Decimal seperator |
|
49 const TUint8 KDecimalSeperator = '.'; |
|
50 |
|
51 /** |
|
52 * Structure for address field Id map |
|
53 */ |
|
54 struct TAddressFieldMessageIdMap |
|
55 { |
|
56 TText8 iField[KNmeaMaxAddressFieldLength]; //Field text |
|
57 TInt iId; //Field id |
|
58 }; |
|
59 |
|
60 /** |
|
61 * NMEA and Sirf specific NMEA sentence sId field text and |
|
62 * id mapping defination |
|
63 */ |
|
64 const struct TAddressFieldMessageIdMap KNmeaAddressIdMap[]= |
|
65 { |
|
66 {"GPGSV", ENmeaGPGSV}, |
|
67 {"GPGLL", ENmeaGPGLL}, |
|
68 {"GPRMC", ENmeaGPRMC}, |
|
69 {"GPVTG", ENmeaGPVTG}, |
|
70 {"GPGGA", ENmeaGPGGA}, |
|
71 {"GPGSA", ENmeaGPGSA}, |
|
72 {"PSRF107", ENmeaPSRF107}, |
|
73 {"PSRF103", ENmeaPSRF103}, |
|
74 {"PSRF101", ENmeaPSRF101}, |
|
75 {"PSRF105", ENmeaPSRF105}, |
|
76 {"PSRF201", ENmeaPSRF201}, |
|
77 {"PNOK", ENmeaProprietaryNok} |
|
78 }; |
|
79 |
|
80 /** |
|
81 * PNOK message id field text and id mapping defination |
|
82 */ |
|
83 const struct TAddressFieldMessageIdMap KNmeaPNokAddressIdMap[]= |
|
84 { |
|
85 {"OK", ENmeaPNokOk}, |
|
86 {"RESET", ENmeaPNokReset}, |
|
87 {"MSGS", ENmeaPNokPeriodicMsgs}, |
|
88 {"LOWPWR", ENmeaPNokLowPwrMode}, |
|
89 {"NIGHTMODE", ENmeaPNokNightMode}, |
|
90 {"VER", ENmeaPNokVersionInfo}, |
|
91 {"STAT", ENmeaPNokPeriodicEvents}, |
|
92 {"TIME", ENmeaPNokReferenceTime} |
|
93 }; |
|
94 |
|
95 |
|
96 |
|
97 // MACROS |
|
98 |
|
99 // LOCAL CONSTANTS AND MACROS |
|
100 |
|
101 // MODULE DATA STRUCTURES |
|
102 |
|
103 // LOCAL FUNCTION PROTOTYPES |
|
104 |
|
105 // FORWARD DECLARATIONS |
|
106 |
|
107 // ============================= LOCAL FUNCTIONS =============================== |
|
108 |
|
109 // ============================ MEMBER FUNCTIONS =============================== |
|
110 |
|
111 |
|
112 // ----------------------------------------------------------------------------- |
|
113 // TBTGPSNmeaParser::TBTGPSNmeaParser |
|
114 // ----------------------------------------------------------------------------- |
|
115 TBTGPSNmeaParser::TBTGPSNmeaParser() : TDelimitedParserBase8() |
|
116 { |
|
117 SetDelimiter(KNmeaFieldDelimiter); |
|
118 } |
|
119 |
|
120 // ----------------------------------------------------------------------------- |
|
121 // TBTGPSNmeaParser::SetNmeaSentence |
|
122 // ----------------------------------------------------------------------------- |
|
123 void TBTGPSNmeaParser::SetNmeaSentence(const TDesC8& aNmea) |
|
124 { |
|
125 iNmea.Set(aNmea); |
|
126 iId = ENmeaNull; |
|
127 if(CheckValidity()) |
|
128 { |
|
129 Parse(TrimSentence()); |
|
130 GetMessageId(); |
|
131 } |
|
132 } |
|
133 |
|
134 // ----------------------------------------------------------------------------- |
|
135 // TBTGPSNmeaParser::NmeaSentence |
|
136 // ----------------------------------------------------------------------------- |
|
137 const TDesC8& TBTGPSNmeaParser::NmeaSentence() const |
|
138 { |
|
139 return iNmea; |
|
140 } |
|
141 |
|
142 // ----------------------------------------------------------------------------- |
|
143 // TBTGPSNmeaParser::IsValid |
|
144 // ----------------------------------------------------------------------------- |
|
145 TBool TBTGPSNmeaParser::IsValid() const |
|
146 { |
|
147 return iId!=ENmeaNull; |
|
148 } |
|
149 |
|
150 // ----------------------------------------------------------------------------- |
|
151 // TBTGPSNmeaParser::MessageId |
|
152 // ----------------------------------------------------------------------------- |
|
153 TInt TBTGPSNmeaParser::MessageId() const |
|
154 { |
|
155 return iId; |
|
156 } |
|
157 |
|
158 // ----------------------------------------------------------------------------- |
|
159 // TBTGPSNmeaParser::GetMessageId |
|
160 // ----------------------------------------------------------------------------- |
|
161 void TBTGPSNmeaParser::GetMessageId() |
|
162 { |
|
163 iId = ENmeaUnknown; |
|
164 Reset(); |
|
165 TPtrC8 address; |
|
166 if(GetFieldBlock(ENmeaFieldAddressField,address)==KErrNone) |
|
167 { |
|
168 for(TInt i=0; |
|
169 i<sizeof(KNmeaAddressIdMap)/sizeof(TAddressFieldMessageIdMap);i++) |
|
170 { |
|
171 TPtrC8 knownAddress(KNmeaAddressIdMap[i].iField); |
|
172 if(address.Compare(knownAddress)==KErrNone) |
|
173 { |
|
174 TInt messageId = KNmeaAddressIdMap[i].iId; |
|
175 //If message if Nokia proprietary message, we have to check next field |
|
176 if(messageId == ENmeaProprietaryNok) |
|
177 { |
|
178 Reset(); |
|
179 Inc();Inc(); |
|
180 if(GetNext(address)==KErrNone) |
|
181 { |
|
182 for(TInt j=0; |
|
183 j<sizeof(KNmeaPNokAddressIdMap)/sizeof(TAddressFieldMessageIdMap); |
|
184 j++) |
|
185 { |
|
186 TPtrC8 nokAddress(KNmeaPNokAddressIdMap[j].iField); |
|
187 if(address.Compare(nokAddress)==KErrNone) |
|
188 { |
|
189 iId = KNmeaPNokAddressIdMap[j].iId; |
|
190 return; |
|
191 } |
|
192 } |
|
193 } |
|
194 } |
|
195 iId = messageId; |
|
196 return; |
|
197 } |
|
198 } |
|
199 } |
|
200 } |
|
201 |
|
202 // ----------------------------------------------------------------------------- |
|
203 // TBTGPSNmeaParser::GetFieldBlock |
|
204 // ----------------------------------------------------------------------------- |
|
205 TInt TBTGPSNmeaParser::GetFieldBlock(TInt aFieldId, TPtrC8& aField) const |
|
206 { |
|
207 Reset(); |
|
208 if(aFieldId != ENmeaFieldAddressField) |
|
209 { |
|
210 TInt messageId = MessageId(); |
|
211 //Check fieldId matches message Id |
|
212 if(aFieldId<messageId || aFieldId>=messageId+KNmeaMessageIdSkip) |
|
213 { |
|
214 return KErrNotFound; |
|
215 } |
|
216 |
|
217 //Skip address field and other fields |
|
218 if(messageId != ENmeaNull) |
|
219 { |
|
220 for(TInt i=0; i<aFieldId-messageId+2; i++) |
|
221 { |
|
222 Inc(); |
|
223 } |
|
224 } |
|
225 } |
|
226 return GetNext(aField); |
|
227 } |
|
228 |
|
229 // ----------------------------------------------------------------------------- |
|
230 // TBTGPSNmeaParser::IsNullField |
|
231 // ----------------------------------------------------------------------------- |
|
232 TBool TBTGPSNmeaParser::IsNullField(TInt aFieldId) const |
|
233 { |
|
234 TPtrC8 fieldBlock; |
|
235 if(GetFieldBlock(aFieldId, fieldBlock)==KErrNone) |
|
236 { |
|
237 return fieldBlock.Length()==0; |
|
238 } |
|
239 //error case |
|
240 return ETrue; |
|
241 } |
|
242 |
|
243 |
|
244 // ----------------------------------------------------------------------------- |
|
245 // TBTGPSNmeaParser::GetFieldData |
|
246 // ----------------------------------------------------------------------------- |
|
247 template <> |
|
248 TInt TBTGPSNmeaParser::GetFieldData<TReal32>(TInt aFieldId, TReal32& aData) const |
|
249 { |
|
250 TPtrC8 fieldBlock; |
|
251 TInt err = GetFieldBlock(aFieldId, fieldBlock); |
|
252 if(err==KErrNone && fieldBlock.Length()>0) |
|
253 { |
|
254 TLex8 lex(fieldBlock); |
|
255 return lex.Val(aData, KDecimalSeperator); |
|
256 } |
|
257 return err; |
|
258 } |
|
259 |
|
260 // ----------------------------------------------------------------------------- |
|
261 // TBTGPSNmeaParser::GetFieldData |
|
262 // ----------------------------------------------------------------------------- |
|
263 template <> |
|
264 TInt TBTGPSNmeaParser::GetFieldData<TReal>(TInt aFieldId, TReal& aData) const |
|
265 { |
|
266 TPtrC8 fieldBlock; |
|
267 TInt err = GetFieldBlock(aFieldId, fieldBlock); |
|
268 if(err==KErrNone && fieldBlock.Length()>0) |
|
269 { |
|
270 TLex8 lex(fieldBlock); |
|
271 return lex.Val(aData, KDecimalSeperator); |
|
272 } |
|
273 return err; |
|
274 } |
|
275 |
|
276 // ----------------------------------------------------------------------------- |
|
277 // TBTGPSNmeaParser::GetFieldData |
|
278 // ----------------------------------------------------------------------------- |
|
279 template <> |
|
280 TInt TBTGPSNmeaParser::GetFieldData<TInt>(TInt aFieldId, TInt& aData) const |
|
281 { |
|
282 TPtrC8 fieldBlock; |
|
283 TInt err = GetFieldBlock(aFieldId, fieldBlock); |
|
284 if(err==KErrNone && fieldBlock.Length()>0) |
|
285 { |
|
286 TLex8 lex(fieldBlock); |
|
287 return lex.Val(aData); |
|
288 } |
|
289 return err; |
|
290 } |
|
291 |
|
292 // ----------------------------------------------------------------------------- |
|
293 // TBTGPSNmeaParser::GetFieldData<TInt> |
|
294 // ----------------------------------------------------------------------------- |
|
295 #define GetFieldDataImplementation(s) \ |
|
296 template <> TInt TBTGPSNmeaParser::GetFieldData<s>(TInt aFieldId, s& aData) const \ |
|
297 { \ |
|
298 TPtrC8 fieldBlock; \ |
|
299 TInt err = GetFieldBlock(aFieldId, fieldBlock); \ |
|
300 if(err==KErrNone && fieldBlock.Length()>0) \ |
|
301 { \ |
|
302 TLex8 lex(fieldBlock); \ |
|
303 return lex.Val(aData); \ |
|
304 } \ |
|
305 return err; \ |
|
306 } |
|
307 |
|
308 // ----------------------------------------------------------------------------- |
|
309 // TBTGPSNmeaParser::NextFieldData |
|
310 // ----------------------------------------------------------------------------- |
|
311 template <class T> |
|
312 TInt TBTGPSNmeaParser::NextFieldData(T& aData) const |
|
313 { |
|
314 //This function must be called when the sentence is valid |
|
315 __ASSERT_DEBUG(IsValid(), Panic(EPanicInvalidNmeaSentence)); |
|
316 |
|
317 TBuf8<KNmeaMaxAddressFieldLength> fieldBuf; |
|
318 TPtrC8 fieldBlock(fieldBuf); |
|
319 TInt err = GetNext(fieldBlock); |
|
320 if(err==KErrNone) |
|
321 { |
|
322 TLex8 lex(fieldBlock); |
|
323 return lex.Val(aData); |
|
324 } |
|
325 return err; |
|
326 } |
|
327 |
|
328 // ----------------------------------------------------------------------------- |
|
329 // TBTGPSNmeaParser::CheckValidity |
|
330 // ----------------------------------------------------------------------------- |
|
331 TBool TBTGPSNmeaParser::CheckValidity() const |
|
332 { |
|
333 TInt length = iNmea.Length(); |
|
334 |
|
335 //Check the length of the NMEA sentence |
|
336 if(length<KNmeaMininumLength) |
|
337 { |
|
338 return EFalse; |
|
339 } |
|
340 |
|
341 //Check checksum |
|
342 TInt checksumDelimiterPos = iNmea.LocateReverse(KNmeaChecksumDelimiter); |
|
343 if((checksumDelimiterPos == KErrNotFound) || (checksumDelimiterPos + KNmeaChecksumFieldLength > length)) |
|
344 { |
|
345 return EFalse; |
|
346 } |
|
347 |
|
348 //Get checsum field |
|
349 TLex8 lex(iNmea.Mid(checksumDelimiterPos, KNmeaChecksumFieldLength)); |
|
350 |
|
351 //Check checksum |
|
352 return VerifyChecksum(iNmea); |
|
353 } |
|
354 |
|
355 // ----------------------------------------------------------------------------- |
|
356 // TBTGPSNmeaParser::TrimSentence |
|
357 // ----------------------------------------------------------------------------- |
|
358 const TPtrC8 TBTGPSNmeaParser::TrimSentence() const |
|
359 { |
|
360 //Check checksum |
|
361 TInt checksumDelimiterPos = iNmea.LocateReverse(KNmeaChecksumDelimiter); |
|
362 |
|
363 return iNmea.Mid( |
|
364 KNmeaDataStartPos, |
|
365 checksumDelimiterPos-KNmeaDataStartPos); |
|
366 } |
|
367 |
|
368 |
|
369 // ---------------------------------------------------------------------------- |
|
370 // TBTGPSNmeaParser::VerifyChecksum |
|
371 // ---------------------------------------------------------------------------- |
|
372 // |
|
373 TBool TBTGPSNmeaParser::VerifyChecksum(const TDesC8& aSentence) const |
|
374 { |
|
375 TUint8 checksum = 0; |
|
376 TInt i; |
|
377 TInt length = aSentence.Length(); |
|
378 for (i = KNmeaDataStartPos; |
|
379 i < length && aSentence[i] != KNmeaChecksumDelimiter; i++) |
|
380 { |
|
381 checksum ^= aSentence[i]; |
|
382 } |
|
383 |
|
384 if (++i + KNmeaDataStartPos < aSentence.Length()) |
|
385 { |
|
386 TUint8 sum = TUint8((CharToNibble(aSentence[i]) << 4) + |
|
387 CharToNibble(aSentence[i+1])); |
|
388 if (sum == checksum) |
|
389 { |
|
390 return ETrue; |
|
391 } |
|
392 } |
|
393 |
|
394 return EFalse; |
|
395 } |
|
396 |
|
397 // ---------------------------------------------------------------------------- |
|
398 // TBTGPSNmeaParser::CharToNibble |
|
399 // ---------------------------------------------------------------------------- |
|
400 // |
|
401 TUint8 TBTGPSNmeaParser::CharToNibble(const TUint8 aChar) const |
|
402 { |
|
403 if (aChar <= '9') |
|
404 { |
|
405 return TUint8(aChar - '0'); |
|
406 } |
|
407 else |
|
408 { |
|
409 return TUint8(aChar - 'A' + 10); |
|
410 } |
|
411 } |
|
412 |
|
413 // End of File |
|
414 |
|
415 |
|
416 |