cleanup specfile for packaging
[profile/ivi/gpsd.git] / driver_aivdm.c
1 /*
2  * Driver for AIS/AIVDM messages.
3  *
4  * See the file AIVDM.txt on the GPSD website for documentation and references.
5  *
6  * Code for message types 1-15, 18-21, and 24 has been tested against
7  * live data with known-good decodings. Code for message types 16-17,
8  * 22-23, and 25-26 has not.
9  *
10  * This file is Copyright (c) 2010 by the GPSD project
11  * BSD terms apply: see the file COPYING in the distribution root for details.
12  */
13 #include <sys/types.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <math.h>
18 #include <ctype.h>
19 #ifndef S_SPLINT_S
20 #include <unistd.h>
21 #endif /* S_SPLINT_S */
22 #include <time.h>
23 #include <stdio.h>
24
25 #include "gpsd.h"
26 #include "bits.h"
27
28 /**
29  * Parse the data from the device
30  */
31
32 static void from_sixbit(char *bitvec, uint start, int count, char *to)
33 {
34     /*@ +type @*/
35 #ifdef S_SPLINT_S
36     /* the real string causes a splint internal error */
37     const char sixchr[] = "abcd";
38 #else
39     const char sixchr[64] =
40         "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^- !\"#$%&'()*+,-./0123456789:;<=>?";
41 #endif /* S_SPLINT_S */
42     int i;
43     char newchar;
44
45     /* six-bit to ASCII */
46     for (i = 0; i < count - 1; i++) {
47         newchar = sixchr[ubits(bitvec, start + 6 * i, 6U)];
48         if (newchar == '@')
49             break;
50         else
51             to[i] = newchar;
52     }
53     to[i] = '\0';
54     /* trim spaces on right end */
55     for (i = count - 2; i >= 0; i--)
56         if (to[i] == ' ' || to[i] == '@')
57             to[i] = '\0';
58         else
59             break;
60     /*@ -type @*/
61 }
62
63 /*@ +charint -fixedformalarray -usedef -branchstate @*/
64 bool aivdm_decode(const char *buf, size_t buflen,
65                   struct aivdm_context_t ais_contexts[AIVDM_CHANNELS], 
66                   struct ais_t *ais)
67 {
68 #ifdef __UNUSED_DEBUG__
69     char *sixbits[64] = {
70         "000000", "000001", "000010", "000011", "000100",
71         "000101", "000110", "000111", "001000", "001001",
72         "001010", "001011", "001100", "001101", "001110",
73         "001111", "010000", "010001", "010010", "010011",
74         "010100", "010101", "010110", "010111", "011000",
75         "011001", "011010", "011011", "011100", "011101",
76         "011110", "011111", "100000", "100001", "100010",
77         "100011", "100100", "100101", "100110", "100111",
78         "101000", "101001", "101010", "101011", "101100",
79         "101101", "101110", "101111", "110000", "110001",
80         "110010", "110011", "110100", "110101", "110110",
81         "110111", "111000", "111001", "111010", "111011",
82         "111100", "111101", "111110", "111111",
83     };
84 #endif /* __UNUSED_DEBUG__ */
85     int nfrags, ifrag, nfields = 0;
86     unsigned char *field[NMEA_MAX*2];
87     unsigned char fieldcopy[NMEA_MAX*2+1];
88     unsigned char *data, *cp = fieldcopy;
89     unsigned char ch, pad;
90     struct aivdm_context_t *ais_context;
91     int i;
92
93     if (buflen == 0)
94         return false;
95
96     /* we may need to dump the raw packet */
97     gpsd_report(LOG_PROG, "AIVDM packet length %zd: %s\n", buflen, buf);
98
99     /* first clear the result, making sure we don't return garbage */
100     memset(ais, 0, sizeof(*ais));
101
102     /* discard overlong sentences */
103     if (strlen(buf) > sizeof(fieldcopy)-1) {
104         gpsd_report(LOG_ERROR, "overlong AIVDM packet.\n");
105         return false;
106     }
107
108     /* extract packet fields */
109     (void)strlcpy((char *)fieldcopy, buf, sizeof(fieldcopy));
110     field[nfields++] = (unsigned char *)buf;
111     for (cp = fieldcopy;
112          cp < fieldcopy + buflen; cp++)
113         if (*cp == ',') {
114             *cp = '\0';
115             field[nfields++] = cp + 1;
116         }
117
118     /* discard sentences with exiguous commas; catches run-ons */
119     if (nfields < 7) {
120         gpsd_report(LOG_ERROR, "malformed AIVDM packet.\n");
121         return false;
122     }
123
124     switch (field[4][0]) {
125     /* FIXME: if fields[4] == "12", it doesn't detect the error */
126     case '\0':
127     case '1':
128         gpsd_report(LOG_ERROR, "invalid AIS channel '%c'. Assuming 'A'\n",
129                                field[4][0]);
130         /*@fallthrough@*/
131     case 'A':
132         ais_context = &ais_contexts[0];
133         break;
134     case '2':
135         gpsd_report(LOG_ERROR, "invalid AIS channel '2'. Assuming 'B'.\n");
136         /*@fallthrough@*/
137     case 'B':
138         ais_context = &ais_contexts[1];
139         break;
140     default:
141         gpsd_report(LOG_ERROR, "invalid AIS channel.\n");
142         return false;
143     }
144
145     nfrags = atoi((char *)field[1]); /* number of fragments to expect */
146     ifrag = atoi((char *)field[2]); /* fragment id */
147     data = field[5];
148     pad = field[6][0]; /* number of padding bits */
149     gpsd_report(LOG_PROG, "nfrags=%d, ifrag=%d, decoded_frags=%d, data=%s\n",
150                 nfrags, ifrag, ais_context->decoded_frags, data);
151
152     /* assemble the binary data */
153
154     /* check fragment ordering */
155     if (ifrag != ais_context->decoded_frags + 1) {
156         gpsd_report(LOG_ERROR, "invalid fragment #%d received, expected #%d.\n",
157                                ifrag, ais_context->decoded_frags + 1);
158         if (ifrag != 1)
159             return false;
160         /* else, ifrag==1: Just discard all that was previously decoded and
161          * simply handle that packet */
162         ais_context->decoded_frags = 0;
163     }
164     if (ifrag == 1) {
165         (void)memset(ais_context->bits, '\0', sizeof(ais_context->bits));
166         ais_context->bitlen = 0;
167     }
168
169     /* wacky 6-bit encoding, shades of FIELDATA */
170     /*@ +charint @*/
171     for (cp = data; cp < data + strlen((char *)data); cp++) {
172         ch = *cp;
173         ch -= 48;
174         if (ch >= 40)
175             ch -= 8;
176 #ifdef __UNUSED_DEBUG__
177         gpsd_report(LOG_RAW, "%c: %s\n", *cp, sixbits[ch]);
178 #endif /* __UNUSED_DEBUG__ */
179         /*@ -shiftnegative @*/
180         for (i = 5; i >= 0; i--) {
181             if ((ch >> i) & 0x01) {
182                 ais_context->bits[ais_context->bitlen / 8] |=
183                     (1 << (7 - ais_context->bitlen % 8));
184             }
185             ais_context->bitlen++;
186         }
187         /*@ +shiftnegative @*/
188     }
189     if (isdigit(pad))
190         ais_context->bitlen -= (pad - '0');     /* ASCII assumption */
191     /*@ -charint @*/
192
193     /* time to pass buffered-up data to where it's actually processed? */
194     if (ifrag == nfrags) {
195         size_t clen = (ais_context->bitlen + 7) / 8;
196         gpsd_report(LOG_INF, "AIVDM payload is %zd bits, %zd chars: %s\n",
197                     ais_context->bitlen, clen,
198                     gpsd_hexdump_wrapper(ais_context->bits, clen, LOG_INF));
199
200         /* clear waiting fragments count */
201         ais_context->decoded_frags = 0;
202
203 #define BITS_PER_BYTE   8
204 #define UBITS(s, l)     ubits((char *)ais_context->bits, s, l)
205 #define SBITS(s, l)     sbits((char *)ais_context->bits, s, l)
206 #define UCHARS(s, to)   from_sixbit((char *)ais_context->bits, s, sizeof(to), to)
207         ais->type = UBITS(0, 6);
208         ais->repeat = UBITS(6, 2);
209         ais->mmsi = UBITS(8, 30);
210         gpsd_report(LOG_INF, "AIVDM message type %d, MMSI %09d:\n",
211                     ais->type, ais->mmsi);
212         /*
213          * Something about the shape of this switch statement confuses
214          * GNU indent so badly that there is no point in trying to be
215          * finer-grained than leaving it all alone.
216          */
217         /* *INDENT-OFF* */
218         switch (ais->type) {
219         case 1: /* Position Report */
220         case 2:
221         case 3:
222             if (ais_context->bitlen != 168) {
223                 gpsd_report(LOG_WARN, "AIVDM message type %d size not 168 bits (%zd).\n",
224                             ais->type,
225                             ais_context->bitlen);
226                 return false;
227             }
228             ais->type1.status           = UBITS(38, 4);
229             ais->type1.turn             = SBITS(42, 8);
230             ais->type1.speed            = UBITS(50, 10);
231             ais->type1.accuracy         = (bool)UBITS(60, 1);
232             ais->type1.lon              = SBITS(61, 28);
233             ais->type1.lat              = SBITS(89, 27);
234             ais->type1.course           = UBITS(116, 12);
235             ais->type1.heading          = UBITS(128, 9);
236             ais->type1.second           = UBITS(137, 6);
237             ais->type1.maneuver         = UBITS(143, 2);
238             //ais->type1.spare          = UBITS(145, 3);
239             ais->type1.raim             = UBITS(148, 1)!=0;
240             ais->type1.radio            = UBITS(149, 20);
241             gpsd_report(LOG_INF,
242                         "Nav=%d TURN=%d SPEED=%d Q=%d Lon=%d Lat=%d COURSE=%d TH=%d Sec=%d\n",
243                         ais->type1.status,
244                         ais->type1.turn,
245                         ais->type1.speed,
246                         (uint)ais->type1.accuracy,
247                         ais->type1.lon,
248                         ais->type1.lat,
249                         ais->type1.course,
250                         ais->type1.heading,
251                         ais->type1.second);
252             break;
253         case 4:         /* Base Station Report */
254         case 11:        /* UTC/Date Response */
255             if (ais_context->bitlen != 168) {
256                 gpsd_report(LOG_WARN, "AIVDM message type %d size not 168 bits (%zd).\n",
257                             ais->type,
258                             ais_context->bitlen);
259                 return false;
260             }
261             ais->type4.year             = UBITS(38, 14);
262             ais->type4.month            = UBITS(52, 4);
263             ais->type4.day              = UBITS(56, 5);
264             ais->type4.hour             = UBITS(61, 5);
265             ais->type4.minute           = UBITS(66, 6);
266             ais->type4.second           = UBITS(72, 6);
267             ais->type4.accuracy         = UBITS(78, 1)!=0;
268             ais->type4.lon              = SBITS(79, 28);
269             ais->type4.lat              = SBITS(107, 27);
270             ais->type4.epfd             = UBITS(134, 4);
271             //ais->type4.spare          = UBITS(138, 10);
272             ais->type4.raim             = UBITS(148, 1)!=0;
273             ais->type4.radio            = UBITS(149, 19);
274             gpsd_report(LOG_INF,
275                         "Date: %4d:%02d:%02dT%02d:%02d:%02d Q=%d Lat=%d  Lon=%d epfd=%d\n",
276                         ais->type4.year,
277                         ais->type4.month,
278                         ais->type4.day,
279                         ais->type4.hour,
280                         ais->type4.minute,
281                         ais->type4.second,
282                         (uint)ais->type4.accuracy,
283                         ais->type4.lat,
284                         ais->type4.lon,
285                         ais->type4.epfd);
286             break;
287         case 5: /* Ship static and voyage related data */
288             if (ais_context->bitlen != 424) {
289                 gpsd_report(LOG_WARN, "AIVDM message type 5 size not 424 bits (%zd).\n",
290                             ais_context->bitlen);
291                 return false;
292             }
293             ais->type5.ais_version  = UBITS(38, 2);
294             ais->type5.imo          = UBITS(40, 30);
295             UCHARS(70, ais->type5.callsign);
296             UCHARS(112, ais->type5.shipname);
297             ais->type5.shiptype     = UBITS(232, 8);
298             ais->type5.to_bow       = UBITS(240, 9);
299             ais->type5.to_stern     = UBITS(249, 9);
300             ais->type5.to_port      = UBITS(258, 6);
301             ais->type5.to_starboard = UBITS(264, 6);
302             ais->type5.epfd         = UBITS(270, 4);
303             ais->type5.month        = UBITS(274, 4);
304             ais->type5.day          = UBITS(278, 5);
305             ais->type5.hour         = UBITS(283, 5);
306             ais->type5.minute       = UBITS(288, 6);
307             ais->type5.draught      = UBITS(294, 8);
308             UCHARS(302, ais->type5.destination);
309             ais->type5.dte          = UBITS(422, 1);
310             //ais->type5.spare        = UBITS(423, 1);
311             gpsd_report(LOG_INF,
312                         "AIS=%d callsign=%s, name=%s destination=%s\n",
313                         ais->type5.ais_version,
314                         ais->type5.callsign,
315                         ais->type5.shipname,
316                         ais->type5.destination);
317             break;
318         case 6: /* Addressed Binary Message */
319             if (ais_context->bitlen < 88 || ais_context->bitlen > 1008) {
320                 gpsd_report(LOG_WARN, "AIVDM message type 6 size is out of range (%zd).\n",
321                             ais_context->bitlen);
322                 return false;
323             }
324             ais->type6.seqno          = UBITS(38, 2);
325             ais->type6.dest_mmsi      = UBITS(40, 30);
326             ais->type6.retransmit     = (bool)UBITS(70, 1);
327             //ais->type6.spare        = UBITS(71, 1);
328             ais->type6.dac            = UBITS(72, 10);
329             ais->type6.fid            = UBITS(82, 6);
330             ais->type6.bitcount       = ais_context->bitlen - 88;
331             (void)memcpy(ais->type6.bitdata,
332                          (char *)ais_context->bits + (88 / BITS_PER_BYTE),
333                          (ais->type6.bitcount + 7) / 8);
334             gpsd_report(LOG_INF, "seqno=%d, dest=%u, dac=%u, fid=%u, cnt=%zd\n",
335                         ais->type6.seqno,
336                         ais->type6.dest_mmsi,
337                         ais->type6.dac,
338                         ais->type6.fid,
339                         ais->type6.bitcount);
340             break;
341         case 7: /* Binary acknowledge */
342         case 13: /* Safety Related Acknowledge */
343         {
344             unsigned int mmsi[4];
345             if (ais_context->bitlen < 72 || ais_context->bitlen > 168) {
346                 gpsd_report(LOG_WARN, "AIVDM message type %d size is out of range (%zd).\n",
347                             ais->type,
348                             ais_context->bitlen);
349                 return false;
350             }
351             for (i = 0; i < sizeof(mmsi)/sizeof(mmsi[0]); i++)
352                 if (ais_context->bitlen > 40 + 32*i)
353                     mmsi[i] = UBITS(40 + 32*i, 30);
354                 else
355                     mmsi[i] = 0;
356             /*@ -usedef @*/
357             ais->type7.mmsi1 = mmsi[0];
358             ais->type7.mmsi2 = mmsi[1];
359             ais->type7.mmsi3 = mmsi[2];
360             ais->type7.mmsi4 = mmsi[3];
361             /*@ +usedef @*/
362             gpsd_report(LOG_INF, "\n");
363             break;
364         }
365         case 8: /* Binary Broadcast Message */
366             if (ais_context->bitlen < 56 || ais_context->bitlen > 1008) {
367                 gpsd_report(LOG_WARN, "AIVDM message type 8 size is out of range (%zd).\n",
368                             ais_context->bitlen);
369                 return false;
370             }
371             //ais->type8.spare        = UBITS(38, 2);
372             ais->type8.dac            = UBITS(40, 10);
373             ais->type8.fid            = UBITS(40, 6);
374             ais->type8.bitcount       = ais_context->bitlen - 56;
375             (void)memcpy(ais->type8.bitdata,
376                          (char *)ais_context->bits + (56 / BITS_PER_BYTE),
377                          (ais->type8.bitcount + 7) / 8);
378             gpsd_report(LOG_INF, "dac=%u, fid=%u, cnt=%zd\n",
379                         ais->type8.dac,
380                         ais->type8.fid,
381                         ais->type8.bitcount);
382             break;
383         case 9: /* Standard SAR Aircraft Position Report */
384             if (ais_context->bitlen != 168) {
385                 gpsd_report(LOG_WARN, "AIVDM message type 9 size not 168 bits (%zd).\n",
386                             ais_context->bitlen);
387                 return false;
388             }
389             ais->type9.alt              = UBITS(38, 12);
390             ais->type9.speed            = UBITS(50, 10);
391             ais->type9.accuracy         = (bool)UBITS(60, 1);
392             ais->type9.lon              = SBITS(61, 28);
393             ais->type9.lat              = SBITS(89, 27);
394             ais->type9.course           = UBITS(116, 12);
395             ais->type9.second           = UBITS(128, 6);
396             ais->type9.regional         = UBITS(134, 8);
397             ais->type9.dte              = UBITS(142, 1);
398             //ais->type9.spare          = UBITS(143, 3);
399             ais->type9.assigned         = UBITS(146, 1)!=0;
400             ais->type9.raim             = UBITS(147, 1)!=0;
401             ais->type9.radio            = UBITS(148, 19);
402             gpsd_report(LOG_INF,
403                         "Alt=%d SPEED=%d Q=%d Lon=%d Lat=%d COURSE=%d Sec=%d\n",
404                         ais->type9.alt,
405                         ais->type9.speed,
406                         (uint)ais->type9.accuracy,
407                         ais->type9.lon,
408                         ais->type9.lat,
409                         ais->type9.course,
410                         ais->type9.second);
411             break;
412         case 10: /* UTC/Date inquiry */
413             if (ais_context->bitlen != 72) {
414                 gpsd_report(LOG_WARN, "AIVDM message type 10 size not 72 bits (%zd).\n",
415                             ais_context->bitlen);
416                 return false;
417             }
418             //ais->type10.spare        = UBITS(38, 2);
419             ais->type10.dest_mmsi      = UBITS(40, 30);
420             //ais->type10.spare2       = UBITS(70, 2);
421             gpsd_report(LOG_INF, "dest=%u\n", ais->type10.dest_mmsi);
422             break;
423         case 12: /* Safety Related Message */
424             if (ais_context->bitlen < 72 || ais_context->bitlen > 1008) {
425                 gpsd_report(LOG_WARN, "AIVDM message type 12 size is out of range (%zd).\n",
426                             ais_context->bitlen);
427                 return false;
428             }
429             ais->type12.seqno          = UBITS(38, 2);
430             ais->type12.dest_mmsi      = UBITS(40, 30);
431             ais->type12.retransmit     = (bool)UBITS(70, 1);
432             //ais->type12.spare        = UBITS(71, 1);
433             from_sixbit((char *)ais_context->bits,
434                         72, ais_context->bitlen-72,
435                         ais->type12.text);
436             gpsd_report(LOG_INF, "seqno=%d, dest=%u\n",
437                         ais->type12.seqno,
438                         ais->type12.dest_mmsi);
439             break;
440         case 14:        /* Safety Related Broadcast Message */
441             if (ais_context->bitlen < 40 || ais_context->bitlen > 1008) {
442                 gpsd_report(LOG_WARN, "AIVDM message type 14 size is out of range (%zd).\n",
443                             ais_context->bitlen);
444                 return false;
445             }
446             //ais->type14.spare          = UBITS(38, 2);
447             from_sixbit((char *)ais_context->bits,
448                         40, ais_context->bitlen-40,
449                         ais->type14.text);
450             gpsd_report(LOG_INF, "\n");
451             break;
452         case 15:        /* Interrogation */
453             if (ais_context->bitlen < 88 || ais_context->bitlen > 168) {
454                 gpsd_report(LOG_WARN, "AIVDM message type 15 size is out of range (%zd).\n",
455                             ais_context->bitlen);
456                 return false;
457             }
458             (void)memset(&ais->type15, '\0', sizeof(ais->type15));
459             //ais->type14.spare         = UBITS(38, 2);
460             ais->type15.mmsi1           = UBITS(40, 30);
461             ais->type15.type1_1         = UBITS(70, 6);
462             ais->type15.type1_1         = UBITS(70, 6);
463             ais->type15.offset1_1       = UBITS(76, 12);
464             //ais->type14.spare2        = UBITS(88, 2);
465             if (ais_context->bitlen > 90) {
466                 ais->type15.type1_2     = UBITS(90, 6);
467                 ais->type15.offset1_2   = UBITS(96, 12);
468                 //ais->type14.spare3    = UBITS(108, 2);
469                 if (ais_context->bitlen > 110) {
470                     ais->type15.mmsi2   = UBITS(110, 30);
471                     ais->type15.type2_1 = UBITS(140, 6);
472                     ais->type15.offset2_1       = UBITS(146, 12);
473                     //ais->type14.spare4        = UBITS(158, 2);
474                 }
475             }
476             gpsd_report(LOG_INF, "\n");
477             break;
478         case 16:        /* Assigned Mode Command */
479             if (ais_context->bitlen != 96 && ais_context->bitlen != 144) {
480                 gpsd_report(LOG_WARN, "AIVDM message type 16 size is out of range (%zd).\n",
481                             ais_context->bitlen);
482                 return false;
483             }
484             ais->type16.mmsi1           = UBITS(40, 30);
485             ais->type16.offset1         = UBITS(70, 12);
486             ais->type16.increment1      = UBITS(82, 10);
487             if (ais_context->bitlen < 144)
488                 ais->type16.mmsi2=ais->type16.offset2=ais->type16.increment2 = 0;
489             else {
490                 ais->type16.mmsi2       = UBITS(92, 30);
491                 ais->type16.offset2     = UBITS(122, 12);
492                 ais->type16.increment2  = UBITS(134, 10);
493             }
494             gpsd_report(LOG_INF, "\n");
495             break;
496         case 17:        /* GNSS Broadcast Binary Message */
497             if (ais_context->bitlen < 80 || ais_context->bitlen > 816) {
498                 gpsd_report(LOG_WARN, "AIVDM message type 17 size is out of range (%zd).\n",
499                             ais_context->bitlen);
500                 return false;
501             }
502             //ais->type17.spare         = UBITS(38, 2);
503             ais->type17.lon             = UBITS(40, 18);
504             ais->type17.lat             = UBITS(58, 17);
505             //ais->type17.spare         = UBITS(75, 4);
506             ais->type17.bitcount        = ais_context->bitlen - 80;
507             (void)memcpy(ais->type17.bitdata,
508                          (char *)ais_context->bits + (80 / BITS_PER_BYTE),
509                          (ais->type17.bitcount + 7) / 8);
510             gpsd_report(LOG_INF, "\n");
511             break;
512         case 18:        /* Standard Class B CS Position Report */
513             if (ais_context->bitlen != 168) {
514                 gpsd_report(LOG_WARN, "AIVDM message type 18 size not 168 bits (%zd).\n",
515                             ais_context->bitlen);
516                 return false;
517             }
518             ais->type18.reserved        = UBITS(38, 8);
519             ais->type18.speed           = UBITS(46, 10);
520             ais->type18.accuracy        = UBITS(56, 1)!=0;
521             ais->type18.lon             = SBITS(57, 28);
522             ais->type18.lat             = SBITS(85, 27);
523             ais->type18.course          = UBITS(112, 12);
524             ais->type18.heading         = UBITS(124, 9);
525             ais->type18.second          = UBITS(133, 6);
526             ais->type18.regional        = UBITS(139, 2);
527             ais->type18.cs              = UBITS(141, 1)!=0;
528             ais->type18.display         = UBITS(142, 1)!=0;
529             ais->type18.dsc             = UBITS(143, 1)!=0;
530             ais->type18.band            = UBITS(144, 1)!=0;
531             ais->type18.msg22           = UBITS(145, 1)!=0;
532             ais->type18.assigned        = UBITS(146, 1)!=0;
533             ais->type18.raim            = UBITS(147, 1)!=0;
534             ais->type18.radio           = UBITS(148, 20);
535             gpsd_report(LOG_INF,
536                         "reserved=%d speed=%d accuracy=%d lon=%d lat=%d course=%d heading=%d sec=%d\n",
537                         ais->type18.reserved,
538                         ais->type18.speed,
539                         (uint)ais->type18.accuracy,
540                         ais->type18.lon,
541                         ais->type18.lat,
542                         ais->type18.course,
543                         ais->type18.heading,
544                         ais->type18.second);
545             break;      
546         case 19:        /* Extended Class B CS Position Report */
547             if (ais_context->bitlen != 312) {
548                 gpsd_report(LOG_WARN, "AIVDM message type 19 size not 312 bits (%zd).\n",
549                             ais_context->bitlen);
550                 return false;
551             }
552             ais->type19.reserved     = UBITS(38, 8);
553             ais->type19.speed        = UBITS(46, 10);
554             ais->type19.accuracy     = UBITS(56, 1)!=0;
555             ais->type19.lon          = SBITS(57, 28);
556             ais->type19.lat          = SBITS(85, 27);
557             ais->type19.course       = UBITS(112, 12);
558             ais->type19.heading      = UBITS(124, 9);
559             ais->type19.second       = UBITS(133, 6);
560             ais->type19.regional     = UBITS(139, 4);
561             UCHARS(143, ais->type19.shipname);
562             ais->type19.shiptype     = UBITS(263, 8);
563             ais->type19.to_bow       = UBITS(271, 9);
564             ais->type19.to_stern     = UBITS(280, 9);
565             ais->type19.to_port      = UBITS(289, 6);
566             ais->type19.to_starboard = UBITS(295, 6);
567             ais->type19.epfd         = UBITS(299, 4);
568             ais->type19.raim         = UBITS(302, 1)!=0;
569             ais->type19.dte          = UBITS(305, 1)!=0;
570             ais->type19.assigned     = UBITS(306, 1)!=0;
571             //ais->type19.spare      = UBITS(307, 5);
572             gpsd_report(LOG_INF,
573                         "reserved=%d speed=%d accuracy=%d lon=%d lat=%d course=%d heading=%d sec=%d name=%s\n",
574                         ais->type19.reserved,
575                         ais->type19.speed,
576                         (uint)ais->type19.accuracy,
577                         ais->type19.lon,
578                         ais->type19.lat,
579                         ais->type19.course,
580                         ais->type19.heading,
581                         ais->type19.second,
582                         ais->type19.shipname);
583             break;
584         case 20:        /* Data Link Management Message */
585             if (ais_context->bitlen < 72 || ais_context->bitlen > 160) {
586                 gpsd_report(LOG_WARN, "AIVDM message type 20 size is out of range (%zd).\n",
587                             ais_context->bitlen);
588                 return false;
589             }
590             //ais->type20.spare         = UBITS(38, 2);
591             ais->type20.offset1         = UBITS(40, 12);
592             ais->type20.number1         = UBITS(52, 4);
593             ais->type20.timeout1        = UBITS(56, 3);
594             ais->type20.increment1      = UBITS(59, 11);
595             ais->type20.offset2         = UBITS(70, 12);
596             ais->type20.number2         = UBITS(82, 4);
597             ais->type20.timeout2        = UBITS(86, 3);
598             ais->type20.increment2      = UBITS(89, 11);
599             ais->type20.offset3         = UBITS(100, 12);
600             ais->type20.number3         = UBITS(112, 4);
601             ais->type20.timeout3        = UBITS(116, 3);
602             ais->type20.increment3      = UBITS(119, 11);
603             ais->type20.offset4         = UBITS(130, 12);
604             ais->type20.number4         = UBITS(142, 4);
605             ais->type20.timeout4        = UBITS(146, 3);
606             ais->type20.increment4      = UBITS(149, 11);
607             break;
608         case 21:        /* Aid-to-Navigation Report */
609             if (ais_context->bitlen < 272 || ais_context->bitlen > 360) {
610                 gpsd_report(LOG_WARN, "AIVDM message type 21 size is out of range (%zd).\n",
611                             ais_context->bitlen);
612                 return false;
613             }
614             ais->type21.aid_type = UBITS(38, 5);
615             from_sixbit((char *)ais_context->bits, 
616                         43, 21, ais->type21.name);
617             if (strlen(ais->type21.name) == 20 && ais_context->bitlen > 272)
618                 from_sixbit((char *)ais_context->bits, 
619                             272, (ais_context->bitlen - 272)/6, 
620                             ais->type21.name+20);
621             ais->type21.accuracy     = UBITS(163, 1);
622             ais->type21.lon          = SBITS(164, 28);
623             ais->type21.lat          = SBITS(192, 27);
624             ais->type21.to_bow       = UBITS(219, 9);
625             ais->type21.to_stern     = UBITS(228, 9);
626             ais->type21.to_port      = UBITS(237, 6);
627             ais->type21.to_starboard = UBITS(243, 6);
628             ais->type21.epfd         = UBITS(249, 4);
629             ais->type21.second       = UBITS(253, 6);
630             ais->type21.off_position = UBITS(259, 1)!=0;
631             ais->type21.regional     = UBITS(260, 8);
632             ais->type21.raim         = UBITS(268, 1)!=0;
633             ais->type21.virtual_aid  = UBITS(269, 1)!=0;
634             ais->type21.assigned     = UBITS(270, 1)!=0;
635             //ais->type21.spare      = UBITS(271, 1);
636             gpsd_report(LOG_INF,
637                         "name=%s accuracy=%d lon=%d lat=%d sec=%d\n",
638                         ais->type21.name,
639                         (uint)ais->type19.accuracy,
640                         ais->type19.lon,
641                         ais->type19.lat,
642                         ais->type19.second);
643             break;
644         case 22:        /* Channel Management */
645             if (ais_context->bitlen != 168) {
646                 gpsd_report(LOG_WARN, "AIVDM message type 22 size not 168 bits (%zd).\n",
647                             ais_context->bitlen);
648                 return false;
649             }
650             ais->type22.channel_a    = UBITS(40, 12);
651             ais->type22.channel_b    = UBITS(52, 12);
652             ais->type22.txrx         = UBITS(64, 4);
653             ais->type22.power        = UBITS(68, 1);
654             ais->type22.addressed    = UBITS(139, 1);
655             if (!ais->type22.addressed) {
656                 ais->type22.area.ne_lon       = SBITS(69, 18);
657                 ais->type22.area.ne_lat       = SBITS(87, 17);
658                 ais->type22.area.sw_lon       = SBITS(104, 18);
659                 ais->type22.area.sw_lat       = SBITS(122, 17);
660             } else {
661                 ais->type22.mmsi.dest1             = SBITS(69, 30);
662                 ais->type22.mmsi.dest2             = SBITS(104, 30);
663             }
664             ais->type22.band_a       = UBITS(140, 1);
665             ais->type22.band_b       = UBITS(141, 1);
666             ais->type22.zonesize     = UBITS(142, 3);
667             break;
668         case 23:        /* Group Assignment Command */
669             if (ais_context->bitlen != 160) {
670                 gpsd_report(LOG_WARN, "AIVDM message type 23 size not 160 bits (%zd).\n",
671                             ais_context->bitlen);
672                 return false;
673             }
674             ais->type23.ne_lon       = SBITS(40, 18);
675             ais->type23.ne_lat       = SBITS(58, 17);
676             ais->type23.sw_lon       = SBITS(75, 18);
677             ais->type23.sw_lat       = SBITS(93, 17);
678             ais->type23.stationtype  = UBITS(110, 4);
679             ais->type23.shiptype     = UBITS(114, 8);
680             ais->type23.txrx         = UBITS(144, 4);
681             ais->type23.interval     = UBITS(146, 4);
682             ais->type23.quiet        = UBITS(150, 4);
683             break;
684         case 24:        /* Class B CS Static Data Report */
685             switch (UBITS(38, 2)) {
686             case 0:
687                 if (ais_context->bitlen != 160) {
688                     gpsd_report(LOG_WARN, "AIVDM message type 24A size not 160 bits (%zd).\n",
689                                 ais_context->bitlen);
690                     return false;
691                 }
692                 if (ais_context->mmsi24) {
693                     gpsd_report(LOG_WARN,
694                                 "AIVDM message type 24 collision on channel %c : Discarding previous sentence 24A from %09u.\n",
695                                 field[4][0],
696                                 ais_context->mmsi24);
697                     /* no return false */
698                 }
699                 ais_context->mmsi24 = ais->mmsi;
700                 UCHARS(40, ais_context->shipname24);
701                 //ais->type24.a.spare   = UBITS(160, 8);
702                 gpsd_report(LOG_INF, "subtype=A name=%s\n",
703                         ais_context->shipname24);
704                 return false;   /* data only partially decoded */
705             case 1:
706                 if (ais_context->bitlen != 168) {
707                     gpsd_report(LOG_WARN, "AIVDM message type 24B size not 168 bits (%zd).\n",
708                                 ais_context->bitlen);
709                     return false;
710                 }
711                 if (ais_context->mmsi24 != ais->mmsi) {
712                     if (ais_context->mmsi24)
713                         gpsd_report(LOG_WARN,
714                                     "AIVDM message type 24 collision on channel %c: MMSI mismatch: %09u vs %09u.\n",
715                                     field[4][0],
716                                     ais_context->mmsi24, ais->mmsi);
717                     else
718                         gpsd_report(LOG_WARN,
719                                     "AIVDM message type 24 collision on channel %c: 24B sentence from %09u without 24A.\n",
720                                     field[4][0],
721                                     ais->mmsi);
722                     return false;
723                 }
724                 (void)strlcpy(ais->type24.shipname, 
725                               ais_context->shipname24,
726                               sizeof(ais_context->shipname24));
727                 ais->type24.shiptype = UBITS(40, 8);
728                 UCHARS(48, ais->type24.vendorid);
729                 UCHARS(90, ais->type24.callsign);
730                 if (AIS_AUXILIARY_MMSI(ais->mmsi)) {
731                     ais->type24.mothership_mmsi   = UBITS(132, 30);
732                     gpsd_report(LOG_INF,
733                                 "subtype=B subsubtype=aux "
734                                 "shiptype=%u vendor=%s callsign=%s "
735                                 "mothership=%09u\n",
736                                 ais->type24.shiptype, ais->type24.vendorid, ais->type24.callsign,
737                                 ais->type24.mothership_mmsi);
738                 } else {
739                     ais->type24.dim.to_bow        = UBITS(132, 9);
740                     ais->type24.dim.to_stern      = UBITS(141, 9);
741                     ais->type24.dim.to_port       = UBITS(150, 6);
742                     ais->type24.dim.to_starboard  = UBITS(156, 6);
743                     gpsd_report(LOG_INF,
744                                 "subtype=B subsubtype=dim "
745                                 "shiptype=%u vendor=%s callsign=%s "
746                                 "bow=%u stern=%u port=%u starboard=%u\n",
747                                 ais->type24.shiptype, ais->type24.vendorid, ais->type24.callsign,
748                                 ais->type24.dim.to_bow, ais->type24.dim.to_stern,
749                                 ais->type24.dim.to_port, ais->type24.dim.to_starboard);
750                 }
751                 //ais->type24.b.spare       = UBITS(162, 8);
752                 ais_context->mmsi24 = 0; /* reset last know 24A for collision detection */
753                 break;
754             default:
755                 gpsd_report(LOG_WARN, "AIVDM message type 24 of subtype unknown.\n");
756                 gpsd_report(LOG_INF, "\n");
757                 return false;
758             }
759             break;
760         case 25:        /* Binary Message, Single Slot */
761             /* this check and the following one reject line noise */
762             if (ais_context->bitlen < 40 || ais_context->bitlen > 168) {
763                 gpsd_report(LOG_WARN, "AIVDM message type 25 size not between 40 to 168 bits (%zd).\n",
764                             ais_context->bitlen);
765                 return false;
766             }
767             ais->type25.addressed       = (bool)UBITS(38, 1);
768             ais->type25.structured      = (bool)UBITS(39, 1);
769             if (ais_context->bitlen < (40 + (16*ais->type25.structured) + (30*ais->type25.addressed))) {
770                 gpsd_report(LOG_WARN, "AIVDM message type 25 too short for mode.\n");
771                 return false;
772             }
773             if (ais->type25.addressed)
774                 ais->type25.dest_mmsi   = UBITS(40, 30);
775             if (ais->type25.structured)
776                 ais->type25.app_id      = UBITS(40+ais->type25.addressed*30,16);
777             /*
778              * Not possible to do this right without machinery we
779              * don't yet have.  The problem is that if the addressed
780              * bit is on the bitfield start won't be on a byte
781              * boundary. Thus the formulas below (and in message type 26)
782              * will work perfectly for brodacst messages, but for addressed
783              * messages the retrieved data will be led by thr 30 bits of
784              * the destination MMSI
785              */
786             ais->type25.bitcount       = ais_context->bitlen - 40 - 16*ais->type25.structured;
787             (void)memcpy(ais->type25.bitdata,
788                          (char *)ais_context->bits+5 + 2 * ais->type25.structured,
789                          (ais->type25.bitcount + 7) / 8);
790             gpsd_report(LOG_INF, "addressed=%d, structured=%d, dest=%u, id=%u, cnt=%zd\n",
791                         ais->type25.addressed,
792                         ais->type25.structured,
793                         ais->type25.dest_mmsi,
794                         ais->type25.app_id,
795                         ais->type25.bitcount);          
796             break;
797         case 26:        /* Binary Message, Multiple Slot */
798             if (ais_context->bitlen < 60 || ais_context->bitlen > 1004) {
799                 gpsd_report(LOG_WARN, "AIVDM message type 26 size is out of range (%zd).\n",
800                             ais_context->bitlen);
801                 return false;
802             }
803             ais->type26.addressed       = (bool)UBITS(38, 1);
804             ais->type26.structured      = (bool)UBITS(39, 1);
805             if (ais->type26.addressed)
806                 ais->type26.dest_mmsi   = UBITS(40, 30);
807             if (ais->type26.structured)
808                 ais->type26.app_id      = UBITS(40+ais->type26.addressed*30,16);
809             ais->type26.bitcount        = ais_context->bitlen - 60 - 16*ais->type26.structured;
810             (void)memcpy(ais->type26.bitdata,
811                          (char *)ais_context->bits+5 + 2 * ais->type26.structured,
812                          (ais->type26.bitcount + 7) / 8);
813             gpsd_report(LOG_INF, "addressed=%d, structured=%d, dest=%u, id=%u, cnt=%zd\n",
814                         ais->type26.addressed,
815                         ais->type26.structured,
816                         ais->type26.dest_mmsi,
817                         ais->type26.app_id,
818                         ais->type26.bitcount);
819             break;
820         default:
821             gpsd_report(LOG_INF, "\n");
822             gpsd_report(LOG_ERROR, "Unparsed AIVDM message type %d.\n",ais->type);
823             return false;
824         }
825         /* *INDENT-ON* */
826 #undef UCHARS
827 #undef SBITS
828 #undef UBITS
829 #undef BITS_PER_BYTE
830
831         /* data is fully decoded */
832         return true;
833     }
834
835     /* we're still waiting on another sentence */
836     ais_context->decoded_frags++;
837     return false;
838 }
839
840 /*@ -charint +fixedformalarray +usedef +branchstate @*/
841
842 /* driver_aivdm.c ends here */