2 * This file is Copyright (c) 2010 by the GPSD project
3 * BSD terms apply: see the file COPYING in the distribution root for details.
8 #endif /* S_SPLINT_S */
20 static int verbose = 0;
21 static bool scaled = true;
22 static bool json = false;
24 /**************************************************************************
28 **************************************************************************/
30 void gpsd_report(int errlevel, const char *fmt, ...)
31 /* assemble command in printf(3) style, use stderr or syslog */
33 if (errlevel <= verbose) {
37 (void)strlcpy(buf, "gpsdecode: ", BUFSIZ);
39 (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt,
42 (void)fputs(buf, stdout);
46 static void aivdm_csv_dump(struct ais_t *ais, char *buf, size_t buflen)
48 (void)snprintf(buf, buflen, "%u|%u|%09u|", ais->type, ais->repeat,
52 case 1: /* Position Report */
55 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
56 "%u|%d|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|0x%x",
60 (uint) ais->type1.accuracy,
67 (uint) ais->type1.raim, ais->type1.radio);
69 case 4: /* Base Station Report */
70 case 11: /* UTC/Date Response */
71 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
72 "%04u-%02u-%02uT%02u:%02u:%02uZ|%u|%d|%d|%u|%u|0x%x",
79 (uint) ais->type4.accuracy,
83 (uint) ais->type4.raim, ais->type4.radio);
85 case 5: /* Ship static and voyage related data */
86 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
87 "%u|%u|%s|%s|%u|%u|%u|%u|%u|%u|%02u-%02uT%02u:%02uZ|%u|%s|%u",
89 ais->type5.ais_version,
96 ais->type5.to_starboard,
103 ais->type5.destination, ais->type5.dte);
105 case 6: /* Binary Message */
106 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
107 "%u|%u|%u|%u|%u|%zd:%s",
109 ais->type6.dest_mmsi,
110 (uint) ais->type6.retransmit,
114 gpsd_hexdump(ais->type6.bitdata,
115 (ais->type6.bitcount + 7) / 8));
117 case 7: /* Binary Acknowledge */
118 case 13: /* Safety Related Acknowledge */
119 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
122 ais->type7.mmsi2, ais->type7.mmsi3, ais->type7.mmsi4);
124 case 8: /* Binary Broadcast Message */
125 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
130 gpsd_hexdump(ais->type8.bitdata,
131 (ais->type8.bitcount + 7) / 8));
134 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
135 "%u|%u|%u|%d|%d|%u|%u|0x%x|%u|%u|0x%x",
138 (uint) ais->type9.accuracy,
145 (uint) ais->type9.raim, ais->type9.radio);
147 case 10: /* UTC/Date Inquiry */
148 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
149 "%u", ais->type10.dest_mmsi);
151 case 12: /* Safety Related Message */
152 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
155 ais->type12.dest_mmsi,
156 (uint) ais->type12.retransmit, ais->type12.text);
158 case 14: /* Safety Related Broadcast Message */
159 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
160 "%s", ais->type14.text);
163 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
164 "%u|%u|%u|%u|%u|%u|%u|%u",
167 ais->type15.offset1_1,
169 ais->type15.offset1_2,
171 ais->type15.type2_1, ais->type15.offset2_1);
174 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
178 ais->type16.increment1,
180 ais->type16.offset2, ais->type16.increment2);
183 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
187 ais->type17.bitcount,
188 gpsd_hexdump(ais->type17.bitdata,
189 (ais->type17.bitcount + 7) / 8));
192 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
193 "%u|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|%u|%u|%u|%u|%u|0x%x",
194 ais->type18.reserved,
196 (uint) ais->type18.accuracy,
202 ais->type18.regional,
203 (uint) ais->type18.cs,
204 (uint) ais->type18.display,
205 (uint) ais->type18.dsc,
206 (uint) ais->type18.band,
207 (uint) ais->type18.msg22,
208 (uint) ais->type18.raim, ais->type18.radio);
211 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
212 "%u|%u|%u|%d|%d|%u|%u|%u|0x%x|%s|%u|%u|%u|%u|%u|%u|%u|%u|%u",
213 ais->type19.reserved,
215 (uint) ais->type19.accuracy,
221 ais->type19.regional,
222 ais->type19.shipname,
223 ais->type19.shiptype,
225 ais->type19.to_stern,
227 ais->type19.to_starboard,
229 (uint) ais->type19.raim,
230 ais->type19.dte, (uint) ais->type19.assigned);
232 case 20: /* Data Link Management Message */
233 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
234 "%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
237 ais->type20.timeout1,
238 ais->type20.increment1,
241 ais->type20.timeout2,
242 ais->type20.increment2,
245 ais->type20.timeout3,
246 ais->type20.increment3,
249 ais->type20.timeout4, ais->type20.increment4);
251 case 21: /* Aid to Navigation */
252 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
253 "%u|%s|%u|%d|%d|%u|%u|%u|%u|%u|%u|%u|0x%x|%u|%u",
254 ais->type21.aid_type,
256 (uint) ais->type21.accuracy,
260 ais->type21.to_stern,
262 ais->type21.to_starboard,
265 ais->type21.regional,
266 (uint) ais->type21.off_position,
267 (uint) ais->type21.raim,
268 (uint) ais->type21.virtual_aid);
270 case 22: /* Channel Management */
271 if (!ais->type22.addressed)
272 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
273 "%u|%u|%u|%u|%d|%d|%d|%d|%u|%u|%u|%u",
274 ais->type22.channel_a,
275 ais->type22.channel_b,
277 (uint) ais->type22.power,
278 ais->type22.area.ne_lon,
279 ais->type22.area.ne_lat,
280 ais->type22.area.sw_lon,
281 ais->type22.area.sw_lat,
282 (uint) ais->type22.addressed,
283 (uint) ais->type22.band_a,
284 (uint) ais->type22.band_b, ais->type22.zonesize);
286 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
287 "%u|%u|%u|%u|%u|%u|%u|%u|%u|%u",
288 ais->type22.channel_a,
289 ais->type22.channel_b,
291 (uint) ais->type22.power,
292 ais->type22.mmsi.dest1,
293 ais->type22.mmsi.dest2,
294 (uint) ais->type22.addressed,
295 (uint) ais->type22.band_a,
296 (uint) ais->type22.band_b, ais->type22.zonesize);
298 case 23: /* Group Management Command */
299 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
300 "%d|%d|%d|%d|%u|%u|%u|%u|%u",
305 ais->type23.stationtype,
306 ais->type23.shiptype,
308 ais->type23.interval, ais->type23.quiet);
310 case 24: /* Class B CS Static Data Report */
311 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
312 "%s|", ais->type24.shipname);
313 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
314 "%u|", ais->type24.shiptype);
315 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
316 "%s|%s|", ais->type24.vendorid, ais->type24.callsign);
317 if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
318 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
319 "%u", ais->type24.mothership_mmsi);
321 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
323 ais->type24.dim.to_bow,
324 ais->type24.dim.to_stern,
325 ais->type24.dim.to_port,
326 ais->type24.dim.to_starboard);
329 case 25: /* Binary Message, Single Slot */
330 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
331 "%u|%u|%u|%u|%zd:%s\r\n",
332 (uint) ais->type25.addressed,
333 (uint) ais->type25.structured,
334 ais->type25.dest_mmsi,
336 ais->type25.bitcount,
337 gpsd_hexdump(ais->type25.bitdata,
338 (ais->type25.bitcount + 7) / 8));
340 case 26: /* Binary Message, Multiple Slot */
341 (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
342 "%u|%u|%u|%u|%zd:%s:%u\r\n",
343 (uint) ais->type26.addressed,
344 (uint) ais->type26.structured,
345 ais->type26.dest_mmsi,
347 ais->type26.bitcount,
348 gpsd_hexdump(ais->type26.bitdata,
349 (ais->type26.bitcount + 7) / 8),
353 (void)snprintf(buf + strlen(buf),
354 buflen - strlen(buf),
355 "unknown AIVDM message content.");
359 (void)strlcat(buf, "\r\n", buflen);
362 /*@ -compdestroy -compdef -usedef @*/
363 static void decode(FILE * fpin, FILE * fpout)
364 /* RTCM or AIS packets on fpin to dump format on fpout */
366 struct gps_packet_t lexer;
367 struct rtcm2_t rtcm2;
368 struct rtcm3_t rtcm3;
370 struct aivdm_context_t aivdm[AIVDM_CHANNELS];
373 memset(&aivdm, '\0', sizeof(aivdm));
374 packet_reset(&lexer);
376 while (packet_get(fileno(fpin), &lexer) > 0) {
377 if (lexer.type == COMMENT_PACKET)
379 #ifdef RTCM104V2_ENABLE
380 else if (lexer.type == RTCM2_PACKET) {
381 rtcm2_unpack(&rtcm2, (char *)lexer.isgps.buf);
383 rtcm2_json_dump(&rtcm2, buf, sizeof(buf));
385 rtcm2_sager_dump(&rtcm2, buf, sizeof(buf));
386 (void)fputs(buf, fpout);
389 #ifdef RTCM104V3_ENABLE
390 else if (lexer.type == RTCM3_PACKET) {
391 rtcm3_unpack(&rtcm3, (char *)lexer.outbuffer);
392 rtcm3_dump(&rtcm3, stdout);
395 else if (lexer.type == AIVDM_PACKET) {
397 (void)fputs((char *)lexer.outbuffer, stdout);
400 ((char *)lexer.outbuffer, lexer.outbuflen, aivdm, &ais)) {
402 aivdm_csv_dump(&ais, buf, sizeof(buf));
404 aivdm_json_dump(&ais, scaled, buf, sizeof(buf));
405 (void)fputs(buf, fpout);
413 /*@ +compdestroy +compdef +usedef @*/
416 static void encode(FILE * fpin, FILE * fpout)
417 /* dump format on fpin to RTCM-104 on fpout */
420 struct gps_data_t gpsdata;
423 memset(&gpsdata, '\0', sizeof(gpsdata)); /* avoid segfault due to garbage in thread-hook slots */
424 while (fgets(inbuf, (int)sizeof(inbuf), fpin) != NULL) {
430 status = libgps_json_unpack(inbuf, &gpsdata, NULL);
432 (void)fprintf(stderr,
433 "gpsdecode: bailing out with status %d (%s) on line %d\n",
434 status, json_error_string(status), lineno);
437 if ((gpsdata.set & RTCM2_SET) != 0) {
440 rtcm2_json_dump(&gpsdata.rtcm2, outbuf, sizeof(outbuf));
441 (void)fputs(outbuf, fpout);
443 if ((gpsdata.set & AIS_SET) != 0) {
445 aivdm_json_dump(&gpsdata.ais, false, outbuf, sizeof(outbuf));
446 (void)fputs(outbuf, fpout);
453 int main(int argc, char **argv)
457 { doencode, dodecode } mode = dodecode;
459 while ((c = getopt(argc, argv, "cdejpuVD:")) != EOF) {
482 verbose = atoi(optarg);
483 gpsd_hexdump_level = verbose;
484 #ifdef CLIENTDEBUG_ENABLE
485 json_enable_debug(verbose - 2, stderr);
490 (void)fprintf(stderr, "gpsdecode revision " VERSION "\n");
495 (void)fputs("gpsdecode [-v]\n", stderr);
502 if (mode == doencode)
503 encode(stdin, stdout);
505 decode(stdin, stdout);
509 /* gpsdecode.c ends here */