1 /*
2 * This file is Copyright (c) 2010-2018 by the GPSD project
3 * SPDX-License-Identifier: BSD-2-clause
4 */
5
6 #include "gpsd_config.h" /* must be before all includes */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdbool.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <unistd.h>
14
15 #include "gpsd.h"
16 #include "bits.h"
17 #include "gps_json.h"
18 #include "strfuncs.h"
19
20 static int verbose = 0;
21 static bool scaled = true;
22 static bool json = true;
23 static bool pseudonmea = false;
24 static bool split24 = false;
25 static bool minlength = false;
26 static unsigned int ntypes = 0;
27 static unsigned int typelist[32];
28 static struct gps_context_t context;
29
30 /**************************************************************************
31 *
32 * Generic machinery
33 *
34 **************************************************************************/
35
36 #ifdef AIVDM_ENABLE
raw_hexdump(char * scbuf,size_t scbuflen,int structured,char * binbuf,size_t binbuflen)37 static const char *raw_hexdump(char *scbuf, size_t scbuflen, int structured,
38 char *binbuf, size_t binbuflen)
39 {
40 if (!structured)
41 return gpsd_hexdump(scbuf, scbuflen, binbuf, binbuflen);
42 /* Data parsed as structured doesn't have correct raw data */
43 #ifndef SQUELCH_ENABLE
44 size_t len =
45 (size_t) ((binbuflen >
46 MAX_PACKET_LENGTH) ? MAX_PACKET_LENGTH : binbuflen) * 2;
47 if (len > scbuflen - 1) len = scbuflen - 1;
48
49 memset(scbuf, 'x', len);
50 scbuf[len] = '\0';
51 #else /* SQUELCH defined */
52 scbuf[0] = '\0';
53 #endif /* SQUELCH_ENABLE */
54 return scbuf;
55 }
56
aivdm_csv_dump(struct ais_t * ais,char * buf,size_t buflen)57 static void aivdm_csv_dump(struct ais_t *ais, char *buf, size_t buflen)
58 {
59 char scratchbuf[MAX_PACKET_LENGTH*2+1];
60 bool imo = false;
61
62 (void)snprintf(buf, buflen, "%u|%u|%09u|", ais->type, ais->repeat,
63 ais->mmsi);
64 switch (ais->type) {
65 case 1: /* Position Report */
66 case 2:
67 case 3:
68 str_appendf(buf, buflen,
69 "%u|%d|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|0x%x",
70 ais->type1.status,
71 ais->type1.turn,
72 ais->type1.speed,
73 (unsigned int) ais->type1.accuracy,
74 ais->type1.lon,
75 ais->type1.lat,
76 ais->type1.course,
77 ais->type1.heading,
78 ais->type1.second,
79 ais->type1.maneuver,
80 (unsigned int) ais->type1.raim, ais->type1.radio);
81 break;
82 case 4: /* Base Station Report */
83 case 11: /* UTC/Date Response */
84 str_appendf(buf, buflen,
85 "%04u-%02u-%02uT%02u:%02u:%02uZ|%u|%d|%d|%u|%u|0x%x",
86 ais->type4.year,
87 ais->type4.month,
88 ais->type4.day,
89 ais->type4.hour,
90 ais->type4.minute,
91 ais->type4.second,
92 (unsigned int) ais->type4.accuracy,
93 ais->type4.lon,
94 ais->type4.lat,
95 ais->type4.epfd,
96 (unsigned int) ais->type4.raim, ais->type4.radio);
97 break;
98 case 5: /* Ship static and voyage related data */
99 str_appendf(buf, buflen,
100 "%u|%u|%s|%s|%u|%u|%u|%u|%u|%u|%02u-%02uT%02u:%02uZ|%u|%s|%u",
101 ais->type5.imo,
102 ais->type5.ais_version,
103 ais->type5.callsign,
104 ais->type5.shipname,
105 ais->type5.shiptype,
106 ais->type5.to_bow,
107 ais->type5.to_stern,
108 ais->type5.to_port,
109 ais->type5.to_starboard,
110 ais->type5.epfd,
111 ais->type5.month,
112 ais->type5.day,
113 ais->type5.hour,
114 ais->type5.minute,
115 ais->type5.draught,
116 ais->type5.destination, ais->type5.dte);
117 break;
118 case 6: /* Binary Message */
119 str_appendf(buf, buflen,
120 "%u|%u|%u|%u|%u",
121 ais->type6.seqno,
122 ais->type6.dest_mmsi,
123 (unsigned int) ais->type6.retransmit,
124 ais->type6.dac,
125 ais->type6.fid);
126 switch(ais->type6.dac) {
127 case 235: /* UK */
128 case 250: /* Rep. Of Ireland */
129 switch(ais->type6.fid) {
130 case 10: /* GLA - AtoN monitoring */
131 str_appendf(buf, buflen,
132 "|%u|%u|%u|%u|%u|%u|%u|%u",
133 ais->type6.dac235fid10.ana_int,
134 ais->type6.dac235fid10.ana_ext1,
135 ais->type6.dac235fid10.ana_ext2,
136 ais->type6.dac235fid10.racon,
137 ais->type6.dac235fid10.light,
138 (unsigned int)ais->type6.dac235fid10.alarm,
139 ais->type6.dac235fid10.stat_ext,
140 (unsigned int)ais->type6.dac235fid10.off_pos);
141 imo = true;
142 break;
143 }
144 break;
145 }
146 if (!imo)
147 str_appendf(buf, buflen,
148 "|%zd:%s",
149 ais->type6.bitcount,
150 raw_hexdump(scratchbuf, sizeof(scratchbuf),
151 ais->type6.structured,
152 ais->type6.bitdata,
153 BITS_TO_BYTES(ais->type6.bitcount)));
154 break;
155 case 7: /* Binary Acknowledge */
156 case 13: /* Safety Related Acknowledge */
157 str_appendf(buf, buflen,
158 "%u|%u|%u|%u",
159 ais->type7.mmsi1,
160 ais->type7.mmsi2, ais->type7.mmsi3, ais->type7.mmsi4);
161 break;
162 case 8: /* Binary Broadcast Message */
163 str_appendf(buf, buflen, "%u|%u", ais->type8.dac, ais->type8.fid);
164 switch(ais->type8.dac) {
165 case 1: /* International */
166 switch(ais->type8.fid) {
167 case 11: /* IMO236 - Met/Hydro message */
168 str_appendf(buf, buflen,
169 "|%d|%d|%02uT%02u:%02uZ|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
170 ais->type8.dac1fid11.lon,
171 ais->type8.dac1fid11.lat,
172 ais->type8.dac1fid11.day,
173 ais->type8.dac1fid11.hour,
174 ais->type8.dac1fid11.minute,
175 ais->type8.dac1fid11.wspeed,
176 ais->type8.dac1fid11.wgust,
177 ais->type8.dac1fid11.wdir,
178 ais->type8.dac1fid11.wgustdir,
179 ais->type8.dac1fid11.airtemp,
180 ais->type8.dac1fid11.humidity,
181 ais->type8.dac1fid11.dewpoint,
182 ais->type8.dac1fid11.pressure,
183 ais->type8.dac1fid11.pressuretend,
184 ais->type8.dac1fid11.visibility,
185 ais->type8.dac1fid11.waterlevel,
186 ais->type8.dac1fid11.leveltrend,
187 ais->type8.dac1fid11.cspeed,
188 ais->type8.dac1fid11.cdir,
189 ais->type8.dac1fid11.cspeed2,
190 ais->type8.dac1fid11.cdir2,
191 ais->type8.dac1fid11.cdepth2,
192 ais->type8.dac1fid11.cspeed3,
193 ais->type8.dac1fid11.cdir3,
194 ais->type8.dac1fid11.cdepth3,
195 ais->type8.dac1fid11.waveheight,
196 ais->type8.dac1fid11.waveperiod,
197 ais->type8.dac1fid11.wavedir,
198 ais->type8.dac1fid11.swellheight,
199 ais->type8.dac1fid11.swellperiod,
200 ais->type8.dac1fid11.swelldir,
201 ais->type8.dac1fid11.seastate,
202 ais->type8.dac1fid11.watertemp,
203 ais->type8.dac1fid11.preciptype,
204 ais->type8.dac1fid11.salinity,
205 ais->type8.dac1fid11.ice);
206 imo = true;
207 break;
208 case 31: /* IMO289 - Met/Hydro message */
209 str_appendf(buf, buflen,
210 "|%d|%d|%02uT%02u:%02uZ|%u|%u|%u|%u|%d|%u|%d|%u|%u|%u|%d|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%d|%u|%u|%u",
211 ais->type8.dac1fid31.lon,
212 ais->type8.dac1fid31.lat,
213 ais->type8.dac1fid31.day,
214 ais->type8.dac1fid31.hour,
215 ais->type8.dac1fid31.minute,
216 ais->type8.dac1fid31.wspeed,
217 ais->type8.dac1fid31.wgust,
218 ais->type8.dac1fid31.wdir,
219 ais->type8.dac1fid31.wgustdir,
220 ais->type8.dac1fid31.airtemp,
221 ais->type8.dac1fid31.humidity,
222 ais->type8.dac1fid31.dewpoint,
223 ais->type8.dac1fid31.pressure,
224 ais->type8.dac1fid31.pressuretend,
225 ais->type8.dac1fid31.visibility,
226 ais->type8.dac1fid31.waterlevel,
227 ais->type8.dac1fid31.leveltrend,
228 ais->type8.dac1fid31.cspeed,
229 ais->type8.dac1fid31.cdir,
230 ais->type8.dac1fid31.cspeed2,
231 ais->type8.dac1fid31.cdir2,
232 ais->type8.dac1fid31.cdepth2,
233 ais->type8.dac1fid31.cspeed3,
234 ais->type8.dac1fid31.cdir3,
235 ais->type8.dac1fid31.cdepth3,
236 ais->type8.dac1fid31.waveheight,
237 ais->type8.dac1fid31.waveperiod,
238 ais->type8.dac1fid31.wavedir,
239 ais->type8.dac1fid31.swellheight,
240 ais->type8.dac1fid31.swellperiod,
241 ais->type8.dac1fid31.swelldir,
242 ais->type8.dac1fid31.seastate,
243 ais->type8.dac1fid31.watertemp,
244 ais->type8.dac1fid31.preciptype,
245 ais->type8.dac1fid31.salinity,
246 ais->type8.dac1fid31.ice);
247 imo = true;
248 break;
249 }
250 break;
251 }
252 if (!imo)
253 str_appendf(buf, buflen,
254 "|%zd:%s",
255 ais->type8.bitcount,
256 raw_hexdump(scratchbuf, sizeof(scratchbuf),
257 ais->type8.structured,
258 ais->type8.bitdata,
259 BITS_TO_BYTES(ais->type8.bitcount)));
260 break;
261 case 9:
262 str_appendf(buf, buflen,
263 "%u|%u|%u|%d|%d|%u|%u|0x%x|%u|%u|0x%x",
264 ais->type9.alt,
265 ais->type9.speed,
266 (unsigned int) ais->type9.accuracy,
267 ais->type9.lon,
268 ais->type9.lat,
269 ais->type9.course,
270 ais->type9.second,
271 ais->type9.regional,
272 ais->type9.dte,
273 (unsigned int) ais->type9.raim, ais->type9.radio);
274 break;
275 case 10: /* UTC/Date Inquiry */
276 str_appendf(buf, buflen, "%u", ais->type10.dest_mmsi);
277 break;
278 case 12: /* Safety Related Message */
279 str_appendf(buf, buflen,
280 "%u|%u|%u|%s",
281 ais->type12.seqno,
282 ais->type12.dest_mmsi,
283 (unsigned int) ais->type12.retransmit, ais->type12.text);
284 break;
285 case 14: /* Safety Related Broadcast Message */
286 str_appendf(buf, buflen, "%s", ais->type14.text);
287 break;
288 case 15:
289 str_appendf(buf, buflen,
290 "%u|%u|%u|%u|%u|%u|%u|%u",
291 ais->type15.mmsi1,
292 ais->type15.type1_1,
293 ais->type15.offset1_1,
294 ais->type15.type1_2,
295 ais->type15.offset1_2,
296 ais->type15.mmsi2,
297 ais->type15.type2_1, ais->type15.offset2_1);
298 break;
299 case 16:
300 str_appendf(buf, buflen,
301 "%u|%u|%u|%u|%u|%u",
302 ais->type16.mmsi1,
303 ais->type16.offset1,
304 ais->type16.increment1,
305 ais->type16.mmsi2,
306 ais->type16.offset2, ais->type16.increment2);
307 break;
308 case 17:
309 str_appendf(buf, buflen,
310 "%d|%d|%zd:%s",
311 ais->type17.lon,
312 ais->type17.lat,
313 ais->type17.bitcount,
314 gpsd_hexdump(scratchbuf, sizeof(scratchbuf),
315 ais->type17.bitdata,
316 BITS_TO_BYTES(ais->type17.bitcount)));
317 break;
318 case 18:
319 str_appendf(buf, buflen,
320 "%u|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|%u|%u|%u|%u|%u|0x%x",
321 ais->type18.reserved,
322 ais->type18.speed,
323 (unsigned int) ais->type18.accuracy,
324 ais->type18.lon,
325 ais->type18.lat,
326 ais->type18.course,
327 ais->type18.heading,
328 ais->type18.second,
329 ais->type18.regional,
330 (unsigned int) ais->type18.cs,
331 (unsigned int) ais->type18.display,
332 (unsigned int) ais->type18.dsc,
333 (unsigned int) ais->type18.band,
334 (unsigned int) ais->type18.msg22,
335 (unsigned int) ais->type18.raim, ais->type18.radio);
336 break;
337 case 19:
338 str_appendf(buf, buflen,
339 "%u|%u|%u|%d|%d|%u|%u|%u|0x%x|%s|%u|%u|%u|%u|%u|%u|%u|%u|%u",
340 ais->type19.reserved,
341 ais->type19.speed,
342 (unsigned int) ais->type19.accuracy,
343 ais->type19.lon,
344 ais->type19.lat,
345 ais->type19.course,
346 ais->type19.heading,
347 ais->type19.second,
348 ais->type19.regional,
349 ais->type19.shipname,
350 ais->type19.shiptype,
351 ais->type19.to_bow,
352 ais->type19.to_stern,
353 ais->type19.to_port,
354 ais->type19.to_starboard,
355 ais->type19.epfd,
356 (unsigned int) ais->type19.raim,
357 ais->type19.dte, (unsigned int) ais->type19.assigned);
358 break;
359 case 20: /* Data Link Management Message */
360 str_appendf(buf, buflen,
361 "%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
362 ais->type20.offset1,
363 ais->type20.number1,
364 ais->type20.timeout1,
365 ais->type20.increment1,
366 ais->type20.offset2,
367 ais->type20.number2,
368 ais->type20.timeout2,
369 ais->type20.increment2,
370 ais->type20.offset3,
371 ais->type20.number3,
372 ais->type20.timeout3,
373 ais->type20.increment3,
374 ais->type20.offset4,
375 ais->type20.number4,
376 ais->type20.timeout4, ais->type20.increment4);
377 break;
378 case 21: /* Aid to Navigation */
379 str_appendf(buf, buflen,
380 "%u|%s|%u|%d|%d|%u|%u|%u|%u|%u|%u|%u|0x%x|%u|%u",
381 ais->type21.aid_type,
382 ais->type21.name,
383 (unsigned int) ais->type21.accuracy,
384 ais->type21.lon,
385 ais->type21.lat,
386 ais->type21.to_bow,
387 ais->type21.to_stern,
388 ais->type21.to_port,
389 ais->type21.to_starboard,
390 ais->type21.epfd,
391 ais->type21.second,
392 ais->type21.regional,
393 (unsigned int) ais->type21.off_position,
394 (unsigned int) ais->type21.raim,
395 (unsigned int) ais->type21.virtual_aid);
396 break;
397 case 22: /* Channel Management */
398 if (!ais->type22.addressed)
399 str_appendf(buf, buflen,
400 "%u|%u|%u|%u|%d|%d|%d|%d|%u|%u|%u|%u",
401 ais->type22.channel_a,
402 ais->type22.channel_b,
403 ais->type22.txrx,
404 (unsigned int) ais->type22.power,
405 ais->type22.area.ne_lon,
406 ais->type22.area.ne_lat,
407 ais->type22.area.sw_lon,
408 ais->type22.area.sw_lat,
409 (unsigned int) ais->type22.addressed,
410 (unsigned int) ais->type22.band_a,
411 (unsigned int) ais->type22.band_b, ais->type22.zonesize);
412 else
413 str_appendf(buf, buflen,
414 "%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
415 ais->type22.channel_a,
416 ais->type22.channel_b,
417 ais->type22.txrx,
418 (unsigned int) ais->type22.power,
419 ais->type22.mmsi.dest1,
420 ais->type22.mmsi.dest2,
421 (unsigned int) ais->type22.addressed,
422 (unsigned int) ais->type22.band_a,
423 (unsigned int) ais->type22.band_b, ais->type22.zonesize);
424 break;
425 case 23: /* Group Management Command */
426 str_appendf(buf, buflen,
427 "%d|%d|%d|%d|%u|%u|%u|%u|%u",
428 ais->type23.ne_lon,
429 ais->type23.ne_lat,
430 ais->type23.sw_lon,
431 ais->type23.sw_lat,
432 ais->type23.stationtype,
433 ais->type23.shiptype,
434 ais->type23.txrx,
435 ais->type23.interval, ais->type23.quiet);
436 break;
437 case 24: /* Class B CS Static Data Report */
438 str_appendf(buf, buflen, "%s|", ais->type24.shipname);
439 str_appendf(buf, buflen, "%u|", ais->type24.shiptype);
440 str_appendf(buf, buflen, "%s|", ais->type24.vendorid);
441 str_appendf(buf, buflen, "%u|", ais->type24.model);
442 str_appendf(buf, buflen, "%u|", ais->type24.serial);
443 str_appendf(buf, buflen, "%s|", ais->type24.callsign);
444 if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
445 str_appendf(buf, buflen, "%u", ais->type24.mothership_mmsi);
446 } else {
447 str_appendf(buf, buflen,
448 "%u|%u|%u|%u",
449 ais->type24.dim.to_bow,
450 ais->type24.dim.to_stern,
451 ais->type24.dim.to_port,
452 ais->type24.dim.to_starboard);
453 }
454 break;
455 case 25: /* Binary Message, Single Slot */
456 str_appendf(buf, buflen,
457 "%u|%u|%u|%u|%zd:%s",
458 (unsigned int) ais->type25.addressed,
459 (unsigned int) ais->type25.structured,
460 ais->type25.dest_mmsi,
461 ais->type25.app_id,
462 ais->type25.bitcount,
463 gpsd_hexdump(scratchbuf, sizeof(scratchbuf),
464 ais->type25.bitdata,
465 BITS_TO_BYTES(ais->type25.bitcount)));
466 break;
467 case 26: /* Binary Message, Multiple Slot */
468 str_appendf(buf, buflen,
469 "%u|%u|%u|%u|%zd:%s:%u",
470 (unsigned int) ais->type26.addressed,
471 (unsigned int) ais->type26.structured,
472 ais->type26.dest_mmsi,
473 ais->type26.app_id,
474 ais->type26.bitcount,
475 gpsd_hexdump(scratchbuf, sizeof(scratchbuf),
476 ais->type26.bitdata,
477 BITS_TO_BYTES(ais->type26.bitcount)),
478 ais->type26.radio);
479 break;
480 case 27: /* Long Range AIS Broadcast message */
481 str_appendf(buf, buflen,
482 "%u|%u|%d|%d|%u|%u|%u|%u",
483 ais->type27.status,
484 (unsigned int)ais->type27.accuracy,
485 ais->type27.lon,
486 ais->type27.lat,
487 ais->type27.speed,
488 ais->type27.course,
489 (unsigned int)ais->type27.raim,
490 (unsigned int)ais->type27.gnss);
491 break;
492 default:
493 str_appendf(buf, buflen, "unknown AIVDM message content.");
494 break;
495 }
496 (void)strlcat(buf, "\r\n", buflen);
497 }
498 #endif
499
filter(gps_mask_t changed,struct gps_device_t * session)500 static bool filter(gps_mask_t changed, struct gps_device_t *session)
501 /* say whether a given message should be visible */
502 {
503 if (ntypes == 0)
504 return true;
505 else {
506 unsigned int i, t;
507
508 if ((changed & AIS_SET)!=0)
509 t = session->gpsdata.ais.type;
510 else if ((changed & RTCM2_SET)!=0)
511 t = session->gpsdata.rtcm2.type;
512 else if ((changed & RTCM3_SET)!=0)
513 t = session->gpsdata.rtcm3.type;
514 else
515 return true;
516 for (i = 0; i < ntypes; i++)
517 if (t == typelist[i])
518 return true;
519 }
520 return false;
521 }
522
pseudonmea_report(gps_mask_t changed,struct gps_device_t * device)523 static void pseudonmea_report(gps_mask_t changed, struct gps_device_t *device)
524 /* report pseudo-NMEA in appropriate circumstances */
525 {
526 if (GPS_PACKET_TYPE(device->lexer.type)
527 && !TEXTUAL_PACKET_TYPE(device->lexer.type)) {
528 char buf[MAX_PACKET_LENGTH * 3 + 2];
529
530 if ((changed & REPORT_IS) != 0) {
531 nmea_tpv_dump(device, buf, sizeof(buf));
532 (void)fputs(buf, stdout);
533 }
534
535 if ((changed & SATELLITE_SET) != 0) {
536 nmea_sky_dump(device, buf, sizeof(buf));
537 (void)fputs(buf, stdout);
538 }
539
540 if ((changed & SUBFRAME_SET) != 0) {
541 nmea_subframe_dump(device, buf, sizeof(buf));
542 (void)fputs(buf, stdout);
543 }
544 #ifdef AIVDM_ENABLE
545 if ((changed & AIS_SET) != 0) {
546 nmea_ais_dump(device, buf, sizeof(buf));
547 (void)fputs(buf, stdout);
548 }
549 #endif /* AIVDM_ENABLE */
550 }
551 }
552
decode(FILE * fpin,FILE * fpout)553 static void decode(FILE *fpin, FILE*fpout)
554 /* sensor data on fpin to dump format on fpout */
555 {
556 struct gps_device_t session;
557 struct gps_policy_t policy;
558 size_t minima[PACKET_TYPES+1];
559 #if defined(SOCKET_EXPORT_ENABLE) || defined(AIVDM_ENABLE)
560 char buf[GPS_JSON_RESPONSE_MAX * 4];
561 #endif
562 int i;
563
564 //This looks like a good idea, but it breaks regression tests
565 //(void)strlcpy(session.gpsdata.dev.path, "stdin", sizeof(session.gpsdata.dev.path));
566 memset(&policy, '\0', sizeof(policy));
567 policy.json = json;
568 policy.scaled = scaled;
569 policy.nmea = pseudonmea;
570
571 gpsd_time_init(&context, time(NULL));
572 context.readonly = true;
573 gpsd_init(&session, &context, NULL);
574 gpsd_clear(&session);
575 session.gpsdata.gps_fd = fileno(fpin);
576 session.gpsdata.dev.baudrate = 38400; /* hack to enable subframes */
577 (void)strlcpy(session.gpsdata.dev.path,
578 "stdin",
579 sizeof(session.gpsdata.dev.path));
580 for (i = 0; i < (int)(sizeof(minima)/sizeof(minima[0])); i++)
581 minima[i] = MAX_PACKET_LENGTH+1;
582
583 for (;;)
584 {
585 gps_mask_t changed = gpsd_poll(&session);
586
587 if (changed == ERROR_SET || changed == NODATA_IS)
588 break;
589 if (session.lexer.type == COMMENT_PACKET)
590 gpsd_set_century(&session);
591 if (verbose >= 1 && TEXTUAL_PACKET_TYPE(session.lexer.type))
592 (void)fputs((char *)session.lexer.outbuffer, fpout);
593 if (session.lexer.outbuflen < minima[session.lexer.type+1])
594 minima[session.lexer.type+1] = session.lexer.outbuflen;
595 /* mask should match what's in report_data() */
596 if ((changed & (REPORT_IS|GST_SET|SATELLITE_SET|SUBFRAME_SET|ATTITUDE_SET|RTCM2_SET|RTCM3_SET|AIS_SET|PASSTHROUGH_IS)) == 0)
597 continue;
598 if (!filter(changed, &session))
599 continue;
600 else if (json) {
601 if ((changed & PASSTHROUGH_IS) != 0) {
602 (void)fputs((char *)session.lexer.outbuffer, fpout);
603 (void)fputs("\n", fpout);
604 }
605 #ifdef SOCKET_EXPORT_ENABLE
606 else {
607 if ((changed & AIS_SET)!=0) {
608 if (session.gpsdata.ais.type == 24 && session.gpsdata.ais.type24.part != both && !split24)
609 continue;
610 }
611 json_data_report(changed,
612 &session, &policy,
613 buf, sizeof(buf));
614 (void)fputs(buf, fpout);
615 }
616 #endif /* SOCKET_EXPORT_ENABLE */
617 #ifdef AIVDM_ENABLE
618 } else if (session.lexer.type == AIVDM_PACKET) {
619 if ((changed & AIS_SET)!=0) {
620 if (session.gpsdata.ais.type == 24 && session.gpsdata.ais.type24.part != both && !split24)
621 continue;
622 aivdm_csv_dump(&session.gpsdata.ais, buf, sizeof(buf));
623 (void)fputs(buf, fpout);
624 }
625 #endif /* AIVDM_ENABLE */
626 }
627 if (policy.nmea)
628 pseudonmea_report(changed, &session);
629 }
630
631 if (minlength)
632 {
633 for (i = 0; i < (int)(sizeof(minima)/sizeof(minima[0])); i++) {
634 /* dump all minima, ignoring comments */
635 if (i != 1 && minima[i] < MAX_PACKET_LENGTH+1) {
636 const struct gps_type_t **dp;
637 char *np = "Unknown";
638 for (dp = gpsd_drivers; *dp; dp++) {
639 if ((*dp)->packet_type == i-1) {
640 np = (*dp)->type_name;
641 break;
642 }
643 }
644 printf("%s (%d): %u\n", np, i-1, (unsigned int)minima[i]);
645 }
646 }
647 }
648 }
649
650 #ifdef SOCKET_EXPORT_ENABLE
encode(FILE * fpin,FILE * fpout)651 static void encode(FILE *fpin, FILE *fpout)
652 /* JSON format on fpin to JSON on fpout - idempotency test */
653 {
654 char inbuf[BUFSIZ];
655 struct gps_policy_t policy;
656 struct gps_device_t session;
657 int lineno = 0;
658
659 memset(&policy, '\0', sizeof(policy));
660 memset(&session, '\0', sizeof(session));
661 session.context = &context;
662 context.errout.debug = LOG_SHOUT;
663 context.errout.label = "gpsdecode";
664 (void)strlcpy(session.gpsdata.dev.path,
665 "stdin",
666 sizeof(session.gpsdata.dev.path));
667 policy.json = true;
668 policy.nmea = pseudonmea;
669 /* Parsing is always made in unscaled mode,
670 * this policy applies to the dumping */
671 policy.scaled = scaled;
672
673 while (fgets(inbuf, (int)sizeof(inbuf), fpin) != NULL) {
674 int status;
675
676 ++lineno;
677 if (inbuf[0] == '#')
678 continue;
679 status = libgps_json_unpack(inbuf, &session.gpsdata, NULL);
680 if (status != 0) {
681 (void)fprintf(stderr,
682 "gpsdecode: dying with status %d (%s) on line %d\n",
683 status, json_error_string(status), lineno);
684 exit(EXIT_FAILURE);
685 }
686 json_data_report(session.gpsdata.set,
687 &session, &policy,
688 inbuf, sizeof(inbuf));
689 (void)fputs(inbuf, fpout);
690 }
691 }
692 #endif /* SOCKET_EXPORT_ENABLE */
693
main(int argc,char ** argv)694 int main(int argc, char **argv)
695 {
696 int c;
697 enum { doencode, dodecode } mode = dodecode;
698
699 gps_context_init(&context, "gpsdecode");
700
701 while ((c = getopt(argc, argv, "cdejmnpst:uvVD:")) != EOF) {
702 switch (c) {
703 case 'c':
704 json = false;
705 break;
706
707 case 'd':
708 mode = dodecode;
709 break;
710
711 case 'e':
712 mode = doencode;
713 break;
714
715 case 'j':
716 json = true;
717 break;
718
719 case 'm':
720 minlength = true;
721 json = false;
722 break;
723
724 case 'n':
725 pseudonmea = true;
726 break;
727
728 case 's':
729 split24 = true;
730 break;
731
732 case 't':
733 typelist[ntypes++] = (unsigned int)atoi(strtok(optarg, ","));
734 for(;;) {
735 char *next = strtok(NULL, ",");
736 if (next == NULL)
737 break;
738 typelist[ntypes++] = (unsigned int)atoi(next);
739 }
740 break;
741
742 case 'u':
743 scaled = false;
744 break;
745
746 case 'v':
747 verbose = 1;
748 break;
749
750 case 'D':
751 context.errout.debug = verbose = atoi(optarg);
752 #if defined(CLIENTDEBUG_ENABLE) && defined(SOCKET_EXPORT_ENABLE)
753 json_enable_debug(verbose - 2, stderr);
754 #endif
755 break;
756
757 case 'V':
758 (void)fprintf(stderr, "gpsdecode revision " VERSION "\n");
759 exit(EXIT_SUCCESS);
760
761 case '?':
762 default:
763 (void)fputs("gpsdecode [-v]\n", stderr);
764 exit(EXIT_FAILURE);
765 }
766 }
767 //argc -= optind;
768 //argv += optind;
769
770 if (mode == doencode) {
771 #ifdef SOCKET_EXPORT_ENABLE
772 encode(stdin, stdout);
773 #else
774 (void)fprintf(stderr, "gpsdecode: encoding support isn't compiled.\n");
775 exit(EXIT_FAILURE);
776 #endif /* SOCKET_EXPORT_ENABLE */
777 } else
778 decode(stdin, stdout);
779 exit(EXIT_SUCCESS);
780 }
781
782 /* gpsdecode.c ends here */
783