2 * Driver for AIS/AIVDM messages.
4 * See the file AIVDM.txt on the GPSD website for documentation and references.
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.
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.
13 #include <sys/types.h>
21 #endif /* S_SPLINT_S */
29 * Parse the data from the device
32 static void from_sixbit(char *bitvec, uint start, int count, char *to)
36 /* the real string causes a splint internal error */
37 const char sixchr[] = "abcd";
39 const char sixchr[64] =
40 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^- !\"#$%&'()*+,-./0123456789:;<=>?";
41 #endif /* S_SPLINT_S */
45 /* six-bit to ASCII */
46 for (i = 0; i < count - 1; i++) {
47 newchar = sixchr[ubits(bitvec, start + 6 * i, 6U)];
54 /* trim spaces on right end */
55 for (i = count - 2; i >= 0; i--)
56 if (to[i] == ' ' || to[i] == '@')
63 /*@ +charint -fixedformalarray -usedef -branchstate @*/
64 bool aivdm_decode(const char *buf, size_t buflen,
65 struct aivdm_context_t ais_contexts[AIVDM_CHANNELS],
68 #ifdef __UNUSED_DEBUG__
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",
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;
96 /* we may need to dump the raw packet */
97 gpsd_report(LOG_PROG, "AIVDM packet length %zd: %s\n", buflen, buf);
99 /* first clear the result, making sure we don't return garbage */
100 memset(ais, 0, sizeof(*ais));
102 /* discard overlong sentences */
103 if (strlen(buf) > sizeof(fieldcopy)-1) {
104 gpsd_report(LOG_ERROR, "overlong AIVDM packet.\n");
108 /* extract packet fields */
109 (void)strlcpy((char *)fieldcopy, buf, sizeof(fieldcopy));
110 field[nfields++] = (unsigned char *)buf;
112 cp < fieldcopy + buflen; cp++)
115 field[nfields++] = cp + 1;
118 /* discard sentences with exiguous commas; catches run-ons */
120 gpsd_report(LOG_ERROR, "malformed AIVDM packet.\n");
124 switch (field[4][0]) {
125 /* FIXME: if fields[4] == "12", it doesn't detect the error */
128 gpsd_report(LOG_ERROR, "invalid AIS channel '%c'. Assuming 'A'\n",
132 ais_context = &ais_contexts[0];
135 gpsd_report(LOG_ERROR, "invalid AIS channel '2'. Assuming 'B'.\n");
138 ais_context = &ais_contexts[1];
141 gpsd_report(LOG_ERROR, "invalid AIS channel.\n");
145 nfrags = atoi((char *)field[1]); /* number of fragments to expect */
146 ifrag = atoi((char *)field[2]); /* fragment id */
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);
152 /* assemble the binary data */
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);
160 /* else, ifrag==1: Just discard all that was previously decoded and
161 * simply handle that packet */
162 ais_context->decoded_frags = 0;
165 (void)memset(ais_context->bits, '\0', sizeof(ais_context->bits));
166 ais_context->bitlen = 0;
169 /* wacky 6-bit encoding, shades of FIELDATA */
171 for (cp = data; cp < data + strlen((char *)data); cp++) {
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));
185 ais_context->bitlen++;
187 /*@ +shiftnegative @*/
190 ais_context->bitlen -= (pad - '0'); /* ASCII assumption */
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));
200 /* clear waiting fragments count */
201 ais_context->decoded_frags = 0;
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);
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.
219 case 1: /* Position Report */
222 if (ais_context->bitlen != 168) {
223 gpsd_report(LOG_WARN, "AIVDM message type %d size not 168 bits (%zd).\n",
225 ais_context->bitlen);
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);
242 "Nav=%d TURN=%d SPEED=%d Q=%d Lon=%d Lat=%d COURSE=%d TH=%d Sec=%d\n",
246 (uint)ais->type1.accuracy,
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",
258 ais_context->bitlen);
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);
275 "Date: %4d:%02d:%02dT%02d:%02d:%02d Q=%d Lat=%d Lon=%d epfd=%d\n",
282 (uint)ais->type4.accuracy,
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);
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);
312 "AIS=%d callsign=%s, name=%s destination=%s\n",
313 ais->type5.ais_version,
316 ais->type5.destination);
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);
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",
336 ais->type6.dest_mmsi,
339 ais->type6.bitcount);
341 case 7: /* Binary acknowledge */
342 case 13: /* Safety Related Acknowledge */
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",
348 ais_context->bitlen);
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);
357 ais->type7.mmsi1 = mmsi[0];
358 ais->type7.mmsi2 = mmsi[1];
359 ais->type7.mmsi3 = mmsi[2];
360 ais->type7.mmsi4 = mmsi[3];
362 gpsd_report(LOG_INF, "\n");
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);
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",
381 ais->type8.bitcount);
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);
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);
403 "Alt=%d SPEED=%d Q=%d Lon=%d Lat=%d COURSE=%d Sec=%d\n",
406 (uint)ais->type9.accuracy,
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);
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);
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);
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,
436 gpsd_report(LOG_INF, "seqno=%d, dest=%u\n",
438 ais->type12.dest_mmsi);
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);
446 //ais->type14.spare = UBITS(38, 2);
447 from_sixbit((char *)ais_context->bits,
448 40, ais_context->bitlen-40,
450 gpsd_report(LOG_INF, "\n");
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);
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);
476 gpsd_report(LOG_INF, "\n");
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);
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;
490 ais->type16.mmsi2 = UBITS(92, 30);
491 ais->type16.offset2 = UBITS(122, 12);
492 ais->type16.increment2 = UBITS(134, 10);
494 gpsd_report(LOG_INF, "\n");
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);
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");
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);
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);
536 "reserved=%d speed=%d accuracy=%d lon=%d lat=%d course=%d heading=%d sec=%d\n",
537 ais->type18.reserved,
539 (uint)ais->type18.accuracy,
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);
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);
573 "reserved=%d speed=%d accuracy=%d lon=%d lat=%d course=%d heading=%d sec=%d name=%s\n",
574 ais->type19.reserved,
576 (uint)ais->type19.accuracy,
582 ais->type19.shipname);
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);
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);
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);
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);
637 "name=%s accuracy=%d lon=%d lat=%d sec=%d\n",
639 (uint)ais->type19.accuracy,
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);
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);
661 ais->type22.mmsi.dest1 = SBITS(69, 30);
662 ais->type22.mmsi.dest2 = SBITS(104, 30);
664 ais->type22.band_a = UBITS(140, 1);
665 ais->type22.band_b = UBITS(141, 1);
666 ais->type22.zonesize = UBITS(142, 3);
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);
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);
684 case 24: /* Class B CS Static Data Report */
685 switch (UBITS(38, 2)) {
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);
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",
696 ais_context->mmsi24);
697 /* no return false */
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 */
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);
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",
716 ais_context->mmsi24, ais->mmsi);
718 gpsd_report(LOG_WARN,
719 "AIVDM message type 24 collision on channel %c: 24B sentence from %09u without 24A.\n",
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);
733 "subtype=B subsubtype=aux "
734 "shiptype=%u vendor=%s callsign=%s "
736 ais->type24.shiptype, ais->type24.vendorid, ais->type24.callsign,
737 ais->type24.mothership_mmsi);
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);
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);
751 //ais->type24.b.spare = UBITS(162, 8);
752 ais_context->mmsi24 = 0; /* reset last know 24A for collision detection */
755 gpsd_report(LOG_WARN, "AIVDM message type 24 of subtype unknown.\n");
756 gpsd_report(LOG_INF, "\n");
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);
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");
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);
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
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,
795 ais->type25.bitcount);
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);
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,
818 ais->type26.bitcount);
821 gpsd_report(LOG_INF, "\n");
822 gpsd_report(LOG_ERROR, "Unparsed AIVDM message type %d.\n",ais->type);
831 /* data is fully decoded */
835 /* we're still waiting on another sentence */
836 ais_context->decoded_frags++;
840 /*@ -charint +fixedformalarray +usedef +branchstate @*/
842 /* driver_aivdm.c ends here */