/src/gpsd/gpsd-3.27.6~dev/gpsd/packet.c
Line | Count | Source |
1 | | /**************************************************************************** |
2 | | |
3 | | NAME: |
4 | | packet.c -- a packet-sniffing engine for reading from GPS devices |
5 | | |
6 | | DESCRIPTION: |
7 | | |
8 | | Initial conditions of the problem: |
9 | | |
10 | | 1. We have a file descriptor open for (possibly non-blocking) read. The device |
11 | | on the other end is sending packets at us. |
12 | | |
13 | | 2. It may require more than one read to gather a packet. Reads may span packet |
14 | | boundaries. |
15 | | |
16 | | 3. There may be leading garbage before the first packet. After the first |
17 | | start-of-packet, the input should be well-formed. |
18 | | |
19 | | The problem: how do we recognize which kind of packet we're getting? |
20 | | |
21 | | No need to handle Garmin USB binary, we know that type by the fact we're |
22 | | connected to the Garmin kernel driver. But we need to be able to tell the |
23 | | others apart and distinguish them from baud barf. |
24 | | |
25 | | Tip of the hat to GitHub semuconsulting/pyspartn for showing how SPARTN works. |
26 | | |
27 | | PERMISSIONS |
28 | | This file is Copyright by the GPSD project |
29 | | SPDX-License-Identifier: BSD-2-clause |
30 | | |
31 | | ***************************************************************************/ |
32 | | |
33 | | #include "../include/gpsd_config.h" // must be before all includes |
34 | | |
35 | | #include <arpa/inet.h> // for htons() |
36 | | #include <ctype.h> |
37 | | #include <errno.h> |
38 | | #include <netinet/in.h> |
39 | | #include <stdbool.h> |
40 | | #include <stdio.h> |
41 | | #include <stdlib.h> // for strtol() |
42 | | #include <string.h> |
43 | | #include <sys/time.h> // for struct timeval |
44 | | #include <sys/types.h> |
45 | | #include <unistd.h> |
46 | | |
47 | | #include "../include/bits.h" |
48 | | #include "../include/driver_greis.h" |
49 | | #include "../include/gpsd.h" |
50 | | #include "../include/crc24q.h" |
51 | | #include "../include/strfuncs.h" |
52 | | |
53 | | /* |
54 | | * The packet-recognition state machine. This takes an incoming byte stream |
55 | | * and tries to segment it into packets. There are four types of packets: |
56 | | * |
57 | | * 1) Comments. These begin with # and end with \r\n. |
58 | | * |
59 | | * 2) NMEA lines. These begin with $, and with \r\n, and have a checksum. |
60 | | * Except $PASHR packets have no checksum! |
61 | | * |
62 | | * 3) Checksummed binary packets. These begin with some fixed leader |
63 | | * character(s), have a length embedded in them, and end with a |
64 | | * checksum (and possibly some fixed trailing bytes). |
65 | | * |
66 | | * 4) ISGPS packets. The input may be a bitstream containing IS-GPS-200 |
67 | | * packets. Each includes a fixed leader byte, a length, and check bits. |
68 | | * In this case, it is not guaranteed that packet starts begin on byte |
69 | | * boundaries; the recognizer has to run a separate state machine against |
70 | | * each byte just to achieve synchronization lock with the bitstream. |
71 | | * |
72 | | * 5) Un-checksummed binary packets. Like case 3, but without |
73 | | * a checksum it's much easier to get a false match from garbage. |
74 | | * The packet recognizer gives checksummed types higher priority. |
75 | | * |
76 | | * Adding support for a new GPS protocol typically requires adding state |
77 | | * transitions to support whatever binary packet structure it has. The |
78 | | * goal is for the lexer to be able to cope with arbitrarily mixed packet |
79 | | * types on the input stream. This is a requirement because (1) sometimes |
80 | | * gpsd wants to switch a device that supports both NMEA and a binary |
81 | | * packet protocol to the latter for more detailed reporting, and (b) in |
82 | | * the presence of device hotplugging, the type of GPS report coming |
83 | | * in is subject to change at any time. |
84 | | * |
85 | | * Caller should consume a packet when it sees one of the *_RECOGNIZED |
86 | | * states. It's good practice to follow the _RECOGNIZED transition |
87 | | * with one that recognizes a leader of the same packet type rather |
88 | | * than dropping back to ground state -- this for example will prevent |
89 | | * the state machine from hopping between recognizing TSIP and |
90 | | * EverMore packets that both start with a DLE. |
91 | | * |
92 | | * Error handling is brutally simple; any time we see an unexpected |
93 | | * character, go to GROUND_STATE and reset the machine (except that a |
94 | | * $ in an NMEA payload only resets back to NMEA_DOLLAR state). Because |
95 | | * another good packet will usually be along in less than a second |
96 | | * repeating the same data, Boyer-Moore-like attempts to do parallel |
97 | | * recognition beyond the headers would make no sense in this |
98 | | * application, they'd just add complexity. |
99 | | * |
100 | | * The NMEA portion of the state machine allows the following talker IDs: |
101 | | * $BD -- Beidou |
102 | | * $EC -- Electronic Chart Display & Information System (ECDIS) |
103 | | * $GA -- Galileo |
104 | | * $GB -- Beidou |
105 | | * $GL -- GLONASS, according to IEIC 61162-1 |
106 | | * $GN -- Mixed GPS and GLONASS data, according to IEIC 61162-1 |
107 | | * $GP -- Global Positioning System. |
108 | | * $GY -- Unicore Gyro |
109 | | * $HC -- Heading/compass (Airmar PB200). |
110 | | * $II -- Integrated Instrumentation (Raytheon's SeaTalk system). |
111 | | * $IN -- Integrated Navigation (Garmin uses this). |
112 | | * $P -- Vendor-specific sentence |
113 | | * $QZ -- QZSS GPS augmentation system |
114 | | * $SD -- Depth Sounder |
115 | | * $SN -- Unicore Sensor data |
116 | | * $ST -- $STI, Skytraq Debug Output |
117 | | * $TI -- Turn indicator (Airmar PB200). |
118 | | * $WI -- Weather instrument (Airmar PB200, Radio Ocean ROWIND, |
119 | | * Vaisala WXT520). |
120 | | * $YX -- Transducer (used by some Airmar equipment including PB100) |
121 | | * |
122 | | * !AB -- NMEA 4.0 Base AIS station |
123 | | * !AD -- MMEA 4.0 Dependent AIS Base Station |
124 | | * !AI -- Mobile AIS station |
125 | | * !AN -- NMEA 4.0 Aid to Navigation AIS station |
126 | | * !AR -- NMEA 4.0 AIS Receiving Station |
127 | | * !AX -- NMEA 4.0 Repeater AIS station |
128 | | * !AS -- NMEA 4.0 Limited Base Station |
129 | | * !AT -- NMEA 4.0 AIS Transmitting Station |
130 | | * !BS -- Base AIS station (deprecated in NMEA 4.0) |
131 | | * !SA -- NMEA 4.0 Physical Shore AIS Station |
132 | | */ |
133 | | |
134 | | enum |
135 | | { |
136 | | #include "../include/packet_states.h" |
137 | | }; |
138 | | |
139 | | static char *state_table[] = { |
140 | | #include "../include/packet_names.h" |
141 | | }; |
142 | | |
143 | 0 | #define SOH (unsigned char)0x01 |
144 | 0 | #define DLE (unsigned char)0x10 |
145 | 0 | #define STX (unsigned char)0x02 |
146 | 0 | #define ETX (unsigned char)0x03 |
147 | 0 | #define MICRO (unsigned char)0xb5 |
148 | | |
149 | | #if defined(TSIP_ENABLE) |
150 | | // Maximum length a TSIP packet can be |
151 | 0 | #define TSIP_MAX_PACKET 255 |
152 | | #endif |
153 | | |
154 | | unsigned casic_checksum(unsigned char *buf, size_t len) |
155 | 0 | { |
156 | | // CASIC uses a 32 bit little-endian checksum |
157 | | // All payloads sizes are 4-byte aligned |
158 | 0 | size_t idx; |
159 | 0 | unsigned crc_computed = 0; |
160 | |
|
161 | 0 | for (idx = 0; idx < len; idx += 4) { |
162 | 0 | crc_computed += getleu32(buf, idx); |
163 | 0 | } |
164 | 0 | return crc_computed; |
165 | 0 | } |
166 | | |
167 | | #ifdef ONCORE_ENABLE |
168 | | static size_t oncore_payload_cksum_length(unsigned char id1, unsigned char id2) |
169 | 0 | { |
170 | 0 | size_t l; |
171 | | |
172 | | /* For the packet sniffer to not terminate the message due to |
173 | | * payload data looking like a trailer, the known payload lengths |
174 | | * including the checksum are given. Return -1 for unknown IDs. |
175 | | */ |
176 | |
|
177 | 0 | #define ONCTYPE(id2,id3) ((((unsigned int)id2) << 8) | (id3)) |
178 | |
|
179 | 0 | switch (ONCTYPE(id1,id2)) { |
180 | | // A... |
181 | 0 | case ONCTYPE('A','a'): |
182 | | // time of day |
183 | 0 | l = 10; |
184 | 0 | break; |
185 | 0 | case ONCTYPE('A','b'): |
186 | | // GMT offset |
187 | 0 | l = 10; |
188 | 0 | break; |
189 | 0 | case ONCTYPE('A','c'): |
190 | | // date |
191 | 0 | l = 11; |
192 | 0 | break; |
193 | 0 | case ONCTYPE('A','d'): |
194 | | // latitude |
195 | 0 | l = 11; |
196 | 0 | break; |
197 | 0 | case ONCTYPE('A','e'): |
198 | | // longitude |
199 | 0 | l = 11; |
200 | 0 | break; |
201 | 0 | case ONCTYPE('A','f'): |
202 | | // height |
203 | 0 | l = 15; |
204 | 0 | break; |
205 | 0 | case ONCTYPE('A','g'): |
206 | | // satellite mask angle |
207 | 0 | l = 8; |
208 | 0 | break; |
209 | | // Command "Ao" gives "Ap" response (select datum) |
210 | 0 | case ONCTYPE('A','p'): |
211 | | // set user datum / select datum |
212 | 0 | l = 25; |
213 | 0 | break; |
214 | 0 | case ONCTYPE('A','q'): |
215 | | // atmospheric correction mode |
216 | 0 | l = 8; |
217 | 0 | break; |
218 | 0 | case ONCTYPE('A','s'): |
219 | | // position-hold position |
220 | 0 | l = 20; |
221 | 0 | break; |
222 | 0 | case ONCTYPE('A','t'): |
223 | | // position-hold mode |
224 | 0 | l = 8; |
225 | 0 | break; |
226 | 0 | case ONCTYPE('A','u'): |
227 | | // altitude hold height |
228 | 0 | l = 12; |
229 | 0 | break; |
230 | 0 | case ONCTYPE('A','v'): |
231 | | // altitude hold mode |
232 | 0 | l = 8; |
233 | 0 | break; |
234 | 0 | case ONCTYPE('A','w'): |
235 | | // time mode |
236 | 0 | l = 8; |
237 | 0 | break; |
238 | 0 | case ONCTYPE('A','y'): |
239 | | // 1PPS offset |
240 | 0 | l = 11; |
241 | 0 | break; |
242 | 0 | case ONCTYPE('A','z'): |
243 | | // 1PPS cable delay |
244 | 0 | l = 11; |
245 | 0 | break; |
246 | 0 | case ONCTYPE('A','N'): |
247 | | // velocity filter |
248 | 0 | l = 8; |
249 | 0 | break; |
250 | 0 | case ONCTYPE('A','O'): |
251 | | // RTCM report mode |
252 | 0 | l = 8; |
253 | 0 | break; |
254 | 0 | case ONCTYPE('A','P'): |
255 | | // pulse mode |
256 | 0 | l = 8; |
257 | 0 | break; |
258 | | |
259 | | // B... |
260 | 0 | case ONCTYPE('B','b'): |
261 | | // visible satellites status |
262 | 0 | l = 92; |
263 | 0 | break; |
264 | 0 | case ONCTYPE('B','j'): |
265 | | // leap seconds pending |
266 | 0 | l = 8; |
267 | 0 | break; |
268 | 0 | case ONCTYPE('B','o'): |
269 | | // UTC offset status |
270 | 0 | l = 8; |
271 | 0 | break; |
272 | | |
273 | | // C... |
274 | 0 | case ONCTYPE('C','b'): |
275 | | // almanac output ("Be" response) |
276 | 0 | l = 33; |
277 | 0 | break; |
278 | 0 | case ONCTYPE('C','c'): |
279 | | // ephemeris data input ("Bf") |
280 | 0 | l = 80; |
281 | 0 | break; |
282 | 0 | case ONCTYPE('C','f'): |
283 | | // set-to-defaults |
284 | 0 | l = 7; |
285 | 0 | break; |
286 | | // Command "Ci" (switch to NMEA, GT versions only) has no response |
287 | 0 | case ONCTYPE('C','h'): |
288 | | // almanac input ("Cb" response) |
289 | 0 | l = 9; |
290 | 0 | break; |
291 | 0 | case ONCTYPE('C','j'): |
292 | | // receiver ID |
293 | 0 | l = 294; |
294 | 0 | break; |
295 | 0 | case ONCTYPE('C','k'): |
296 | | // pseudorng correction inp. ("Ce") |
297 | 0 | l = 7; |
298 | 0 | break; |
299 | | |
300 | | // E... |
301 | 0 | case ONCTYPE('E','a'): |
302 | | // position/status/data |
303 | 0 | l = 76; |
304 | 0 | break; |
305 | 0 | case ONCTYPE('E','n'): |
306 | | // time RAIM setup and status |
307 | 0 | l = 69; |
308 | 0 | break; |
309 | 0 | case ONCTYPE('E','q'): |
310 | | // ASCII position |
311 | 0 | l = 96; |
312 | 0 | break; |
313 | | |
314 | | // F... |
315 | 0 | case ONCTYPE('F','a'): |
316 | | // self-test |
317 | 0 | l = 9; |
318 | 0 | break; |
319 | | |
320 | | // G... |
321 | 0 | case ONCTYPE('G','d'): |
322 | | // position hold or survey |
323 | 0 | l = 8; |
324 | 0 | break; |
325 | 0 | case ONCTYPE('G','e'): |
326 | | // T-RAIM enable |
327 | 0 | l = 8; |
328 | 0 | break; |
329 | | // H... |
330 | 0 | case ONCTYPE('H','a'): |
331 | | // position/status/data |
332 | 0 | l = 154; |
333 | 0 | break; |
334 | | |
335 | | // S... |
336 | 0 | case ONCTYPE('S','z'): |
337 | | // system power-on failure |
338 | 0 | l = 8; |
339 | 0 | break; |
340 | | |
341 | 0 | default: |
342 | 0 | return 0; |
343 | 0 | } |
344 | | |
345 | 0 | return l - 6; // Subtract header and trailer. |
346 | 0 | } |
347 | | #endif // ONCORE_ENABLE |
348 | | |
349 | | #ifdef GREIS_ENABLE |
350 | | |
351 | | // Convert hex char to binary form. Requires that c be a hex char. |
352 | | static unsigned long greis_hex2bin(char c) |
353 | 0 | { |
354 | 0 | if (('a' <= c) && |
355 | 0 | ('f' >= c)) { |
356 | 0 | c = c + 10 - 'a'; |
357 | 0 | } else if (('A' <= c) && |
358 | 0 | ('F' >= c)) { |
359 | 0 | c = c + 10 - 'A'; |
360 | 0 | } else if (('0' <= c) && |
361 | 0 | ('9' >= c)) { |
362 | 0 | c -= '0'; |
363 | 0 | } |
364 | | // FIXME: No error handling? |
365 | |
|
366 | 0 | return c; |
367 | 0 | } |
368 | | |
369 | | #endif // GREIS_ENABLE |
370 | | |
371 | | /* nmea_checksum(*errout, buf) -- check NMEA checksum for message in buffer. |
372 | | * Also handles !AI checksums. |
373 | | * |
374 | | * Return: True = Checksum good |
375 | | * False -- checksum bad |
376 | | */ |
377 | | static bool nmea_checksum(const struct gpsd_errout_t *errout, |
378 | | const char *buf, const char *endp) |
379 | 0 | { |
380 | 0 | bool checksum_ok = true; |
381 | 0 | const char *end; |
382 | 0 | unsigned int n, csum = 0; |
383 | 0 | char csum_s[3] = { '0', '0', '0' }; |
384 | | |
385 | | /* These have no checksum: |
386 | | * GPS-320FW emits $PLCS |
387 | | * MTK-3301 emits $POLYN |
388 | | * Skytraq S2525F8-BD-RTK emits $STI |
389 | | * Telit SL869 emits $GPTXT |
390 | | * Ashtech (old!) $PASHR,MCA and $PASHR,PBN with no checksum |
391 | | * All undocumented, Let them fail, except $STI. |
392 | | */ |
393 | 0 | if (str_starts_with(buf, "$STI,")) { |
394 | | // Let this one go... |
395 | 0 | return true; |
396 | 0 | } |
397 | | |
398 | | /* Some messages, like !AIVMD, !AIVMO, can have "stuff" after the |
399 | | * checksum. Some messages can have "*" in the body of a message. |
400 | | * At least one GPS (the Firefly 1a) emits \r\r\n at the end. |
401 | | * |
402 | | * So scan backwards until we find the *. Use the 2 chars to the |
403 | | * right as the checksum. |
404 | | */ |
405 | 0 | for (end = endp - 1; buf < end; end--) { |
406 | 0 | if ('*' == *end) { |
407 | 0 | break; |
408 | 0 | } |
409 | 0 | } |
410 | |
|
411 | 0 | if ('*' != *end) { |
412 | | // no asterisk found |
413 | 0 | return false; |
414 | 0 | } |
415 | | |
416 | | /* Verify checksum is 2 hex digits. Irnoge trailing stuff. |
417 | | * Magellan EC-10X has lower case hex in checksum. It is rare. */ |
418 | 0 | if (!isxdigit((unsigned char) end[1]) || |
419 | 0 | !isxdigit((unsigned char) end[2])) { |
420 | 0 | return false; |
421 | 0 | } |
422 | | |
423 | | // compute the checksum |
424 | 0 | for (n = 1; buf + n < end; n++) { |
425 | 0 | csum ^= buf[n]; |
426 | 0 | } |
427 | 0 | (void)snprintf(csum_s, sizeof(csum_s), "%02X", csum); |
428 | 0 | checksum_ok = (csum_s[0] == toupper((int)end[1]) && |
429 | 0 | csum_s[1] == toupper((int)end[2])); |
430 | 0 | if (!checksum_ok) { |
431 | 0 | GPSD_LOG(LOG_WARN, errout, |
432 | 0 | "bad checksum in NMEA packet; got %c%c expected %s.\n", |
433 | 0 | end[1], end[2], csum_s); |
434 | 0 | } |
435 | |
|
436 | 0 | return checksum_ok; |
437 | 0 | } |
438 | | |
439 | | // Convert SPARTN TF015 (Embedded Auth Len) to bytes |
440 | | static unsigned spartn_auth_len(unsigned index) |
441 | 0 | { |
442 | | // 5 to 7 TBD |
443 | 0 | static unsigned id2len[] = {8, 12, 16, 32, 64, 0, 0, 0}; |
444 | |
|
445 | 0 | return id2len[index & 7]; |
446 | 0 | } |
447 | | |
448 | | // push back the last character grabbed, setting a specified state |
449 | | static bool character_pushback(struct gps_lexer_t *lexer, |
450 | | unsigned int newstate) |
451 | 0 | { |
452 | 0 | --lexer->inbufptr; |
453 | 0 | --lexer->char_counter; |
454 | 0 | lexer->state = newstate; |
455 | 0 | if (lexer->errout.debug >= LOG_RAW2) { |
456 | 0 | unsigned char c = *lexer->inbufptr; |
457 | |
|
458 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
459 | 0 | "%08ld: character '%c' [%02x] pushed back, state set to %s\n", |
460 | 0 | lexer->char_counter, |
461 | 0 | (isprint((int)c) ? c : '.'), c, |
462 | 0 | state_table[lexer->state]); |
463 | 0 | } |
464 | |
|
465 | 0 | return false; |
466 | 0 | } |
467 | | |
468 | | // shift the input buffer to discard one character and reread data |
469 | | static void character_discard(struct gps_lexer_t *lexer) |
470 | 0 | { |
471 | 0 | memmove(lexer->inbuffer, lexer->inbuffer + 1, (size_t)-- lexer->inbuflen); |
472 | 0 | lexer->inbufptr = lexer->inbuffer; |
473 | 0 | if (lexer->errout.debug >= LOG_RAW1) { |
474 | 0 | char scratchbuf[MAX_PACKET_LENGTH*4+1]; |
475 | |
|
476 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
477 | 0 | "Character discarded, buffer %zu chars = %s\n", |
478 | 0 | lexer->inbuflen, |
479 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
480 | 0 | lexer->inbuffer, lexer->inbuflen)); |
481 | 0 | } |
482 | 0 | } |
483 | | |
484 | | /* get 0-origin big-endian words relative to start of packet buffer |
485 | | * used for Zodiac */ |
486 | 0 | #define getzuword(i) (unsigned)(lexer->inbuffer[2 * (i)] | \ |
487 | 0 | (lexer->inbuffer[2 * (i) + 1] << 8)) |
488 | 0 | #define getzword(i) (short)(lexer->inbuffer[2 * (i)] | \ |
489 | 0 | (lexer->inbuffer[2 * (i) + 1] << 8)) |
490 | | |
491 | | static bool nextstate(struct gps_lexer_t *lexer, unsigned char c) |
492 | 0 | { |
493 | 0 | static int n = 0; |
494 | 0 | enum isgpsstat_t isgpsstat; |
495 | 0 | #ifdef SUPERSTAR2_ENABLE |
496 | 0 | static unsigned char ctmp; |
497 | 0 | #endif // SUPERSTAR2_ENABLE |
498 | |
|
499 | 0 | n++; |
500 | 0 | switch (lexer->state) { |
501 | 0 | case GROUND_STATE: |
502 | 0 | n = 0; |
503 | 0 | #ifdef STASH_ENABLE |
504 | 0 | lexer->stashbuflen = 0; |
505 | 0 | #endif |
506 | 0 | switch (c) { |
507 | 0 | #ifdef SUPERSTAR2_ENABLE |
508 | 0 | case SOH: // 0x01 |
509 | 0 | lexer->state = SUPERSTAR2_LEADER; |
510 | 0 | break; |
511 | 0 | #endif // SUPERSTAR2_ENABLE |
512 | 0 | #ifdef NAVCOM_ENABLE |
513 | 0 | case STX: // 0x02 |
514 | 0 | lexer->state = NAVCOM_LEADER_1; |
515 | 0 | break; |
516 | 0 | #endif // NAVCOM_ENABLE |
517 | 0 | #if defined(TSIP_ENABLE) || defined(EVERMORE_ENABLE) || defined(GARMIN_ENABLE) |
518 | 0 | case DLE: // 0x10 |
519 | 0 | lexer->state = DLE_LEADER; |
520 | 0 | break; |
521 | 0 | #endif // TSIP_ENABLE || EVERMORE_ENABLE || GARMIN_ENABLE |
522 | 0 | case '!': |
523 | 0 | lexer->state = AIS_BANG; |
524 | 0 | break; |
525 | 0 | case '#': |
526 | 0 | lexer->state = COMMENT_BODY; |
527 | 0 | break; |
528 | 0 | case '$': |
529 | 0 | lexer->state = NMEA_DOLLAR; |
530 | 0 | break; |
531 | 0 | #if defined(TNT_ENABLE) || defined(GARMINTXT_ENABLE) || defined(ONCORE_ENABLE) |
532 | 0 | case '@': |
533 | 0 | if (ISGPS_MESSAGE == rtcm2_decode(lexer, c)) { |
534 | 0 | lexer->state = RTCM2_RECOGNIZED; |
535 | 0 | break; |
536 | 0 | } |
537 | 0 | lexer->state = AT1_LEADER; |
538 | 0 | break; |
539 | 0 | #endif // TNT_ENABLE, GARMINTXT_ENABLE, ONCORE_ENABLE |
540 | 0 | #ifdef ITRAX_ENABLE |
541 | 0 | case '<': |
542 | 0 | lexer->state = ITALK_LEADER_1; |
543 | 0 | break; |
544 | 0 | #endif // ITRAX_ENABLE |
545 | 0 | #ifdef TRIPMATE_ENABLE |
546 | 0 | case 'A': |
547 | 0 | if (ISGPS_MESSAGE == rtcm2_decode(lexer, c)) { |
548 | 0 | lexer->state = RTCM2_RECOGNIZED; |
549 | 0 | break; |
550 | 0 | } |
551 | 0 | lexer->state = ASTRAL_1; |
552 | 0 | break; |
553 | 0 | #endif // TRIPMATE_ENABLE |
554 | 0 | #ifdef EARTHMATE_ENABLE |
555 | 0 | case 'E': |
556 | 0 | if (ISGPS_MESSAGE == rtcm2_decode(lexer, c)) { |
557 | 0 | lexer->state = RTCM2_RECOGNIZED; |
558 | 0 | break; |
559 | 0 | } |
560 | 0 | lexer->state = EARTHA_1; |
561 | 0 | break; |
562 | 0 | #endif // EARTHMATE_ENABLE |
563 | 0 | #ifdef GEOSTAR_ENABLE |
564 | 0 | case 'P': |
565 | 0 | lexer->state = GEOSTAR_LEADER_1; |
566 | 0 | break; |
567 | 0 | #endif // GEOSTAR_ENABLE |
568 | 0 | #ifdef GREIS_ENABLE |
569 | 0 | case 'R': |
570 | 0 | lexer->state = GREIS_REPLY_1; |
571 | 0 | break; |
572 | 0 | #endif // GREIS_ENABLE |
573 | 0 | case '{': |
574 | 0 | return character_pushback(lexer, JSON_LEADER); |
575 | 0 | #ifdef GREIS_ENABLE |
576 | | // Tilda, Not the only possibility, but a distinctive cycle starter. |
577 | 0 | case '~': |
578 | 0 | lexer->state = GREIS_ID_1; |
579 | 0 | break; |
580 | 0 | #endif // GREIS_ENABLE |
581 | 0 | #if defined(SIRF_ENABLE) || defined(SKYTRAQ_ENABLE) |
582 | 0 | case 0xa0: // latin1 non breaking space |
583 | 0 | lexer->state = SIRF_LEADER_1; |
584 | 0 | break; |
585 | 0 | #endif // SIRF_ENABLE || SKYTRAQ_ENABLE |
586 | 0 | case MICRO: // latin1 micro, 0xb5 |
587 | 0 | lexer->state = UBX_LEADER_1; |
588 | 0 | break; |
589 | 0 | case 0xba: // latin1 MASCULINE ORDINAL INDICATOR |
590 | | // got 1st, of 2, bytes of leader |
591 | 0 | lexer->state = CASIC_LEADER_1; |
592 | 0 | break; |
593 | 0 | case 0xD3: // latin1 capital O acute |
594 | 0 | lexer->state = RTCM3_LEADER_1; |
595 | 0 | break; |
596 | 0 | case 0xf1: // latin1 small letter N with tilde |
597 | | // got 1st, of 2, bytes of leader |
598 | 0 | lexer->state = ALLY_LEADER_1; |
599 | 0 | break; |
600 | 0 | #ifdef ZODIAC_ENABLE |
601 | 0 | case 0xff: // lattin1 small y with diaeresis |
602 | 0 | lexer->state = ZODIAC_LEADER_1; |
603 | 0 | break; |
604 | 0 | #endif // ZODIAC_ENABLE |
605 | 0 | case 's': |
606 | | // SPARTN, 0x73 |
607 | 0 | if (0 == |
608 | 0 | (lexer->type_mask & PACKET_TYPEMASK(SPARTN_PACKET))) { |
609 | 0 | lexer->state = SPARTN_PRE_1; |
610 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, "SPARTN 0x73\n"); |
611 | 0 | break; |
612 | 0 | } // else |
613 | 0 | FALLTHROUGH |
614 | 0 | default: |
615 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
616 | 0 | lexer->state = RTCM2_SYNC_STATE; |
617 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
618 | 0 | lexer->state = RTCM2_RECOGNIZED; |
619 | 0 | } |
620 | 0 | break; |
621 | 0 | } |
622 | 0 | break; |
623 | 0 | case COMMENT_BODY: |
624 | 0 | if ('\n' == c) { |
625 | 0 | lexer->state = COMMENT_RECOGNIZED; |
626 | 0 | } else if ('\r' == c || |
627 | 0 | '\t' == c) { |
628 | | // allow tabs and CR in comments |
629 | 0 | } else if (!isprint(c)) { |
630 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, "COMMENT: x%x\n", c); |
631 | 0 | return character_pushback(lexer, GROUND_STATE); |
632 | 0 | } |
633 | 0 | break; |
634 | 0 | case NMEA_DOLLAR: |
635 | | // We have the leading $ |
636 | 0 | switch (c) { |
637 | 0 | case 'A': |
638 | | /* $A (SiRF Ack), $AI (Mobile Class A or B AIS Station?), or |
639 | | * $AP (autopliot) */ |
640 | 0 | lexer->state = NMEA_LEAD_A; |
641 | 0 | break; |
642 | 0 | case 'B': // $BD |
643 | 0 | lexer->state = BEIDOU_LEAD_1; |
644 | 0 | break; |
645 | 0 | case 'E': // $E, ECDIS |
646 | | // codacy thinks this is impossible |
647 | 0 | lexer->state = ECDIS_LEAD_1; |
648 | 0 | break; |
649 | 0 | case 'G': // $GP, $GN, $GY, etc. |
650 | 0 | lexer->state = NMEA_PUB_LEAD; |
651 | 0 | break; |
652 | 0 | case 'H': // $H, Heading/compass. gyro |
653 | 0 | lexer->state = HEADCOMP_LEAD_1; |
654 | 0 | break; |
655 | 0 | case 'I': // $I, Seatalk |
656 | 0 | lexer->state = SEATALK_LEAD_1; |
657 | 0 | break; |
658 | 0 | case 'P': // $P, vendor sentence |
659 | 0 | lexer->state = NMEA_VENDOR_LEAD; |
660 | 0 | break; |
661 | 0 | case 'Q': // $QZ |
662 | 0 | lexer->state = QZSS_LEAD_1; |
663 | 0 | break; |
664 | 0 | case 'S': // $S |
665 | | // $SD, $SN, $ST |
666 | 0 | lexer->state = SOUNDER_LEAD_1; |
667 | 0 | break; |
668 | 0 | case 'T': // $T, Turn indicator |
669 | 0 | lexer->state = TURN_LEAD_1; |
670 | 0 | break; |
671 | 0 | case 'W': // $W, Weather instrument |
672 | 0 | lexer->state = WEATHER_LEAD_1; |
673 | 0 | break; |
674 | 0 | case 'Y': // $Y |
675 | 0 | lexer->state = TRANSDUCER_LEAD_1; |
676 | 0 | break; |
677 | 0 | default: |
678 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
679 | 0 | break; |
680 | 0 | } |
681 | 0 | break; |
682 | 0 | case NMEA_PUB_LEAD: |
683 | | /* |
684 | | * $GP == GPS, $GL = GLONASS only, $GN = mixed GPS and GLONASS, |
685 | | * according to NMEA (IEIC 61162-1) DRAFT 02/06/2009. |
686 | | * We have a log from China with a BeiDou device using $GB |
687 | | * rather than $BD. |
688 | | * |
689 | | * Unicore uses the non-standard $GY for IMU data. |
690 | | */ |
691 | 0 | if ('A' == c || // $GA, Galileo only |
692 | 0 | 'B' == c || // $GB, BeiDou only |
693 | 0 | 'L' == c || // $GL, GLONASS only |
694 | 0 | 'N' == c || // $GN, mixed |
695 | 0 | 'P' == c || // $GP, GPS |
696 | 0 | 'Y' == c) { // $GY, Gyro (IMU) |
697 | 0 | lexer->state = NMEA_LEADER_END; |
698 | 0 | } else { |
699 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
700 | 0 | } |
701 | 0 | break; |
702 | 0 | case NMEA_VENDOR_LEAD: |
703 | 0 | if ('A' == c) { // $PA |
704 | 0 | lexer->state = NMEA_PASHR_A; |
705 | 0 | } else if (isalpha(c)) { |
706 | 0 | lexer->state = NMEA_LEADER_END; |
707 | 0 | } else { |
708 | 0 | (void) character_pushback(lexer, GROUND_STATE); |
709 | 0 | } |
710 | 0 | break; |
711 | | /* |
712 | | * Without the following six states (NMEA_PASH_*, NMEA_BINARY_*) |
713 | | * DLE in a $PASHR can fool the sniffer into thinking it sees a |
714 | | * TSIP packet. Hilarity ensues. |
715 | | */ |
716 | 0 | case NMEA_PASHR_A: |
717 | 0 | if ('S' == c) { // $PAS |
718 | 0 | lexer->state = NMEA_PASHR_S; |
719 | 0 | } else if (isalpha(c)) { |
720 | 0 | lexer->state = NMEA_LEADER_END; |
721 | 0 | } else { |
722 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
723 | 0 | } |
724 | 0 | break; |
725 | 0 | case NMEA_PASHR_S: |
726 | 0 | if ('H' == c) { // $PASH |
727 | 0 | lexer->state = NMEA_PASHR_H; |
728 | 0 | } else if (isalpha(c)) { |
729 | 0 | lexer->state = NMEA_LEADER_END; |
730 | 0 | } else { |
731 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
732 | 0 | } |
733 | 0 | break; |
734 | 0 | case NMEA_PASHR_H: |
735 | 0 | if ('R' == c) { // $PASHR |
736 | 0 | lexer->state = NMEA_BINARY_BODY; |
737 | 0 | } else if (isalpha(c)) { |
738 | 0 | lexer->state = NMEA_LEADER_END; |
739 | 0 | } else { |
740 | 0 | (void) character_pushback(lexer, GROUND_STATE); |
741 | 0 | } |
742 | 0 | break; |
743 | 0 | case NMEA_BINARY_BODY: |
744 | 0 | if ('\r' == c) { |
745 | 0 | lexer->state = NMEA_BINARY_CR; |
746 | 0 | } |
747 | 0 | break; |
748 | 0 | case NMEA_BINARY_CR: |
749 | 0 | if (c == '\n') { |
750 | 0 | lexer->state = NMEA_BINARY_NL; |
751 | 0 | } else { |
752 | 0 | lexer->state = NMEA_BINARY_BODY; |
753 | 0 | } |
754 | 0 | break; |
755 | 0 | case NMEA_BINARY_NL: |
756 | 0 | if ('$' == c) { |
757 | 0 | (void)character_pushback(lexer, NMEA_RECOGNIZED); |
758 | 0 | } else { |
759 | 0 | lexer->state = NMEA_BINARY_BODY; |
760 | 0 | } |
761 | 0 | break; |
762 | | // end PASHR, TSIP mitigation |
763 | | |
764 | | // start of AIS states |
765 | 0 | case AIS_BANG: |
766 | 0 | if ('A' == c) { // !A |
767 | 0 | lexer->state = AIS_LEAD_1; |
768 | 0 | } else if ('B' == c) { // !B |
769 | 0 | lexer->state = AIS_LEAD_ALT1; |
770 | 0 | } else if ('S' == c) { // !S |
771 | 0 | lexer->state = AIS_LEAD_ALT3; |
772 | 0 | } else { |
773 | 0 | return character_pushback(lexer, GROUND_STATE); |
774 | 0 | } |
775 | 0 | break; |
776 | 0 | case AIS_LEAD_1: |
777 | 0 | if (NULL != strchr("BDINRSTX", c)) { |
778 | | // !AB, !AD, !AI, !AN, !AR, !AS, !AT, !AX |
779 | 0 | lexer->state = AIS_LEAD_2; |
780 | 0 | } else { |
781 | 0 | return character_pushback(lexer, GROUND_STATE); |
782 | 0 | } |
783 | 0 | break; |
784 | 0 | case AIS_LEAD_2: |
785 | 0 | if (isalpha(c)) { |
786 | 0 | lexer->state = AIS_LEADER_END; |
787 | 0 | } else { |
788 | 0 | return character_pushback(lexer, GROUND_STATE); |
789 | 0 | } |
790 | 0 | break; |
791 | 0 | case AIS_LEAD_ALT1: |
792 | 0 | if ('S' == c) { |
793 | | // !BS |
794 | 0 | lexer->state = AIS_LEAD_ALT2; |
795 | 0 | } else { |
796 | 0 | return character_pushback(lexer, GROUND_STATE); |
797 | 0 | } |
798 | 0 | break; |
799 | 0 | case AIS_LEAD_ALT2: |
800 | 0 | if (isalpha(c)) { |
801 | 0 | lexer->state = AIS_LEADER_END; |
802 | 0 | } else { |
803 | 0 | return character_pushback(lexer, GROUND_STATE); |
804 | 0 | } |
805 | 0 | break; |
806 | 0 | case AIS_LEAD_ALT3: |
807 | 0 | if ('A' == c) { |
808 | | // !SA |
809 | 0 | lexer->state = AIS_LEAD_ALT4; |
810 | 0 | } else { |
811 | 0 | return character_pushback(lexer, GROUND_STATE); |
812 | 0 | } |
813 | 0 | break; |
814 | 0 | case AIS_LEAD_ALT4: |
815 | 0 | if (isalpha(c)) { |
816 | 0 | lexer->state = AIS_LEADER_END; |
817 | 0 | } else { |
818 | 0 | return character_pushback(lexer, GROUND_STATE); |
819 | 0 | } |
820 | 0 | break; |
821 | 0 | case AIS_LEADER_END: |
822 | | // We stay here grabbing the body of the message, until \r\n |
823 | 0 | if ('\r' == c) { |
824 | 0 | lexer->state = AIS_CR; |
825 | 0 | } else if ('\n' == c) { |
826 | | /* not strictly correct (missing \r), but helps with |
827 | | * interpreting logfiles. */ |
828 | 0 | lexer->state = AIS_RECOGNIZED; |
829 | 0 | } else if (!isprint(c)) { |
830 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
831 | 0 | } |
832 | 0 | break; |
833 | 0 | case AIS_CR: |
834 | 0 | if ('\n' == c) { |
835 | 0 | lexer->state = AIS_RECOGNIZED; |
836 | 0 | } else { |
837 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
838 | 0 | } |
839 | 0 | break; |
840 | | // end of AIS states |
841 | | |
842 | 0 | #if defined(TNT_ENABLE) || defined(GARMINTXT_ENABLE) || defined(ONCORE_ENABLE) |
843 | 0 | case AT1_LEADER: |
844 | 0 | switch (c) { |
845 | 0 | #ifdef ONCORE_ENABLE |
846 | 0 | case '@': |
847 | 0 | lexer->state = ONCORE_AT2; |
848 | 0 | break; |
849 | 0 | #endif // ONCORE_ENABLE |
850 | 0 | #ifdef TNT_ENABLE |
851 | 0 | case '*': |
852 | | /* |
853 | | * TNT has similar structure to NMEA packet, '*' before |
854 | | * optional checksum ends the packet. Since '*' cannot be |
855 | | * received from GARMIN working in TEXT mode, use this |
856 | | * difference to tell that this is not GARMIN TEXT packet, |
857 | | * could be TNT. |
858 | | */ |
859 | 0 | lexer->state = NMEA_LEADER_END; |
860 | 0 | break; |
861 | 0 | #endif // TNT_ENABLE |
862 | 0 | #if defined(GARMINTXT_ENABLE) |
863 | 0 | case '\r': |
864 | | /* stay in this state, next character should be '\n' |
865 | | * in the theory we can stop search here and don't wait for '\n' */ |
866 | 0 | lexer->state = AT1_LEADER; |
867 | 0 | break; |
868 | 0 | case '\n': |
869 | | // end of packet found |
870 | 0 | lexer->state = GTXT_RECOGNIZED; |
871 | 0 | break; |
872 | 0 | #endif // GARMINTXT_ENABLE |
873 | 0 | default: |
874 | 0 | if (!isprint(c)) { |
875 | 0 | return character_pushback(lexer, GROUND_STATE); |
876 | 0 | } |
877 | 0 | } |
878 | 0 | break; |
879 | 0 | #endif // TNT_ENABLE || GARMINTXT_ENABLE || ONCORE_ENABLE |
880 | 0 | case NMEA_LEADER_END: |
881 | | // We stay here grabbing the body of the message |
882 | 0 | if ('\r' == c) { |
883 | 0 | lexer->state = NMEA_CR; |
884 | 0 | } else if ('\n' == c) { |
885 | | /* not strictly correct (missing \r), but helps with |
886 | | * interpreting logfiles. */ |
887 | 0 | lexer->state = NMEA_RECOGNIZED; |
888 | 0 | } else if ('$' == c) { |
889 | 0 | #ifdef STASH_ENABLE |
890 | 0 | (void)character_pushback(lexer, STASH_RECOGNIZED); |
891 | | #else |
892 | | (void)character_pushback(lexer, GROUND_STATE); |
893 | | #endif |
894 | 0 | } else if (!isprint(c)) { |
895 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
896 | 0 | } |
897 | 0 | break; |
898 | 0 | case NMEA_CR: |
899 | 0 | if ('\n' == c) { |
900 | 0 | lexer->state = NMEA_RECOGNIZED; |
901 | 0 | } else if ('\r' == c) { |
902 | | /* |
903 | | * There's a GPS called a Jackson Labs Firefly-1a that emits \r\r\n |
904 | | * at the end of each sentence. Don't be confused by this. |
905 | | */ |
906 | 0 | lexer->state = NMEA_CR; |
907 | 0 | } else { |
908 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
909 | 0 | } |
910 | 0 | break; |
911 | 0 | case AIS_RECOGNIZED: |
912 | | // AIS and NMEA often mixed treat them similar to start |
913 | 0 | FALLTHROUGH |
914 | 0 | case NMEA_RECOGNIZED: |
915 | 0 | if ('#' == c) { |
916 | 0 | lexer->state = COMMENT_BODY; |
917 | 0 | } else if ('$' == c) { |
918 | | // codacy thinks this state is impossible |
919 | 0 | lexer->state = NMEA_DOLLAR; |
920 | 0 | } else if ('!' == c) { |
921 | 0 | lexer->state = AIS_BANG; |
922 | 0 | } else if (MICRO == c) { // latin1 micro, 0xb5 |
923 | | // LEA-5H can/will output NMEA/UBX back to back |
924 | | // codacy says this state impossible? |
925 | 0 | lexer->state = UBX_LEADER_1; |
926 | 0 | } else if ('{' == c) { |
927 | | // codacy says this state impossible? |
928 | 0 | return character_pushback(lexer, JSON_LEADER); |
929 | 0 | } else { |
930 | 0 | return character_pushback(lexer, GROUND_STATE); |
931 | 0 | } |
932 | 0 | break; |
933 | 0 | case SEATALK_LEAD_1: |
934 | 0 | if ('I' == c || |
935 | 0 | 'N' == c) { // $II or $IN are accepted |
936 | 0 | lexer->state = NMEA_LEADER_END; |
937 | 0 | } else { |
938 | 0 | return character_pushback(lexer, GROUND_STATE); |
939 | 0 | } |
940 | 0 | break; |
941 | 0 | case WEATHER_LEAD_1: |
942 | 0 | if ('I' == c) { // $WI, Weather instrument leader accepted |
943 | 0 | lexer->state = NMEA_LEADER_END; |
944 | 0 | } else { |
945 | 0 | return character_pushback(lexer, GROUND_STATE); |
946 | 0 | } |
947 | 0 | break; |
948 | 0 | case HEADCOMP_LEAD_1: |
949 | 0 | if ('C' == c || // $HC, Heading/compass leader accepted |
950 | 0 | 'E' == c) { // $HE, Gyro, north seeking |
951 | 0 | lexer->state = NMEA_LEADER_END; |
952 | 0 | } else { |
953 | 0 | return character_pushback(lexer, GROUND_STATE); |
954 | 0 | } |
955 | 0 | break; |
956 | 0 | case TURN_LEAD_1: |
957 | 0 | if ('I' == c) { // $TI, Turn indicator leader accepted |
958 | 0 | lexer->state = NMEA_LEADER_END; |
959 | 0 | } else { |
960 | 0 | return character_pushback(lexer, GROUND_STATE); |
961 | 0 | } |
962 | 0 | break; |
963 | 0 | case ECDIS_LEAD_1: |
964 | 0 | if ('C' == c) { // $EC, ECDIS leader accepted |
965 | 0 | lexer->state = NMEA_LEADER_END; |
966 | 0 | } else { |
967 | 0 | return character_pushback(lexer, GROUND_STATE); |
968 | 0 | } |
969 | 0 | break; |
970 | 0 | case SOUNDER_LEAD_1: |
971 | 0 | if ('D' == c || // $SD, Depth-sounder |
972 | 0 | 'N' == c || // $SN, to $SNRSTAT |
973 | 0 | 'T' == c) { // $ST, to $STI |
974 | | // leader accepted |
975 | 0 | lexer->state = NMEA_LEADER_END; |
976 | 0 | } else { |
977 | 0 | return character_pushback(lexer, GROUND_STATE); |
978 | 0 | } |
979 | 0 | break; |
980 | 0 | case TRANSDUCER_LEAD_1: |
981 | 0 | if ('X' == c) { // $YX, Transducer leader accepted |
982 | 0 | lexer->state = NMEA_LEADER_END; |
983 | 0 | } else { |
984 | 0 | return character_pushback(lexer, GROUND_STATE); |
985 | 0 | } |
986 | 0 | break; |
987 | 0 | case BEIDOU_LEAD_1: |
988 | 0 | if ('D' == c) { // $BD, Beidou leader accepted |
989 | 0 | lexer->state = NMEA_LEADER_END; |
990 | 0 | } else { |
991 | 0 | return character_pushback(lexer, GROUND_STATE); |
992 | 0 | } |
993 | 0 | break; |
994 | 0 | case QZSS_LEAD_1: |
995 | 0 | if ('Z' == c) { // $QZ, QZSS leader accepted |
996 | 0 | lexer->state = NMEA_LEADER_END; |
997 | 0 | } else { |
998 | 0 | return character_pushback(lexer, GROUND_STATE); |
999 | 0 | } |
1000 | 0 | break; |
1001 | 0 | #ifdef TRIPMATE_ENABLE |
1002 | 0 | case ASTRAL_1: |
1003 | 0 | if ('S' == c) { // AS |
1004 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1005 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1006 | 0 | break; |
1007 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1008 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1009 | 0 | break; |
1010 | 0 | } |
1011 | 0 | lexer->state = ASTRAL_2; |
1012 | 0 | } else |
1013 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1014 | 0 | break; |
1015 | 0 | case ASTRAL_2: |
1016 | 0 | if ('T' == c) { // AST |
1017 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1018 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1019 | 0 | break; |
1020 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1021 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1022 | 0 | break; |
1023 | 0 | } |
1024 | 0 | lexer->state = ASTRAL_3; |
1025 | 0 | } else { |
1026 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1027 | 0 | } |
1028 | 0 | break; |
1029 | 0 | case ASTRAL_3: |
1030 | 0 | if ('R' == c) { // ASTR |
1031 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1032 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1033 | 0 | break; |
1034 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1035 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1036 | 0 | break; |
1037 | 0 | } |
1038 | 0 | lexer->state = ASTRAL_5; |
1039 | 0 | } else { |
1040 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1041 | 0 | } |
1042 | 0 | break; |
1043 | 0 | case ASTRAL_4: |
1044 | 0 | if ('A' == c) { // ASTRA |
1045 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1046 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1047 | 0 | break; |
1048 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1049 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1050 | 0 | break; |
1051 | 0 | } |
1052 | 0 | lexer->state = ASTRAL_2; |
1053 | 0 | } else { |
1054 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1055 | 0 | } |
1056 | 0 | break; |
1057 | 0 | case ASTRAL_5: |
1058 | 0 | if ('L' == c) { // ASTRAL |
1059 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1060 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1061 | 0 | break; |
1062 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1063 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1064 | 0 | break; |
1065 | 0 | } |
1066 | 0 | lexer->state = NMEA_RECOGNIZED; |
1067 | 0 | } else { |
1068 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1069 | 0 | } |
1070 | 0 | break; |
1071 | 0 | #endif // TRIPMATE_ENABLE |
1072 | 0 | #ifdef EARTHMATE_ENABLE |
1073 | 0 | case EARTHA_1: |
1074 | 0 | if ('A' == c) { // EA |
1075 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1076 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1077 | 0 | break; |
1078 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1079 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1080 | 0 | break; |
1081 | 0 | } |
1082 | 0 | lexer->state = EARTHA_2; |
1083 | 0 | } else { |
1084 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1085 | 0 | } |
1086 | 0 | break; |
1087 | 0 | case EARTHA_2: |
1088 | 0 | if ('R' == c) { // EAR |
1089 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1090 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1091 | 0 | break; |
1092 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1093 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1094 | 0 | break; |
1095 | 0 | } |
1096 | 0 | lexer->state = EARTHA_3; |
1097 | 0 | } else { |
1098 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1099 | 0 | } |
1100 | 0 | break; |
1101 | 0 | case EARTHA_3: |
1102 | 0 | if ('T' == c) { // EART |
1103 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1104 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1105 | 0 | break; |
1106 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1107 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1108 | 0 | break; |
1109 | 0 | } |
1110 | 0 | lexer->state = EARTHA_4; |
1111 | 0 | } else { |
1112 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1113 | 0 | } |
1114 | 0 | break; |
1115 | 0 | case EARTHA_4: |
1116 | 0 | if ('H' == c) { // EARTH |
1117 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1118 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1119 | 0 | break; |
1120 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1121 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1122 | 0 | break; |
1123 | 0 | } |
1124 | 0 | lexer->state = EARTHA_5; |
1125 | 0 | } else { |
1126 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1127 | 0 | } |
1128 | 0 | break; |
1129 | 0 | case EARTHA_5: |
1130 | 0 | if ('A' == c) { // EARTHA |
1131 | 0 | if (ISGPS_SYNC == (isgpsstat = rtcm2_decode(lexer, c))) { |
1132 | 0 | lexer->state = RTCM2_SYNC_STATE; |
1133 | 0 | break; |
1134 | 0 | } else if (ISGPS_MESSAGE == isgpsstat) { |
1135 | 0 | lexer->state = RTCM2_RECOGNIZED; |
1136 | 0 | break; |
1137 | 0 | } |
1138 | 0 | lexer->state = NMEA_RECOGNIZED; |
1139 | 0 | } else { |
1140 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1141 | 0 | } |
1142 | 0 | break; |
1143 | 0 | #endif // EARTHMATE_ENABLE |
1144 | 0 | case NMEA_LEAD_A: |
1145 | 0 | if ('c' == c) { // $Ac |
1146 | 0 | lexer->state = SIRF_ACK_LEAD_2; |
1147 | 0 | } else if ('I' == c) { // $AI, Mobile Class A or B AIS Station |
1148 | 0 | lexer->state = AIS_LEAD_2; |
1149 | 0 | } else if ('P' == c) { // $AP, auto pilot |
1150 | 0 | lexer->state = NMEA_LEADER_END; |
1151 | 0 | } else { |
1152 | 0 | return character_pushback(lexer, GROUND_STATE); |
1153 | 0 | } |
1154 | 0 | break; |
1155 | 0 | case SIRF_ACK_LEAD_2: |
1156 | 0 | if ('k' == c) { // $Ack |
1157 | 0 | lexer->state = NMEA_LEADER_END; |
1158 | 0 | } else { |
1159 | 0 | return character_pushback(lexer, GROUND_STATE); |
1160 | 0 | } |
1161 | 0 | break; |
1162 | 0 | #if defined(SIRF_ENABLE) || defined(SKYTRAQ_ENABLE) |
1163 | 0 | case SIRF_LEADER_1: |
1164 | 0 | # ifdef SKYTRAQ_ENABLE |
1165 | | // Skytraq leads with 0xA0,0xA1 |
1166 | 0 | if (0xa1 == c) { |
1167 | 0 | lexer->state = SKY_LEADER_2; |
1168 | 0 | break; |
1169 | 0 | } |
1170 | 0 | # endif // SKYTRAQ_ENABLE |
1171 | 0 | # ifdef SIRF_ENABLE |
1172 | | // SIRF leads with 0xA0,0xA2 |
1173 | 0 | if (0xa2 == c) { |
1174 | 0 | lexer->state = SIRF_LEADER_2; |
1175 | 0 | break; |
1176 | 0 | } |
1177 | 0 | # endif // SIRF_ENABLE |
1178 | 0 | return character_pushback(lexer, GROUND_STATE); |
1179 | 0 | break; |
1180 | 0 | #endif // SIRF_ENABLE || SKYTRAQ_ENABLE |
1181 | 0 | #ifdef SIRF_ENABLE |
1182 | 0 | case SIRF_LEADER_2: |
1183 | | // first part of length, MSB |
1184 | 0 | lexer->length = (c & 0x7f) << 8; |
1185 | 0 | if (lexer->length > MAX_PACKET_LENGTH) { |
1186 | 0 | lexer->length = 0; |
1187 | 0 | return character_pushback(lexer, GROUND_STATE); |
1188 | 0 | } // else |
1189 | 0 | lexer->state = SIRF_LENGTH_1; |
1190 | 0 | break; |
1191 | 0 | case SIRF_LENGTH_1: |
1192 | | // second part of length |
1193 | 0 | lexer->length += c + 2; |
1194 | 0 | if (lexer->length > MAX_PACKET_LENGTH) { |
1195 | 0 | lexer->length = 0; |
1196 | 0 | return character_pushback(lexer, GROUND_STATE); |
1197 | 0 | } // else |
1198 | 0 | lexer->state = SIRF_PAYLOAD; |
1199 | 0 | break; |
1200 | 0 | case SIRF_PAYLOAD: |
1201 | 0 | if (0 == --lexer->length) { |
1202 | 0 | lexer->state = SIRF_DELIVERED; |
1203 | 0 | } |
1204 | 0 | break; |
1205 | 0 | case SIRF_DELIVERED: |
1206 | 0 | if (0xb0 == c) { // latin1 degree sign |
1207 | 0 | lexer->state = SIRF_TRAILER_1; |
1208 | 0 | } else { |
1209 | 0 | return character_pushback(lexer, GROUND_STATE); |
1210 | 0 | } |
1211 | 0 | break; |
1212 | 0 | case SIRF_TRAILER_1: |
1213 | 0 | if (0xb3 == c) { // latin1 superscript 3 |
1214 | 0 | lexer->state = SIRF_RECOGNIZED; |
1215 | 0 | } else { |
1216 | 0 | return character_pushback(lexer, GROUND_STATE); |
1217 | 0 | } |
1218 | 0 | break; |
1219 | 0 | case SIRF_RECOGNIZED: |
1220 | 0 | if (0xa0 == c) { // latin1 no break space |
1221 | 0 | lexer->state = SIRF_LEADER_1; |
1222 | 0 | } else { |
1223 | 0 | return character_pushback(lexer, GROUND_STATE); |
1224 | 0 | } |
1225 | 0 | break; |
1226 | 0 | #endif // SIRF_ENABLE |
1227 | 0 | #ifdef SKYTRAQ_ENABLE |
1228 | 0 | case SKY_LEADER_2: |
1229 | | // MSB of length is first |
1230 | 0 | lexer->length = (size_t)(c << 8); |
1231 | 0 | lexer->state = SKY_LENGTH_1; |
1232 | 0 | break; |
1233 | 0 | case SKY_LENGTH_1: |
1234 | | // Skytraq length can be any 16 bit number, except 0 |
1235 | 0 | lexer->length += c; |
1236 | 0 | if (0 == lexer->length) { |
1237 | 0 | return character_pushback(lexer, GROUND_STATE); |
1238 | 0 | } |
1239 | 0 | if (MAX_PACKET_LENGTH < lexer->length) { |
1240 | 0 | lexer->length = 0; |
1241 | 0 | return character_pushback(lexer, GROUND_STATE); |
1242 | 0 | } |
1243 | 0 | lexer->state = SKY_PAYLOAD; |
1244 | 0 | break; |
1245 | 0 | case SKY_PAYLOAD: |
1246 | 0 | if (0 == --lexer->length) { |
1247 | 0 | lexer->state = SKY_DELIVERED; |
1248 | 0 | } |
1249 | 0 | break; |
1250 | 0 | case SKY_DELIVERED: |
1251 | 0 | { |
1252 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
1253 | 0 | unsigned char csum = 0; |
1254 | |
|
1255 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
1256 | 0 | "Skytraq = %s\n", |
1257 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
1258 | 0 | lexer->inbuffer, |
1259 | 0 | lexer->inbufptr - (unsigned char *)lexer->inbuffer)); |
1260 | 0 | for (n = 4; |
1261 | 0 | (unsigned char *)(lexer->inbuffer + n) < lexer->inbufptr - 1; |
1262 | 0 | n++) { |
1263 | 0 | csum ^= lexer->inbuffer[n]; |
1264 | 0 | } |
1265 | 0 | if (csum != c) { |
1266 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
1267 | 0 | "Skytraq bad checksum 0x%hhx, expecting 0x%x\n", |
1268 | 0 | csum, c); |
1269 | 0 | lexer->state = GROUND_STATE; |
1270 | 0 | break; |
1271 | 0 | } |
1272 | 0 | } |
1273 | 0 | lexer->state = SKY_CSUM; |
1274 | 0 | break; |
1275 | 0 | case SKY_CSUM: |
1276 | 0 | if ('\r' != c) { |
1277 | 0 | return character_pushback(lexer, GROUND_STATE); |
1278 | 0 | } |
1279 | 0 | lexer->state = SKY_TRAILER_1; |
1280 | 0 | break; |
1281 | 0 | case SKY_TRAILER_1: |
1282 | 0 | if ('\n' != c) { |
1283 | 0 | return character_pushback(lexer, GROUND_STATE); |
1284 | 0 | } |
1285 | 0 | lexer->state = SKY_RECOGNIZED; |
1286 | 0 | break; |
1287 | 0 | case SKY_RECOGNIZED: |
1288 | 0 | if (0xa0 != c) { // non break space |
1289 | 0 | return character_pushback(lexer, GROUND_STATE); |
1290 | 0 | } |
1291 | 0 | lexer->state = SIRF_LEADER_1; |
1292 | 0 | break; |
1293 | 0 | #endif // SKYTRAQ |
1294 | 0 | case SPARTN_PRE_1: |
1295 | | // message type, 1 bit of length |
1296 | 0 | lexer->length = c & 1; |
1297 | 0 | lexer->state = SPARTN_PRE_2; |
1298 | 0 | break; |
1299 | 0 | case SPARTN_PRE_2: |
1300 | | // 8 bits of length |
1301 | 0 | lexer->length = (lexer->length << 8) + (c & 0xff); |
1302 | 0 | lexer->state = SPARTN_PRE_3; |
1303 | 0 | break; |
1304 | 0 | case SPARTN_PRE_3: |
1305 | | // 1 bit of length, 1 bit of eaf, 2 bits CRC type, 4 bits frame CRC |
1306 | 0 | lexer->length = (lexer->length << 1) + ((c >> 7) & 1); |
1307 | 0 | lexer->state = SPARTN_PAYDESC_1; |
1308 | 0 | break; |
1309 | 0 | case SPARTN_PAYDESC_1: |
1310 | | // 4 bits subtype, 1 bit time tag type, 3 bits time tag |
1311 | 0 | lexer->state = SPARTN_PAYDESC_2; |
1312 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
1313 | 0 | "SPARTN: PD1 length %zu eaf %u subtype %u " |
1314 | 0 | "timetagtype %u c[4] x%x\n", |
1315 | 0 | lexer->length, (lexer->inbuffer[3] >> 6) & 1, |
1316 | 0 | (c >> 4) & 0x0f, (c >> 3) & 1,lexer->inbuffer[3]); |
1317 | 0 | break; |
1318 | 0 | case SPARTN_PAYDESC_2: |
1319 | | // 8 bits timetag |
1320 | 0 | lexer->state = SPARTN_PAYDESC_3; |
1321 | 0 | break; |
1322 | 0 | case SPARTN_PAYDESC_3: |
1323 | | // 5 bits timetag 3 bits of (tt2 or solution) |
1324 | 0 | if (0x08 == (lexer->inbuffer[4] & 0x08)) { |
1325 | | // eaf 1 means 2 extra payload description bytes (timetag2) |
1326 | 0 | lexer->state = SPARTN_PAYDESC_4; |
1327 | 0 | } else { |
1328 | 0 | lexer->state = SPARTN_PAYDESC_6; |
1329 | 0 | } |
1330 | 0 | break; |
1331 | 0 | case SPARTN_PAYDESC_4: |
1332 | | // 8 bits timetag2 |
1333 | 0 | lexer->state = SPARTN_PAYDESC_5; |
1334 | 0 | break; |
1335 | 0 | case SPARTN_PAYDESC_5: |
1336 | | // 5 bits timetag2 3 bits of solution proc ID |
1337 | 0 | lexer->state = SPARTN_PAYDESC_6; |
1338 | 0 | break; |
1339 | 0 | case SPARTN_PAYDESC_6: |
1340 | | // 4 bits solution ID, 4 bits Solution Proc ID |
1341 | 0 | if (0x40 == (lexer->inbuffer[3] & 0x40)) { |
1342 | | // eaf 1 means 2 extra payload description bytes |
1343 | 0 | lexer->state = SPARTN_PAYDESC_7; |
1344 | 0 | } else { |
1345 | 0 | lexer->state = SPARTN_PAYLOAD; |
1346 | 0 | } |
1347 | | // add CRC length, 1, 2, 3, or 4 bytes |
1348 | 0 | lexer->length += ((lexer->inbuffer[3] >> 4) & 3) + 1; |
1349 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
1350 | 0 | "SPARTN: PD6 length %zu eaf %u timetagtype %u " |
1351 | 0 | "crct %u\n", |
1352 | 0 | lexer->length, (lexer->inbuffer[3] >> 6) & 1, |
1353 | 0 | (lexer->inbuffer[4] >> 3) & 1, |
1354 | 0 | (lexer->inbuffer[3] >> 4) & 3); |
1355 | 0 | break; |
1356 | 0 | case SPARTN_PAYDESC_7: |
1357 | | // 4 bits Enc ID, 4 bits Enc Seq Num |
1358 | 0 | lexer->state = SPARTN_PAYDESC_8; |
1359 | 0 | break; |
1360 | 0 | case SPARTN_PAYDESC_8: |
1361 | | // 2 bit Enc Seq Num, 1 bit Auth Ind, 3 Embed Auth Len |
1362 | 0 | lexer->state = SPARTN_PAYLOAD; |
1363 | 0 | lexer->length += spartn_auth_len(c & 3); |
1364 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
1365 | 0 | "SPARTN: PD8 x%02x length %zu eaf %u timetagtype %u " |
1366 | 0 | "eal %u/%u\n", |
1367 | 0 | c, lexer->length, (lexer->inbuffer[3] >> 6) & 1, |
1368 | 0 | (lexer->inbuffer[4] >> 3) & 1, |
1369 | 0 | c & 3, spartn_auth_len(c & 3)); |
1370 | 0 | break; |
1371 | 0 | case SPARTN_PAYLOAD: |
1372 | 0 | if (0 == --lexer->length) { |
1373 | | // Done with payload, encryption and crc |
1374 | 0 | lexer->state = SPARTN_RECOGNIZED; |
1375 | 0 | } |
1376 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
1377 | 0 | "SPARTN: PAY x%02x length4 %zu eaf %u timetagtype %u\n", |
1378 | 0 | c, lexer->length, (lexer->inbuffer[3] >> 6) & 1, |
1379 | 0 | (lexer->inbuffer[4] >> 3) & 1); |
1380 | 0 | break; |
1381 | | |
1382 | 0 | #ifdef SUPERSTAR2_ENABLE |
1383 | 0 | case SUPERSTAR2_LEADER: |
1384 | 0 | ctmp = c; // seems a dodgy way to keep state... |
1385 | 0 | lexer->state = SUPERSTAR2_ID1; |
1386 | 0 | break; |
1387 | 0 | case SUPERSTAR2_ID1: |
1388 | 0 | if ((ctmp ^ 0xff) == c) { |
1389 | 0 | lexer->state = SUPERSTAR2_ID2; |
1390 | 0 | } else { |
1391 | 0 | return character_pushback(lexer, GROUND_STATE); |
1392 | 0 | } |
1393 | 0 | break; |
1394 | 0 | case SUPERSTAR2_ID2: |
1395 | 0 | lexer->length = (size_t) c; // how many data bytes follow this byte |
1396 | 0 | if (lexer->length) { |
1397 | 0 | lexer->state = SUPERSTAR2_PAYLOAD; |
1398 | 0 | } else { |
1399 | 0 | lexer->state = SUPERSTAR2_CKSUM1; // no data, jump to checksum |
1400 | 0 | } |
1401 | 0 | break; |
1402 | 0 | case SUPERSTAR2_PAYLOAD: |
1403 | 0 | if (0 == --lexer->length) { |
1404 | | // Done with payload |
1405 | 0 | lexer->state = SUPERSTAR2_CKSUM1; |
1406 | 0 | } |
1407 | 0 | break; |
1408 | 0 | case SUPERSTAR2_CKSUM1: |
1409 | 0 | lexer->state = SUPERSTAR2_CKSUM2; |
1410 | 0 | break; |
1411 | 0 | case SUPERSTAR2_CKSUM2: |
1412 | | // checksum not checked here? |
1413 | 0 | lexer->state = SUPERSTAR2_RECOGNIZED; |
1414 | 0 | break; |
1415 | 0 | case SUPERSTAR2_RECOGNIZED: |
1416 | 0 | if (SOH == c) { |
1417 | 0 | lexer->state = SUPERSTAR2_LEADER; |
1418 | 0 | } else { |
1419 | 0 | return character_pushback(lexer, GROUND_STATE); |
1420 | 0 | } |
1421 | 0 | break; |
1422 | 0 | #endif // SUPERSTAR2_ENABLE |
1423 | 0 | #ifdef ONCORE_ENABLE |
1424 | 0 | case ONCORE_AT2: |
1425 | 0 | if (isupper(c)) { |
1426 | 0 | lexer->length = (size_t)c; |
1427 | 0 | lexer->state = ONCORE_ID1; |
1428 | 0 | } else { |
1429 | 0 | return character_pushback(lexer, GROUND_STATE); |
1430 | 0 | } |
1431 | 0 | break; |
1432 | 0 | case ONCORE_ID1: |
1433 | 0 | if (!isalpha(c)) { |
1434 | 0 | return character_pushback(lexer, GROUND_STATE); |
1435 | 0 | } |
1436 | 0 | lexer->length = |
1437 | 0 | oncore_payload_cksum_length((unsigned char)lexer->length, c); |
1438 | 0 | if (0 != lexer->length) { |
1439 | 0 | lexer->state = ONCORE_PAYLOAD; |
1440 | 0 | } |
1441 | | // else? |
1442 | 0 | break; |
1443 | 0 | case ONCORE_PAYLOAD: |
1444 | 0 | if (0 == --lexer->length) { |
1445 | 0 | lexer->state = ONCORE_CHECKSUM; |
1446 | 0 | } |
1447 | 0 | break; |
1448 | 0 | case ONCORE_CHECKSUM: |
1449 | 0 | if ('\r' != c) { |
1450 | 0 | return character_pushback(lexer, GROUND_STATE); |
1451 | 0 | } |
1452 | 0 | lexer->state = ONCORE_CR; |
1453 | 0 | break; |
1454 | 0 | case ONCORE_CR: |
1455 | 0 | if ('\n' == c) { |
1456 | 0 | lexer->state = ONCORE_RECOGNIZED; |
1457 | 0 | } else { |
1458 | 0 | lexer->state = ONCORE_PAYLOAD; |
1459 | 0 | } |
1460 | 0 | break; |
1461 | 0 | case ONCORE_RECOGNIZED: |
1462 | 0 | if ('@' == c) { |
1463 | 0 | lexer->state = AT1_LEADER; |
1464 | 0 | } else { |
1465 | 0 | return character_pushback(lexer, GROUND_STATE); |
1466 | 0 | } |
1467 | 0 | break; |
1468 | 0 | #endif // ONCORE_ENABLE |
1469 | 0 | #if defined(TSIP_ENABLE) || defined(EVERMORE_ENABLE) || defined(GARMIN_ENABLE) |
1470 | 0 | case DLE_LEADER: |
1471 | 0 | #ifdef EVERMORE_ENABLE |
1472 | 0 | if (STX == c) { // DLE (0x10), STX (0x01) |
1473 | 0 | lexer->state = EVERMORE_LEADER_2; |
1474 | 0 | break; |
1475 | 0 | } |
1476 | 0 | #endif // EVERMORE_ENABLE |
1477 | 0 | #if defined(TSIP_ENABLE) || defined(GARMIN_ENABLE) || defined(NAVCOM_ENABLE) |
1478 | | // garmin is special case of TSIP |
1479 | | // check last because there's no checksum |
1480 | 0 | #if defined(TSIP_ENABLE) |
1481 | 0 | if (0x13 <= c) { // DLE (0x10), DC3 |
1482 | 0 | lexer->length = TSIP_MAX_PACKET; |
1483 | 0 | lexer->state = TSIP_PAYLOAD; |
1484 | 0 | break; |
1485 | 0 | } |
1486 | 0 | #endif // TSIP_ENABLE |
1487 | 0 | if (DLE == c) { // DLE (0x10), DLE (0x10) |
1488 | 0 | lexer->state = GROUND_STATE; |
1489 | 0 | break; |
1490 | 0 | } |
1491 | | // give up |
1492 | 0 | lexer->state = GROUND_STATE; |
1493 | 0 | break; |
1494 | 0 | #endif // TSIP_ENABLE |
1495 | 0 | #ifdef NAVCOM_ENABLE |
1496 | 0 | case NAVCOM_LEADER_1: |
1497 | 0 | if (0x99 == c) { // latin1 TM (0x99) |
1498 | 0 | lexer->state = NAVCOM_LEADER_2; |
1499 | 0 | } else { |
1500 | 0 | return character_pushback(lexer, GROUND_STATE); |
1501 | 0 | } |
1502 | 0 | break; |
1503 | 0 | case NAVCOM_LEADER_2: |
1504 | 0 | if ('f' == c) { // (TM), f |
1505 | 0 | lexer->state = NAVCOM_LEADER_3; |
1506 | 0 | } else { |
1507 | 0 | return character_pushback(lexer, GROUND_STATE); |
1508 | 0 | } |
1509 | 0 | break; |
1510 | 0 | case NAVCOM_LEADER_3: |
1511 | | // command ID |
1512 | 0 | lexer->state = NAVCOM_ID; |
1513 | 0 | break; |
1514 | 0 | case NAVCOM_ID: |
1515 | | // Length LSB |
1516 | 0 | lexer->length = c; |
1517 | 0 | lexer->state = NAVCOM_LENGTH_1; |
1518 | 0 | break; |
1519 | 0 | case NAVCOM_LENGTH_1: |
1520 | | /* Length USB. Navcom allows payload length up to 32767 - 4 |
1521 | | * Navcom length includes command ID, length bytes. and checksum. |
1522 | | * More than just the payload length. |
1523 | | * Minimum 4 bytes */ |
1524 | 0 | lexer->length += (c << 8); |
1525 | 0 | if (4 >lexer->length ) { |
1526 | | // too short |
1527 | 0 | return character_pushback(lexer, GROUND_STATE); |
1528 | 0 | } |
1529 | | // don't count ID, length and checksum in payload length |
1530 | 0 | lexer->length -= 4; |
1531 | 0 | if (MAX_PACKET_LENGTH < lexer->length) { |
1532 | 0 | lexer->length = 0; |
1533 | 0 | return character_pushback(lexer, GROUND_STATE); |
1534 | 0 | } // else |
1535 | 0 | lexer->state = NAVCOM_LENGTH_2; |
1536 | 0 | break; |
1537 | 0 | case NAVCOM_LENGTH_2: |
1538 | 0 | if (0 == --lexer->length) { |
1539 | 0 | lexer->state = NAVCOM_PAYLOAD; |
1540 | 0 | } |
1541 | 0 | break; |
1542 | 0 | case NAVCOM_PAYLOAD: |
1543 | 0 | { |
1544 | 0 | unsigned char csum = lexer->inbuffer[3]; |
1545 | 0 | for (n = 4; |
1546 | 0 | (unsigned char *)(lexer->inbuffer + n) < lexer->inbufptr - 1; |
1547 | 0 | n++) |
1548 | 0 | csum ^= lexer->inbuffer[n]; |
1549 | 0 | if (csum != c) { |
1550 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
1551 | 0 | "Navcom packet type 0x%hhx bad checksum 0x%hhx, " |
1552 | 0 | "expecting 0x%x\n", |
1553 | 0 | lexer->inbuffer[3], csum, c); |
1554 | 0 | lexer->state = GROUND_STATE; |
1555 | 0 | break; |
1556 | 0 | } |
1557 | 0 | } |
1558 | 0 | lexer->state = NAVCOM_CSUM; |
1559 | 0 | break; |
1560 | 0 | case NAVCOM_CSUM: |
1561 | 0 | if (ETX == c) { // ETX (0x03) |
1562 | 0 | lexer->state = NAVCOM_RECOGNIZED; |
1563 | 0 | } else { |
1564 | 0 | return character_pushback(lexer, GROUND_STATE); |
1565 | 0 | } |
1566 | 0 | break; |
1567 | 0 | case NAVCOM_RECOGNIZED: |
1568 | 0 | if (STX == c) { // STX (0x02) |
1569 | 0 | lexer->state = NAVCOM_LEADER_1; |
1570 | 0 | } else { |
1571 | 0 | return character_pushback(lexer, GROUND_STATE); |
1572 | 0 | } |
1573 | 0 | break; |
1574 | 0 | #endif // NAVCOM_ENABLE |
1575 | 0 | #endif // TSIP_ENABLE || EVERMORE_ENABLE || GARMIN_ENABLE |
1576 | 0 | case RTCM3_LEADER_1: |
1577 | | // high 6 bits must be zero, low 2 bits are MSB of a 10-bit length |
1578 | 0 | if (0 == (c & 0xFC)) { |
1579 | 0 | lexer->length = (size_t)c << 8; |
1580 | 0 | lexer->state = RTCM3_LEADER_2; |
1581 | 0 | } else { |
1582 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
1583 | 0 | "RTCM3 must be zero bits aren't: %u\n", c & 0xFC); |
1584 | 0 | return character_pushback(lexer, GROUND_STATE); |
1585 | 0 | } |
1586 | 0 | break; |
1587 | 0 | case RTCM3_LEADER_2: |
1588 | | // third byte is the low 8 bits of the RTCM3 packet length |
1589 | 0 | lexer->length |= c; |
1590 | 0 | lexer->length += 3; // to get the three checksum bytes |
1591 | 0 | lexer->state = RTCM3_PAYLOAD; |
1592 | 0 | break; |
1593 | 0 | case RTCM3_PAYLOAD: |
1594 | 0 | if (0 == --lexer->length) { |
1595 | 0 | lexer->state = RTCM3_RECOGNIZED; |
1596 | 0 | } |
1597 | 0 | break; |
1598 | 0 | #ifdef ZODIAC_ENABLE |
1599 | 0 | case ZODIAC_EXPECTED: |
1600 | 0 | FALLTHROUGH |
1601 | 0 | case ZODIAC_RECOGNIZED: |
1602 | 0 | if (0xff == c) { // y with diaeresis |
1603 | 0 | lexer->state = ZODIAC_LEADER_1; |
1604 | 0 | } else { |
1605 | 0 | return character_pushback(lexer, GROUND_STATE); |
1606 | 0 | } |
1607 | 0 | break; |
1608 | 0 | case ZODIAC_LEADER_1: |
1609 | 0 | if (0x81 == c) { // latin1 non-printing |
1610 | 0 | lexer->state = ZODIAC_LEADER_2; |
1611 | 0 | } else { |
1612 | 0 | (void)character_pushback(lexer, GROUND_STATE); |
1613 | 0 | } |
1614 | 0 | break; |
1615 | 0 | case ZODIAC_LEADER_2: |
1616 | 0 | lexer->state = ZODIAC_ID_1; |
1617 | 0 | break; |
1618 | 0 | case ZODIAC_ID_1: |
1619 | 0 | lexer->state = ZODIAC_ID_2; |
1620 | 0 | break; |
1621 | 0 | case ZODIAC_ID_2: |
1622 | 0 | lexer->length = (size_t)c; |
1623 | 0 | lexer->state = ZODIAC_LENGTH_1; |
1624 | 0 | break; |
1625 | 0 | case ZODIAC_LENGTH_1: |
1626 | 0 | lexer->length += (c << 8); |
1627 | 0 | lexer->state = ZODIAC_LENGTH_2; |
1628 | 0 | break; |
1629 | 0 | case ZODIAC_LENGTH_2: |
1630 | 0 | lexer->state = ZODIAC_FLAGS_1; |
1631 | 0 | break; |
1632 | 0 | case ZODIAC_FLAGS_1: |
1633 | 0 | lexer->state = ZODIAC_FLAGS_2; |
1634 | 0 | break; |
1635 | 0 | case ZODIAC_FLAGS_2: |
1636 | 0 | lexer->state = ZODIAC_HSUM_1; |
1637 | 0 | break; |
1638 | 0 | case ZODIAC_HSUM_1: |
1639 | 0 | { |
1640 | 0 | short sum = getzword(0) + getzword(1) + getzword(2) + getzword(3); |
1641 | 0 | sum *= -1; |
1642 | 0 | if (sum != getzword(4)) { |
1643 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
1644 | 0 | "Zodiac Header checksum 0x%x expecting 0x%x\n", |
1645 | 0 | sum, getzword(4)); |
1646 | 0 | lexer->state = GROUND_STATE; |
1647 | 0 | break; |
1648 | 0 | } |
1649 | 0 | } |
1650 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
1651 | 0 | "Zodiac header id=%u len=%u flags=%x\n", |
1652 | 0 | getzuword(1), getzuword(2), getzuword(3)); |
1653 | 0 | if (0 == lexer->length) { |
1654 | 0 | lexer->state = ZODIAC_RECOGNIZED; |
1655 | 0 | break; |
1656 | 0 | } |
1657 | 0 | lexer->length *= 2; // word count to byte count |
1658 | 0 | lexer->length += 2; // checksum |
1659 | | // 10 bytes is the length of the Zodiac header |
1660 | | // no idea what Zodiac max length really is |
1661 | 0 | if ((MAX_PACKET_LENGTH - 10) < lexer->length) { |
1662 | 0 | lexer->length = 0; |
1663 | 0 | return character_pushback(lexer, GROUND_STATE); |
1664 | 0 | } // else |
1665 | 0 | lexer->state = ZODIAC_PAYLOAD; |
1666 | 0 | break; |
1667 | 0 | case ZODIAC_PAYLOAD: |
1668 | 0 | if (0 == --lexer->length) { |
1669 | 0 | lexer->state = ZODIAC_RECOGNIZED; |
1670 | 0 | } |
1671 | 0 | break; |
1672 | 0 | #endif // ZODIAC_ENABLE |
1673 | 0 | case UBX_LEADER_1: |
1674 | 0 | if ('b' == c) { // micro, b |
1675 | 0 | lexer->state = UBX_LEADER_2; |
1676 | 0 | } else { |
1677 | 0 | return character_pushback(lexer, GROUND_STATE); |
1678 | 0 | } |
1679 | 0 | break; |
1680 | 0 | case UBX_LEADER_2: |
1681 | 0 | lexer->state = UBX_CLASS_ID; |
1682 | 0 | break; |
1683 | 0 | case UBX_CLASS_ID: |
1684 | 0 | lexer->state = UBX_MESSAGE_ID; |
1685 | 0 | break; |
1686 | 0 | case UBX_MESSAGE_ID: |
1687 | 0 | lexer->length = (size_t)c; |
1688 | 0 | lexer->state = UBX_LENGTH_1; |
1689 | 0 | break; |
1690 | 0 | case UBX_LENGTH_1: |
1691 | 0 | lexer->length += (c << 8); |
1692 | 0 | if (0 == lexer->length) { |
1693 | | // no payload |
1694 | 0 | lexer->state = UBX_CHECKSUM_A; |
1695 | 0 | } else if (MAX_PACKET_LENGTH >= lexer->length) { |
1696 | | // normal size payload |
1697 | 0 | lexer->state = UBX_LENGTH_2; |
1698 | 0 | } else { |
1699 | | // bad length |
1700 | 0 | lexer->length = 0; |
1701 | 0 | return character_pushback(lexer, GROUND_STATE); |
1702 | 0 | } |
1703 | 0 | break; |
1704 | 0 | case UBX_LENGTH_2: |
1705 | 0 | lexer->state = UBX_PAYLOAD; |
1706 | 0 | break; |
1707 | 0 | case UBX_PAYLOAD: |
1708 | 0 | if (0 == --lexer->length) { |
1709 | 0 | lexer->state = UBX_CHECKSUM_A; |
1710 | 0 | } |
1711 | | // else stay in payload state |
1712 | 0 | break; |
1713 | 0 | case UBX_CHECKSUM_A: |
1714 | 0 | lexer->state = UBX_RECOGNIZED; |
1715 | 0 | break; |
1716 | 0 | case UBX_RECOGNIZED: |
1717 | 0 | if (MICRO == c) { // latin1 micro (0xb5) |
1718 | 0 | lexer->state = UBX_LEADER_1; |
1719 | 0 | } else if ('$' == c) { // LEA-5H can/will output NMEA/UBX back to back |
1720 | 0 | lexer->state = NMEA_DOLLAR; |
1721 | 0 | } else if ('{' == c) { |
1722 | | // codacy thinks this can never happen |
1723 | 0 | return character_pushback(lexer, JSON_LEADER); |
1724 | 0 | } else { |
1725 | 0 | return character_pushback(lexer, GROUND_STATE); |
1726 | 0 | } |
1727 | 0 | break; |
1728 | | |
1729 | | // start ALLYSTAR |
1730 | 0 | case ALLY_LEADER_1: |
1731 | 0 | if (0xd9 == c) { // latin capital letter U with grave |
1732 | | // got 2nd, of 2, bytes of leader |
1733 | 0 | lexer->state = ALLY_LEADER_2; |
1734 | 0 | } else { |
1735 | 0 | return character_pushback(lexer, GROUND_STATE); |
1736 | 0 | } |
1737 | 0 | break; |
1738 | 0 | case ALLY_LEADER_2: |
1739 | | // got 1 byte Class ID |
1740 | 0 | lexer->state = ALLY_CLASS_ID; |
1741 | 0 | break; |
1742 | 0 | case ALLY_CLASS_ID: |
1743 | | // got 1 byte Message ID |
1744 | 0 | lexer->state = ALLY_MESSAGE_ID; |
1745 | 0 | break; |
1746 | 0 | case ALLY_MESSAGE_ID: |
1747 | | // got 1st, of 2, bytes of length |
1748 | 0 | lexer->length = (size_t)c; |
1749 | 0 | lexer->state = ALLY_LENGTH_1; |
1750 | 0 | break; |
1751 | 0 | case ALLY_LENGTH_1: |
1752 | | // got 2nd, of 2, bytes of length |
1753 | 0 | lexer->length += (c << 8); |
1754 | 0 | if (MAX_PACKET_LENGTH <= lexer->length) { |
1755 | | // bad length |
1756 | 0 | lexer->length = 0; |
1757 | 0 | return character_pushback(lexer, GROUND_STATE); |
1758 | 0 | } // else |
1759 | | |
1760 | | /* no payload or normal size payload. |
1761 | | * no idea the real max. */ |
1762 | 0 | lexer->state = ALLY_PAYLOAD; |
1763 | 0 | break; |
1764 | 0 | case ALLY_PAYLOAD: |
1765 | 0 | if (0 == lexer->length) { |
1766 | | // got 1st, of 2, bytes of checksum |
1767 | 0 | lexer->state = ALLY_CHECKSUM_A; |
1768 | 0 | } // else stay in payload state |
1769 | |
|
1770 | 0 | if (0 < lexer->length) { |
1771 | | // Pacify Coverity 498037 about underflow |
1772 | 0 | lexer->length--; |
1773 | 0 | } // else something bad happened... |
1774 | 0 | break; |
1775 | 0 | case ALLY_CHECKSUM_A: |
1776 | | // got 2nd, of 2, bytes of checksum |
1777 | 0 | lexer->state = ALLY_RECOGNIZED; |
1778 | 0 | break; |
1779 | 0 | case ALLY_RECOGNIZED: |
1780 | 0 | if (0xf1 == c) { // latin1 small letter N with tilde |
1781 | 0 | lexer->state = ALLY_LEADER_1; |
1782 | 0 | } else if ('$' == c) { // LEA-5H can/will output NMEA/ALL back to back |
1783 | 0 | lexer->state = NMEA_DOLLAR; |
1784 | 0 | } else if ('{' == c) { |
1785 | | // codacy thinks this can never happen |
1786 | 0 | return character_pushback(lexer, JSON_LEADER); |
1787 | 0 | } else { |
1788 | 0 | return character_pushback(lexer, GROUND_STATE); |
1789 | 0 | } |
1790 | 0 | break; |
1791 | | // send ALLYSTAR |
1792 | | |
1793 | | // start CASIC |
1794 | 0 | case CASIC_LEADER_1: |
1795 | 0 | if (0xce == c) { // LATIN CAPITAL LETTER I WITH CIRCUMFLEX |
1796 | | // got 2nd, of 2, bytes of leader |
1797 | 0 | lexer->state = CASIC_LEADER_2; |
1798 | 0 | } else { |
1799 | 0 | return character_pushback(lexer, GROUND_STATE); |
1800 | 0 | } |
1801 | 0 | break; |
1802 | 0 | case CASIC_LEADER_2: |
1803 | | // got 1st, of 2, bytes of length |
1804 | 0 | lexer->length = (size_t)c; |
1805 | 0 | lexer->state = CASIC_LENGTH_1; |
1806 | 0 | break; |
1807 | 0 | case CASIC_LENGTH_1: |
1808 | | /* got 2nd, of 2, bytes of length |
1809 | | * Validate the length field, the driver and code at |
1810 | | * CASIC_RECOGNIZED require this. |
1811 | | * Max length seems to be RXM-SVPOS 1536 (packet total 1554) |
1812 | | * Their doc says payload "<2k bytes" |
1813 | | */ |
1814 | 0 | lexer->length += (c << 8); |
1815 | 0 | if (2048 <= lexer->length || |
1816 | 0 | 0 != (lexer->length % 4)) { |
1817 | | // bad length |
1818 | 0 | return character_pushback(lexer, GROUND_STATE); |
1819 | 0 | } // else |
1820 | | |
1821 | | /* no payload or normal size payload. */ |
1822 | 0 | lexer->state = CASIC_LENGTH_2; |
1823 | 0 | break; |
1824 | 0 | case CASIC_LENGTH_2: |
1825 | 0 | lexer->state = CASIC_CLASS_ID; |
1826 | 0 | break; |
1827 | 0 | case CASIC_CLASS_ID: |
1828 | 0 | lexer->state = CASIC_MESSAGE_ID; |
1829 | 0 | break; |
1830 | 0 | case CASIC_MESSAGE_ID: |
1831 | | // We're at the first byte of payload, or the first byte of |
1832 | | // checksum. Go directly to CASIC_PAYLOAD. |
1833 | 0 | lexer->state = CASIC_PAYLOAD; |
1834 | 0 | FALLTHROUGH |
1835 | 0 | case CASIC_PAYLOAD: |
1836 | 0 | if (0 == lexer->length) { |
1837 | | // got 1st, of 4, bytes of checksum |
1838 | 0 | lexer->state = CASIC_CHECKSUM_A; |
1839 | 0 | } else if (2048 <= lexer->length) { |
1840 | | /* RXM-SVPOS seems to have the longest length: 1552, use 2048 |
1841 | | * Their doc says payload "<2k bytes" |
1842 | | * how could this happen? |
1843 | | * stay in payload state */ |
1844 | 0 | lexer->length = 0; |
1845 | 0 | } else { |
1846 | | // more to go, stay in payload state, Coverity 498037 |
1847 | 0 | lexer->length--; |
1848 | 0 | } |
1849 | 0 | break; |
1850 | 0 | case CASIC_CHECKSUM_A: |
1851 | | // got 2nd, of 4, bytes of checksum |
1852 | 0 | lexer->state = CASIC_CHECKSUM_B; |
1853 | 0 | break; |
1854 | 0 | case CASIC_CHECKSUM_B: |
1855 | | // got 3rd, of 4, bytes of checksum |
1856 | 0 | lexer->state = CASIC_CHECKSUM_C; |
1857 | 0 | break; |
1858 | 0 | case CASIC_CHECKSUM_C: |
1859 | | // got 4th, of 4, bytes of checksum |
1860 | 0 | lexer->state = CASIC_RECOGNIZED; |
1861 | 0 | break; |
1862 | 0 | case CASIC_RECOGNIZED: |
1863 | 0 | if (0xba == c) { // latin1 MASCULINE ORDINAL INDICATOR |
1864 | 0 | lexer->state = CASIC_LEADER_1; |
1865 | 0 | } else if ('$' == c) { |
1866 | | // CASIC can/will output NMEA/CASIC back to back |
1867 | 0 | lexer->state = NMEA_DOLLAR; |
1868 | 0 | } else if ('{' == c) { |
1869 | | // JSON |
1870 | 0 | return character_pushback(lexer, JSON_LEADER); |
1871 | 0 | } |
1872 | | // Unknown.. |
1873 | 0 | return character_pushback(lexer, GROUND_STATE); |
1874 | 0 | break; |
1875 | | // end CASIC |
1876 | 0 | #ifdef EVERMORE_ENABLE |
1877 | 0 | case EVERMORE_LEADER_1: |
1878 | 0 | if (STX == c) { // DLE, STX |
1879 | 0 | lexer->state = EVERMORE_LEADER_2; |
1880 | 0 | } else { |
1881 | 0 | return character_pushback(lexer, GROUND_STATE); |
1882 | 0 | } |
1883 | 0 | break; |
1884 | 0 | case EVERMORE_LEADER_2: |
1885 | 0 | lexer->length = (size_t)c; |
1886 | 0 | if (DLE == c) { |
1887 | 0 | lexer->state = EVERMORE_PAYLOAD_DLE; |
1888 | 0 | } else { |
1889 | 0 | lexer->state = EVERMORE_PAYLOAD; |
1890 | 0 | } |
1891 | 0 | break; |
1892 | 0 | case EVERMORE_PAYLOAD: |
1893 | 0 | if (DLE == c) { |
1894 | | // Evermore doubles DLE's |
1895 | 0 | lexer->state = EVERMORE_PAYLOAD_DLE; |
1896 | 0 | } else if (0 == --lexer->length) { |
1897 | 0 | return character_pushback(lexer, GROUND_STATE); |
1898 | 0 | } |
1899 | 0 | break; |
1900 | 0 | case EVERMORE_PAYLOAD_DLE: |
1901 | 0 | switch (c) { |
1902 | 0 | case DLE: |
1903 | 0 | lexer->state = EVERMORE_PAYLOAD; |
1904 | 0 | break; |
1905 | 0 | case ETX: |
1906 | 0 | lexer->state = EVERMORE_RECOGNIZED; |
1907 | 0 | break; |
1908 | 0 | default: |
1909 | 0 | lexer->state = GROUND_STATE; |
1910 | 0 | } |
1911 | 0 | break; |
1912 | 0 | case EVERMORE_RECOGNIZED: |
1913 | 0 | if (DLE == c) { |
1914 | 0 | lexer->state = EVERMORE_LEADER_1; |
1915 | 0 | } else { |
1916 | 0 | return character_pushback(lexer, GROUND_STATE); |
1917 | 0 | } |
1918 | 0 | break; |
1919 | 0 | #endif // EVERMORE_ENABLE |
1920 | 0 | #ifdef ITRAX_ENABLE |
1921 | 0 | case ITALK_LEADER_1: |
1922 | 0 | if ('!' == c) { // <! |
1923 | 0 | lexer->state = ITALK_LEADER_2; |
1924 | 0 | } else { |
1925 | 0 | return character_pushback(lexer, GROUND_STATE); |
1926 | 0 | } |
1927 | 0 | break; |
1928 | 0 | case ITALK_LEADER_2: |
1929 | 0 | lexer->length = (size_t)(lexer->inbuffer[6] & 0xff); |
1930 | 0 | lexer->state = ITALK_LENGTH; |
1931 | 0 | break; |
1932 | 0 | case ITALK_LENGTH: |
1933 | 0 | lexer->length += 1; // fix number of words in payload |
1934 | 0 | lexer->length *= 2; // convert to number of bytes |
1935 | 0 | lexer->length += 3; // add trailer length |
1936 | 0 | lexer->state = ITALK_PAYLOAD; |
1937 | 0 | break; |
1938 | 0 | case ITALK_PAYLOAD: |
1939 | | // lookahead for "<!" because sometimes packets are short but valid |
1940 | 0 | if (('>' == c) && |
1941 | 0 | ('<' == lexer->inbufptr[0]) && |
1942 | 0 | ('!' == lexer->inbufptr[1])) { |
1943 | 0 | lexer->state = ITALK_RECOGNIZED; |
1944 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
1945 | 0 | "ITALK: trying to process runt packet\n"); |
1946 | 0 | } else if (0 == --lexer->length) { |
1947 | 0 | lexer->state = ITALK_DELIVERED; |
1948 | 0 | } |
1949 | 0 | break; |
1950 | 0 | case ITALK_DELIVERED: |
1951 | 0 | if ('>' == c) { |
1952 | 0 | lexer->state = ITALK_RECOGNIZED; |
1953 | 0 | } else { |
1954 | 0 | return character_pushback(lexer, GROUND_STATE); |
1955 | 0 | } |
1956 | 0 | break; |
1957 | 0 | case ITALK_RECOGNIZED: |
1958 | 0 | if ('<' == c) { |
1959 | 0 | lexer->state = ITALK_LEADER_1; |
1960 | 0 | } else { |
1961 | 0 | return character_pushback(lexer, GROUND_STATE); |
1962 | 0 | } |
1963 | 0 | break; |
1964 | 0 | #endif // ITRAX_ENABLE |
1965 | 0 | #ifdef GEOSTAR_ENABLE |
1966 | 0 | case GEOSTAR_LEADER_1: |
1967 | 0 | if ('S' == c) { // PS |
1968 | 0 | lexer->state = GEOSTAR_LEADER_2; |
1969 | 0 | } else { |
1970 | 0 | return character_pushback(lexer, GROUND_STATE); |
1971 | 0 | } |
1972 | 0 | break; |
1973 | 0 | case GEOSTAR_LEADER_2: |
1974 | 0 | if ('G' == c) { // PSG |
1975 | 0 | lexer->state = GEOSTAR_LEADER_3; |
1976 | 0 | } else { |
1977 | 0 | return character_pushback(lexer, GROUND_STATE); |
1978 | 0 | } |
1979 | 0 | break; |
1980 | 0 | case GEOSTAR_LEADER_3: |
1981 | 0 | if ('G' == c) { // PSGG |
1982 | 0 | lexer->state = GEOSTAR_LEADER_4; |
1983 | 0 | } else { |
1984 | 0 | return character_pushback(lexer, GROUND_STATE); |
1985 | 0 | } |
1986 | 0 | break; |
1987 | 0 | case GEOSTAR_LEADER_4: |
1988 | 0 | lexer->state = GEOSTAR_MESSAGE_ID_1; |
1989 | 0 | break; |
1990 | 0 | case GEOSTAR_MESSAGE_ID_1: |
1991 | 0 | lexer->state = GEOSTAR_MESSAGE_ID_2; |
1992 | 0 | break; |
1993 | 0 | case GEOSTAR_MESSAGE_ID_2: |
1994 | 0 | lexer->length = c * 4; |
1995 | 0 | lexer->state = GEOSTAR_LENGTH_1; |
1996 | 0 | break; |
1997 | 0 | case GEOSTAR_LENGTH_1: |
1998 | 0 | lexer->length += (c << 8) * 4; |
1999 | 0 | if (MAX_PACKET_LENGTH < lexer->length) { |
2000 | 0 | lexer->length = 0; |
2001 | 0 | return character_pushback(lexer, GROUND_STATE); |
2002 | 0 | } // else |
2003 | 0 | lexer->state = GEOSTAR_LENGTH_2; |
2004 | 0 | break; |
2005 | 0 | case GEOSTAR_LENGTH_2: |
2006 | 0 | lexer->state = GEOSTAR_PAYLOAD; |
2007 | 0 | break; |
2008 | 0 | case GEOSTAR_PAYLOAD: |
2009 | 0 | if (0 == --lexer->length) { |
2010 | 0 | lexer->state = GEOSTAR_CHECKSUM_A; |
2011 | 0 | } |
2012 | | // else stay in payload state |
2013 | 0 | break; |
2014 | 0 | case GEOSTAR_CHECKSUM_A: |
2015 | 0 | lexer->state = GEOSTAR_CHECKSUM_B; |
2016 | 0 | break; |
2017 | 0 | case GEOSTAR_CHECKSUM_B: |
2018 | 0 | lexer->state = GEOSTAR_CHECKSUM_C; |
2019 | 0 | break; |
2020 | 0 | case GEOSTAR_CHECKSUM_C: |
2021 | 0 | lexer->state = GEOSTAR_RECOGNIZED; |
2022 | 0 | break; |
2023 | 0 | case GEOSTAR_RECOGNIZED: |
2024 | 0 | if ('P' == c) { // P |
2025 | 0 | lexer->state = GEOSTAR_LEADER_1; |
2026 | 0 | } else { |
2027 | 0 | return character_pushback(lexer, GROUND_STATE); |
2028 | 0 | } |
2029 | 0 | break; |
2030 | 0 | #endif // GEOSTAR_ENABLE |
2031 | 0 | #ifdef GREIS_ENABLE |
2032 | 0 | case GREIS_EXPECTED: |
2033 | 0 | FALLTHROUGH |
2034 | 0 | case GREIS_RECOGNIZED: |
2035 | 0 | if (!isascii(c)) { |
2036 | 0 | return character_pushback(lexer, GROUND_STATE); |
2037 | 0 | } |
2038 | 0 | if ('#' == c) { |
2039 | | // Probably a comment used by the testsuite |
2040 | 0 | lexer->state = COMMENT_BODY; |
2041 | 0 | } else if ('\n' == c || |
2042 | 0 | '\r' == c) { |
2043 | | // Arbitrary CR/LF allowed here, so continue to expect GREIS |
2044 | 0 | lexer->state = GREIS_EXPECTED; |
2045 | 0 | character_discard(lexer); |
2046 | 0 | } else { |
2047 | 0 | lexer->state = GREIS_ID_1; |
2048 | 0 | } |
2049 | 0 | break; |
2050 | 0 | case GREIS_REPLY_1: |
2051 | 0 | if ('E' != c) { // RE |
2052 | 0 | return character_pushback(lexer, GROUND_STATE); |
2053 | 0 | } |
2054 | 0 | lexer->state = GREIS_REPLY_2; |
2055 | 0 | break; |
2056 | 0 | case GREIS_ID_1: |
2057 | 0 | if (!isascii(c)) { |
2058 | 0 | return character_pushback(lexer, GROUND_STATE); |
2059 | 0 | } |
2060 | 0 | lexer->state = GREIS_ID_2; |
2061 | 0 | break; |
2062 | 0 | case GREIS_REPLY_2: |
2063 | 0 | FALLTHROUGH |
2064 | 0 | case GREIS_ID_2: |
2065 | 0 | if (!isxdigit(c)) { |
2066 | 0 | return character_pushback(lexer, GROUND_STATE); |
2067 | 0 | } |
2068 | 0 | lexer->length = greis_hex2bin(c) << 8; |
2069 | 0 | lexer->state = GREIS_LENGTH_1; |
2070 | 0 | break; |
2071 | 0 | case GREIS_LENGTH_1: |
2072 | 0 | if (!isxdigit(c)) { |
2073 | 0 | return character_pushback(lexer, GROUND_STATE); |
2074 | 0 | } |
2075 | 0 | lexer->length += greis_hex2bin(c) << 4; |
2076 | 0 | lexer->state = GREIS_LENGTH_2; |
2077 | 0 | break; |
2078 | 0 | case GREIS_LENGTH_2: |
2079 | 0 | if (!isxdigit(c)) { |
2080 | 0 | return character_pushback(lexer, GROUND_STATE); |
2081 | 0 | } |
2082 | 0 | lexer->length += greis_hex2bin(c); |
2083 | 0 | lexer->state = GREIS_PAYLOAD; |
2084 | 0 | break; |
2085 | 0 | case GREIS_PAYLOAD: |
2086 | 0 | if (0 == --lexer->length) { |
2087 | 0 | lexer->state = GREIS_RECOGNIZED; |
2088 | 0 | } |
2089 | | // else stay in payload state |
2090 | 0 | break; |
2091 | 0 | #endif // GREIS_ENABLE |
2092 | 0 | #ifdef TSIP_ENABLE |
2093 | 0 | case TSIP_LEADER: |
2094 | | // unused case. see TSIP_RECOGNIZED |
2095 | 0 | if (0x13 <= c) { // DC3 |
2096 | 0 | lexer->length = TSIP_MAX_PACKET; |
2097 | 0 | lexer->state = TSIP_PAYLOAD; |
2098 | 0 | } else { |
2099 | 0 | return character_pushback(lexer, GROUND_STATE); |
2100 | 0 | } |
2101 | 0 | break; |
2102 | 0 | case TSIP_PAYLOAD: |
2103 | 0 | if (DLE == c) { |
2104 | 0 | lexer->state = TSIP_DLE; |
2105 | 0 | } |
2106 | 0 | if (0 == --lexer->length ) { |
2107 | | // uh, oh, packet too long, probably was never TSIP |
2108 | | // note lexer->length is unsigned |
2109 | 0 | lexer->state = GROUND_STATE; |
2110 | 0 | } |
2111 | 0 | break; |
2112 | 0 | case TSIP_DLE: |
2113 | 0 | switch (c) { |
2114 | 0 | case ETX: |
2115 | 0 | lexer->state = TSIP_RECOGNIZED; |
2116 | 0 | break; |
2117 | 0 | case DLE: |
2118 | 0 | lexer->length = TSIP_MAX_PACKET; |
2119 | 0 | lexer->state = TSIP_PAYLOAD; |
2120 | 0 | break; |
2121 | 0 | default: |
2122 | 0 | lexer->state = GROUND_STATE; |
2123 | 0 | break; |
2124 | 0 | } |
2125 | 0 | break; |
2126 | 0 | case TSIP_RECOGNIZED: |
2127 | 0 | if (DLE == c) { |
2128 | | /* |
2129 | | * Don't go to TSIP_LEADER state -- TSIP packets aren't |
2130 | | * checksummed, so false positives are easy. We might be |
2131 | | * looking at another DLE-stuffed protocol like EverMore |
2132 | | * or Garmin streaming binary. |
2133 | | */ |
2134 | 0 | lexer->state = DLE_LEADER; |
2135 | 0 | } else { |
2136 | 0 | return character_pushback(lexer, GROUND_STATE); |
2137 | 0 | } |
2138 | 0 | break; |
2139 | 0 | #endif // TSIP_ENABLE |
2140 | 0 | case RTCM2_SYNC_STATE: |
2141 | 0 | FALLTHROUGH |
2142 | 0 | case RTCM2_SKIP_STATE: |
2143 | 0 | if (ISGPS_MESSAGE == (isgpsstat = rtcm2_decode(lexer, c))) { |
2144 | 0 | lexer->state = RTCM2_RECOGNIZED; |
2145 | 0 | } else if (ISGPS_NO_SYNC == isgpsstat) { |
2146 | 0 | lexer->state = GROUND_STATE; |
2147 | 0 | } |
2148 | 0 | break; |
2149 | | |
2150 | 0 | case RTCM2_RECOGNIZED: |
2151 | 0 | if ('#' == c) { |
2152 | | /* |
2153 | | * There's a remote possibility this could fire when # = |
2154 | | * 0x23 is legitimate in-stream RTCM2 data. No help for |
2155 | | * it, the test framework needs this case so it can inject |
2156 | | * # EOF and we'll miss a packet. |
2157 | | */ |
2158 | 0 | return character_pushback(lexer, GROUND_STATE); |
2159 | 0 | } |
2160 | 0 | if (ISGPS_SYNC == rtcm2_decode(lexer, c)) { |
2161 | 0 | lexer->state = RTCM2_SYNC_STATE; |
2162 | 0 | } else { |
2163 | 0 | lexer->state = GROUND_STATE; |
2164 | 0 | } |
2165 | 0 | break; |
2166 | 0 | case JSON_LEADER: |
2167 | 0 | switch (c) { |
2168 | 0 | case '{': |
2169 | 0 | FALLTHROUGH |
2170 | 0 | case '[': |
2171 | 0 | lexer->json_depth++; |
2172 | 0 | break; |
2173 | 0 | case '}': |
2174 | 0 | FALLTHROUGH |
2175 | 0 | case ']': |
2176 | 0 | if (0 == --lexer->json_depth) { |
2177 | 0 | lexer->state = JSON_RECOGNIZED; |
2178 | 0 | } |
2179 | 0 | break; |
2180 | 0 | case ',': |
2181 | 0 | break; |
2182 | 0 | case '"': |
2183 | 0 | lexer->state = JSON_STRINGLITERAL; |
2184 | 0 | lexer->json_after = JSON_END_ATTRIBUTE; |
2185 | 0 | break; |
2186 | 0 | default: |
2187 | 0 | if (isspace(c)) { |
2188 | 0 | break; |
2189 | 0 | } |
2190 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
2191 | 0 | "%08ld: missing attribute start after header\n", |
2192 | 0 | lexer->char_counter); |
2193 | 0 | lexer->state = GROUND_STATE; |
2194 | 0 | } |
2195 | 0 | break; |
2196 | 0 | case JSON_STRINGLITERAL: |
2197 | 0 | if ('\\' == c) { |
2198 | 0 | lexer->state = JSON_STRING_SOLIDUS; |
2199 | 0 | } else if ('"' == c) { |
2200 | 0 | lexer->state = lexer->json_after; |
2201 | 0 | } |
2202 | 0 | break; |
2203 | 0 | case JSON_STRING_SOLIDUS: |
2204 | 0 | lexer->state = JSON_STRINGLITERAL; |
2205 | 0 | break; |
2206 | 0 | case JSON_END_ATTRIBUTE: |
2207 | 0 | if (isspace(c)) { |
2208 | 0 | break; |
2209 | 0 | } |
2210 | 0 | if (':' == c) { |
2211 | 0 | lexer->state = JSON_EXPECT_VALUE; |
2212 | 0 | } else { |
2213 | | // saw something other than value start after colon |
2214 | 0 | return character_pushback(lexer, GROUND_STATE); |
2215 | 0 | } |
2216 | 0 | break; |
2217 | 0 | case JSON_EXPECT_VALUE: |
2218 | 0 | if (isspace(c)) { |
2219 | 0 | break; |
2220 | 0 | } |
2221 | 0 | switch (c) { |
2222 | 0 | case '"': |
2223 | 0 | lexer->state = JSON_STRINGLITERAL; |
2224 | 0 | lexer->json_after = JSON_END_VALUE; |
2225 | 0 | break; |
2226 | 0 | case '{': |
2227 | 0 | FALLTHROUGH |
2228 | 0 | case '[': |
2229 | 0 | return character_pushback(lexer, JSON_LEADER); |
2230 | 0 | break; |
2231 | 0 | case '-': |
2232 | 0 | FALLTHROUGH |
2233 | 0 | case '0': |
2234 | 0 | FALLTHROUGH |
2235 | 0 | case '1': |
2236 | 0 | FALLTHROUGH |
2237 | 0 | case '2': |
2238 | 0 | FALLTHROUGH |
2239 | 0 | case '3': |
2240 | 0 | FALLTHROUGH |
2241 | 0 | case '4': |
2242 | 0 | FALLTHROUGH |
2243 | 0 | case '5': |
2244 | 0 | FALLTHROUGH |
2245 | 0 | case '6': |
2246 | 0 | FALLTHROUGH |
2247 | 0 | case '7': |
2248 | 0 | FALLTHROUGH |
2249 | 0 | case '8': |
2250 | 0 | FALLTHROUGH |
2251 | 0 | case '9': |
2252 | 0 | lexer->state = JSON_NUMBER; |
2253 | 0 | break; |
2254 | 0 | case 'f': |
2255 | 0 | FALLTHROUGH |
2256 | 0 | case 'n': |
2257 | 0 | FALLTHROUGH |
2258 | 0 | case 't': |
2259 | | /* |
2260 | | * This is a bit more permissive than strictly necessary, as |
2261 | | * GPSD JSON does not include the null token. Still, it's |
2262 | | * futureproofing. |
2263 | | */ |
2264 | 0 | lexer->state = JSON_SPECIAL; |
2265 | 0 | break; |
2266 | 0 | default: |
2267 | | // couldn't recognize start of value literal |
2268 | 0 | return character_pushback(lexer, GROUND_STATE); |
2269 | 0 | } |
2270 | 0 | break; |
2271 | 0 | case JSON_NUMBER: |
2272 | | /* |
2273 | | * Will recognize some ill-formed numeric literals. |
2274 | | * Should be OK as we're already three stages deep inside |
2275 | | * JSON recognition; odds that we'll actually see an |
2276 | | * ill-formed literal are quite low. and the worst |
2277 | | * possible result if it happens is our JSON parser will |
2278 | | * quietly chuck out the object. |
2279 | | */ |
2280 | 0 | if (NULL == strchr("1234567890.eE+-", c)) { |
2281 | 0 | return character_pushback(lexer, JSON_END_VALUE); |
2282 | 0 | } |
2283 | 0 | break; |
2284 | 0 | case JSON_SPECIAL: |
2285 | 0 | if (NULL == strchr("truefalsnil", c)) { |
2286 | 0 | return character_pushback(lexer, JSON_END_VALUE); |
2287 | 0 | } |
2288 | 0 | break; |
2289 | 0 | case JSON_END_VALUE: |
2290 | 0 | if (isspace(c)) { |
2291 | 0 | break; |
2292 | 0 | } |
2293 | 0 | if ('}' == c || |
2294 | 0 | ']' == c) { |
2295 | 0 | return character_pushback(lexer, JSON_LEADER); |
2296 | 0 | } |
2297 | 0 | if (',' != c) { |
2298 | | // trailing garbage after JSON value |
2299 | 0 | return character_pushback(lexer, GROUND_STATE); |
2300 | 0 | } |
2301 | 0 | lexer->state = JSON_LEADER; |
2302 | 0 | break; |
2303 | 0 | #ifdef STASH_ENABLE |
2304 | 0 | case STASH_RECOGNIZED: |
2305 | 0 | if ('$' != c) { |
2306 | 0 | return character_pushback(lexer, GROUND_STATE); |
2307 | 0 | } |
2308 | 0 | lexer->state = NMEA_DOLLAR; |
2309 | 0 | break; |
2310 | 0 | #endif // STASH_ENABLE |
2311 | 0 | } |
2312 | | |
2313 | | /* Catch length overflow. Should not happen. |
2314 | | * length is size_t, so underflow looks like overflow too. */ |
2315 | 0 | if (MAX_PACKET_LENGTH <= lexer->length) { |
2316 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
2317 | 0 | "Too long: %zu state %u %s c x%x\n", |
2318 | 0 | lexer->length, lexer->state, state_table[lexer->state], c); |
2319 | | // exit(255); |
2320 | 0 | lexer->length = 0; |
2321 | 0 | return character_pushback(lexer, GROUND_STATE); |
2322 | 0 | } |
2323 | 0 | return true; // no pushback |
2324 | 0 | } |
2325 | | |
2326 | | // packet grab succeeded, move to output buffer |
2327 | | static void packet_accept(struct gps_lexer_t *lexer, int packet_type) |
2328 | 0 | { |
2329 | 0 | size_t packetlen = lexer->inbufptr - lexer->inbuffer; |
2330 | |
|
2331 | 0 | if (sizeof(lexer->outbuffer) > packetlen) { |
2332 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
2333 | |
|
2334 | 0 | memcpy(lexer->outbuffer, lexer->inbuffer, packetlen); |
2335 | 0 | lexer->outbuflen = packetlen; |
2336 | 0 | lexer->outbuffer[packetlen] = '\0'; |
2337 | 0 | lexer->type = packet_type; |
2338 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
2339 | 0 | "Packet type %d accepted %zu = %s\n", |
2340 | 0 | packet_type, packetlen, |
2341 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
2342 | 0 | lexer->outbuffer, |
2343 | 0 | lexer->outbuflen)); |
2344 | 0 | } else { |
2345 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
2346 | 0 | "Rejected too long packet type %d len %zu\n", |
2347 | 0 | packet_type, packetlen); |
2348 | 0 | } |
2349 | 0 | } |
2350 | | |
2351 | | // shift the input buffer to discard all data up to current input pointer |
2352 | | static void packet_discard(struct gps_lexer_t *lexer) |
2353 | 0 | { |
2354 | 0 | size_t discard = lexer->inbufptr - lexer->inbuffer; |
2355 | 0 | size_t remaining = lexer->inbuflen - discard; |
2356 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
2357 | |
|
2358 | 0 | if (sizeof(lexer->inbuffer) < discard) { |
2359 | | // Huh? |
2360 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
2361 | 0 | "packet_discard() of %zu??\n", discard); |
2362 | 0 | lexer->inbufptr = lexer->inbuffer; |
2363 | 0 | lexer->inbuflen = 0; |
2364 | 0 | return; |
2365 | 0 | } // else |
2366 | | |
2367 | 0 | lexer->inbufptr = memmove(lexer->inbuffer, lexer->inbufptr, remaining); |
2368 | 0 | lexer->inbuflen = remaining; |
2369 | |
|
2370 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
2371 | 0 | "packet_discard() of %zu, chars remaining is %zu = %s\n", |
2372 | 0 | discard, remaining, |
2373 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
2374 | 0 | lexer->inbuffer, lexer->inbuflen)); |
2375 | 0 | } |
2376 | | |
2377 | | #ifdef STASH_ENABLE |
2378 | | // See test/daemon/isync.log for why the stash is needed. |
2379 | | |
2380 | | // stash the input buffer up to current input pointer |
2381 | | static void packet_stash(struct gps_lexer_t *lexer) |
2382 | 0 | { |
2383 | 0 | size_t stashlen = lexer->inbufptr - lexer->inbuffer; |
2384 | |
|
2385 | 0 | if (sizeof(lexer->stashbuffer) < stashlen) { |
2386 | | // too big! |
2387 | 0 | stashlen = 0; |
2388 | 0 | lexer->stashbuffer[0] = '\0'; |
2389 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
2390 | 0 | "packet_stash: too big, discarding.\n"); |
2391 | 0 | } else { |
2392 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
2393 | |
|
2394 | 0 | memcpy(lexer->stashbuffer, lexer->inbuffer, stashlen); |
2395 | |
|
2396 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
2397 | 0 | "Packet stash of %zu = %s\n", |
2398 | 0 | stashlen, |
2399 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
2400 | 0 | lexer->stashbuffer, stashlen)); |
2401 | 0 | } |
2402 | 0 | lexer->stashbuflen = stashlen; |
2403 | 0 | } |
2404 | | |
2405 | | // return stash to start of input buffer |
2406 | | static void packet_unstash(struct gps_lexer_t *lexer) |
2407 | 0 | { |
2408 | 0 | size_t available = sizeof(lexer->inbuffer) - lexer->inbuflen; |
2409 | 0 | size_t stashlen = lexer->stashbuflen; |
2410 | |
|
2411 | 0 | if (stashlen <= available) { |
2412 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
2413 | |
|
2414 | 0 | memmove(lexer->inbuffer + stashlen, lexer->inbuffer, lexer->inbuflen); |
2415 | 0 | memcpy(lexer->inbuffer, lexer->stashbuffer, stashlen); |
2416 | 0 | lexer->inbuflen += stashlen; |
2417 | 0 | lexer->stashbuflen = 0; |
2418 | |
|
2419 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
2420 | 0 | "Packet unstash of %zu, reconstructed is %zu = %s\n", |
2421 | 0 | stashlen, lexer->inbuflen, |
2422 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
2423 | 0 | lexer->inbuffer, lexer->inbuflen)); |
2424 | 0 | } else { |
2425 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
2426 | 0 | "Rejected too long unstash of %zu\n", stashlen); |
2427 | 0 | lexer->stashbuflen = 0; |
2428 | 0 | } |
2429 | 0 | } |
2430 | | #endif // STASH_ENABLE |
2431 | | |
2432 | | // entry points begin here |
2433 | | |
2434 | | // reset lexer structure |
2435 | | void lexer_init(struct gps_lexer_t *lexer, struct gpsd_errout_t *errout) |
2436 | 0 | { |
2437 | 0 | memset(lexer, 0, sizeof(struct gps_lexer_t)); |
2438 | | /* let memset() do all the zeros |
2439 | | * |
2440 | | * lexer->char_counter = 0; |
2441 | | * lexer->retry_counter = 0; |
2442 | | * lexer->json_depth = 0; |
2443 | | * lexer->start_time.tv_sec = 0; |
2444 | | * lexer->start_time.tv_nsec = 0; |
2445 | | */ |
2446 | | // set start_time to help out autobaud. |
2447 | 0 | (void)clock_gettime(CLOCK_REALTIME, &lexer->start_time); |
2448 | | // No SPARTN decode by default. |
2449 | 0 | lexer->type_mask = PACKET_TYPEMASK(SPARTN_PACKET); |
2450 | 0 | packet_reset(lexer); |
2451 | 0 | lexer->errout = *errout; // srtucture copy |
2452 | 0 | } |
2453 | | |
2454 | | // grab one packet from inbufptr |
2455 | | // move it to outbuffer[0], set outbuflen, and add a NUL. |
2456 | | // adjust pointers and lengths, then return |
2457 | | void packet_parse(struct gps_lexer_t *lexer) |
2458 | 0 | { |
2459 | |
|
2460 | 0 | lexer->outbuflen = 0; |
2461 | 0 | while (0 < packet_buffered_input(lexer)) { |
2462 | 0 | unsigned char c = *lexer->inbufptr++; |
2463 | 0 | unsigned int oldstate = lexer->state; |
2464 | 0 | unsigned inbuflen; // bytes in inbuffer for message |
2465 | 0 | unsigned idx; // index into inbuffer |
2466 | 0 | unsigned crc_computed; // the CRC/checksum we computed |
2467 | 0 | unsigned crc_expected; // the CRC/checksum the message claims to have |
2468 | 0 | enum {PASS, ACCEPT} acc_dis; |
2469 | 0 | int packet_type; // gpsd packet type |
2470 | 0 | unsigned pkt_id; // native type or ID the message thinks it is |
2471 | 0 | unsigned data_len; // What the message says the data length is. |
2472 | 0 | unsigned char ck_a, ck_b; // for ubx check bytes |
2473 | 0 | #ifdef STASH_ENABLE |
2474 | 0 | bool unstash = false; |
2475 | 0 | #endif // STASH_ENABLE |
2476 | |
|
2477 | 0 | if (!nextstate(lexer, c)) { |
2478 | 0 | continue; |
2479 | 0 | } |
2480 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
2481 | 0 | "%08ld: character '%c' [%02x], %s -> %s\n", |
2482 | 0 | lexer->char_counter, (isprint(c) ? c : '.'), c, |
2483 | 0 | state_table[oldstate], state_table[lexer->state]); |
2484 | 0 | lexer->char_counter++; |
2485 | 0 | inbuflen = lexer->inbufptr - lexer->inbuffer; |
2486 | 0 | acc_dis = PASS; |
2487 | | |
2488 | | /* check if we have a _RECOGNISED state, if so, perform final |
2489 | | * checks on the packet, before decoding. |
2490 | | * Cases alpha sorted to be easy to find. */ |
2491 | 0 | switch (lexer->state) { |
2492 | 0 | case AIS_RECOGNIZED: |
2493 | 0 | acc_dis = ACCEPT; |
2494 | 0 | if (!nmea_checksum(&lexer->errout, |
2495 | 0 | (const char *)lexer->inbuffer, |
2496 | 0 | (const char *)lexer->inbufptr)) { |
2497 | 0 | packet_type = BAD_PACKET; |
2498 | 0 | lexer->state = GROUND_STATE; |
2499 | 0 | break; |
2500 | 0 | } |
2501 | 0 | packet_type = AIVDM_PACKET; |
2502 | 0 | break; |
2503 | | |
2504 | 0 | case ALLY_RECOGNIZED: |
2505 | | // ALLYSTAR use a TCP like checksum, 8-bit Fletcher Algorithm |
2506 | 0 | ck_a = (unsigned char)0; |
2507 | 0 | ck_b = (unsigned char)0; |
2508 | | // payload length |
2509 | 0 | data_len = getleu16(lexer->inbuffer, 4); |
2510 | |
|
2511 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, "ALLY: buflen %d. paylen %u\n", |
2512 | 0 | inbuflen, data_len); |
2513 | 0 | if (inbuflen < (data_len + 8)) { |
2514 | 0 | GPSD_LOG(LOG_INFO, &lexer->errout, |
2515 | 0 | "ALLY: bad length %d/%u\n", |
2516 | 0 | inbuflen, data_len); |
2517 | 0 | packet_type = BAD_PACKET; |
2518 | 0 | lexer->state = GROUND_STATE; |
2519 | 0 | acc_dis = ACCEPT; |
2520 | 0 | break; |
2521 | 0 | } |
2522 | | // from class ID (byte 2), msg ID, length, to end of payload |
2523 | 0 | for (idx = 0; idx < (data_len + 4); idx++) { |
2524 | 0 | ck_a += lexer->inbuffer[idx + 2]; |
2525 | 0 | ck_b += ck_a; |
2526 | 0 | } |
2527 | 0 | if (ck_a == lexer->inbuffer[data_len + 6] && |
2528 | 0 | ck_b == lexer->inbuffer[data_len + 7]) { |
2529 | 0 | packet_type = ALLYSTAR_PACKET; |
2530 | 0 | } else { |
2531 | 0 | char scratchbuf[200]; |
2532 | |
|
2533 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
2534 | 0 | "ALLY: bad checksum 0x%02hhx%02hhx length %d/%u" |
2535 | 0 | ", %s\n", |
2536 | 0 | ck_a, |
2537 | 0 | ck_b, |
2538 | 0 | inbuflen, data_len, |
2539 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
2540 | 0 | lexer->inbuffer, lexer->inbuflen)); |
2541 | 0 | packet_type = BAD_PACKET; |
2542 | 0 | lexer->state = GROUND_STATE; |
2543 | 0 | } |
2544 | 0 | acc_dis = ACCEPT; |
2545 | 0 | break; |
2546 | | |
2547 | 0 | case CASIC_RECOGNIZED: |
2548 | | /* Payload length. This field has already been partially |
2549 | | * validated in nextstate(). */ |
2550 | 0 | data_len = getleu16(lexer->inbuffer, 2); |
2551 | 0 | if (inbuflen < (data_len + 10)) { |
2552 | 0 | GPSD_LOG(LOG_INFO, &lexer->errout, |
2553 | 0 | "CASIC: bad length %d/%u\n", |
2554 | 0 | inbuflen, data_len); |
2555 | 0 | packet_type = BAD_PACKET; |
2556 | 0 | lexer->state = GROUND_STATE; |
2557 | 0 | acc_dis = ACCEPT; |
2558 | 0 | break; |
2559 | 0 | } |
2560 | 0 | crc_computed = casic_checksum(lexer->inbuffer + 2, data_len + 4); |
2561 | 0 | crc_expected = getleu32(lexer->inbuffer, data_len + 6); |
2562 | 0 | if (crc_computed == crc_expected) { |
2563 | 0 | packet_type = CASIC_PACKET; |
2564 | 0 | } else { |
2565 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2566 | 0 | "CASIC checksum 0x%04x over length %d," |
2567 | 0 | " expecting 0x%04x (type 0x%02hhx%02hhx)\n", |
2568 | 0 | crc_computed, |
2569 | 0 | data_len + 4, |
2570 | 0 | crc_expected, |
2571 | 0 | lexer->inbuffer[4], lexer->inbuffer[5]); |
2572 | 0 | packet_type = BAD_PACKET; |
2573 | 0 | lexer->state = GROUND_STATE; |
2574 | 0 | } |
2575 | 0 | acc_dis = ACCEPT; |
2576 | 0 | break; |
2577 | | |
2578 | 0 | case COMMENT_RECOGNIZED: |
2579 | 0 | packet_type = COMMENT_PACKET; |
2580 | 0 | acc_dis = ACCEPT; |
2581 | 0 | lexer->state = GROUND_STATE; |
2582 | 0 | break; |
2583 | | |
2584 | 0 | #ifdef EVERMORE_ENABLE |
2585 | 0 | case EVERMORE_RECOGNIZED: |
2586 | | // Evermore uses DLE stuffing, what a PITA. |
2587 | | // Assume failure. |
2588 | 0 | packet_type = BAD_PACKET; |
2589 | 0 | acc_dis = ACCEPT; |
2590 | 0 | lexer->state = GROUND_STATE; |
2591 | |
|
2592 | 0 | do { |
2593 | | // the do{} is only done once, just so we can break |
2594 | | |
2595 | | // check for leader |
2596 | 0 | idx = 0; |
2597 | 0 | if (DLE != lexer->inbuffer[idx++] || |
2598 | 0 | STX != lexer->inbuffer[idx++]) { |
2599 | | // should not happen |
2600 | 0 | break; |
2601 | 0 | } |
2602 | | |
2603 | | // get one byte length, if length is 0x10, two DLE are sent. |
2604 | 0 | data_len = lexer->inbuffer[idx++]; |
2605 | 0 | if (DLE == data_len && |
2606 | 0 | DLE != lexer->inbuffer[idx++]) { |
2607 | | // should not happen |
2608 | 0 | break; |
2609 | 0 | } |
2610 | 0 | if (8 > data_len) { |
2611 | | /* should not happen, need 1 byte of data for message ID |
2612 | | * shortest message is 8 bytes of data_len */ |
2613 | 0 | break; |
2614 | 0 | } |
2615 | | |
2616 | 0 | data_len -= 2; |
2617 | 0 | crc_computed = 0; |
2618 | 0 | for (; data_len > 0; data_len--) { |
2619 | 0 | crc_computed += lexer->inbuffer[idx]; |
2620 | 0 | if (DLE == lexer->inbuffer[idx++] && |
2621 | 0 | DLE != lexer->inbuffer[idx++]) { |
2622 | | // should not happen, DLE not doubled. |
2623 | 0 | break; |
2624 | 0 | } |
2625 | 0 | } |
2626 | | // get one byte checksum |
2627 | 0 | crc_expected = lexer->inbuffer[idx++]; |
2628 | 0 | if (DLE == crc_expected && |
2629 | 0 | DLE != lexer->inbuffer[idx++]) { |
2630 | | // should not happen, DLE not doubled. |
2631 | 0 | break; |
2632 | 0 | } |
2633 | | // get two byte trailer |
2634 | 0 | if (DLE != lexer->inbuffer[idx++] || |
2635 | 0 | ETX != lexer->inbuffer[idx]) { |
2636 | | // we used to say n++ here, but scan-build complains |
2637 | | // bad trailer |
2638 | 0 | break; |
2639 | 0 | } |
2640 | 0 | crc_computed &= 0xff; |
2641 | 0 | if (crc_computed != crc_expected) { |
2642 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2643 | 0 | "EverMore checksum failed: %02x != %02x\n", |
2644 | 0 | crc_computed, crc_expected); |
2645 | 0 | break; |
2646 | 0 | } |
2647 | 0 | packet_type = EVERMORE_PACKET; |
2648 | 0 | lexer->state = EVERMORE_RECOGNIZED; |
2649 | 0 | break; // redundant |
2650 | 0 | } while (0); |
2651 | 0 | break; |
2652 | 0 | #endif // EVERMORE_ENABLE |
2653 | | |
2654 | 0 | #ifdef GEOSTAR_ENABLE |
2655 | 0 | case GEOSTAR_RECOGNIZED: |
2656 | | // GeoStar uses a XOR 32bit checksum |
2657 | 0 | acc_dis = ACCEPT; |
2658 | 0 | crc_computed = 0; |
2659 | | |
2660 | | // Calculate checksum |
2661 | 0 | for (idx = 0; idx < inbuflen; idx += 4) { |
2662 | 0 | crc_computed ^= getleu32(lexer->inbuffer, idx); |
2663 | 0 | } |
2664 | |
|
2665 | 0 | if (0 != crc_computed) { |
2666 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2667 | 0 | "GeoStar checksum failed 0x%x over length %d\n", |
2668 | 0 | crc_computed, inbuflen); |
2669 | 0 | packet_type = BAD_PACKET; |
2670 | 0 | lexer->state = GROUND_STATE; |
2671 | 0 | break; |
2672 | 0 | } |
2673 | 0 | packet_type = GEOSTAR_PACKET; |
2674 | 0 | break; |
2675 | 0 | #endif // GEOSTAR_ENABLE |
2676 | | |
2677 | 0 | #ifdef GREIS_ENABLE |
2678 | 0 | case GREIS_RECOGNIZED: |
2679 | 0 | acc_dis = ACCEPT; |
2680 | |
|
2681 | 0 | if ('R' == lexer->inbuffer[0] && |
2682 | 0 | 'E' == lexer->inbuffer[1]) { |
2683 | | // Replies don't have checksum |
2684 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
2685 | 0 | "Accept GREIS reply packet len %d\n", inbuflen); |
2686 | 0 | packet_type = GREIS_PACKET; |
2687 | 0 | break; |
2688 | 0 | } |
2689 | 0 | if ('E' == lexer->inbuffer[0] && |
2690 | 0 | 'R' == lexer->inbuffer[1]) { |
2691 | | // Error messages don't have checksum |
2692 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
2693 | 0 | "Accept GREIS error packet len %d\n", inbuflen); |
2694 | 0 | packet_type = GREIS_PACKET; |
2695 | 0 | break; |
2696 | 0 | } |
2697 | | // 8-bit checksum |
2698 | 0 | crc_computed = greis_checksum(lexer->inbuffer, inbuflen); |
2699 | |
|
2700 | 0 | if (0 != crc_computed) { |
2701 | | /* |
2702 | | * Print hex instead of raw characters, since they might be |
2703 | | * unprintable. If \0, it will even mess up the log output. |
2704 | | */ |
2705 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2706 | 0 | "REJECT GREIS len %d." |
2707 | 0 | " Bad checksum %#02x, expecting 0." |
2708 | 0 | " Packet type in hex: 0x%02x%02x", |
2709 | 0 | inbuflen, crc_computed, |
2710 | 0 | lexer->inbuffer[0], |
2711 | 0 | lexer->inbuffer[1]); |
2712 | 0 | packet_type = BAD_PACKET; |
2713 | | // got this far, fair to expect we will get more GREIS |
2714 | 0 | lexer->state = GREIS_EXPECTED; |
2715 | 0 | break; |
2716 | 0 | } |
2717 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
2718 | 0 | "Accept GREIS packet type '%c%c' len %d\n", |
2719 | 0 | lexer->inbuffer[0], lexer->inbuffer[1], inbuflen); |
2720 | 0 | packet_type = GREIS_PACKET; |
2721 | 0 | break; |
2722 | 0 | #endif // GREIS_ENABLE |
2723 | | |
2724 | 0 | case GROUND_STATE: |
2725 | 0 | character_discard(lexer); |
2726 | 0 | break; |
2727 | | |
2728 | 0 | #ifdef GARMINTXT_ENABLE |
2729 | 0 | case GTXT_RECOGNIZED: |
2730 | | // As of June 2023, we have no regression of GARMINTXT. |
2731 | 0 | if (57 <= inbuflen) { |
2732 | 0 | packet_accept(lexer, GARMINTXT_PACKET); |
2733 | 0 | packet_discard(lexer); |
2734 | 0 | lexer->state = GROUND_STATE; |
2735 | 0 | } else { |
2736 | 0 | packet_accept(lexer, BAD_PACKET); |
2737 | 0 | lexer->state = GROUND_STATE; |
2738 | 0 | } |
2739 | 0 | break; |
2740 | 0 | #endif |
2741 | | |
2742 | 0 | #ifdef ITRAX_ENABLE |
2743 | 0 | #define getib(j) ((uint8_t)lexer->inbuffer[(j)]) |
2744 | 0 | #define getiw(i) ((uint16_t)(((uint16_t)getib((i) + 1) << 8) | \ |
2745 | 0 | (uint16_t)getib((i)))) |
2746 | | |
2747 | 0 | case ITALK_RECOGNIZED: |
2748 | | // number of words |
2749 | 0 | data_len = lexer->inbuffer[6] & 0xff; |
2750 | | |
2751 | | // expected checksum |
2752 | 0 | crc_expected = getiw(7 + 2 * data_len); |
2753 | |
|
2754 | 0 | crc_computed = 0; |
2755 | 0 | for (idx = 0; idx < data_len; idx++) { |
2756 | 0 | uint16_t tmpw = getiw(7 + 2 * idx); |
2757 | 0 | uint32_t tmpdw = (crc_computed + 1) * (tmpw + idx); |
2758 | 0 | crc_computed ^= (tmpdw & 0xffff) ^ ((tmpdw >> 16) & 0xffff); |
2759 | 0 | } |
2760 | 0 | if (0 == data_len || |
2761 | 0 | crc_computed == crc_expected) { |
2762 | 0 | packet_type = ITALK_PACKET; |
2763 | 0 | } else { |
2764 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2765 | 0 | "ITALK: checksum failed - " |
2766 | 0 | "type 0x%02x expected 0x%04x got 0x%04x\n", |
2767 | 0 | lexer->inbuffer[4], crc_expected, crc_computed); |
2768 | 0 | packet_type = BAD_PACKET; |
2769 | 0 | lexer->state = GROUND_STATE; |
2770 | 0 | } |
2771 | 0 | acc_dis = ACCEPT; |
2772 | 0 | #undef getiw |
2773 | 0 | #undef getib |
2774 | 0 | break; |
2775 | 0 | #endif // ITRAX_ENABLE |
2776 | | |
2777 | 0 | case JSON_RECOGNIZED: |
2778 | 0 | if (11 <= inbuflen) { |
2779 | | // {"class": } |
2780 | 0 | packet_type = JSON_PACKET; |
2781 | 0 | } else { |
2782 | 0 | packet_type = BAD_PACKET; |
2783 | 0 | } |
2784 | 0 | lexer->state = GROUND_STATE; |
2785 | 0 | acc_dis = ACCEPT; |
2786 | 0 | break; |
2787 | | |
2788 | 0 | #ifdef NAVCOM_ENABLE |
2789 | 0 | case NAVCOM_RECOGNIZED: |
2790 | | // By the time we got here we know checksum is OK |
2791 | 0 | packet_type = NAVCOM_PACKET; |
2792 | 0 | acc_dis = ACCEPT; |
2793 | 0 | break; |
2794 | 0 | #endif // NAVCOM_ENABLE |
2795 | | |
2796 | 0 | case NMEA_RECOGNIZED: |
2797 | 0 | if (nmea_checksum(&lexer->errout, |
2798 | 0 | (const char *)lexer->inbuffer, |
2799 | 0 | (const char *)lexer->inbufptr)) { |
2800 | 0 | packet_type = NMEA_PACKET; |
2801 | 0 | #ifdef STASH_ENABLE |
2802 | 0 | unstash = true; |
2803 | 0 | #endif // STASH_ENABLE |
2804 | 0 | } else { |
2805 | 0 | lexer->state = GROUND_STATE; |
2806 | 0 | packet_type = BAD_PACKET; |
2807 | 0 | } |
2808 | 0 | acc_dis = ACCEPT; |
2809 | 0 | break; |
2810 | | |
2811 | 0 | #ifdef ONCORE_ENABLE |
2812 | 0 | case ONCORE_RECOGNIZED: |
2813 | 0 | acc_dis = ACCEPT; |
2814 | 0 | crc_computed = 0; |
2815 | 0 | for (idx = 2; idx < inbuflen - 2; idx++) { |
2816 | 0 | crc_computed ^= lexer->inbuffer[idx]; |
2817 | 0 | } |
2818 | |
|
2819 | 0 | if (0 != crc_computed) { |
2820 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2821 | 0 | "REJECT OnCore packet @@%c%c len %d\n", |
2822 | 0 | lexer->inbuffer[2], lexer->inbuffer[3], inbuflen); |
2823 | 0 | lexer->state = GROUND_STATE; |
2824 | 0 | packet_type = BAD_PACKET; |
2825 | 0 | break; |
2826 | 0 | } |
2827 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
2828 | 0 | "Accept OnCore packet @@%c%c len %d\n", |
2829 | 0 | lexer->inbuffer[2], lexer->inbuffer[3], inbuflen); |
2830 | 0 | packet_type = ONCORE_PACKET; |
2831 | 0 | break; |
2832 | 0 | #endif // ONCORE_ENABLE |
2833 | | |
2834 | 0 | case RTCM2_RECOGNIZED: |
2835 | | /* |
2836 | | * RTCM packets don't have checksums. The six bits of parity |
2837 | | * per word and the preamble better be good enough. |
2838 | | */ |
2839 | 0 | packet_type = RTCM2_PACKET; |
2840 | 0 | acc_dis = ACCEPT; |
2841 | 0 | break; |
2842 | | |
2843 | 0 | case RTCM3_RECOGNIZED: |
2844 | | // RTCM3 message header not always at inbuffer[0] |
2845 | 0 | for (idx = 0; idx < inbuflen; idx++) { |
2846 | 0 | if (0xd3 == lexer->inbuffer[idx]) { |
2847 | 0 | break; |
2848 | 0 | } |
2849 | 0 | } |
2850 | 0 | if (2048 < idx) { |
2851 | 0 | idx = 0; // can't happen, but pacify fuzzer. |
2852 | 0 | } |
2853 | | // we assume xd3 must be in there! |
2854 | | // yes, the top 6 bits should be zero, total 10 bits of length |
2855 | 0 | data_len = (lexer->inbuffer[idx + 1] << 8) | |
2856 | 0 | lexer->inbuffer[idx + 2]; |
2857 | 0 | data_len &= 0x03ff; // truncate below 1024, so pacify fuzzer |
2858 | 0 | if (LOG_IO <= lexer->errout.debug) { |
2859 | 0 | char outbuf[BUFSIZ]; |
2860 | | // 12 bits of message type |
2861 | 0 | pkt_id = (lexer->inbuffer[idx + 3] << 4) | |
2862 | 0 | (lexer->inbuffer[idx + 4] >> 4); |
2863 | | |
2864 | | // print the inbuffer packet, +3 to peek ahead. (maybe) |
2865 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
2866 | 0 | "RTCM3 data_len %u type %u idx %u inbufflen %u " |
2867 | 0 | " buf %s\n", |
2868 | 0 | data_len, pkt_id, idx, inbuflen, |
2869 | 0 | gps_hexdump(outbuf, sizeof(outbuf), |
2870 | 0 | &lexer->inbuffer[idx], data_len + 6 + 3)); |
2871 | 0 | } |
2872 | | |
2873 | | // The CRC includes the preamble, and data. |
2874 | 0 | if (crc24q_check(&lexer->inbuffer[idx], data_len + 6)) { |
2875 | 0 | packet_type = RTCM3_PACKET; |
2876 | 0 | } else { |
2877 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2878 | 0 | "RTCM3 data crc failure, " |
2879 | 0 | "%0x against %02x %02x %02x\n", |
2880 | 0 | crc24q_hash(&lexer->inbuffer[idx], data_len + 3), |
2881 | 0 | lexer->inbufptr[idx + data_len + 1], |
2882 | 0 | lexer->inbufptr[idx + data_len + 2], |
2883 | 0 | lexer->inbufptr[idx + data_len + 3]); |
2884 | 0 | packet_type = BAD_PACKET; |
2885 | 0 | } |
2886 | 0 | acc_dis = ACCEPT; |
2887 | 0 | lexer->state = GROUND_STATE; |
2888 | 0 | break; |
2889 | | |
2890 | 0 | #ifdef SIRF_ENABLE |
2891 | 0 | case SIRF_RECOGNIZED: |
2892 | 0 | { |
2893 | 0 | unsigned char *trailer; |
2894 | 0 | trailer = lexer->inbufptr - 4; |
2895 | |
|
2896 | 0 | crc_expected = (trailer[0] << 8) | trailer[1]; |
2897 | 0 | crc_computed = 0; |
2898 | |
|
2899 | 0 | for (idx = 4; idx < (inbuflen - 4); idx++) { |
2900 | 0 | crc_computed += lexer->inbuffer[idx]; |
2901 | 0 | } |
2902 | 0 | crc_computed &= 0x7fff; |
2903 | 0 | if (crc_expected == crc_computed) { |
2904 | 0 | packet_type = SIRF_PACKET; |
2905 | 0 | acc_dis = ACCEPT; |
2906 | 0 | } else { |
2907 | 0 | packet_type = BAD_PACKET; |
2908 | 0 | acc_dis = ACCEPT; |
2909 | 0 | lexer->state = GROUND_STATE; |
2910 | 0 | } |
2911 | 0 | } |
2912 | 0 | break; |
2913 | 0 | #endif // SIRF_ENABLE |
2914 | | |
2915 | 0 | case SPARTN_RECOGNIZED: |
2916 | 0 | packet_type = SPARTN_PACKET; |
2917 | 0 | lexer->state = GROUND_STATE; |
2918 | 0 | acc_dis = ACCEPT; |
2919 | 0 | break; |
2920 | 0 | #ifdef SKYTRAQ_ENABLE |
2921 | 0 | case SKY_RECOGNIZED: |
2922 | 0 | packet_type = SKY_PACKET; |
2923 | 0 | acc_dis = ACCEPT; |
2924 | 0 | break; |
2925 | 0 | #endif // SKYTRAQ_ENABLE |
2926 | | |
2927 | 0 | #ifdef STASH_ENABLE |
2928 | 0 | case STASH_RECOGNIZED: |
2929 | 0 | packet_stash(lexer); |
2930 | 0 | packet_discard(lexer); |
2931 | 0 | break; |
2932 | 0 | #endif // STASH_ENABLE |
2933 | | |
2934 | 0 | #ifdef SUPERSTAR2_ENABLE |
2935 | 0 | case SUPERSTAR2_RECOGNIZED: |
2936 | |
|
2937 | 0 | crc_computed = 0; |
2938 | 0 | lexer->length = 4 + (size_t)lexer->inbuffer[3] + 2; |
2939 | 0 | if (261 < lexer->length) { |
2940 | | // can't happen, pacify coverity by checking anyway. |
2941 | 0 | lexer->length = 261; |
2942 | 0 | } |
2943 | 0 | for (idx = 0; idx < lexer->length - 2; idx++) { |
2944 | 0 | crc_computed += lexer->inbuffer[idx]; |
2945 | 0 | } |
2946 | 0 | crc_expected = getleu16(lexer->inbuffer, lexer->length - 2); |
2947 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
2948 | 0 | "SuperStarII pkt dump: type %u len %zu\n", |
2949 | 0 | lexer->inbuffer[1], lexer->length); |
2950 | 0 | if (crc_expected != crc_computed) { |
2951 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
2952 | 0 | "REJECT SuperStarII packet type 0x%02x" |
2953 | 0 | "%zd bad checksum 0x%04x, expecting 0x%04x\n", |
2954 | 0 | lexer->inbuffer[1], lexer->length, |
2955 | 0 | crc_computed, crc_expected); |
2956 | 0 | packet_type = BAD_PACKET; |
2957 | 0 | lexer->state = GROUND_STATE; |
2958 | 0 | } else { |
2959 | 0 | packet_type = SUPERSTAR2_PACKET; |
2960 | 0 | } |
2961 | 0 | acc_dis = ACCEPT; |
2962 | 0 | break; |
2963 | 0 | #endif // SUPERSTAR2_ENABLE |
2964 | | |
2965 | 0 | #if defined(TSIP_ENABLE) || defined(GARMIN_ENABLE) |
2966 | 0 | case TSIP_RECOGNIZED: |
2967 | | /* Could be Garmin, or TSIP. Both are DLE stuffed. |
2968 | | * |
2969 | | * Garmin: DLE, ID, Length, data..., checksum, DLE, ETX |
2970 | | * TSIP: DLE, ID, data..., DLE, ETX |
2971 | | * |
2972 | | * Note: TSIP has no length, or checksum. Shame! |
2973 | | * So we check for Garmin length and checksum, if they |
2974 | | * fail, we check for TSIP ID's, maybe their matching lengths. |
2975 | | */ |
2976 | | |
2977 | | // Assume bad |
2978 | 0 | packet_type = BAD_PACKET; |
2979 | 0 | lexer->state = GROUND_STATE; |
2980 | 0 | acc_dis = ACCEPT; |
2981 | |
|
2982 | 0 | do { |
2983 | 0 | int dlecnt; |
2984 | | |
2985 | | // don't count stuffed DLEs in the length |
2986 | 0 | dlecnt = 0; |
2987 | 0 | for (idx = 0; idx < inbuflen; idx++) { |
2988 | 0 | if (DLE == lexer->inbuffer[idx]) { |
2989 | 0 | dlecnt++; |
2990 | 0 | } |
2991 | 0 | } |
2992 | 0 | if (dlecnt > 2) { |
2993 | 0 | dlecnt -= 2; |
2994 | 0 | dlecnt /= 2; |
2995 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
2996 | 0 | "Unstuffed %d DLEs\n", dlecnt); |
2997 | 0 | inbuflen -= dlecnt; |
2998 | 0 | } |
2999 | |
|
3000 | 0 | if (5 > inbuflen) { |
3001 | | // Message has no data. Can't be GARMIN or TSIP. |
3002 | 0 | break; |
3003 | 0 | } |
3004 | 0 | #ifdef GARMIN_ENABLE |
3005 | 0 | do { |
3006 | 0 | #ifdef TSIP_ENABLE |
3007 | | // last packet was TSIP, shortcut garmin |
3008 | 0 | if (TSIP_PACKET == lexer->type) { |
3009 | 0 | break; |
3010 | 0 | } |
3011 | 0 | #endif // TSIP_ENABLE |
3012 | | // We know DLE == lexer->inbuffer[0] |
3013 | 0 | idx = 1; |
3014 | | |
3015 | | // Garmin promises ID's 3 (ETX) and 16 (DLE) are never used |
3016 | 0 | pkt_id = lexer->inbuffer[idx++]; // packet ID, byte 1. |
3017 | | |
3018 | | // Get data length from packet. |
3019 | 0 | data_len = lexer->inbuffer[idx++]; |
3020 | 0 | crc_computed = data_len + pkt_id; |
3021 | 0 | if (DLE == data_len && |
3022 | 0 | DLE != lexer->inbuffer[idx++]) { |
3023 | | // Bad DLE stuffing |
3024 | 0 | break; |
3025 | 0 | } |
3026 | | // Compute checksum. |
3027 | 0 | data_len++; |
3028 | 0 | for (; data_len > 0; data_len--) { |
3029 | 0 | crc_computed += lexer->inbuffer[idx]; |
3030 | 0 | if (DLE == lexer->inbuffer[idx++] && |
3031 | 0 | DLE != lexer->inbuffer[idx++]) { |
3032 | | // Bad DLE stuffing |
3033 | 0 | break; |
3034 | 0 | } |
3035 | 0 | } |
3036 | |
|
3037 | 0 | crc_computed &= 0xff; |
3038 | 0 | if (0 != crc_computed) { |
3039 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
3040 | 0 | "Garmin checksum failed: %02x!=0\n", |
3041 | 0 | crc_computed); |
3042 | 0 | break; |
3043 | 0 | } |
3044 | | |
3045 | | // Check for trailer where expected |
3046 | 0 | if (DLE != lexer->inbuffer[idx++] || |
3047 | 0 | ETX != lexer->inbuffer[idx]) { |
3048 | | // we used to say idx++ here, but scan-build complains |
3049 | 0 | break; |
3050 | 0 | } |
3051 | | |
3052 | | // A good packet! |
3053 | 0 | packet_type = GARMIN_PACKET; |
3054 | 0 | break; // redundant... |
3055 | 0 | } while (0); |
3056 | |
|
3057 | 0 | if (GARMIN_PACKET == packet_type) { |
3058 | 0 | break; |
3059 | 0 | } |
3060 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, "Not a Garmin packet\n"); |
3061 | | // Could be TSIP, but line noise can look like TSIP. |
3062 | |
|
3063 | 0 | #endif // GARMIN_ENABLE |
3064 | 0 | #ifdef TSIP_ENABLE |
3065 | 0 | do { |
3066 | | /* Since TSIP has no length, or checksum, |
3067 | | * check for some common TSIP packet types: |
3068 | | * 0x13, TSIP Parsing Error Notification |
3069 | | * 0x1c, Hardware/Software Version Information |
3070 | | * 0x38, Request SV system data |
3071 | | * 0x40, Almanac |
3072 | | * 0x41, GPS time, data length 10 |
3073 | | * 0x42, Single Precision Fix XYZ, data length 16 |
3074 | | * 0x43, Velocity Fix XYZ, ECEF, data length 20 |
3075 | | * 0x45, Software Version Information, data length 10 |
3076 | | * 0x46, Health of Receiver, data length 2 |
3077 | | * 0x47, Signal Level all Sats Tracked, data length 1+5*numSV |
3078 | | * 0x48, GPS System Messages, data length 22 |
3079 | | * 0x49, Almanac Health Page, data length 32 |
3080 | | * 0x4a, Single Precision Fix LLA, data length 20 |
3081 | | * 0x4b, Machine Code Status, data length 3 |
3082 | | * 0x4c, Operating Parameters Report, data length 17 |
3083 | | * 0x4d, Oscillator Offset |
3084 | | * 0x4e, Response to set GPS time |
3085 | | * 0x54, One Satellite Bias, data length 12 |
3086 | | * 0x55, I/O Options, data length 4 |
3087 | | * 0x56, Velocity Fix ENU, data length 20 |
3088 | | * 0x57, Last Computed Fix Report, data length 8 |
3089 | | * 0x58, Satellite System Data |
3090 | | * 0x58-05, UTC |
3091 | | * 0x59, Satellite Health |
3092 | | * 0x5a, Raw Measurements |
3093 | | * 0x5b, Satellite Ephemeris Status, data length 16 |
3094 | | * 0x5c, Satellite Tracking Status, data length 24 |
3095 | | * 0x5d, Satellite Tracking Stat, multi-gnss, data length 26 |
3096 | | * 0x5e, Additional Fix Status Report |
3097 | | * 0x5f, Severe Failure Notification |
3098 | | * 0x5F-01-0B: Reset Error Codes |
3099 | | * 0x5F-02: Ascii text message |
3100 | | * 0x6c, Satellite Selection List, data length 18+numSV |
3101 | | * 0x6d, All-In-View Satellites, data length 17+numSV |
3102 | | * 0x6f, Synced Measurement Packet |
3103 | | * 0x72, PV filter parameters |
3104 | | * 0x74, Altitude filter parameters |
3105 | | * 0x78, Max DGPS correction age |
3106 | | * 0x7b, NMEA message schedule |
3107 | | * 0x82, Differential Position Fix Mode, data length 1 |
3108 | | * 0x83, Double Precision Fix XYZ, data length 36 |
3109 | | * 0x84, Double Precision Fix LLA, data length 36 |
3110 | | * 0x85, DGPS Correction status |
3111 | | * 0x8f, Superpackets |
3112 | | * 0x8f-01, |
3113 | | * 0x8f-02, |
3114 | | * 0x8f-03, port configuration |
3115 | | * 0x8f-14, datum |
3116 | | * 0x8f-15, datum |
3117 | | * 0x8f-17, Single Precision UTM |
3118 | | * 0x8f-18, Double Precision UTM |
3119 | | * 0x8f-20, LLA & ENU |
3120 | | * 0x8f-26, SEEPROM write status |
3121 | | * 0x8f-40, TAIP Configuration |
3122 | | * 0x8f-42, Stored Production Parameters |
3123 | | * 0x90-XX, Version/Config (TSIPv1) |
3124 | | * 0xa1-00, Timing Info (TSIPv1) |
3125 | | * 0xa1-01, Frequency Info (TSIPv1) |
3126 | | * 0xa1-02, Position Info (TSIPv1) |
3127 | | * 0xbb, GPS Navigation Configuration |
3128 | | * 0xbc, Receiver Port Configuration |
3129 | | * |
3130 | | * <DLE>[pkt id] [data] <DLE><ETX> |
3131 | | * |
3132 | | * The best description is in [TSIP], the Trimble Standard |
3133 | | * Interface Protocol manual; unless otherwise specified |
3134 | | * that is where these type/length notifications are from. |
3135 | | * |
3136 | | * Note that not all Trimble chips conform perfectly to this |
3137 | | * specification, nor does it cover every packet type we |
3138 | | * may see on the wire. |
3139 | | */ |
3140 | 0 | pkt_id = lexer->inbuffer[1]; // packet ID |
3141 | | // *INDENT-OFF* |
3142 | | // FIXME: combine this if, and the next ones? |
3143 | 0 | if (!((0x13 == pkt_id) || |
3144 | 0 | (0x1c == pkt_id) || |
3145 | 0 | (0x38 == pkt_id) || |
3146 | 0 | ((0x41 <= pkt_id) && (0x4c >= pkt_id)) || |
3147 | 0 | ((0x54 <= pkt_id) && (0x57 >= pkt_id)) || |
3148 | 0 | ((0x5a <= pkt_id) && (0x5f >= pkt_id)) || |
3149 | 0 | (0x6c == pkt_id) || |
3150 | 0 | (0x6d == pkt_id) || |
3151 | 0 | (0x82 <= pkt_id && |
3152 | 0 | 0x84 >= pkt_id) || |
3153 | 0 | (0x8f <= pkt_id && |
3154 | 0 | 0x93 >= pkt_id) || |
3155 | 0 | (0xbb == pkt_id) || |
3156 | 0 | (0xbc == pkt_id) || |
3157 | 0 | ((0xa1 <= pkt_id && |
3158 | 0 | 0xa3 >= pkt_id)))) { |
3159 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
3160 | 0 | "Packet ID 0x%02x out of range for TSIP\n", |
3161 | 0 | pkt_id); |
3162 | 0 | break; |
3163 | 0 | } |
3164 | | // *INDENT-ON* |
3165 | 0 | #define TSIP_ID_AND_LENGTH(id, len) ((id == pkt_id) && \ |
3166 | 0 | (len == (inbuflen - 4))) |
3167 | | |
3168 | 0 | if (0x13 == pkt_id) { |
3169 | 0 | ; // pass |
3170 | | /* |
3171 | | * Not in [TSIP], Accutime Gold only. Variable length. |
3172 | | */ |
3173 | 0 | } else if ((0x1c == pkt_id) && |
3174 | 0 | (11 <= inbuflen)) { |
3175 | 0 | ; // pass |
3176 | 0 | } else if (TSIP_ID_AND_LENGTH(0x41, 10)) { |
3177 | 0 | ; // pass |
3178 | 0 | } else if (TSIP_ID_AND_LENGTH(0x42, 16)) { |
3179 | 0 | ; // pass |
3180 | 0 | } else if (TSIP_ID_AND_LENGTH(0x43, 20)) { |
3181 | 0 | ; // pass |
3182 | 0 | } else if (TSIP_ID_AND_LENGTH(0x45, 10)) { |
3183 | 0 | ; // pass |
3184 | 0 | } else if (TSIP_ID_AND_LENGTH(0x46, 2)) { |
3185 | 0 | ; // pass |
3186 | 0 | } else if ((0x47 == pkt_id) && |
3187 | 0 | (0 == (inbuflen % 5))) { |
3188 | | /* |
3189 | | * 0x47 data length 1+5*numSV, packetlen is 5+5*numSV |
3190 | | * FIXME, should be a proper length calculation |
3191 | | */ |
3192 | 0 | ; // pass |
3193 | 0 | } else if (TSIP_ID_AND_LENGTH(0x48, 22)) { |
3194 | 0 | ; // pass |
3195 | 0 | } else if (TSIP_ID_AND_LENGTH(0x49, 32)) { |
3196 | 0 | ; // pass |
3197 | 0 | } else if (TSIP_ID_AND_LENGTH(0x4a, 20)) { |
3198 | 0 | ; // pass |
3199 | 0 | } else if (TSIP_ID_AND_LENGTH(0x4b, 3)) { |
3200 | 0 | ; // pass |
3201 | 0 | } else if (TSIP_ID_AND_LENGTH(0x4c, 17)) { |
3202 | 0 | ; // pass |
3203 | 0 | } else if (TSIP_ID_AND_LENGTH(0x54, 12)) { |
3204 | 0 | ; // pass |
3205 | 0 | } else if (TSIP_ID_AND_LENGTH(0x55, 4)) { |
3206 | 0 | ; // pass |
3207 | 0 | } else if (TSIP_ID_AND_LENGTH(0x56, 20)) { |
3208 | 0 | ; // pass |
3209 | 0 | } else if (TSIP_ID_AND_LENGTH(0x57, 8)) { |
3210 | 0 | ; // pass |
3211 | 0 | } else if (TSIP_ID_AND_LENGTH(0x5a, 25)) { |
3212 | 0 | ; // pass |
3213 | 0 | } else if (TSIP_ID_AND_LENGTH(0x5b, 16)) { |
3214 | 0 | ; // pass |
3215 | 0 | } else if (TSIP_ID_AND_LENGTH(0x5c, 24)) { |
3216 | 0 | ; // pass |
3217 | 0 | } else if (TSIP_ID_AND_LENGTH(0x5d, 26)) { |
3218 | 0 | ; // pass |
3219 | 0 | } else if (TSIP_ID_AND_LENGTH(0x5e, 2)) { |
3220 | 0 | ; // pass |
3221 | | /* |
3222 | | * Not in [TSIP]. the TSIP driver doesn't use type 0x5f. |
3223 | | * but we test for it so as to avoid setting packet not_tsip |
3224 | | */ |
3225 | 0 | } else if (TSIP_ID_AND_LENGTH(0x5f, 66)) { |
3226 | | /* |
3227 | | * 0x6c data length 18+numSV, total packetlen is 22+numSV |
3228 | | * numSV up to 224 |
3229 | | */ |
3230 | 0 | ; // pass |
3231 | 0 | } else if ((0x6c == pkt_id) && |
3232 | 0 | ((22 <= inbuflen) && |
3233 | 0 | (246 >= inbuflen))) { |
3234 | | /* |
3235 | | * 0x6d data length 17+numSV, total packetlen is 21+numSV |
3236 | | * numSV up to 32 |
3237 | | */ |
3238 | 0 | ; // pass |
3239 | 0 | } else if ((0x6d == pkt_id) && |
3240 | 0 | ((21 <= inbuflen) && |
3241 | 0 | (53 >= inbuflen))) { |
3242 | 0 | ; // pass |
3243 | 0 | } else if (TSIP_ID_AND_LENGTH(0x82, 1)) { |
3244 | 0 | ; // pass |
3245 | 0 | } else if (TSIP_ID_AND_LENGTH(0x83, 36)) { |
3246 | 0 | ; // pass |
3247 | 0 | } else if (TSIP_ID_AND_LENGTH(0x84, 36)) { |
3248 | | // pass |
3249 | 0 | } else if (0x8f <= pkt_id && |
3250 | 0 | 0x93 >= pkt_id) { |
3251 | | // pass, TSIP super packets, variable length |
3252 | | // pass, TSIPv1 version/config/info super packet |
3253 | 0 | } else if (0xa0 <= pkt_id && |
3254 | 0 | 0xa3 >= pkt_id) { |
3255 | | // PASS, TSIPv1 |
3256 | | // FIXME: check for sub packet id 0 to 2 |
3257 | | /* |
3258 | | * This is according to [TSIP]. |
3259 | | */ |
3260 | 0 | } else if (TSIP_ID_AND_LENGTH(0xbb, 40)) { |
3261 | 0 | ; // pass |
3262 | | /* |
3263 | | * The Accutime Gold ships a version of this packet with a |
3264 | | * 43-byte payload. We only use the first 21 bytes, and |
3265 | | * parts after byte 27 are padding. |
3266 | | */ |
3267 | 0 | } else if (TSIP_ID_AND_LENGTH(0xbb, 43)) { |
3268 | 0 | ; // pass |
3269 | 0 | } else { |
3270 | 0 | ; // pass |
3271 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
3272 | 0 | "TSIP REJECT pkt_id = %#02x, inbuflen= %d\n", |
3273 | 0 | pkt_id, inbuflen); |
3274 | 0 | break; |
3275 | 0 | } |
3276 | 0 | #undef TSIP_ID_AND_LENGTH |
3277 | | // Debug |
3278 | 0 | GPSD_LOG(LOG_RAW, &lexer->errout, |
3279 | 0 | "TSIP pkt_id = %#02x, inbuflen= %d\n", |
3280 | 0 | pkt_id, inbuflen); |
3281 | 0 | packet_type = TSIP_PACKET; |
3282 | 0 | lexer->state = TSIP_RECOGNIZED; |
3283 | 0 | break; // redundant |
3284 | 0 | } while (0); |
3285 | |
|
3286 | 0 | if (BAD_PACKET == packet_type) { |
3287 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, "Not a TSIP packet\n"); |
3288 | 0 | acc_dis = ACCEPT; |
3289 | 0 | lexer->state = GROUND_STATE; |
3290 | 0 | } |
3291 | 0 | break; // redundant |
3292 | 0 | #endif // TSIP_ENABLE |
3293 | 0 | } while (0); |
3294 | 0 | break; |
3295 | 0 | #endif // TSIP_ENABLE || GARMIN_ENABLE |
3296 | | |
3297 | 0 | case UBX_RECOGNIZED: |
3298 | | // UBX use a TCP like checksum |
3299 | 0 | ck_a = (unsigned char)0; |
3300 | 0 | ck_b = (unsigned char)0; |
3301 | |
|
3302 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, "UBX: len %d\n", inbuflen); |
3303 | 0 | for (idx = 2; idx < (inbuflen - 2); idx++) { |
3304 | 0 | ck_a += lexer->inbuffer[idx]; |
3305 | 0 | ck_b += ck_a; |
3306 | 0 | } |
3307 | 0 | if (ck_a == lexer->inbuffer[inbuflen - 2] && |
3308 | 0 | ck_b == lexer->inbuffer[inbuflen - 1]) { |
3309 | 0 | packet_type = UBX_PACKET; |
3310 | 0 | } else { |
3311 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
3312 | 0 | "UBX checksum 0x%02hhx%02hhx over length %d," |
3313 | 0 | " expecting 0x%02hhx%02hhx (type 0x%02hhx%02hhx)\n", |
3314 | 0 | ck_a, |
3315 | 0 | ck_b, |
3316 | 0 | inbuflen, |
3317 | 0 | lexer->inbuffer[inbuflen - 2], |
3318 | 0 | lexer->inbuffer[inbuflen - 1], |
3319 | 0 | lexer->inbuffer[2], lexer->inbuffer[3]); |
3320 | 0 | packet_type = BAD_PACKET; |
3321 | 0 | lexer->state = GROUND_STATE; |
3322 | 0 | } |
3323 | 0 | acc_dis = ACCEPT; |
3324 | 0 | break; |
3325 | | |
3326 | 0 | #ifdef ZODIAC_ENABLE |
3327 | 0 | case ZODIAC_RECOGNIZED: |
3328 | | // be paranoid, look ahead for a good checksum |
3329 | 0 | data_len = getzuword(2); |
3330 | 0 | if (253 < data_len) { |
3331 | | // pacify coverity, 253 seems to be max length |
3332 | 0 | data_len = 253; |
3333 | 0 | } |
3334 | 0 | crc_computed = 0; |
3335 | 0 | for (idx = 0; idx < data_len; idx++) { |
3336 | 0 | crc_computed += getzword(5 + idx); |
3337 | 0 | } |
3338 | 0 | crc_expected = getzword(5 + data_len); |
3339 | 0 | crc_computed += crc_expected; |
3340 | 0 | crc_computed &= 0x0ff; |
3341 | 0 | if (0 == data_len || |
3342 | 0 | 0 == crc_computed) { |
3343 | 0 | packet_type = ZODIAC_PACKET; |
3344 | 0 | } else { |
3345 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
3346 | 0 | "Zodiac data checksum 0x%x over length %u, " |
3347 | 0 | "expecting 0x%x\n", |
3348 | 0 | crc_expected, data_len, getzword(5 + data_len)); |
3349 | 0 | packet_type = BAD_PACKET; |
3350 | 0 | lexer->state = GROUND_STATE; |
3351 | 0 | } |
3352 | 0 | acc_dis = ACCEPT; |
3353 | 0 | break; |
3354 | 0 | #endif // ZODIAC_ENABLE |
3355 | |
|
3356 | 0 | } |
3357 | 0 | if (ACCEPT == acc_dis) { |
3358 | 0 | packet_accept(lexer, packet_type); |
3359 | 0 | packet_discard(lexer); |
3360 | 0 | #ifdef STASH_ENABLE |
3361 | 0 | if (unstash && |
3362 | 0 | 0 != lexer->stashbuflen) { |
3363 | 0 | packet_unstash(lexer); |
3364 | 0 | } |
3365 | 0 | #endif // STASH_ENABLE |
3366 | 0 | break; |
3367 | 0 | } |
3368 | 0 | } // while |
3369 | 0 | } |
3370 | | |
3371 | | /* packet_get() -- deprecated 2023, use packet_get1() instead |
3372 | | * exposed in Python FFI. |
3373 | | */ |
3374 | | ssize_t packet_get(int fd, struct gps_lexer_t *lexer) |
3375 | 0 | { |
3376 | 0 | struct gps_device_t session = {{0}}; |
3377 | 0 | ssize_t retval; |
3378 | 0 | ssize_t inbufptrcnt = lexer->inbufptr - lexer->inbuffer; |
3379 | |
|
3380 | 0 | session.gpsdata.gps_fd = fd; |
3381 | 0 | session.lexer = *lexer; // structure copy |
3382 | | |
3383 | | // fix inbufptr |
3384 | 0 | session.lexer.inbufptr = session.lexer.inbuffer + inbufptrcnt; |
3385 | |
|
3386 | 0 | retval = packet_get1(&session); |
3387 | |
|
3388 | 0 | *lexer = session.lexer; // structure copy |
3389 | | |
3390 | | // fix inbufptr |
3391 | 0 | inbufptrcnt = session.lexer.inbufptr - session.lexer.inbuffer; |
3392 | 0 | lexer->inbufptr = lexer->inbuffer + inbufptrcnt; |
3393 | |
|
3394 | 0 | return retval; |
3395 | 0 | } |
3396 | | |
3397 | | |
3398 | | /* packet_get1_chunked() - grab an http/1.1 chunked packet; |
3399 | | * |
3400 | | * Handle http/1.1 chunking as a layer above the packet layer. |
3401 | | * so far only NTRIP v2 uses it. Perversely the chunks do |
3402 | | * not seem to align with received packets. |
3403 | | * |
3404 | | * A pointless feature in http/1.1 |
3405 | | * |
3406 | | * return: greater than zero: length |
3407 | | * > 0 == got a packet. |
3408 | | * 0 == EOF or no full packet |
3409 | | * -1 == I/O error |
3410 | | */ |
3411 | | static ssize_t packet_get1_chunked(struct gps_device_t *session) |
3412 | 0 | { |
3413 | 0 | ssize_t recvd; |
3414 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
3415 | | // (int) to pacify Codacy |
3416 | 0 | int fd = (int)session->gpsdata.gps_fd; |
3417 | 0 | struct gps_lexer_t *lexer = &session->lexer; |
3418 | 0 | size_t idx = 0; // index into inbuffer. |
3419 | 0 | unsigned char *tmp_bufptr; // pointer to head in tmp_buffer |
3420 | 0 | ssize_t taken; |
3421 | | // make tmp_buffer large, to simplify overflow prevention |
3422 | 0 | unsigned char tmp_buffer[sizeof(lexer->inbuffer) * 2]; |
3423 | |
|
3424 | 0 | GPSD_LOG(LOG_PROG, &lexer->errout, |
3425 | 0 | "PACKET: packet_get1_chunked(fd %d) enter inbuflen %zu " |
3426 | 0 | "offset %d remaining %d\n", |
3427 | 0 | fd, lexer->inbuflen, (int) (lexer->inbufptr - lexer->inbuffer), |
3428 | 0 | lexer->chunk_remaining); |
3429 | |
|
3430 | 0 | if (sizeof(lexer->inbuffer) < lexer->inbuflen) { |
3431 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3432 | 0 | "PACKET: packet_get1_chunked(fd %d) start inbuflen %zu " |
3433 | 0 | "< 0 !!!\n", |
3434 | 0 | fd, lexer->inbuflen); |
3435 | 0 | return -1; // unrecoverable error |
3436 | 0 | } |
3437 | | |
3438 | 0 | errno = 0; |
3439 | 0 | recvd = 0; |
3440 | 0 | if (2048 > lexer->inbuflen) { |
3441 | | /* Do not bother to read if we already have enough for longest |
3442 | | * RTCM3 message. Longest RTCM3 message is 1023 plus header |
3443 | | * and chunk overhead. |
3444 | | * O_NONBLOCK set, so this should not block. |
3445 | | * Best not to block on an unresponsive NTRIP server. |
3446 | | * They tend to be bursty. Like 18kb, then nothing for many |
3447 | | * seconds. */ |
3448 | 0 | recvd = read(fd, lexer->inbuffer + lexer->inbuflen, |
3449 | 0 | sizeof(lexer->inbuffer) - lexer->inbuflen); |
3450 | 0 | } else { |
3451 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3452 | 0 | "PACKET: packet_get1_chunked(fd %d) got enough inbuflen %zu " |
3453 | 0 | "offset %d\n", |
3454 | 0 | fd, lexer->inbuflen, |
3455 | 0 | (int) (lexer->inbufptr - lexer->inbuffer)); |
3456 | 0 | } |
3457 | |
|
3458 | 0 | if (0 == recvd && |
3459 | 0 | 0 == lexer->inbuflen) { |
3460 | | /* When reading from a TCP socket, and no bytes ready, read() |
3461 | | * returns 0 and sets errno to 11 (Resource temporarily unavailable). |
3462 | | */ |
3463 | 0 | if (EAGAIN != errno) { |
3464 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
3465 | 0 | "PACKET: packet_get1_chunked(fd %d) recvd %zd %s(%d)\n", |
3466 | 0 | fd, recvd, strerror(errno), errno); |
3467 | 0 | return -1; // unrecoverable error. |
3468 | 0 | } // else |
3469 | 0 | GPSD_LOG(LOG_RAW2, &lexer->errout, |
3470 | 0 | "PACKET: packet_get1_chunked(fd %d) no bytes ready\n", |
3471 | 0 | fd); |
3472 | 0 | return 1; // pretend we got something, to keep connection open |
3473 | 0 | } // else |
3474 | | |
3475 | 0 | if (0 > recvd) { |
3476 | 0 | if (EAGAIN == errno || |
3477 | 0 | EINTR == errno) { |
3478 | 0 | GPSD_LOG(LOG_RAW2, &lexer->errout, "PACKET: no bytes ready\n"); |
3479 | 0 | recvd = 0; |
3480 | | // No new bytes, maybe already have enough bytes for a message |
3481 | 0 | } else { |
3482 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
3483 | 0 | "PACKET: packet_get1_chunked(fd %d) errno: %s(%d)\n", |
3484 | 0 | fd, strerror(errno), errno); |
3485 | 0 | return -1; // unrecoverable error. |
3486 | 0 | } |
3487 | 0 | } // else |
3488 | | |
3489 | | // Got some data. |
3490 | 0 | lexer->inbuflen += recvd; |
3491 | |
|
3492 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3493 | 0 | "PACKET: packet_get1_chunked(fd %d) recvd %zd inbuflen %zd " |
3494 | 0 | "mid remaining %d >%.100s<\n", |
3495 | 0 | fd, recvd, lexer->inbuflen, lexer->chunk_remaining, |
3496 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3497 | 0 | lexer->inbufptr, lexer->inbuflen)); |
3498 | | |
3499 | | /* Preversly, the buffer may be just 4 bytes. |
3500 | | * Some servers send just 0x36340d0a in one packet |
3501 | | * smallest valid chunk: "0\r\n\r\n" |
3502 | | * Give up for now */ |
3503 | 0 | if (5 >= lexer->inbuflen) { |
3504 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3505 | 0 | "PACKET: packet_get1_chunked(fd %d) < 5 remaining %d\n", |
3506 | 0 | fd, lexer->chunk_remaining); |
3507 | 0 | return 0; // got nothing. |
3508 | 0 | } |
3509 | | /* The length in the header may be up to 1023, plus message |
3510 | | * overhead. |
3511 | | * Here we may have N remaining at the head of inbuffer, followed |
3512 | | * by part, or all, of the next bit to unchunk.*/ |
3513 | 0 | if (0 > lexer->chunk_remaining) { |
3514 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3515 | 0 | "PACKET: packet_get1_chunkedfd %d) remaining %d < 0 !!!\n", |
3516 | 0 | fd, lexer->chunk_remaining); |
3517 | 0 | return -1; // unrecoverable error. |
3518 | 0 | } |
3519 | 0 | if (lexer->inbuflen > (long unsigned)lexer->chunk_remaining) { |
3520 | | // need unchunking |
3521 | 0 | size_t tmp_buflen = lexer->inbuflen - lexer->chunk_remaining; |
3522 | 0 | int chunk_num; // many chunks in one buffer, |
3523 | | |
3524 | | /* Make a copy of the unchunked part of inbuffer. |
3525 | | * Then unchunk it back into inbuffer. */ |
3526 | 0 | lexer->inbufptr = &lexer->inbuffer[lexer->chunk_remaining]; |
3527 | 0 | memset(tmp_buffer, 0, sizeof(tmp_buffer)); |
3528 | 0 | memmove(tmp_buffer, lexer->inbufptr, tmp_buflen); |
3529 | | |
3530 | | // get ready to copy chunks back into the inbuffer |
3531 | 0 | tmp_bufptr = tmp_buffer; |
3532 | 0 | lexer->inbuflen = lexer->chunk_remaining; |
3533 | |
|
3534 | 0 | for (chunk_num = 0; ; chunk_num++) { |
3535 | 0 | size_t needed = 0; |
3536 | 0 | int chunk_size = 0; // given chunk size |
3537 | 0 | long chunk_size_l = 0; // given chunk size, as a long |
3538 | 0 | unsigned char *endptr; // for strtol() |
3539 | | |
3540 | | // get the hexadecimal chunk size. |
3541 | 0 | chunk_size_l = strtol((char *)tmp_bufptr, (char **)&endptr, 16); |
3542 | 0 | if (0 > chunk_size_l || |
3543 | 0 | 10000 < chunk_size_l) { |
3544 | | // don't let chunk be negative, or too large. |
3545 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3546 | 0 | "PACKET: packet_get1_chunkedfd %d) invalid " |
3547 | 0 | "chunk_size %ld!!!\n", |
3548 | 0 | fd, chunk_size_l); |
3549 | 0 | return -1; // unrecoverable error. |
3550 | 0 | } |
3551 | 0 | chunk_size = chunk_size_l; // We already tested it fits. |
3552 | |
|
3553 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3554 | 0 | "PACKET: packet_get1_chunkedfd %d) doing chunk %d " |
3555 | 0 | "size %d inbuflen %zu >%.200s<\n", |
3556 | 0 | fd, chunk_num, chunk_size, lexer->inbuflen, |
3557 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3558 | 0 | tmp_bufptr, tmp_buflen)); |
3559 | |
|
3560 | 0 | idx = endptr - tmp_bufptr; |
3561 | | |
3562 | | // check for valid hex ending |
3563 | | // need better test for overrun |
3564 | 0 | if (';' != *endptr && |
3565 | 0 | '\r' != *endptr) { |
3566 | | // invalid ending. valid endings are ':' or '\r\n' (0d0a). |
3567 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
3568 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) " |
3569 | 0 | "invalid ending idx %zu (x%x).\n", |
3570 | 0 | fd, idx, *endptr); |
3571 | | // unrecoverable? |
3572 | 0 | break; // assume we need more input?? |
3573 | 0 | } |
3574 | 0 | idx++; // skip past the ":" or "\r" |
3575 | | |
3576 | | // move past '\n' line ending |
3577 | 0 | for (; tmp_bufptr[idx] < tmp_buffer[sizeof(tmp_buffer) - 1]; |
3578 | 0 | idx++) { |
3579 | 0 | if ('\n' == tmp_bufptr[idx]) { |
3580 | 0 | break; |
3581 | 0 | } |
3582 | 0 | } |
3583 | 0 | if ('\n' != tmp_bufptr[idx]) { |
3584 | | // Invalid ending. The only valid ending is '\n'. |
3585 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3586 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) " |
3587 | 0 | "invalid ending 2, idx %zu x%02x\n", |
3588 | 0 | fd, idx, tmp_bufptr[idx]); |
3589 | 0 | break; // assume we need more input. |
3590 | 0 | } |
3591 | 0 | idx++; // move past the trailing '\n' |
3592 | | |
3593 | | /* to unchunk we need chunk size + 2 more for \r\n + 2 more |
3594 | | * for the tailing \r\n */ |
3595 | 0 | needed = chunk_size + 2 + idx; |
3596 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3597 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) size %d " |
3598 | 0 | "idx %zu buflen %zu needed %zu %s\n", |
3599 | 0 | fd, chunk_size, idx, tmp_buflen, needed, |
3600 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3601 | 0 | tmp_bufptr, 10)); |
3602 | 0 | if (needed > tmp_buflen) { |
3603 | | /* Don't have enough yet. Annoyingly, centipede can send |
3604 | | * the chunk count line, but not the chunked data yet!! |
3605 | | * Like this: "64\r\n". |
3606 | | * Save the fragment back into inbuffer |
3607 | | */ |
3608 | 0 | memcpy(lexer->inbufptr, tmp_bufptr, tmp_buflen); |
3609 | 0 | lexer->inbuflen += tmp_buflen; |
3610 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3611 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) " |
3612 | 0 | "chunk %d not full needed %zd tmp_buflen %zu\n", |
3613 | 0 | fd, chunk_num, needed, tmp_buflen); |
3614 | 0 | break; |
3615 | 0 | } |
3616 | 0 | lexer->chunk_remaining += chunk_size; |
3617 | | /* enough data in inbuffer, starting at tmp_bufptr[idx] |
3618 | | * move past that chunk header. */ |
3619 | 0 | tmp_bufptr += idx; |
3620 | 0 | tmp_buflen -= idx; |
3621 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3622 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) got " |
3623 | 0 | "chunk %d >%s<\n", |
3624 | 0 | fd, chunk_num, |
3625 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3626 | 0 | lexer->inbufptr, chunk_size)); |
3627 | | |
3628 | | // save the chunk into inbuffer |
3629 | 0 | memcpy(lexer->inbufptr, tmp_bufptr, chunk_size); |
3630 | 0 | lexer->inbuflen += chunk_size; |
3631 | 0 | lexer->inbufptr += chunk_size; |
3632 | | |
3633 | | // skip past the chunk trailer (\r\n) |
3634 | 0 | tmp_bufptr += chunk_size + 2; |
3635 | 0 | tmp_buflen -= chunk_size + 2; |
3636 | 0 | if (0 == tmp_buflen) { |
3637 | 0 | break; |
3638 | 0 | } |
3639 | | // smallest valid chunk: "0\r\n\r\n" |
3640 | 0 | if (5 >= tmp_buflen) { |
3641 | | // left overs!, put back into inbuffer later. |
3642 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3643 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) " |
3644 | 0 | "left over %zu inbuflen %zu\n", |
3645 | 0 | fd, tmp_buflen, lexer->inbuflen); |
3646 | 0 | break; |
3647 | 0 | } |
3648 | 0 | } |
3649 | 0 | } // else, inbuf already unchunked |
3650 | | |
3651 | 0 | if (0 == lexer->inbuflen) { |
3652 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3653 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) got nothing,\n", |
3654 | 0 | fd); |
3655 | 0 | return 1; // not right, close enough |
3656 | 0 | } |
3657 | | // data starts at lexer->inbuffer[0] |
3658 | 0 | if (0 > lexer->chunk_remaining) { |
3659 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3660 | 0 | "PACKET: packet_get1_chunkedfd %d) remaining %d < 0 !!!\n", |
3661 | 0 | fd, lexer->chunk_remaining); |
3662 | 0 | return -1; // unrecoverable error |
3663 | 0 | } |
3664 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3665 | 0 | "PACKET: packet_get1_chunked(fd %d) inbuflen %zu remaining %d " |
3666 | 0 | "unchunked %.200s\n", |
3667 | 0 | fd, lexer->inbuflen, lexer->chunk_remaining, |
3668 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3669 | 0 | lexer->inbuffer, lexer->inbuflen)); |
3670 | |
|
3671 | 0 | if (2 <= lexer->inbuflen) { |
3672 | | /* now get one message |
3673 | | * don't underflow inbuflen, or voerrun inbuffer |
3674 | | * RTCM3 message header not always at inbufptr[0] |
3675 | | */ |
3676 | 0 | for (idx = 0; idx < (lexer->inbuflen - 1); idx++) { |
3677 | 0 | if (0xd3 == lexer->inbuffer[idx] && |
3678 | 0 | 0 == (0xfc & lexer->inbuffer[idx + 1])) { |
3679 | | // Looking for 0xd3, followed by 6 zeros. |
3680 | 0 | break; |
3681 | 0 | } |
3682 | 0 | } |
3683 | 0 | } |
3684 | 0 | if (0xd3 != lexer->inbuffer[idx]) { |
3685 | | // start of RTCM3 not found. |
3686 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3687 | 0 | "PACKET: packet_get1_chunked(fd %d) RTCM3 start not " |
3688 | 0 | "found, idx %zu, %.200s\n", |
3689 | 0 | fd, idx, |
3690 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3691 | 0 | lexer->inbuffer, lexer->inbuflen)); |
3692 | 0 | return 1; // not right, close enough |
3693 | 0 | } |
3694 | | /* Prolly should check for start of next RTCM3, to ensure we |
3695 | | * have all of the first one. |
3696 | | * packet_parse() works much better is the start (0xd3) of |
3697 | | * messages is at inbuffer[0] |
3698 | | */ |
3699 | 0 | memmove(lexer->inbuffer, &lexer->inbuffer[idx], lexer->inbuflen - idx); |
3700 | 0 | lexer->inbufptr = lexer->inbuffer; |
3701 | 0 | lexer->inbuflen -= idx; |
3702 | 0 | lexer->chunk_remaining -= idx; |
3703 | 0 | if (sizeof(lexer->inbuffer) < lexer->inbuflen) { |
3704 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3705 | 0 | "PACKET: packet_get1_chunked(fd %d) mid inbuflen %zu !!! " |
3706 | 0 | "idx %zu \n", |
3707 | 0 | fd, lexer->inbuflen, idx); |
3708 | 0 | return -1; // unrecoverable error |
3709 | 0 | } |
3710 | 0 | if (0 > lexer->chunk_remaining) { |
3711 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3712 | 0 | "PACKET: packet_get1_chunked(fd %d) idx %zu remaining %d " |
3713 | 0 | "< 0 !!!\n", |
3714 | 0 | fd, idx, lexer->chunk_remaining); |
3715 | 0 | return -1; // unrecoverable error |
3716 | 0 | } |
3717 | 0 | lexer->outbuflen = 0; |
3718 | |
|
3719 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3720 | 0 | "PACKET: NTRIP: packet_get1_chunked(fd %d) to packet_parse() " |
3721 | 0 | "inbuflen %zu idx %zu outbuflen %zu remaining %d pbu %d " |
3722 | 0 | ">%.200s<\n", |
3723 | 0 | fd, lexer->inbuflen, idx, lexer->outbuflen, |
3724 | 0 | lexer->chunk_remaining, (int) packet_buffered_input(lexer), |
3725 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3726 | 0 | lexer->inbufptr, lexer->inbuflen)); |
3727 | 0 | taken = lexer->inbuflen; |
3728 | 0 | packet_parse(lexer); |
3729 | 0 | taken -= lexer->inbuflen; |
3730 | 0 | lexer->chunk_remaining -= taken; |
3731 | |
|
3732 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3733 | 0 | "PACKET: packet_get1_chunked(fd %d) fm packet_parse() taken %zd " |
3734 | 0 | "inbuflen %zd outbuflen %zd remaining %d >%.200s<\n", |
3735 | 0 | fd, taken, lexer->inbuflen, lexer->outbuflen, |
3736 | 0 | lexer->chunk_remaining, |
3737 | 0 | gps_hexdump(scratchbuf, sizeof(scratchbuf), |
3738 | 0 | lexer->outbuffer, lexer->outbuflen)); |
3739 | |
|
3740 | 0 | if (sizeof(lexer->inbuffer) < lexer->inbuflen) { |
3741 | 0 | GPSD_LOG(LOG_ERROR, &lexer->errout, |
3742 | 0 | "PACKET: packet_get1_chunked(fd %d) start inbuflen %zu " |
3743 | 0 | "< 0 !!!\n", |
3744 | 0 | fd, lexer->inbuflen); |
3745 | 0 | return -1; // unrecoverable error |
3746 | 0 | } |
3747 | 0 | return (ssize_t)lexer->outbuflen; |
3748 | 0 | } |
3749 | | |
3750 | | /* grab a packet; |
3751 | | * return: greater than zero: length |
3752 | | * > 0 == got a packet. |
3753 | | * 0 == EOF or no full packet |
3754 | | * -1 == I/O error |
3755 | | */ |
3756 | | ssize_t packet_get1(struct gps_device_t *session) |
3757 | 0 | { |
3758 | | /* recvd, and watned big enough to hold size_t and ssize_t |
3759 | | * to Pacify Coveruty 498038, and avoid signed/unsigned math */ |
3760 | 0 | long long recvd; |
3761 | 0 | long long wanted; |
3762 | 0 | char scratchbuf[MAX_PACKET_LENGTH * 4 + 1]; |
3763 | 0 | int fd = session->gpsdata.gps_fd; |
3764 | 0 | struct gps_lexer_t *lexer = &session->lexer; |
3765 | |
|
3766 | 0 | if (true == lexer->chunked) { |
3767 | | // De-chunking too complicated to do unlike below. |
3768 | 0 | return packet_get1_chunked(session); |
3769 | 0 | } |
3770 | | |
3771 | 0 | errno = 0; |
3772 | 0 | wanted = sizeof(lexer->inbuffer) - lexer->inbuflen; |
3773 | 0 | if (0 >= wanted) { |
3774 | | // should never happen, pacify Coverity 498039 |
3775 | 0 | return -1; |
3776 | 0 | } |
3777 | | /* O_NONBLOCK set, so this should not block. |
3778 | | * Best not to block on an unresponsive GNSS receiver */ |
3779 | 0 | recvd = read(fd, lexer->inbuffer + lexer->inbuflen, wanted); |
3780 | |
|
3781 | 0 | if (-1 >= recvd) { |
3782 | 0 | if (EAGAIN == errno || |
3783 | 0 | EINTR == errno) { |
3784 | 0 | GPSD_LOG(LOG_RAW2, &lexer->errout, "PACKET: no bytes ready\n"); |
3785 | 0 | recvd = 0; |
3786 | | // fall through, input buffer may be nonempty |
3787 | 0 | } else { |
3788 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
3789 | 0 | "PACKET: packet_get1(fd %d) errno: %s(%d)\n", |
3790 | 0 | fd, strerror(errno), errno); |
3791 | 0 | return -1; |
3792 | 0 | } |
3793 | 0 | } else { |
3794 | 0 | GPSD_LOG(LOG_RAW1, &lexer->errout, |
3795 | 0 | "PACKET: Read %lld chars to buffer[%zd] (total %lld): %s\n", |
3796 | 0 | recvd, lexer->inbuflen, lexer->inbuflen + recvd, |
3797 | 0 | gpsd_packetdump(scratchbuf, sizeof(scratchbuf), |
3798 | 0 | lexer->inbufptr, (size_t) recvd)); |
3799 | 0 | lexer->inbuflen += recvd; |
3800 | 0 | } |
3801 | 0 | GPSD_LOG(LOG_SPIN, &lexer->errout, |
3802 | 0 | "PACKET: packet_get1(fd %d) recvd %lld %s(%d)\n", |
3803 | 0 | fd, recvd, strerror(errno), errno); |
3804 | | /* |
3805 | | * Bail out, indicating no more input, only if we just received |
3806 | | * nothing from the device and there is nothing waiting in the |
3807 | | * packet input buffer. |
3808 | | */ |
3809 | 0 | if (0 >= recvd && |
3810 | 0 | 0 >= packet_buffered_input(lexer)) { |
3811 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3812 | 0 | "PACKET: packet_get1(fd %d) recvd %lld\n", |
3813 | 0 | fd, recvd); |
3814 | 0 | return recvd; |
3815 | 0 | } |
3816 | | |
3817 | | // Otherwise, consume from the packet input buffer |
3818 | | // coverity[tainted_data] |
3819 | 0 | packet_parse(lexer); |
3820 | | |
3821 | | // if input buffer is full, discard |
3822 | 0 | if (sizeof(lexer->inbuffer) <= (lexer->inbuflen)) { |
3823 | | // coverity[tainted_data] |
3824 | 0 | packet_discard(lexer); |
3825 | 0 | lexer->state = GROUND_STATE; |
3826 | 0 | GPSD_LOG(LOG_WARN, &lexer->errout, |
3827 | 0 | "PACKET: packet_get1() inbuffer overflow.\n"); |
3828 | 0 | } |
3829 | | |
3830 | | /* |
3831 | | * If we gathered a packet, return its length; it will have been |
3832 | | * consumed out of the input buffer and moved to the output |
3833 | | * buffer. We don't care whether the read() returned 0 or -1 and |
3834 | | * gathered packet data was all buffered or whether it was partly |
3835 | | * just physically read. |
3836 | | * |
3837 | | * Note: this choice greatly simplifies life for callers of |
3838 | | * packet_get1(), but means that they cannot tell when a nonzero |
3839 | | * return means there was a successful physical read. They will |
3840 | | * thus credit a data source that drops out with being alive |
3841 | | * slightly longer than it actually was. This is unlikely to |
3842 | | * matter as long as any policy timeouts are large compared to |
3843 | | * the time required to consume the greatest possible amount |
3844 | | * of buffered input, but if you hack this code you need to |
3845 | | * be aware of the issue. It might also slightly affect |
3846 | | * performance profiling. |
3847 | | */ |
3848 | 0 | if (0 < lexer->outbuflen) { |
3849 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3850 | 0 | "PACKET: packet_get1(fd %d) outbuflen %zd\n", |
3851 | 0 | fd, lexer->outbuflen); |
3852 | 0 | return (ssize_t)lexer->outbuflen; |
3853 | 0 | } |
3854 | | /* |
3855 | | * Otherwise recvd is the size of whatever packet fragment we got. |
3856 | | * It can still be 0 or -1 at this point even if buffer data |
3857 | | * was consumed. |
3858 | | */ |
3859 | 0 | GPSD_LOG(LOG_IO, &lexer->errout, |
3860 | 0 | "PACKET: packet_get1(fd %d) recvd %lld\n", |
3861 | 0 | fd, recvd); |
3862 | 0 | return recvd; |
3863 | 0 | } |
3864 | | |
3865 | | // return the packet machine to the ground state |
3866 | | void packet_reset(struct gps_lexer_t *lexer) |
3867 | 0 | { |
3868 | 0 | lexer->type = BAD_PACKET; |
3869 | 0 | lexer->state = GROUND_STATE; |
3870 | 0 | lexer->inbuflen = 0; |
3871 | 0 | lexer->inbufptr = lexer->inbuffer; |
3872 | 0 | isgps_init(lexer); |
3873 | 0 | #ifdef STASH_ENABLE |
3874 | 0 | lexer->stashbuflen = 0; |
3875 | 0 | #endif // STASH_ENABLE |
3876 | 0 | } |
3877 | | |
3878 | | |
3879 | | #ifdef __UNUSED__ |
3880 | | // push back the last packet grabbed |
3881 | | void packet_pushback(struct gps_lexer_t *lexer) |
3882 | | { |
3883 | | if (MAX_PACKET_LENGTH > (lexer->outbuflen + lexer->inbuflen)) { |
3884 | | memmove(lexer->inbuffer + lexer->outbuflen, |
3885 | | lexer->inbuffer, lexer->inbuflen); |
3886 | | memmove(lexer->inbuffer, lexer->outbuffer, lexer->outbuflen); |
3887 | | lexer->inbuflen += lexer->outbuflen; |
3888 | | lexer->inbufptr += lexer->outbuflen; |
3889 | | lexer->outbuflen = 0; |
3890 | | } |
3891 | | } |
3892 | | #endif // __UNUSED |
3893 | | |
3894 | | // vim: set expandtab shiftwidth=4 |