cleanup specfile for packaging
[profile/ivi/gpsd.git] / gpsdecode.c
1 /*
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.
4  */
5 #include <sys/types.h>
6 #ifndef S_SPLINT_S
7 #include <unistd.h>
8 #endif /* S_SPLINT_S */
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <stdbool.h>
15 #include <ctype.h>
16
17 #include "gpsd.h"
18 #include "gps_json.h"
19
20 static int verbose = 0;
21 static bool scaled = true;
22 static bool json = false;
23
24 /**************************************************************************
25  *
26  * Generic machinery
27  *
28  **************************************************************************/
29
30 void gpsd_report(int errlevel, const char *fmt, ...)
31 /* assemble command in printf(3) style, use stderr or syslog */
32 {
33     if (errlevel <= verbose) {
34         char buf[BUFSIZ];
35         va_list ap;
36
37         (void)strlcpy(buf, "gpsdecode: ", BUFSIZ);
38         va_start(ap, fmt);
39         (void)vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt,
40                         ap);
41         va_end(ap);
42         (void)fputs(buf, stdout);
43     }
44 }
45
46 static void aivdm_csv_dump(struct ais_t *ais, char *buf, size_t buflen)
47 {
48     (void)snprintf(buf, buflen, "%u|%u|%09u|", ais->type, ais->repeat,
49                    ais->mmsi);
50     /*@ -formatcode @*/
51     switch (ais->type) {
52     case 1:                     /* Position Report */
53     case 2:
54     case 3:
55         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
56                        "%u|%d|%u|%u|%d|%d|%u|%u|%u|0x%x|%u|0x%x",
57                        ais->type1.status,
58                        ais->type1.turn,
59                        ais->type1.speed,
60                        (uint) ais->type1.accuracy,
61                        ais->type1.lon,
62                        ais->type1.lat,
63                        ais->type1.course,
64                        ais->type1.heading,
65                        ais->type1.second,
66                        ais->type1.maneuver,
67                        (uint) ais->type1.raim, ais->type1.radio);
68         break;
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",
73                        ais->type4.year,
74                        ais->type4.month,
75                        ais->type4.day,
76                        ais->type4.hour,
77                        ais->type4.minute,
78                        ais->type4.second,
79                        (uint) ais->type4.accuracy,
80                        ais->type4.lon,
81                        ais->type4.lat,
82                        ais->type4.epfd,
83                        (uint) ais->type4.raim, ais->type4.radio);
84         break;
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",
88                        ais->type5.imo,
89                        ais->type5.ais_version,
90                        ais->type5.callsign,
91                        ais->type5.shipname,
92                        ais->type5.shiptype,
93                        ais->type5.to_bow,
94                        ais->type5.to_stern,
95                        ais->type5.to_port,
96                        ais->type5.to_starboard,
97                        ais->type5.epfd,
98                        ais->type5.month,
99                        ais->type5.day,
100                        ais->type5.hour,
101                        ais->type5.minute,
102                        ais->type5.draught,
103                        ais->type5.destination, ais->type5.dte);
104         break;
105     case 6:                     /* Binary Message */
106         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
107                        "%u|%u|%u|%u|%u|%zd:%s",
108                        ais->type6.seqno,
109                        ais->type6.dest_mmsi,
110                        (uint) ais->type6.retransmit,
111                        ais->type6.dac,
112                        ais->type6.fid,
113                        ais->type6.bitcount,
114                        gpsd_hexdump(ais->type6.bitdata,
115                                     (ais->type6.bitcount + 7) / 8));
116         break;
117     case 7:                     /* Binary Acknowledge */
118     case 13:                    /* Safety Related Acknowledge */
119         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
120                        "%u|%u|%u|%u",
121                        ais->type7.mmsi1,
122                        ais->type7.mmsi2, ais->type7.mmsi3, ais->type7.mmsi4);
123         break;
124     case 8:                     /* Binary Broadcast Message */
125         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
126                        "%u|%u|%zd:%s",
127                        ais->type8.dac,
128                        ais->type8.fid,
129                        ais->type8.bitcount,
130                        gpsd_hexdump(ais->type8.bitdata,
131                                     (ais->type8.bitcount + 7) / 8));
132         break;
133     case 9:
134         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
135                        "%u|%u|%u|%d|%d|%u|%u|0x%x|%u|%u|0x%x",
136                        ais->type9.alt,
137                        ais->type9.speed,
138                        (uint) ais->type9.accuracy,
139                        ais->type9.lon,
140                        ais->type9.lat,
141                        ais->type9.course,
142                        ais->type9.second,
143                        ais->type9.regional,
144                        ais->type9.dte,
145                        (uint) ais->type9.raim, ais->type9.radio);
146         break;
147     case 10:                    /* UTC/Date Inquiry */
148         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
149                        "%u", ais->type10.dest_mmsi);
150         break;
151     case 12:                    /* Safety Related Message */
152         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
153                        "%u|%u|%u|%s",
154                        ais->type12.seqno,
155                        ais->type12.dest_mmsi,
156                        (uint) ais->type12.retransmit, ais->type12.text);
157         break;
158     case 14:                    /* Safety Related Broadcast Message */
159         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
160                        "%s", ais->type14.text);
161         break;
162     case 15:
163         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
164                        "%u|%u|%u|%u|%u|%u|%u|%u",
165                        ais->type15.mmsi1,
166                        ais->type15.type1_1,
167                        ais->type15.offset1_1,
168                        ais->type15.type1_2,
169                        ais->type15.offset1_2,
170                        ais->type15.mmsi2,
171                        ais->type15.type2_1, ais->type15.offset2_1);
172         break;
173     case 16:
174         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
175                        "%u|%u|%u|%u|%u|%u",
176                        ais->type16.mmsi1,
177                        ais->type16.offset1,
178                        ais->type16.increment1,
179                        ais->type16.mmsi2,
180                        ais->type16.offset2, ais->type16.increment2);
181         break;
182     case 17:
183         (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
184                        "%d|%d|%zd:%s",
185                        ais->type17.lon,
186                        ais->type17.lat,
187                        ais->type17.bitcount,
188                        gpsd_hexdump(ais->type17.bitdata,
189                                     (ais->type17.bitcount + 7) / 8));
190         break;
191     case 18:
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,
195                        ais->type18.speed,
196                        (uint) ais->type18.accuracy,
197                        ais->type18.lon,
198                        ais->type18.lat,
199                        ais->type18.course,
200                        ais->type18.heading,
201                        ais->type18.second,
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);
209         break;
210     case 19:
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,
214                        ais->type19.speed,
215                        (uint) ais->type19.accuracy,
216                        ais->type19.lon,
217                        ais->type19.lat,
218                        ais->type19.course,
219                        ais->type19.heading,
220                        ais->type19.second,
221                        ais->type19.regional,
222                        ais->type19.shipname,
223                        ais->type19.shiptype,
224                        ais->type19.to_bow,
225                        ais->type19.to_stern,
226                        ais->type19.to_port,
227                        ais->type19.to_starboard,
228                        ais->type19.epfd,
229                        (uint) ais->type19.raim,
230                        ais->type19.dte, (uint) ais->type19.assigned);
231         break;
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",
235                        ais->type20.offset1,
236                        ais->type20.number1,
237                        ais->type20.timeout1,
238                        ais->type20.increment1,
239                        ais->type20.offset2,
240                        ais->type20.number2,
241                        ais->type20.timeout2,
242                        ais->type20.increment2,
243                        ais->type20.offset3,
244                        ais->type20.number3,
245                        ais->type20.timeout3,
246                        ais->type20.increment3,
247                        ais->type20.offset4,
248                        ais->type20.number4,
249                        ais->type20.timeout4, ais->type20.increment4);
250         break;
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,
255                        ais->type21.name,
256                        (uint) ais->type21.accuracy,
257                        ais->type21.lon,
258                        ais->type21.lat,
259                        ais->type21.to_bow,
260                        ais->type21.to_stern,
261                        ais->type21.to_port,
262                        ais->type21.to_starboard,
263                        ais->type21.epfd,
264                        ais->type21.second,
265                        ais->type21.regional,
266                        (uint) ais->type21.off_position,
267                        (uint) ais->type21.raim,
268                        (uint) ais->type21.virtual_aid);
269         break;
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,
276                            ais->type22.txrx,
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);
285         else
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,
290                            ais->type22.txrx,
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);
297         break;
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",
301                        ais->type23.ne_lon,
302                        ais->type23.ne_lat,
303                        ais->type23.sw_lon,
304                        ais->type23.sw_lat,
305                        ais->type23.stationtype,
306                        ais->type23.shiptype,
307                        ais->type23.txrx,
308                        ais->type23.interval, ais->type23.quiet);
309         break;
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);
320         } else {
321             (void)snprintf(buf + strlen(buf), buflen - strlen(buf),
322                            "%u|%u|%u|%u",
323                            ais->type24.dim.to_bow,
324                            ais->type24.dim.to_stern,
325                            ais->type24.dim.to_port,
326                            ais->type24.dim.to_starboard);
327         }
328         break;
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,
335                        ais->type25.app_id,
336                        ais->type25.bitcount,
337                        gpsd_hexdump(ais->type25.bitdata,
338                                     (ais->type25.bitcount + 7) / 8));
339         break;
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,
346                        ais->type26.app_id,
347                        ais->type26.bitcount,
348                        gpsd_hexdump(ais->type26.bitdata,
349                                     (ais->type26.bitcount + 7) / 8),
350                        ais->type26.radio);
351         break;
352     default:
353         (void)snprintf(buf + strlen(buf),
354                        buflen - strlen(buf),
355                        "unknown AIVDM message content.");
356         break;
357     }
358     /*@ +formatcode @*/
359     (void)strlcat(buf, "\r\n", buflen);
360 }
361
362 /*@ -compdestroy -compdef -usedef @*/
363 static void decode(FILE * fpin, FILE * fpout)
364 /* RTCM or AIS packets on fpin to dump format on fpout */
365 {
366     struct gps_packet_t lexer;
367     struct rtcm2_t rtcm2;
368     struct rtcm3_t rtcm3;
369     struct ais_t ais;
370     struct aivdm_context_t aivdm[AIVDM_CHANNELS];
371     char buf[BUFSIZ];
372
373     memset(&aivdm, '\0', sizeof(aivdm));
374     packet_reset(&lexer);
375
376     while (packet_get(fileno(fpin), &lexer) > 0) {
377         if (lexer.type == COMMENT_PACKET)
378             continue;
379 #ifdef RTCM104V2_ENABLE
380         else if (lexer.type == RTCM2_PACKET) {
381             rtcm2_unpack(&rtcm2, (char *)lexer.isgps.buf);
382             if (json)
383                 rtcm2_json_dump(&rtcm2, buf, sizeof(buf));
384             else
385                 rtcm2_sager_dump(&rtcm2, buf, sizeof(buf));
386             (void)fputs(buf, fpout);
387         }
388 #endif
389 #ifdef RTCM104V3_ENABLE
390         else if (lexer.type == RTCM3_PACKET) {
391             rtcm3_unpack(&rtcm3, (char *)lexer.outbuffer);
392             rtcm3_dump(&rtcm3, stdout);
393         }
394 #endif
395         else if (lexer.type == AIVDM_PACKET) {
396             if (verbose >= 1)
397                 (void)fputs((char *)lexer.outbuffer, stdout);
398             /*@ -uniondef */
399             if (aivdm_decode
400                 ((char *)lexer.outbuffer, lexer.outbuflen, aivdm, &ais)) {
401                 if (!json)
402                     aivdm_csv_dump(&ais, buf, sizeof(buf));
403                 else
404                     aivdm_json_dump(&ais, scaled, buf, sizeof(buf));
405                 (void)fputs(buf, fpout);
406             }
407
408             /*@ +uniondef */
409         }
410     }
411 }
412
413 /*@ +compdestroy +compdef +usedef @*/
414
415 /*@ -compdestroy @*/
416 static void encode(FILE * fpin, FILE * fpout)
417 /* dump format on fpin to RTCM-104 on fpout */
418 {
419     char inbuf[BUFSIZ];
420     struct gps_data_t gpsdata;
421     int lineno = 0;
422
423     memset(&gpsdata, '\0', sizeof(gpsdata));    /* avoid segfault due to garbage in thread-hook slots */
424     while (fgets(inbuf, (int)sizeof(inbuf), fpin) != NULL) {
425         int status;
426
427         ++lineno;
428         if (inbuf[0] == '#')
429             continue;
430         status = libgps_json_unpack(inbuf, &gpsdata, NULL);
431         if (status != 0) {
432             (void)fprintf(stderr,
433                           "gpsdecode: bailing out with status %d (%s) on line %d\n",
434                           status, json_error_string(status), lineno);
435             exit(1);
436         }
437         if ((gpsdata.set & RTCM2_SET) != 0) {
438             /* this works */
439             char outbuf[BUFSIZ];
440             rtcm2_json_dump(&gpsdata.rtcm2, outbuf, sizeof(outbuf));
441             (void)fputs(outbuf, fpout);
442         }
443         if ((gpsdata.set & AIS_SET) != 0) {
444             char outbuf[BUFSIZ];
445             aivdm_json_dump(&gpsdata.ais, false, outbuf, sizeof(outbuf));
446             (void)fputs(outbuf, fpout);
447         }
448     }
449 }
450
451 /*@ +compdestroy @*/
452
453 int main(int argc, char **argv)
454 {
455     int c;
456     enum
457     { doencode, dodecode } mode = dodecode;
458
459     while ((c = getopt(argc, argv, "cdejpuVD:")) != EOF) {
460         switch (c) {
461         case 'c':
462             json = false;
463             break;
464
465         case 'd':
466             mode = dodecode;
467             break;
468
469         case 'e':
470             mode = doencode;
471             break;
472
473         case 'j':
474             json = true;
475             break;
476
477         case 'u':
478             scaled = false;
479             break;
480
481         case 'D':
482             verbose = atoi(optarg);
483             gpsd_hexdump_level = verbose;
484 #ifdef CLIENTDEBUG_ENABLE
485             json_enable_debug(verbose - 2, stderr);
486 #endif
487             break;
488
489         case 'V':
490             (void)fprintf(stderr, "gpsdecode revision " VERSION "\n");
491             exit(0);
492
493         case '?':
494         default:
495             (void)fputs("gpsdecode [-v]\n", stderr);
496             exit(1);
497         }
498     }
499     argc -= optind;
500     argv += optind;
501
502     if (mode == doencode)
503         encode(stdin, stdout);
504     else
505         decode(stdin, stdout);
506     exit(0);
507 }
508
509 /* gpsdecode.c ends here */