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