/src/gpsd/gpsd-3.27.6~dev/drivers/driver_ais.c
Line | Count | Source |
1 | | /* |
2 | | * Driver for AIS messages. |
3 | | * |
4 | | * See the file AIVDM.txt on the GPSD website for documentation and references. |
5 | | * AIVDM de-armoring is handled elsewhere; this is the binary-packet driver. |
6 | | * |
7 | | * Code for message types 1-15, 18-21, and 24 has been tested against |
8 | | * live data with known-good decodings. Code for message types 16-17, |
9 | | * 22-23, and 25-27 has not. |
10 | | * For the special IMO messages (types 6 and 8), only the following have been |
11 | | * tested against known-good decodings: |
12 | | * - IMO236 met/hydro message: Type=8, DAC=1, FI=11 |
13 | | * - IMO289 met/hydro message: Type=8, DAC=1, FI=31 |
14 | | * |
15 | | * This file is Copyright 2010 by the GPSD project |
16 | | * SPDX-License-Identifier: BSD-2-clause |
17 | | */ |
18 | | |
19 | | #include "../include/gpsd_config.h" // must be before all includes |
20 | | |
21 | | #include <ctype.h> |
22 | | #include <stdlib.h> |
23 | | #include <string.h> |
24 | | |
25 | | #include "../include/gpsd.h" |
26 | | #include "../include/bits.h" |
27 | | |
28 | | /* |
29 | | * Parse the data from the device |
30 | | */ |
31 | | |
32 | | // beginning at bitvec bit start, unpack count sixbit characters |
33 | | static void from_sixbit_untrimmed(const struct gpsd_errout_t *errout, |
34 | | const unsigned char *bitvec, |
35 | | const size_t bitlen, |
36 | | const unsigned start, |
37 | | unsigned count, char *to, |
38 | | const size_t to_sz) |
39 | 9.81k | { |
40 | 9.81k | const char sixchr[65] = |
41 | 9.81k | "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"; |
42 | 9.81k | unsigned i; |
43 | | |
44 | 9.81k | if (bitlen <= start) { |
45 | 79 | GPSD_LOG(LOG_WARN, errout, "AIVDM bitlen %zu <= start %u\n", |
46 | 79 | bitlen, start); |
47 | 79 | to[0] = '\0'; |
48 | 79 | return; |
49 | 79 | } |
50 | 9.73k | if (to_sz <= count) { |
51 | 0 | count = to_sz - 1; |
52 | 0 | } |
53 | | |
54 | | // six-bit to ASCII |
55 | 79.1k | for (i = 0; i < count; i++) { |
56 | 74.0k | char newchar = sixchr[ubits(bitvec, start + 6 * i, 6U, false)]; |
57 | | |
58 | 74.0k | if ('@' == newchar) { |
59 | 4.66k | break; |
60 | 4.66k | } |
61 | 69.4k | to[i] = newchar; |
62 | 69.4k | } |
63 | 9.73k | to[i] = '\0'; |
64 | 9.73k | } |
65 | | |
66 | | // trim spaces on right end |
67 | | static void trim_spaces_on_right_end(char *to, size_t max) |
68 | 9.81k | { |
69 | 9.81k | long long i; |
70 | | |
71 | | // pacify Coverity 498043, overflow |
72 | 15.4k | for (i = strnlen(to, max) - 1; i >= 0; i--) { |
73 | 13.3k | if (' ' == to[i] || |
74 | 7.67k | '@' == to[i]) { |
75 | 5.65k | to[i] = '\0'; |
76 | 7.67k | } else { |
77 | 7.67k | break; |
78 | 7.67k | } |
79 | 13.3k | } |
80 | 9.81k | } |
81 | | |
82 | | /* beginning at bitvec bit start, unpack count sixbit characters |
83 | | * and remove trailing spaces */ |
84 | | static void from_sixbit(const struct gpsd_errout_t *errout, |
85 | | const unsigned char *bitvec, const size_t bitlen, |
86 | | const unsigned start, |
87 | | const unsigned count, char *to, const size_t to_sz) |
88 | 9.45k | { |
89 | 9.45k | from_sixbit_untrimmed(errout, bitvec, bitlen, start, count, to, to_sz); |
90 | 9.45k | trim_spaces_on_right_end(to, count); |
91 | 9.45k | } |
92 | | |
93 | 137k | #define UBITS(s, l) ubits(bits, s, l, false) |
94 | 11.2k | #define SBITS(s, l) sbits(bits, s, l, false) |
95 | | #define UCHARS(start, to) \ |
96 | 9.01k | from_sixbit(errout, bits, bitlen, start, sizeof(to) - 1, \ |
97 | 9.01k | to, sizeof(to)) |
98 | | |
99 | | #define ENDCHARS(start, to, to_sz) \ |
100 | 436 | from_sixbit(errout, bits, bitlen, start, (bitlen - start) / 6, \ |
101 | 436 | to, to_sz) |
102 | | |
103 | | /* decode an AIS binary packet |
104 | | * |
105 | | * Return: True on success |
106 | | * False on failure |
107 | | */ |
108 | | bool ais_binary_decode(const struct gpsd_errout_t *errout, |
109 | | struct ais_t *ais, |
110 | | const unsigned char *bits, size_t bitlen, |
111 | | struct ais_type24_queue_t *type24_queue) |
112 | 16.4k | { |
113 | 16.4k | unsigned int u; |
114 | 16.4k | size_t bytelen = BITS_TO_BYTES(bitlen); |
115 | | |
116 | 16.4k | ais->type = UBITS(0, 6); |
117 | 16.4k | ais->repeat = UBITS(6, 2); |
118 | 16.4k | ais->mmsi = UBITS(8, 30); |
119 | 16.4k | GPSD_LOG(LOG_INF, errout, |
120 | 16.4k | "AIVDM message type %d, MMSI %09d bitlen %zu bytelen %zu\n", |
121 | 16.4k | ais->type, ais->mmsi, bitlen, bytelen); |
122 | | |
123 | 16.4k | #define PERMISSIVE_LENGTH_CHECK(correct) \ |
124 | 16.4k | if (bitlen < correct) { \ |
125 | 667 | GPSD_LOG(LOG_ERROR, errout, \ |
126 | 667 | "AIVDM message type %d size < %d bits (%zd).\n", \ |
127 | 667 | ais->type, correct, bitlen); \ |
128 | 667 | return false; \ |
129 | 1.68k | } else if (bitlen > correct) { \ |
130 | 695 | GPSD_LOG(LOG_WARN, errout, \ |
131 | 695 | "AIVDM message type %d size > %d bits (%zd).\n", \ |
132 | 695 | ais->type, correct, bitlen); \ |
133 | 695 | } |
134 | | |
135 | 16.4k | #define RANGE_CHECK(min, max) \ |
136 | 16.4k | if (bitlen < min || \ |
137 | 9.97k | bitlen > max) { \ |
138 | 2.25k | GPSD_LOG(LOG_ERROR, errout, \ |
139 | 2.25k | "AIVDM message type %d size is out of range: " \ |
140 | 2.25k | " %u <= (%zu) <= %u.\n", \ |
141 | 2.25k | ais->type, min, bitlen, max); \ |
142 | 2.25k | return false; \ |
143 | 2.25k | } |
144 | | |
145 | 16.4k | #define RANGE_CHECK6(min, max) \ |
146 | 16.4k | if (bitlen < min || \ |
147 | 3.28k | bitlen > max) { \ |
148 | 1.28k | GPSD_LOG(LOG_ERROR, errout, \ |
149 | 1.28k | "AIVDM message type %d dac %u fid %u size is out of " \ |
150 | 1.28k | "range %u <= (%zu) <= %u.\n", \ |
151 | 1.28k | ais->type, ais->type6.dac, ais->type6.fid, \ |
152 | 1.28k | min, bitlen, max); \ |
153 | 1.28k | return false; \ |
154 | 1.28k | } |
155 | | |
156 | 16.4k | #define RANGE_CHECK8(min, max) \ |
157 | 16.4k | if (bitlen < min || \ |
158 | 6.72k | bitlen > max) { \ |
159 | 1.56k | GPSD_LOG(LOG_ERROR, errout, \ |
160 | 1.56k | "AIVDM message type %d dac %u fid %u size is out of " \ |
161 | 1.56k | "range %u <= (%zu) <= %u.\n", \ |
162 | 1.56k | ais->type, ais->type8.dac, ais->type8.fid, \ |
163 | 1.56k | min, bitlen, max); \ |
164 | 1.56k | return false; \ |
165 | 1.56k | } |
166 | | |
167 | | /* |
168 | | * Something about the shape of this switch statement confuses |
169 | | * GNU indent so badly that there is no point in trying to be |
170 | | * finer-grained than leaving it all alone. |
171 | | */ |
172 | | |
173 | | // calculate offset into array |
174 | 16.4k | #define OFF(index) (ARRAY_BASE + (ELEMENT_SIZE * index)) |
175 | | |
176 | 16.4k | switch (ais->type) { |
177 | 150 | case 1: // Position Report |
178 | 150 | FALLTHROUGH |
179 | 282 | case 2: |
180 | 282 | FALLTHROUGH |
181 | 414 | case 3: |
182 | | // per https://www.navcen.uscg.gov/ais-class-a-reports |
183 | | // In 2023, most of our samples are 168, but some are 163 and 204. |
184 | 414 | RANGE_CHECK(163, 204) |
185 | 140 | ais->type1.status = UBITS(38, 4); |
186 | 140 | ais->type1.turn = SBITS(42, 8); |
187 | 140 | ais->type1.speed = UBITS(50, 10); |
188 | 140 | ais->type1.accuracy = UBITS(60, 1) != 0; |
189 | 140 | ais->type1.lon = SBITS(61, 28); |
190 | 140 | ais->type1.lat = SBITS(89, 27); |
191 | 140 | ais->type1.course = UBITS(116, 12); |
192 | 140 | ais->type1.heading = UBITS(128, 9); |
193 | 140 | ais->type1.second = UBITS(137, 6); |
194 | 140 | ais->type1.maneuver = UBITS(143, 2); |
195 | | // ais->type1.spare = UBITS(145, 3); |
196 | 140 | ais->type1.raim = UBITS(148, 1) != 0; |
197 | 140 | if (bitlen >= 168) { |
198 | 73 | ais->type1.radio = UBITS(149, 19); |
199 | 73 | } else { |
200 | | // less than 168, as of 2023 we have no examples of this. |
201 | 67 | ais->type1.radio = UBITS(149, bitlen - 149); |
202 | 67 | } |
203 | 140 | break; |
204 | 149 | case 4: // Base Station Report |
205 | 149 | FALLTHROUGH |
206 | 274 | case 11: // UTC/Date Response |
207 | 274 | PERMISSIVE_LENGTH_CHECK(168) |
208 | 134 | ais->type4.year = UBITS(38, 14); |
209 | 134 | ais->type4.month = UBITS(52, 4); |
210 | 134 | ais->type4.day = UBITS(56, 5); |
211 | 134 | ais->type4.hour = UBITS(61, 5); |
212 | 134 | ais->type4.minute = UBITS(66, 6); |
213 | 134 | ais->type4.second = UBITS(72, 6); |
214 | 134 | ais->type4.accuracy = UBITS(78, 1) != 0; |
215 | 134 | ais->type4.lon = SBITS(79, 28); |
216 | 134 | ais->type4.lat = SBITS(107, 27); |
217 | 134 | ais->type4.epfd = UBITS(134, 4); |
218 | | // ais->type4.spare = UBITS(138, 10); |
219 | 134 | ais->type4.raim = UBITS(148, 1) != 0; |
220 | 134 | ais->type4.radio = UBITS(149, 19); |
221 | 134 | break; |
222 | 292 | case 5: // Ship static and voyage related data |
223 | 292 | if (424 != bitlen) { |
224 | 226 | GPSD_LOG(LOG_WARN, errout, |
225 | 226 | "AIVDM message type 5 size not 424 bits (%zd).\n", |
226 | 226 | bitlen); |
227 | | /* |
228 | | * For unknown reasons, a lot of transmitters in the wild ship |
229 | | * with a length of 420 or 422. This is a recoverable error. |
230 | | */ |
231 | 226 | if (420 > bitlen) { |
232 | 93 | return false; |
233 | 93 | } |
234 | 226 | } |
235 | 199 | ais->type5.ais_version = UBITS(38, 2); |
236 | 199 | ais->type5.imo = UBITS(40, 30); |
237 | 199 | UCHARS(70, ais->type5.callsign); |
238 | 199 | UCHARS(112, ais->type5.shipname); |
239 | 199 | ais->type5.shiptype = UBITS(232, 8); |
240 | 199 | ais->type5.to_bow = UBITS(240, 9); |
241 | 199 | ais->type5.to_stern = UBITS(249, 9); |
242 | 199 | ais->type5.to_port = UBITS(258, 6); |
243 | 199 | ais->type5.to_starboard = UBITS(264, 6); |
244 | 199 | ais->type5.epfd = UBITS(270, 4); |
245 | 199 | ais->type5.month = UBITS(274, 4); |
246 | 199 | ais->type5.day = UBITS(278, 5); |
247 | 199 | ais->type5.hour = UBITS(283, 5); |
248 | 199 | ais->type5.minute = UBITS(288, 6); |
249 | 199 | ais->type5.draught = UBITS(294, 8); |
250 | 199 | UCHARS(302, ais->type5.destination); |
251 | 199 | if (423 <= bitlen) { |
252 | 113 | ais->type5.dte = UBITS(422, 1); |
253 | 113 | } |
254 | | // ais->type5.spare = UBITS(423, 1); |
255 | 199 | break; |
256 | 3.63k | case 6: // Addressed Binary Message |
257 | 3.63k | RANGE_CHECK(88, 1008); |
258 | 3.45k | ais->type6.seqno = UBITS(38, 2); |
259 | 3.45k | ais->type6.dest_mmsi = UBITS(40, 30); |
260 | 3.45k | ais->type6.retransmit = UBITS(70, 1) != 0; |
261 | | // ais->type6.spare = UBITS(71, 1); |
262 | 3.45k | ais->type6.dac = UBITS(72, 10); |
263 | 3.45k | ais->type6.fid = UBITS(82, 6); |
264 | 3.45k | ais->type6.bitcount = bitlen - 88; |
265 | | // not strictly required - helps stability in testing |
266 | 3.45k | (void)memset(ais->type6.bitdata, '\0', sizeof(ais->type6.bitdata)); |
267 | 3.45k | ais->type6.structured = false; |
268 | | // Inland AIS |
269 | 3.45k | GPSD_LOG(LOG_PROG, errout, |
270 | 3.45k | "AIVDM: type 6 dac %u fid %u bitlen %zu\n", |
271 | 3.45k | ais->type6.dac, ais->type6.fid, bitlen); |
272 | 3.45k | switch (ais->type6.dac) { |
273 | 2.22k | case 1: |
274 | | // International |
275 | 2.22k | switch (ais->type6.fid) { |
276 | 334 | case 12: // IMO236 - Dangerous cargo indication |
277 | 334 | RANGE_CHECK6(144, 360); |
278 | 199 | UCHARS(88, ais->type6.dac1fid12.lastport); |
279 | 199 | ais->type6.dac1fid12.lmonth = UBITS(118, 4); |
280 | 199 | ais->type6.dac1fid12.lday = UBITS(122, 5); |
281 | 199 | ais->type6.dac1fid12.lhour = UBITS(127, 5); |
282 | 199 | ais->type6.dac1fid12.lminute = UBITS(132, 6); |
283 | 199 | if (144 < bitlen) { |
284 | 133 | RANGE_CHECK6(360, 360); |
285 | 66 | UCHARS(138, ais->type6.dac1fid12.nextport); |
286 | 66 | ais->type6.dac1fid12.nmonth = UBITS(168, 4); |
287 | 66 | ais->type6.dac1fid12.nday = UBITS(172, 5); |
288 | 66 | ais->type6.dac1fid12.nhour = UBITS(177, 5); |
289 | 66 | ais->type6.dac1fid12.nminute = UBITS(182, 6); |
290 | 66 | UCHARS(188, ais->type6.dac1fid12.dangerous); |
291 | 66 | UCHARS(308, ais->type6.dac1fid12.imdcat); |
292 | 66 | ais->type6.dac1fid12.unid = UBITS(332, 13); |
293 | 66 | ais->type6.dac1fid12.amount = UBITS(345, 10); |
294 | 66 | ais->type6.dac1fid12.unit = UBITS(355, 2); |
295 | | // skip 3 bits |
296 | 66 | } |
297 | 132 | ais->type6.structured = true; |
298 | 132 | break; |
299 | 234 | case 14: |
300 | | // IMO236 - Tidal Window |
301 | | // similar to fid 32. |
302 | 234 | RANGE_CHECK6(87, 1008); |
303 | 234 | ais->type6.dac1fid32.month = UBITS(88, 4); |
304 | 234 | ais->type6.dac1fid32.day = UBITS(92, 5); |
305 | 603 | #define ARRAY_BASE 97 |
306 | 603 | #define ELEMENT_SIZE 93 |
307 | 603 | for (u = 0; ; u++) { |
308 | 603 | size_t off = OFF(u); |
309 | 603 | struct tidal_t *tp = &ais->type6.dac1fid32.tidals[u]; |
310 | 603 | if (off >= bitlen || |
311 | 437 | ROWS(ais->type6.dac1fid32.tidals) <= u) { |
312 | 234 | break; |
313 | 234 | } |
314 | 369 | tp->lat = SBITS(off + 0, 27); |
315 | 369 | tp->lon = SBITS(off + 27, 28); |
316 | 369 | tp->from_hour = UBITS(off + 55, 5); |
317 | 369 | tp->from_min = UBITS(off + 60, 6); |
318 | 369 | tp->to_hour = UBITS(off + 66, 5); |
319 | 369 | tp->to_min = UBITS(off + 71, 6); |
320 | 369 | tp->cdir = UBITS(off + 77, 9); |
321 | 369 | tp->cspeed = UBITS(off + 86, 7); |
322 | 369 | } |
323 | 234 | ais->type6.dac1fid32.ntidals = u; |
324 | 234 | #undef ARRAY_BASE |
325 | 234 | #undef ELEMENT_SIZE |
326 | 234 | ais->type6.structured = true; |
327 | 234 | break; |
328 | 67 | case 15: |
329 | | // IMO236 - Extended Ship Static and Voyage Related Data |
330 | 67 | RANGE_CHECK6(67, 1008); |
331 | 67 | ais->type6.dac1fid15.airdraught = UBITS(56, 11); |
332 | 67 | ais->type6.structured = true; |
333 | 67 | break; |
334 | 202 | case 16: |
335 | | // IMO236 - Number of persons on board |
336 | 202 | RANGE_CHECK6(236, 289); |
337 | 66 | if (136 == ais->type6.bitcount) { |
338 | 0 | ais->type6.dac1fid16.persons = UBITS(88, 13); // 289 |
339 | 66 | } else { |
340 | 66 | ais->type6.dac1fid16.persons = UBITS(55, 13); // 236 |
341 | 66 | } |
342 | 66 | ais->type6.structured = true; |
343 | 66 | break; |
344 | 205 | case 18: |
345 | | // IMO289 - Clearance time to enter port |
346 | | // sometimes bitlen == 168! |
347 | 205 | RANGE_CHECK6(168, 1008); |
348 | 138 | ais->type6.dac1fid18.linkage = UBITS(88, 10); |
349 | 138 | ais->type6.dac1fid18.month = UBITS(98, 4); |
350 | 138 | ais->type6.dac1fid18.day = UBITS(102, 5); |
351 | 138 | ais->type6.dac1fid18.hour = UBITS(107, 5); |
352 | 138 | ais->type6.dac1fid18.minute = UBITS(112, 6); |
353 | 138 | UCHARS(118, ais->type6.dac1fid18.portname); |
354 | 138 | if (318 <= bitlen) { |
355 | 66 | UCHARS(238, ais->type6.dac1fid18.destination); |
356 | 66 | ais->type6.dac1fid18.lon = SBITS(268, 25); |
357 | 66 | ais->type6.dac1fid18.lat = SBITS(293, 24); |
358 | | // skip 43 bits |
359 | 66 | } |
360 | 138 | ais->type6.structured = true; |
361 | 138 | break; |
362 | 142 | case 20: // IMO289 - Berthing data - addressed |
363 | 142 | RANGE_CHECK6(360, 1008); |
364 | 66 | ais->type6.dac1fid20.linkage = UBITS(88, 10); |
365 | 66 | ais->type6.dac1fid20.berth_length = UBITS(98, 9); |
366 | 66 | ais->type6.dac1fid20.berth_depth = UBITS(107, 8); |
367 | 66 | ais->type6.dac1fid20.position = UBITS(115, 3); |
368 | 66 | ais->type6.dac1fid20.month = UBITS(118, 4); |
369 | 66 | ais->type6.dac1fid20.day = UBITS(122, 5); |
370 | 66 | ais->type6.dac1fid20.hour = UBITS(127, 5); |
371 | 66 | ais->type6.dac1fid20.minute = UBITS(132, 6); |
372 | 66 | ais->type6.dac1fid20.availability = UBITS(138, 1); |
373 | 66 | ais->type6.dac1fid20.agent = UBITS(139, 2); |
374 | 66 | ais->type6.dac1fid20.fuel = UBITS(141, 2); |
375 | 66 | ais->type6.dac1fid20.chandler = UBITS(143, 2); |
376 | 66 | ais->type6.dac1fid20.stevedore = UBITS(145, 2); |
377 | 66 | ais->type6.dac1fid20.electrical = UBITS(147, 2); |
378 | 66 | ais->type6.dac1fid20.water = UBITS(149, 2); |
379 | 66 | ais->type6.dac1fid20.customs = UBITS(151, 2); |
380 | 66 | ais->type6.dac1fid20.cartage = UBITS(153, 2); |
381 | 66 | ais->type6.dac1fid20.crane = UBITS(155, 2); |
382 | 66 | ais->type6.dac1fid20.lift = UBITS(157, 2); |
383 | 66 | ais->type6.dac1fid20.medical = UBITS(159, 2); |
384 | 66 | ais->type6.dac1fid20.navrepair = UBITS(161, 2); |
385 | 66 | ais->type6.dac1fid20.provisions = UBITS(163, 2); |
386 | 66 | ais->type6.dac1fid20.shiprepair = UBITS(165, 2); |
387 | 66 | ais->type6.dac1fid20.surveyor = UBITS(167, 2); |
388 | 66 | ais->type6.dac1fid20.steam = UBITS(169, 2); |
389 | 66 | ais->type6.dac1fid20.tugs = UBITS(171, 2); |
390 | 66 | ais->type6.dac1fid20.solidwaste = UBITS(173, 2); |
391 | 66 | ais->type6.dac1fid20.liquidwaste = UBITS(175, 2); |
392 | 66 | ais->type6.dac1fid20.hazardouswaste = UBITS(177, 2); |
393 | 66 | ais->type6.dac1fid20.ballast = UBITS(179, 2); |
394 | 66 | ais->type6.dac1fid20.additional = UBITS(181, 2); |
395 | 66 | ais->type6.dac1fid20.regional1 = UBITS(183, 2); |
396 | 66 | ais->type6.dac1fid20.regional2 = UBITS(185, 2); |
397 | 66 | ais->type6.dac1fid20.future1 = UBITS(187, 2); |
398 | 66 | ais->type6.dac1fid20.future2 = UBITS(189, 2); |
399 | 66 | UCHARS(191, ais->type6.dac1fid20.berth_name); |
400 | 66 | ais->type6.dac1fid20.berth_lon = SBITS(311, 25); |
401 | 66 | ais->type6.dac1fid20.berth_lat = SBITS(336, 24); |
402 | 66 | ais->type6.structured = true; |
403 | 66 | break; |
404 | 0 | case 23: // IMO289 - Area notice - addressed |
405 | 0 | break; |
406 | 218 | case 25: // IMO289 - Dangerous cargo indication |
407 | 546 | #define ARRAY_BASE 100 |
408 | 546 | #define ELEMENT_SIZE 17 |
409 | 218 | RANGE_CHECK6(100, 1008); |
410 | 152 | ais->type6.dac1fid25.unit = UBITS(88, 2); |
411 | 152 | ais->type6.dac1fid25.amount = UBITS(90, 10); |
412 | 546 | for (u = 0; ; u++) { |
413 | 546 | size_t off = OFF(u); |
414 | 546 | if (off >= bitlen || |
415 | 397 | ROWS(ais->type6.dac1fid25.cargos) <= u) { |
416 | 152 | break; |
417 | 152 | } |
418 | 394 | ais->type6.dac1fid25.cargos[u].code = UBITS(off, 4); |
419 | 394 | ais->type6.dac1fid25.cargos[u].subtype = |
420 | 394 | UBITS(off + 4, 13); |
421 | 394 | } |
422 | 152 | ais->type6.dac1fid25.ncargos = u; |
423 | 152 | ais->type6.structured = true; |
424 | 152 | #undef ARRAY_BASE |
425 | 152 | #undef ELEMENT_SIZE |
426 | 152 | break; |
427 | 312 | case 28: // IMO289 - Route info - addressed |
428 | 312 | RANGE_CHECK6(149, 1008); |
429 | 244 | ais->type6.dac1fid28.linkage = UBITS(88, 10); |
430 | 244 | ais->type6.dac1fid28.sender = UBITS(98, 3); |
431 | 244 | ais->type6.dac1fid28.rtype = UBITS(101, 5); |
432 | 244 | ais->type6.dac1fid28.month = UBITS(106, 4); |
433 | 244 | ais->type6.dac1fid28.day = UBITS(110, 5); |
434 | 244 | ais->type6.dac1fid28.hour = UBITS(115, 5); |
435 | 244 | ais->type6.dac1fid28.minute = UBITS(120, 6); |
436 | 244 | ais->type6.dac1fid28.duration = UBITS(126, 18); |
437 | 244 | ais->type6.dac1fid28.waycount = UBITS(144, 5); |
438 | 740 | #define ARRAY_BASE 149 |
439 | 740 | #define ELEMENT_SIZE 55 |
440 | 740 | for (u = 0; ; u++) { |
441 | 740 | size_t off = OFF(u); |
442 | 740 | if (off >= bitlen || |
443 | 563 | ROWS(ais->type6.dac1fid28.waypoints) <= u || |
444 | 563 | u >= ais->type6.dac1fid28.waycount) { |
445 | 244 | break; |
446 | 244 | } |
447 | 496 | ais->type6.dac1fid28.waypoints[u].lon = SBITS(off + 0, 28); |
448 | 496 | ais->type6.dac1fid28.waypoints[u].lat = SBITS(off + 28, 27); |
449 | 496 | } |
450 | 244 | #undef ARRAY_BASE |
451 | 244 | #undef ELEMENT_SIZE |
452 | 244 | ais->type6.structured = true; |
453 | 244 | break; |
454 | 135 | case 30: // IMO289 - Text description - addressed |
455 | 135 | RANGE_CHECK6(98, 1008); |
456 | 69 | ais->type6.dac1fid30.linkage = UBITS(88, 10); |
457 | 69 | ENDCHARS(98, ais->type6.dac1fid30.text, |
458 | 69 | sizeof(ais->type6.dac1fid30.text)); |
459 | 69 | ais->type6.structured = true; |
460 | 69 | break; |
461 | 304 | case 32: // IMO289 - Tidal Window |
462 | | // similar to fid 14. |
463 | 304 | RANGE_CHECK6(97, 1008); |
464 | 238 | ais->type6.dac1fid32.month = UBITS(88, 4); |
465 | 238 | ais->type6.dac1fid32.day = UBITS(92, 5); |
466 | 617 | #define ARRAY_BASE 97 |
467 | 617 | #define ELEMENT_SIZE 88 |
468 | 617 | for (u = 0; ; u++) { |
469 | 617 | size_t off = OFF(u); |
470 | 617 | if (off >= bitlen || |
471 | 434 | ROWS(ais->type6.dac1fid32.tidals) <= u) { |
472 | 238 | break; |
473 | 238 | } |
474 | 379 | struct tidal_t *tp = &ais->type6.dac1fid32.tidals[u]; |
475 | | |
476 | 379 | tp->lon = SBITS(off + 0, 25); |
477 | 379 | tp->lat = SBITS(off + 25, 24); |
478 | 379 | tp->from_hour = UBITS(off + 49, 5); |
479 | 379 | tp->from_min = UBITS(off + 54, 6); |
480 | 379 | tp->to_hour = UBITS(off + 60, 5); |
481 | 379 | tp->to_min = UBITS(off + 65, 6); |
482 | 379 | tp->cdir = UBITS(off + 71, 9); |
483 | 379 | tp->cspeed = UBITS(off + 80, 8); |
484 | 379 | } |
485 | 238 | ais->type6.dac1fid32.ntidals = u; |
486 | 238 | #undef ARRAY_BASE |
487 | 238 | #undef ELEMENT_SIZE |
488 | 238 | ais->type6.structured = true; |
489 | 238 | break; |
490 | 2.22k | } |
491 | 1.47k | break; |
492 | 1.47k | case 200: |
493 | 818 | switch (ais->type6.fid) { |
494 | 201 | case 21: // ETA at lock/bridge/terminal |
495 | 201 | RANGE_CHECK6(248, 248); |
496 | 66 | UCHARS(88, ais->type6.dac200fid21.country); |
497 | 66 | UCHARS(100, ais->type6.dac200fid21.locode); |
498 | 66 | UCHARS(118, ais->type6.dac200fid21.section); |
499 | 66 | UCHARS(148, ais->type6.dac200fid21.terminal); |
500 | 66 | UCHARS(178, ais->type6.dac200fid21.hectometre); |
501 | 66 | ais->type6.dac200fid21.month = UBITS(208, 4); |
502 | 66 | ais->type6.dac200fid21.day = UBITS(212, 5); |
503 | 66 | ais->type6.dac200fid21.hour = UBITS(217, 5); |
504 | 66 | ais->type6.dac200fid21.minute = UBITS(222, 6); |
505 | 66 | ais->type6.dac200fid21.tugs = UBITS(228, 3); |
506 | 66 | ais->type6.dac200fid21.airdraught = UBITS(231, 12); |
507 | | // skip 5 bits |
508 | 66 | ais->type6.structured = true; |
509 | 66 | break; |
510 | 353 | case 22: // RTA at lock/bridge/terminal |
511 | 353 | RANGE_CHECK6(232, 232); |
512 | 219 | UCHARS(88, ais->type6.dac200fid22.country); |
513 | 219 | UCHARS(100, ais->type6.dac200fid22.locode); |
514 | 219 | UCHARS(118, ais->type6.dac200fid22.section); |
515 | 219 | UCHARS(148, ais->type6.dac200fid22.terminal); |
516 | 219 | UCHARS(178, ais->type6.dac200fid22.hectometre); |
517 | 219 | ais->type6.dac200fid22.month = UBITS(208, 4); |
518 | 219 | ais->type6.dac200fid22.day = UBITS(212, 5); |
519 | 219 | ais->type6.dac200fid22.hour = UBITS(217, 5); |
520 | 219 | ais->type6.dac200fid22.minute = UBITS(222, 6); |
521 | 219 | ais->type6.dac200fid22.status = UBITS(228, 2); |
522 | | // skip 2 bits |
523 | 219 | ais->type6.structured = true; |
524 | 219 | break; |
525 | 198 | case 55: |
526 | | // Number of Persons On Board |
527 | 198 | RANGE_CHECK6(168, 168); |
528 | 66 | ais->type6.dac200fid55.crew = UBITS(88, 8); |
529 | 66 | ais->type6.dac200fid55.passengers = UBITS(96, 13); |
530 | 66 | ais->type6.dac200fid55.personnel = UBITS(109, 8); |
531 | | // skip 51 bits |
532 | 66 | ais->type6.structured = true; |
533 | 66 | break; |
534 | 818 | } |
535 | 417 | break; |
536 | 417 | case 235: |
537 | 66 | FALLTHROUGH |
538 | 319 | case 250: |
539 | | // UK and Republic Of Ireland |
540 | 319 | switch (ais->type6.fid) { |
541 | 247 | case 10: // GLA - AtoN monitoring data |
542 | 247 | RANGE_CHECK6(136, 136); |
543 | 108 | ais->type6.dac235fid10.ana_int = UBITS(88, 10); |
544 | 108 | ais->type6.dac235fid10.ana_ext1 = UBITS(98, 10); |
545 | 108 | ais->type6.dac235fid10.ana_ext2 = UBITS(108, 10); |
546 | 108 | ais->type6.dac235fid10.racon = UBITS(118, 2); |
547 | 108 | ais->type6.dac235fid10.light = UBITS(120, 2); |
548 | 108 | ais->type6.dac235fid10.alarm = UBITS(122, 1); |
549 | 108 | ais->type6.dac235fid10.stat_ext = UBITS(123, 8); |
550 | 108 | ais->type6.dac235fid10.off_pos = UBITS(131, 1); |
551 | | // skip 4 bits |
552 | 108 | ais->type6.structured = true; |
553 | 108 | break; |
554 | 319 | } |
555 | 180 | break; |
556 | 180 | default: |
557 | 95 | break; |
558 | 3.45k | } |
559 | 2.16k | if (!ais->type6.structured) { |
560 | 300 | u = BITS_TO_BYTES(ais->type6.bitcount); |
561 | 300 | if (sizeof(ais->type6.bitdata) < u) { |
562 | 0 | u = sizeof(ais->type6.bitdata); |
563 | 0 | ais->type6.bitcount = u * 8; |
564 | 0 | } |
565 | 300 | (void)memcpy(ais->type6.bitdata, bits + (88 / CHAR_BIT), u); |
566 | 300 | GPSD_LOG(LOG_WARN, errout, |
567 | 300 | "AIVDM: type 6 unknown dac %u fid %u bitlen %zu\n", |
568 | 300 | ais->type6.dac, ais->type6.fid, bitlen); |
569 | 300 | } |
570 | 2.16k | break; |
571 | 296 | case 7: // Binary acknowledge |
572 | 296 | FALLTHROUGH |
573 | 525 | case 13: // Safety Related Acknowledge |
574 | 525 | { |
575 | 525 | unsigned int mmsi[4]; |
576 | 525 | unsigned seqno[4]; |
577 | 525 | RANGE_CHECK(72, 168); |
578 | 1.22k | #define ARRAY_BASE 40 |
579 | 1.22k | #define ELEMENT_SIZE 32 |
580 | 1.53k | for (u = 0; u < ROWS(mmsi); u++) { |
581 | 1.22k | size_t off = OFF(u); |
582 | | |
583 | 1.22k | if (off < bitlen) { |
584 | 821 | mmsi[u] = UBITS(off, 30); |
585 | 821 | seqno[u] = UBITS(off + 32, 2); |
586 | 821 | } else { |
587 | 407 | mmsi[u] = 0; |
588 | 407 | seqno[u] = 0; |
589 | 407 | } |
590 | 1.22k | } |
591 | 307 | #undef ARRAY_BASE |
592 | 307 | #undef ELEMENT_SIZE |
593 | 307 | ais->type7.mmsi1 = mmsi[0]; |
594 | 307 | ais->type7.seqno1 = seqno[0]; |
595 | 307 | ais->type7.mmsi2 = mmsi[1]; |
596 | 307 | ais->type7.seqno2 = seqno[1]; |
597 | 307 | ais->type7.mmsi3 = mmsi[2]; |
598 | 307 | ais->type7.seqno3 = seqno[2]; |
599 | 307 | ais->type7.mmsi4 = mmsi[3]; |
600 | 307 | ais->type7.seqno4 = seqno[3]; |
601 | 307 | break; |
602 | 525 | } |
603 | 3.54k | case 8: // Binary Broadcast Message |
604 | 3.54k | RANGE_CHECK8(56, 1008); |
605 | | // ais->type8.spare = UBITS(38, 2); |
606 | 3.40k | ais->type8.dac = UBITS(40, 10); |
607 | 3.40k | ais->type8.fid = UBITS(50, 6); |
608 | 3.40k | ais->type8.bitcount = bitlen - 56; |
609 | | // not strictly required - helps stability in testing |
610 | 3.40k | (void)memset(ais->type8.bitdata, '\0', sizeof(ais->type8.bitdata)); |
611 | 3.40k | ais->type8.structured = false; |
612 | 3.40k | GPSD_LOG(LOG_PROG, errout, "AIVDM: type 8 dac %u fid %u bitlen %zu\n", |
613 | 3.40k | ais->type8.dac, ais->type8.fid, bitlen); |
614 | 3.40k | switch (ais->type8.dac) { |
615 | 2.37k | case 1: |
616 | | // International |
617 | 2.37k | switch (ais->type8.fid) { |
618 | 202 | case 11: // IMO236 - Meteorological/Hydrological data |
619 | | // layout is almost identical to FID=31 from IMO289 |
620 | | // FIXME: we get length 352?? |
621 | 202 | RANGE_CHECK8(346, 352); |
622 | 66 | ais->type8.dac1fid11.lat = SBITS(56, 24); |
623 | 66 | ais->type8.dac1fid11.lon = SBITS(80, 25); |
624 | 66 | ais->type8.dac1fid11.day = UBITS(105, 5); |
625 | 66 | ais->type8.dac1fid11.hour = UBITS(110, 5); |
626 | 66 | ais->type8.dac1fid11.minute = UBITS(115, 6); |
627 | 66 | ais->type8.dac1fid11.wspeed = UBITS(121, 7); |
628 | 66 | ais->type8.dac1fid11.wgust = UBITS(128, 7); |
629 | 66 | ais->type8.dac1fid11.wdir = UBITS(135, 9); |
630 | 66 | ais->type8.dac1fid11.wgustdir = UBITS(144, 9); |
631 | 66 | ais->type8.dac1fid11.airtemp = UBITS(153, 11); |
632 | 66 | ais->type8.dac1fid11.humidity = UBITS(164, 7); |
633 | 66 | ais->type8.dac1fid11.dewpoint = UBITS(171, 10); |
634 | 66 | ais->type8.dac1fid11.pressure = UBITS(181, 9); |
635 | 66 | ais->type8.dac1fid11.pressuretend = UBITS(190, 2); |
636 | 66 | ais->type8.dac1fid11.visibility = UBITS(192, 8); |
637 | 66 | ais->type8.dac1fid11.waterlevel = UBITS(200, 9); |
638 | 66 | ais->type8.dac1fid11.leveltrend = UBITS(209, 2); |
639 | 66 | ais->type8.dac1fid11.cspeed = UBITS(211, 8); |
640 | 66 | ais->type8.dac1fid11.cdir = UBITS(219, 9); |
641 | 66 | ais->type8.dac1fid11.cspeed2 = UBITS(228, 8); |
642 | 66 | ais->type8.dac1fid11.cdir2 = UBITS(236, 9); |
643 | 66 | ais->type8.dac1fid11.cdepth2 = UBITS(245, 5); |
644 | 66 | ais->type8.dac1fid11.cspeed3 = UBITS(250, 8); |
645 | 66 | ais->type8.dac1fid11.cdir3 = UBITS(258, 9); |
646 | 66 | ais->type8.dac1fid11.cdepth3 = UBITS(267, 5); |
647 | 66 | ais->type8.dac1fid11.waveheight = UBITS(272, 8); |
648 | 66 | ais->type8.dac1fid11.waveperiod = UBITS(280, 6); |
649 | 66 | ais->type8.dac1fid11.wavedir = UBITS(286, 9); |
650 | 66 | ais->type8.dac1fid11.swellheight = UBITS(295, 8); |
651 | 66 | ais->type8.dac1fid11.swellperiod = UBITS(303, 6); |
652 | 66 | ais->type8.dac1fid11.swelldir = UBITS(309, 9); |
653 | 66 | ais->type8.dac1fid11.seastate = UBITS(318, 4); |
654 | 66 | ais->type8.dac1fid11.watertemp = UBITS(322, 10); |
655 | 66 | ais->type8.dac1fid11.preciptype = UBITS(332, 3); |
656 | 66 | ais->type8.dac1fid11.salinity = UBITS(335, 9); |
657 | 66 | ais->type8.dac1fid11.ice = UBITS(344, 2); |
658 | 66 | ais->type8.structured = true; |
659 | 66 | break; |
660 | 211 | case 13: // IMO236 - Fairway closed |
661 | 211 | RANGE_CHECK8(468, 468); |
662 | 66 | UCHARS(56, ais->type8.dac1fid13.reason); |
663 | 66 | UCHARS(176, ais->type8.dac1fid13.closefrom); |
664 | 66 | UCHARS(296, ais->type8.dac1fid13.closeto); |
665 | 66 | ais->type8.dac1fid13.radius = UBITS(416, 10); |
666 | 66 | ais->type8.dac1fid13.extunit = UBITS(426, 2); |
667 | 66 | ais->type8.dac1fid13.fday = UBITS(428, 5); |
668 | 66 | ais->type8.dac1fid13.fmonth = UBITS(433, 4); |
669 | 66 | ais->type8.dac1fid13.fhour = UBITS(437, 5); |
670 | 66 | ais->type8.dac1fid13.fminute = UBITS(442, 6); |
671 | 66 | ais->type8.dac1fid13.tday = UBITS(448, 5); |
672 | 66 | ais->type8.dac1fid13.tmonth = UBITS(453, 4); |
673 | 66 | ais->type8.dac1fid13.thour = UBITS(457, 5); |
674 | 66 | ais->type8.dac1fid13.tminute = UBITS(462, 6); |
675 | | // skip 4 bits |
676 | 66 | ais->type8.structured = true; |
677 | 66 | break; |
678 | 198 | case 15: // IMO236 - |
679 | | // Extended |
680 | | // ship and |
681 | | // voyage |
682 | 198 | RANGE_CHECK8(67, 72); |
683 | 66 | ais->type8.dac1fid15.airdraught = UBITS(56, 11); |
684 | | // skip 5 bits |
685 | 66 | ais->type8.structured = true; |
686 | 66 | break; |
687 | 339 | case 16: |
688 | | // Number of Persons On Board |
689 | | // dac 1, fid 18. bitlen = 776 ??? |
690 | 339 | RANGE_CHECK8(72, 776); |
691 | 205 | if (136 == ais->type8.bitcount) { |
692 | 66 | ais->type8.dac1fid16.persons = UBITS(88, 13); // 289 |
693 | 66 | ais->type8.structured = true; |
694 | 139 | } else if (72 == ais->type8.bitcount) { |
695 | 66 | ais->type8.dac1fid16.persons = UBITS(55, 13); // 236 |
696 | 66 | ais->type8.structured = true; |
697 | 66 | } |
698 | 205 | break; |
699 | 589 | case 17: |
700 | | // IMO289 - VTS-generated/synthetic targets |
701 | 589 | RANGE_CHECK8(56, 1008); |
702 | 1.74k | #define ARRAY_BASE 56 |
703 | 1.74k | #define ELEMENT_SIZE 122 |
704 | 1.74k | for (u = 0; ; u++) { |
705 | 1.74k | struct target_t *tp; |
706 | 1.74k | size_t off = OFF(u); |
707 | 1.74k | if (off >= bitlen || |
708 | 1.25k | ROWS(ais->type8.dac1fid17.targets) <= u) { |
709 | 589 | break; |
710 | 589 | } |
711 | 1.15k | tp = &ais->type8.dac1fid17.targets[u]; |
712 | 1.15k | tp->idtype = UBITS(off + 0, 2); |
713 | 1.15k | switch (tp->idtype) { |
714 | 176 | case DAC1FID17_IDTYPE_MMSI: |
715 | 176 | tp->id.mmsi = UBITS(off + 2, 42); |
716 | 176 | break; |
717 | 374 | case DAC1FID17_IDTYPE_IMO: |
718 | 374 | tp->id.imo = UBITS(off + 2, 42); |
719 | 374 | break; |
720 | 339 | case DAC1FID17_IDTYPE_CALLSIGN: |
721 | 339 | UCHARS(off + 2, tp->id.callsign); |
722 | 339 | break; |
723 | 264 | default: |
724 | 264 | UCHARS(off + 2, tp->id.other); |
725 | 264 | break; |
726 | 1.15k | } |
727 | | // skip 4 bits |
728 | 1.15k | tp->lat = SBITS(off + 48, 24); |
729 | 1.15k | tp->lon = SBITS(off + 72, 25); |
730 | 1.15k | tp->course = UBITS(off + 97, 9); |
731 | 1.15k | tp->second = UBITS(off + 106, 6); |
732 | 1.15k | tp->speed = UBITS(off + 112, 10); |
733 | 1.15k | } |
734 | 589 | ais->type8.dac1fid17.ntargets = u; |
735 | 589 | #undef ARRAY_BASE |
736 | 589 | #undef ELEMENT_SIZE |
737 | 589 | ais->type8.structured = true; |
738 | 589 | break; |
739 | 132 | case 19: // IMO289 - Marine Traffic Signal |
740 | 132 | RANGE_CHECK8(258, 1008); |
741 | 66 | ais->type8.dac1fid19.linkage = UBITS(56, 10); |
742 | 66 | UCHARS(66, ais->type8.dac1fid19.station); |
743 | 66 | ais->type8.dac1fid19.lon = SBITS(186, 25); |
744 | 66 | ais->type8.dac1fid19.lat = SBITS(211, 24); |
745 | 66 | ais->type8.dac1fid19.status = UBITS(235, 2); |
746 | 66 | ais->type8.dac1fid19.signal = UBITS(237, 5); |
747 | 66 | ais->type8.dac1fid19.hour = UBITS(242, 5); |
748 | 66 | ais->type8.dac1fid19.minute = UBITS(247, 6); |
749 | 66 | ais->type8.dac1fid19.nextsignal = UBITS(253, 5); |
750 | | // skip 102 bits |
751 | 66 | ais->type8.structured = true; |
752 | 66 | break; |
753 | 0 | case 21: // IMO289 - Weather obs. report from ship |
754 | 0 | break; |
755 | 0 | case 22: // IMO289 - Area notice - broadcast |
756 | 0 | break; |
757 | 56 | case 24: |
758 | | // IMO289 - Extended ship static & voyage-related data |
759 | 56 | break; |
760 | 0 | case 26: // IMO289 - Environmental |
761 | 0 | break; |
762 | 295 | case 27: // IMO289 - Route information - broadcast |
763 | 295 | RANGE_CHECK8(117, 1008); |
764 | 229 | ais->type8.dac1fid27.linkage = UBITS(56, 10); |
765 | 229 | ais->type8.dac1fid27.sender = UBITS(66, 3); |
766 | 229 | ais->type8.dac1fid27.rtype = UBITS(69, 5); |
767 | 229 | ais->type8.dac1fid27.month = UBITS(74, 4); |
768 | 229 | ais->type8.dac1fid27.day = UBITS(78, 5); |
769 | 229 | ais->type8.dac1fid27.hour = UBITS(83, 5); |
770 | 229 | ais->type8.dac1fid27.minute = UBITS(88, 6); |
771 | 229 | ais->type8.dac1fid27.duration = UBITS(94, 18); |
772 | 229 | ais->type8.dac1fid27.waycount = UBITS(112, 5); |
773 | 635 | #define ARRAY_BASE 117 |
774 | 635 | #define ELEMENT_SIZE 55 |
775 | 768 | for (u = 0; u < ais->type8.dac1fid27.waycount; u++) { |
776 | 635 | size_t off = OFF(u); |
777 | 635 | if (off >= bitlen || |
778 | 539 | ROWS(ais->type8.dac1fid27.waypoints) <= u) { |
779 | 96 | break; |
780 | 96 | } |
781 | 539 | ais->type8.dac1fid27.waypoints[u].lon = SBITS(off + 0, 28); |
782 | 539 | ais->type8.dac1fid27.waypoints[u].lat = SBITS(off + 28, 27); |
783 | 539 | } |
784 | 229 | #undef ARRAY_BASE |
785 | 229 | #undef ELEMENT_SIZE |
786 | 229 | ais->type8.structured = true; |
787 | 229 | break; |
788 | 132 | case 29: // IMO289 - Text Description - broadcast |
789 | 132 | RANGE_CHECK8(66, 1008); |
790 | 66 | ais->type8.dac1fid29.linkage = UBITS(56, 10); |
791 | 66 | ENDCHARS(66, ais->type8.dac1fid29.text, |
792 | 66 | sizeof(ais->type8.dac1fid29.text)); |
793 | 66 | ais->type8.structured = true; |
794 | 66 | break; |
795 | 199 | case 31: // IMO289 - Meteorological/Hydrological data |
796 | | // 368?? |
797 | 199 | RANGE_CHECK8(340, 368); |
798 | 66 | ais->type8.dac1fid31.lon = SBITS(56, 25); |
799 | 66 | ais->type8.dac1fid31.lat = SBITS(81, 24); |
800 | 66 | ais->type8.dac1fid31.accuracy = (bool)UBITS(105, 1); |
801 | 66 | ais->type8.dac1fid31.day = UBITS(106, 5); |
802 | 66 | ais->type8.dac1fid31.hour = UBITS(111, 5); |
803 | 66 | ais->type8.dac1fid31.minute = UBITS(116, 6); |
804 | 66 | ais->type8.dac1fid31.wspeed = UBITS(122, 7); |
805 | 66 | ais->type8.dac1fid31.wgust = UBITS(129, 7); |
806 | 66 | ais->type8.dac1fid31.wdir = UBITS(136, 9); |
807 | 66 | ais->type8.dac1fid31.wgustdir = UBITS(145, 9); |
808 | 66 | ais->type8.dac1fid31.airtemp = SBITS(154, 11); |
809 | 66 | ais->type8.dac1fid31.humidity = UBITS(165, 7); |
810 | 66 | ais->type8.dac1fid31.dewpoint = SBITS(172, 10); |
811 | 66 | ais->type8.dac1fid31.pressure = UBITS(182, 9); |
812 | 66 | ais->type8.dac1fid31.pressuretend = UBITS(191, 2); |
813 | 66 | ais->type8.dac1fid31.visgreater = UBITS(193, 1); |
814 | 66 | ais->type8.dac1fid31.visibility = UBITS(194, 7); |
815 | 66 | ais->type8.dac1fid31.waterlevel = UBITS(201, 12); |
816 | 66 | ais->type8.dac1fid31.leveltrend = UBITS(213, 2); |
817 | 66 | ais->type8.dac1fid31.cspeed = UBITS(215, 8); |
818 | 66 | ais->type8.dac1fid31.cdir = UBITS(223, 9); |
819 | 66 | ais->type8.dac1fid31.cspeed2 = UBITS(232, 8); |
820 | 66 | ais->type8.dac1fid31.cdir2 = UBITS(240, 9); |
821 | 66 | ais->type8.dac1fid31.cdepth2 = UBITS(249, 5); |
822 | 66 | ais->type8.dac1fid31.cspeed3 = UBITS(254, 8); |
823 | 66 | ais->type8.dac1fid31.cdir3 = UBITS(262, 9); |
824 | 66 | ais->type8.dac1fid31.cdepth3 = UBITS(271, 5); |
825 | 66 | ais->type8.dac1fid31.waveheight = UBITS(276, 8); |
826 | 66 | ais->type8.dac1fid31.waveperiod = UBITS(284, 6); |
827 | 66 | ais->type8.dac1fid31.wavedir = UBITS(290, 9); |
828 | 66 | ais->type8.dac1fid31.swellheight = UBITS(299, 8); |
829 | 66 | ais->type8.dac1fid31.swellperiod = UBITS(307, 6); |
830 | 66 | ais->type8.dac1fid31.swelldir = UBITS(313, 9); |
831 | 66 | ais->type8.dac1fid31.seastate = UBITS(322, 4); |
832 | 66 | ais->type8.dac1fid31.watertemp = SBITS(326, 10); |
833 | 66 | ais->type8.dac1fid31.preciptype = UBITS(336, 3); |
834 | 66 | ais->type8.dac1fid31.salinity = UBITS(339, 9); |
835 | 66 | ais->type8.dac1fid31.ice = UBITS(348, 2); |
836 | 66 | ais->type8.structured = true; |
837 | 66 | break; |
838 | 2.37k | } |
839 | 1.49k | break; |
840 | 1.49k | case 200: |
841 | 951 | switch (ais->type8.fid) { |
842 | 274 | case 10: // Inland ship static and voyage related data |
843 | | // bitlen = 424?? |
844 | 274 | RANGE_CHECK8(168, 424); |
845 | 139 | UCHARS(56, ais->type8.dac200fid10.vin); |
846 | 139 | ais->type8.dac200fid10.length = UBITS(104, 13); |
847 | 139 | ais->type8.dac200fid10.beam = UBITS(117, 10); |
848 | 139 | ais->type8.dac200fid10.shiptype = UBITS(127, 14); |
849 | 139 | ais->type8.dac200fid10.hazard = UBITS(141, 3); |
850 | 139 | ais->type8.dac200fid10.draught = UBITS(144, 11); |
851 | 139 | ais->type8.dac200fid10.loaded = UBITS(155, 2); |
852 | 139 | ais->type8.dac200fid10.speed_q = (bool)UBITS(157, 1); |
853 | 139 | ais->type8.dac200fid10.course_q = (bool)UBITS(158, 1); |
854 | 139 | ais->type8.dac200fid10.heading_q = (bool)UBITS(159, 1); |
855 | | // skip 8 bits |
856 | | /* |
857 | | * Attempt to prevent false matches with this message type |
858 | | * by range-checking certain fields. |
859 | | */ |
860 | 139 | if (DAC200FID10_HAZARD_MAX < ais->type8.dac200fid10.hazard || |
861 | 70 | !isascii((int)ais->type8.dac200fid10.vin[0])) { |
862 | 70 | ais->type8.structured = false; |
863 | 70 | } else { |
864 | 69 | ais->type8.structured = true; |
865 | 69 | } |
866 | 139 | break; |
867 | 203 | case 23: // EMMA warning |
868 | 203 | RANGE_CHECK8(256, 256); |
869 | 66 | ais->type8.dac200fid23.start_year = UBITS(56, 8); |
870 | 66 | ais->type8.dac200fid23.start_month = UBITS(64, 4); |
871 | 66 | ais->type8.dac200fid23.start_day = UBITS(68, 5); |
872 | 66 | ais->type8.dac200fid23.end_year = UBITS(73, 8); |
873 | 66 | ais->type8.dac200fid23.end_month = UBITS(81, 4); |
874 | 66 | ais->type8.dac200fid23.end_day = UBITS(85, 5); |
875 | 66 | ais->type8.dac200fid23.start_hour = UBITS(90, 5); |
876 | 66 | ais->type8.dac200fid23.start_minute = UBITS(95, 6); |
877 | 66 | ais->type8.dac200fid23.end_hour = UBITS(101, 5); |
878 | 66 | ais->type8.dac200fid23.end_minute = UBITS(106, 6); |
879 | 66 | ais->type8.dac200fid23.start_lon = SBITS(112, 28); |
880 | 66 | ais->type8.dac200fid23.start_lat = SBITS(140, 27); |
881 | 66 | ais->type8.dac200fid23.end_lon = SBITS(167, 28); |
882 | 66 | ais->type8.dac200fid23.end_lat = SBITS(195, 27); |
883 | 66 | ais->type8.dac200fid23.type = UBITS(222, 4); |
884 | 66 | ais->type8.dac200fid23.min = SBITS(226, 9); |
885 | 66 | ais->type8.dac200fid23.max = SBITS(235, 9); |
886 | 66 | ais->type8.dac200fid23.intensity = UBITS(244, 2); |
887 | 66 | ais->type8.dac200fid23.wind = UBITS(246, 4); |
888 | | // skip 6 bits |
889 | 66 | ais->type8.structured = true; |
890 | 66 | break; |
891 | 203 | case 24: // Water level |
892 | 203 | RANGE_CHECK8(168, 168); |
893 | 66 | UCHARS(56, ais->type8.dac200fid24.country); |
894 | 330 | #define ARRAY_BASE 68 |
895 | 330 | #define ELEMENT_SIZE 25 |
896 | 330 | for (u = 0; ; u++) { |
897 | 330 | size_t off = OFF(u); |
898 | 330 | if (off >= bitlen || |
899 | 264 | ROWS(ais->type8.dac200fid24.gauges) <= u) { |
900 | 66 | break; |
901 | 66 | } |
902 | 264 | ais->type8.dac200fid24.gauges[u].id = UBITS(off + 0, 11); |
903 | 264 | ais->type8.dac200fid24.gauges[u].level = SBITS(off + 11, |
904 | 264 | 14); |
905 | 264 | } |
906 | 66 | ais->type8.dac200fid24.ngauges = u; |
907 | 66 | #undef ARRAY_BASE |
908 | 66 | #undef ELEMENT_SIZE |
909 | | // skip 6 bits |
910 | 66 | ais->type8.structured = true; |
911 | 66 | break; |
912 | 203 | case 40: // Signal status |
913 | 203 | RANGE_CHECK8(168, 168); |
914 | 66 | ais->type8.dac200fid40.lon = SBITS(56, 28); |
915 | 66 | ais->type8.dac200fid40.lat = SBITS(84, 27); |
916 | 66 | ais->type8.dac200fid40.form = UBITS(111, 4); |
917 | 66 | ais->type8.dac200fid40.facing = UBITS(115, 9); |
918 | 66 | ais->type8.dac200fid40.direction = UBITS(124, 3); |
919 | 66 | ais->type8.dac200fid40.status = UBITS(127, 30); |
920 | | // skip 11 bits |
921 | 66 | ais->type8.structured = true; |
922 | 66 | break; |
923 | 951 | } |
924 | 405 | break; |
925 | 405 | default: |
926 | 82 | break; |
927 | 3.40k | } |
928 | | // land here if we failed to match a known DAC/FID |
929 | 1.97k | if (!ais->type8.structured) { |
930 | 366 | u = BITS_TO_BYTES(ais->type8.bitcount); |
931 | 366 | if (sizeof(ais->type8.bitdata) < u) { |
932 | 0 | u = sizeof(ais->type8.bitdata); |
933 | 0 | ais->type8.bitcount = u * 8; |
934 | 0 | } |
935 | 366 | (void)memcpy(ais->type8.bitdata, bits + (56 / CHAR_BIT), u); |
936 | | |
937 | 366 | size_t valid_bits_in_last_byte = ais->type8.bitcount % CHAR_BIT; |
938 | 366 | if (valid_bits_in_last_byte > 0) { |
939 | | // huh?? |
940 | 208 | ais->type8.bitdata[u - 1] &= |
941 | 208 | (0xFF << (8 - valid_bits_in_last_byte)); |
942 | 208 | } |
943 | 366 | GPSD_LOG(LOG_WARN, errout, |
944 | 366 | "AIVDM: type 8 unknown dac %u fid %u bitlen %zu\n", |
945 | 366 | ais->type8.dac, ais->type8.fid, bitlen); |
946 | 366 | } |
947 | 1.97k | break; |
948 | 213 | case 9: // Standard SAR Aircraft Position Report |
949 | 213 | PERMISSIVE_LENGTH_CHECK(168); |
950 | 137 | ais->type9.alt = UBITS(38, 12); |
951 | 137 | ais->type9.speed = UBITS(50, 10); |
952 | 137 | ais->type9.accuracy = (bool)UBITS(60, 1); |
953 | 137 | ais->type9.lon = SBITS(61, 28); |
954 | 137 | ais->type9.lat = SBITS(89, 27); |
955 | 137 | ais->type9.course = UBITS(116, 12); |
956 | 137 | ais->type9.second = UBITS(128, 6); |
957 | 137 | ais->type9.regional = UBITS(134, 8); |
958 | 137 | ais->type9.dte = UBITS(142, 1); |
959 | | // ais->type9.spare = UBITS(143, 3); |
960 | 137 | ais->type9.assigned = UBITS(146, 1) != 0; |
961 | 137 | ais->type9.raim = UBITS(147, 1) != 0; |
962 | 137 | ais->type9.radio = UBITS(148, 20); |
963 | 137 | break; |
964 | 219 | case 10: // UTC/Date inquiry |
965 | 219 | PERMISSIVE_LENGTH_CHECK(72); |
966 | | // ais->type10.spare = UBITS(38, 2); |
967 | 134 | ais->type10.dest_mmsi = UBITS(40, 30); |
968 | | // ais->type10.spare2 = UBITS(70, 2); |
969 | 134 | break; |
970 | 223 | case 12: // Safety Related Message |
971 | 223 | RANGE_CHECK(72, 1008); |
972 | 79 | ais->type12.seqno = UBITS(38, 2); |
973 | 79 | ais->type12.dest_mmsi = UBITS(40, 30); |
974 | 79 | ais->type12.retransmit = (bool)UBITS(70, 1); |
975 | | // ais->type12.spare = UBITS(71, 1); |
976 | 79 | ENDCHARS(72, ais->type12.text, sizeof(ais->type12.text)); |
977 | 79 | break; |
978 | 235 | case 14: // Safety Related Broadcast Message |
979 | 235 | RANGE_CHECK(40, 960); |
980 | | // ais->type14.spare = UBITS(38, 2); |
981 | 100 | ENDCHARS(40, ais->type14.text, sizeof(ais->type14.text)); |
982 | 100 | break; |
983 | 337 | case 15: |
984 | | // Interrogation |
985 | 337 | RANGE_CHECK(88, 168); |
986 | 198 | (void)memset(&ais->type15, '\0', sizeof(ais->type15)); |
987 | | // ais->type14.spare = UBITS(38, 2); |
988 | 198 | ais->type15.mmsi1 = UBITS(40, 30); |
989 | 198 | ais->type15.type1_1 = UBITS(70, 6); |
990 | 198 | ais->type15.offset1_1 = UBITS(76, 12); |
991 | | // ais->type14.spare2 = UBITS(88, 2); |
992 | 198 | if (90 < bitlen) { |
993 | 132 | ais->type15.type1_2 = UBITS(90, 6); |
994 | 132 | ais->type15.offset1_2 = UBITS(96, 12); |
995 | | // ais->type14.spare3 = UBITS(108, 2); |
996 | 132 | if (110 < bitlen) { |
997 | 66 | ais->type15.mmsi2 = UBITS(110, 30); |
998 | 66 | ais->type15.type2_1 = UBITS(140, 6); |
999 | 66 | ais->type15.offset2_1 = UBITS(146, 12); |
1000 | | // ais->type14.spare4 = UBITS(158, 2); |
1001 | 66 | } |
1002 | 132 | } |
1003 | 198 | break; |
1004 | 308 | case 16: |
1005 | | // Assigned Mode Command |
1006 | 308 | RANGE_CHECK(96, 168); |
1007 | 141 | ais->type16.mmsi1 = UBITS(40, 30); |
1008 | 141 | ais->type16.offset1 = UBITS(70, 12); |
1009 | 141 | ais->type16.increment1 = UBITS(82, 10); |
1010 | 141 | if (144 > bitlen) { |
1011 | 74 | ais->type16.mmsi2 = ais->type16.offset2 = 0; |
1012 | 74 | ais->type16.increment2 = 0; |
1013 | 74 | } else { |
1014 | 67 | ais->type16.mmsi2 = UBITS(92, 30); |
1015 | 67 | ais->type16.offset2 = UBITS(122, 12); |
1016 | 67 | ais->type16.increment2 = UBITS(134, 10); |
1017 | 67 | } |
1018 | 141 | break; |
1019 | 221 | case 17: |
1020 | | // GNSS Broadcast Binary Message |
1021 | | // ITU-R M1371-5 Table 68 |
1022 | 221 | RANGE_CHECK(80, 816); |
1023 | | // ais->type17.spare = UBITS(38, 2); |
1024 | 82 | ais->type17.lon = SBITS(40, 18); |
1025 | 82 | ais->type17.lat = SBITS(58, 17); |
1026 | | // ais->type17.spare = UBITS(75, 5); |
1027 | 82 | ais->type17.bitcount = bitlen - 80; |
1028 | 82 | if (736 < ais->type17.bitcount) { |
1029 | 0 | ais->type17.bitcount = 736; |
1030 | 0 | } |
1031 | 82 | u = BITS_TO_BYTES(ais->type17.bitcount); |
1032 | 82 | if (sizeof(ais->type17.bitdata) < u) { |
1033 | 0 | u = sizeof(ais->type17.bitdata); |
1034 | 0 | ais->type17.bitcount = u * 8; |
1035 | 0 | } |
1036 | 82 | (void)memcpy(ais->type17.bitdata, bits + (80 / CHAR_BIT), u); |
1037 | 82 | break; |
1038 | 204 | case 18: // Standard Class B CS Position Report |
1039 | | // Per https://www.navcen.uscg.gov/ais-class-b-reports |
1040 | 204 | PERMISSIVE_LENGTH_CHECK(168) |
1041 | 135 | ais->type18.reserved = UBITS(38, 8); |
1042 | 135 | ais->type18.speed = UBITS(46, 10); |
1043 | 135 | ais->type18.accuracy = UBITS(56, 1) != 0; |
1044 | 135 | ais->type18.lon = SBITS(57, 28); |
1045 | 135 | ais->type18.lat = SBITS(85, 27); |
1046 | 135 | ais->type18.course = UBITS(112, 12); |
1047 | 135 | ais->type18.heading = UBITS(124, 9); |
1048 | 135 | ais->type18.second = UBITS(133, 6); |
1049 | 135 | ais->type18.regional = UBITS(139, 2); |
1050 | 135 | ais->type18.cs = UBITS(141, 1) != 0; |
1051 | 135 | ais->type18.display = UBITS(142, 1) != 0; |
1052 | 135 | ais->type18.dsc = UBITS(143, 1) != 0; |
1053 | 135 | ais->type18.band = UBITS(144, 1) != 0; |
1054 | 135 | ais->type18.msg22 = UBITS(145, 1) != 0; |
1055 | 135 | ais->type18.assigned = UBITS(146, 1) != 0; |
1056 | 135 | ais->type18.raim = UBITS(147, 1) != 0; |
1057 | 135 | ais->type18.radio = UBITS(148, 20); |
1058 | 135 | break; |
1059 | 211 | case 19: // Extended Class B CS Position Report |
1060 | 211 | PERMISSIVE_LENGTH_CHECK(312) |
1061 | 135 | ais->type19.reserved = UBITS(38, 8); |
1062 | 135 | ais->type19.speed = UBITS(46, 10); |
1063 | 135 | ais->type19.accuracy = UBITS(56, 1) != 0; |
1064 | 135 | ais->type19.lon = SBITS(57, 28); |
1065 | 135 | ais->type19.lat = SBITS(85, 27); |
1066 | 135 | ais->type19.course = UBITS(112, 12); |
1067 | 135 | ais->type19.heading = UBITS(124, 9); |
1068 | 135 | ais->type19.second = UBITS(133, 6); |
1069 | 135 | ais->type19.regional = UBITS(139, 4); |
1070 | 135 | UCHARS(143, ais->type19.shipname); |
1071 | 135 | ais->type19.shiptype = UBITS(263, 8); |
1072 | 135 | ais->type19.to_bow = UBITS(271, 9); |
1073 | 135 | ais->type19.to_stern = UBITS(280, 9); |
1074 | 135 | ais->type19.to_port = UBITS(289, 6); |
1075 | 135 | ais->type19.to_starboard = UBITS(295, 6); |
1076 | 135 | ais->type19.epfd = UBITS(301, 4); |
1077 | 135 | ais->type19.raim = UBITS(305, 1) != 0; |
1078 | 135 | ais->type19.dte = UBITS(306, 1) != 0; |
1079 | 135 | ais->type19.assigned = UBITS(307, 1) != 0; |
1080 | | // ais->type19.spare = UBITS(308, 4); |
1081 | 135 | break; |
1082 | 210 | case 20: // Data Link Management Message |
1083 | 210 | RANGE_CHECK(72, 186); |
1084 | | // ais->type20.spare = UBITS(38, 2); |
1085 | 69 | ais->type20.offset1 = UBITS(40, 12); |
1086 | 69 | ais->type20.number1 = UBITS(52, 4); |
1087 | 69 | ais->type20.timeout1 = UBITS(56, 3); |
1088 | 69 | ais->type20.increment1 = UBITS(59, 11); |
1089 | 69 | ais->type20.offset2 = UBITS(70, 12); |
1090 | 69 | ais->type20.number2 = UBITS(82, 4); |
1091 | 69 | ais->type20.timeout2 = UBITS(86, 3); |
1092 | 69 | ais->type20.increment2 = UBITS(89, 11); |
1093 | 69 | ais->type20.offset3 = UBITS(100, 12); |
1094 | 69 | ais->type20.number3 = UBITS(112, 4); |
1095 | 69 | ais->type20.timeout3 = UBITS(116, 3); |
1096 | 69 | ais->type20.increment3 = UBITS(119, 11); |
1097 | 69 | ais->type20.offset4 = UBITS(130, 12); |
1098 | 69 | ais->type20.number4 = UBITS(142, 4); |
1099 | 69 | ais->type20.timeout4 = UBITS(146, 3); |
1100 | 69 | ais->type20.increment4 = UBITS(149, 11); |
1101 | 69 | break; |
1102 | 503 | case 21: // Aid-to-Navigation Report |
1103 | | // Per https://www.navcen.uscg.gov/ais-class-b-reports |
1104 | 503 | RANGE_CHECK(272, 368); |
1105 | 361 | ais->type21.aid_type = UBITS(38, 5); |
1106 | 361 | from_sixbit_untrimmed(errout, bits, bitlen, 43, 20, ais->type21.name, |
1107 | 361 | sizeof(ais->type21.name)); |
1108 | 361 | ais->type21.accuracy = UBITS(163, 1); |
1109 | 361 | ais->type21.lon = SBITS(164, 28); |
1110 | 361 | ais->type21.lat = SBITS(192, 27); |
1111 | 361 | ais->type21.to_bow = UBITS(219, 9); |
1112 | 361 | ais->type21.to_stern = UBITS(228, 9); |
1113 | 361 | ais->type21.to_port = UBITS(237, 6); |
1114 | 361 | ais->type21.to_starboard = UBITS(243, 6); |
1115 | 361 | ais->type21.epfd = UBITS(249, 4); |
1116 | 361 | ais->type21.second = UBITS(253, 6); |
1117 | 361 | ais->type21.off_position = UBITS(259, 1) != 0; |
1118 | 361 | ais->type21.regional = UBITS(260, 8); |
1119 | 361 | ais->type21.raim = UBITS(268, 1) != 0; |
1120 | 361 | ais->type21.virtual_aid = UBITS(269, 1) != 0; |
1121 | 361 | ais->type21.assigned = UBITS(270, 1) != 0; |
1122 | | // ais->type21.spare = UBITS(271, 1); |
1123 | 361 | if (20 == strnlen(ais->type21.name, 21) && |
1124 | 190 | 272 < bitlen) { |
1125 | 122 | ENDCHARS(272, ais->type21.name + 20, |
1126 | 122 | sizeof(ais->type21.name) - 20); |
1127 | 122 | } |
1128 | 361 | trim_spaces_on_right_end(ais->type21.name, sizeof(ais->type21.name)); |
1129 | 361 | break; |
1130 | 290 | case 22: // Channel Management |
1131 | 290 | PERMISSIVE_LENGTH_CHECK(168) |
1132 | 209 | ais->type22.channel_a = UBITS(40, 12); |
1133 | 209 | ais->type22.channel_b = UBITS(52, 12); |
1134 | 209 | ais->type22.txrx = UBITS(64, 4); |
1135 | 209 | ais->type22.power = UBITS(68, 1); |
1136 | 209 | ais->type22.addressed = UBITS(139, 1); |
1137 | 209 | if (!ais->type22.addressed) { |
1138 | 136 | ais->type22.area.ne_lon = SBITS(69, 18); |
1139 | 136 | ais->type22.area.ne_lat = SBITS(87, 17); |
1140 | 136 | ais->type22.area.sw_lon = SBITS(104, 18); |
1141 | 136 | ais->type22.area.sw_lat = SBITS(122, 17); |
1142 | 136 | } else { |
1143 | 73 | ais->type22.mmsi.dest1 = UBITS(69, 30); |
1144 | 73 | ais->type22.mmsi.dest2 = UBITS(104, 30); |
1145 | 73 | } |
1146 | 209 | ais->type22.band_a = UBITS(140, 1); |
1147 | 209 | ais->type22.band_b = UBITS(141, 1); |
1148 | 209 | ais->type22.zonesize = UBITS(142, 3); |
1149 | 209 | break; |
1150 | 204 | case 23: // Group Assignment Command |
1151 | 204 | PERMISSIVE_LENGTH_CHECK(160) |
1152 | 137 | ais->type23.ne_lon = SBITS(40, 18); |
1153 | 137 | ais->type23.ne_lat = SBITS(58, 17); |
1154 | 137 | ais->type23.sw_lon = SBITS(75, 18); |
1155 | 137 | ais->type23.sw_lat = SBITS(93, 17); |
1156 | 137 | ais->type23.stationtype = UBITS(110, 4); |
1157 | 137 | ais->type23.shiptype = UBITS(114, 8); |
1158 | 137 | ais->type23.txrx = UBITS(144, 4); |
1159 | 137 | ais->type23.interval = UBITS(146, 4); |
1160 | 137 | ais->type23.quiet = UBITS(150, 4); |
1161 | 137 | break; |
1162 | 2.84k | case 24: // Class B CS Static Data Report |
1163 | 2.84k | switch (UBITS(38, 2)) { |
1164 | 2.04k | case 0: |
1165 | 2.04k | RANGE_CHECK(160, 168); |
1166 | | // save incoming 24A shipname/MMSI pairs in a circular queue |
1167 | 1.89k | { |
1168 | 1.89k | struct ais_type24a_t *saveptr = |
1169 | 1.89k | &type24_queue->ships[type24_queue->index]; |
1170 | | |
1171 | 1.89k | GPSD_LOG(LOG_PROG, errout, "AIVDM: 24A from %09u stashed.\n", |
1172 | 1.89k | ais->mmsi); |
1173 | 1.89k | saveptr->mmsi = ais->mmsi; |
1174 | 1.89k | UCHARS(40, saveptr->shipname); |
1175 | 1.89k | ++type24_queue->index; |
1176 | 1.89k | type24_queue->index %= MAX_TYPE24_INTERLEAVE; |
1177 | 1.89k | } |
1178 | | // ais->type24.a.spare = UBITS(160, 8); |
1179 | | |
1180 | 1.89k | UCHARS(40, ais->type24.shipname); |
1181 | 1.89k | ais->type24.part = part_a; |
1182 | 1.89k | return true; |
1183 | 736 | case 1: |
1184 | 736 | PERMISSIVE_LENGTH_CHECK(168) |
1185 | 663 | ais->type24.shiptype = UBITS(40, 8); |
1186 | | /* |
1187 | | * In ITU-R 1371-4, there are new model and serial fields |
1188 | | * carved out of the right-hand end of vendorid, which is |
1189 | | * reduced from 7 chars to 3. To cope with older AIS |
1190 | | * implementations conforming to revision 3 and older, |
1191 | | * unpack the trailing bits *both* ways; truly |
1192 | | * revision-4-conformant implementations will have up to |
1193 | | * four characters of trailing garbage on the vendorid, |
1194 | | * and older implementations will have garbafe in the |
1195 | | * model and serial fields. |
1196 | | */ |
1197 | 663 | UCHARS(48, ais->type24.vendorid); |
1198 | 663 | ais->type24.model = UBITS(66, 4); |
1199 | 663 | ais->type24.serial = UBITS(70, 20); |
1200 | 663 | UCHARS(90, ais->type24.callsign); |
1201 | 663 | if (AIS_AUXILIARY_MMSI(ais->mmsi)) { |
1202 | 118 | ais->type24.mothership_mmsi = UBITS(132, 30); |
1203 | 545 | } else { |
1204 | 545 | ais->type24.dim.to_bow = UBITS(132, 9); |
1205 | 545 | ais->type24.dim.to_stern = UBITS(141, 9); |
1206 | 545 | ais->type24.dim.to_port = UBITS(150, 6); |
1207 | 545 | ais->type24.dim.to_starboard = UBITS(156, 6); |
1208 | 545 | } |
1209 | | // ais->type24.b.spare = UBITS(162, 8); |
1210 | | |
1211 | | // search the 24A queue for a matching MMSI |
1212 | 4.98k | for (u = 0; u < MAX_TYPE24_INTERLEAVE; u++) { |
1213 | 4.53k | if (type24_queue->ships[u].mmsi == ais->mmsi) { |
1214 | 213 | (void)strlcpy(ais->type24.shipname, |
1215 | 213 | type24_queue->ships[u].shipname, |
1216 | 213 | sizeof(ais->type24.shipname)); |
1217 | 213 | GPSD_LOG(LOG_PROG, errout, |
1218 | 213 | "AIVDM 24B from %09u matches a 24A.\n", |
1219 | 213 | ais->mmsi); |
1220 | | // prevent false match if a 24B is repeated |
1221 | 213 | type24_queue->ships[u].mmsi = 0; |
1222 | 213 | ais->type24.part = both; |
1223 | 213 | return true; |
1224 | 213 | } |
1225 | 4.53k | } |
1226 | | |
1227 | | // no match, return Part B |
1228 | 450 | ais->type24.part = part_b; |
1229 | 450 | return true; |
1230 | 69 | default: |
1231 | 69 | GPSD_LOG(LOG_WARN, errout, |
1232 | 69 | "AIVDM message type 24 of subtype unknown.\n"); |
1233 | 69 | return false; |
1234 | 2.84k | } |
1235 | | // break; |
1236 | 437 | case 25: |
1237 | | // Binary Message, Single Slot |
1238 | | // this check and the following ones reject line noise |
1239 | | // ITU-R M1371-5 Table 80 |
1240 | 437 | RANGE_CHECK(80, 168); |
1241 | 296 | ais->type25.addressed = (bool)UBITS(38, 1); |
1242 | 296 | ais->type25.structured = (bool)UBITS(39, 1); // binary data flag |
1243 | | |
1244 | 296 | u = 40U + (32U * ais->type25.addressed) + |
1245 | 296 | (16U * ais->type25.structured); |
1246 | 296 | if (bitlen < u) { |
1247 | 69 | GPSD_LOG(LOG_WARN, errout, |
1248 | 69 | "AIVDM type 25 bitlen %zu wrong want %u.\n", |
1249 | 69 | bitlen, u); |
1250 | 69 | return false; |
1251 | 69 | } |
1252 | 227 | ais->type25.bitcount = bitlen - 40 - 16 * ais->type25.structured; |
1253 | 227 | if (ais->type25.addressed) { |
1254 | 150 | ais->type25.bitcount -= 32; |
1255 | 150 | ais->type25.dest_mmsi = UBITS(40, 30); |
1256 | | // plus 2 bits of padding |
1257 | 150 | if (98 < ais->type25.bitcount) { |
1258 | | // ITU-R M.1371-5 Table 80 |
1259 | 0 | ais->type25.bitcount = 98; |
1260 | 0 | } |
1261 | 150 | } else { |
1262 | 77 | if (128 < ais->type25.bitcount) { |
1263 | | // ITU-R M.1371-5 Table 80 |
1264 | 0 | ais->type25.bitcount = 128; |
1265 | 0 | } |
1266 | 77 | } |
1267 | 227 | if (ais->type25.structured) { |
1268 | 119 | ais->type25.bitcount -= 16; |
1269 | 119 | ais->type25.app_id = UBITS(40 + ais->type25.addressed * 32, 16); |
1270 | 119 | } |
1271 | 227 | u = BITS_TO_BYTES(ais->type25.bitcount); |
1272 | 227 | if (sizeof(ais->type25.bitdata) < u) { |
1273 | 85 | u = sizeof(ais->type25.bitdata); |
1274 | 85 | ais->type25.bitcount = u * 8; |
1275 | 85 | } |
1276 | | // bit 40 is exactly 5 bytes in; 2 bytes is 16 bits |
1277 | 227 | (void)memcpy(ais->type25.bitdata, |
1278 | 227 | bits + 5 + 2 * ais->type25.structured + |
1279 | 227 | 4 * ais->type25.addressed, u); |
1280 | 227 | break; |
1281 | 617 | case 26: |
1282 | | // Binary Message, Multiple Slot |
1283 | | // ITU-R M1371-5 Tables 28 and 82 |
1284 | 617 | RANGE_CHECK(96, 1064); |
1285 | 460 | ais->type26.addressed = (bool)UBITS(38, 1); |
1286 | 460 | ais->type26.structured = (bool)UBITS(39, 1); // binary data flag |
1287 | 460 | u = 40U + (16U * ais->type26.structured) + |
1288 | 460 | (32U * ais->type26.addressed) + 20; |
1289 | 460 | if (bitlen < u) { |
1290 | 68 | GPSD_LOG(LOG_WARN, errout, |
1291 | 68 | "AIVDM type 26 %zu wrong, want %u.\n", bitlen, u); |
1292 | 68 | return false; |
1293 | 68 | } |
1294 | 392 | ais->type26.bitcount = bitlen - 60 - 16 * ais->type26.structured; |
1295 | 392 | if (ais->type26.addressed) { |
1296 | 227 | ais->type26.bitcount -= 30; |
1297 | 227 | ais->type26.dest_mmsi = UBITS(40, 30); |
1298 | 227 | if (72 < ais->type26.bitcount) { |
1299 | | // ITU-R M.1371-5 Table 28 |
1300 | 81 | ais->type26.bitcount = 72; |
1301 | 81 | } |
1302 | 227 | } else { |
1303 | | // broadcast |
1304 | 165 | if (104 < ais->type26.bitcount) { |
1305 | | // ITU-R M.1371-5 Table 28 |
1306 | 70 | ais->type26.bitcount = 104; |
1307 | 70 | } |
1308 | 165 | } |
1309 | 392 | if (ais->type26.structured) { |
1310 | 184 | ais->type26.bitcount -= 16; |
1311 | 184 | ais->type26.app_id = UBITS(40 + ais->type26.addressed * 32, 16); |
1312 | 184 | } |
1313 | 392 | u = BITS_TO_BYTES(ais->type26.bitcount); |
1314 | 392 | if (sizeof(ais->type26.bitdata) < u) { |
1315 | 74 | u = sizeof(ais->type26.bitdata); |
1316 | 74 | ais->type26.bitcount = 8 * u; |
1317 | 74 | } |
1318 | | // bit 40 is exactly 5 bytes in; 2 bytes is 16 bits |
1319 | 392 | (void)memcpy(ais->type26.bitdata, |
1320 | 392 | bits + 5 + 2 * ais->type26.structured + |
1321 | 392 | 4 * ais->type26.addressed, u); |
1322 | 392 | break; |
1323 | 277 | case 27: // Long Range AIS Broadcast message |
1324 | 277 | RANGE_CHECK(96, 168); |
1325 | 139 | if (96 != bitlen) { |
1326 | | /* |
1327 | | * This is an implementation error observed in the wild, |
1328 | | * sending a full 168-bit slot rather than just 96 bits. |
1329 | | */ |
1330 | 73 | GPSD_LOG(LOG_WARN, errout, |
1331 | 73 | "oversized 168-bit AIVDM message type 27.\n"); |
1332 | 73 | } |
1333 | 139 | ais->type27.accuracy = (bool)UBITS(38, 1); |
1334 | 139 | ais->type27.raim = UBITS(39, 1) != 0; |
1335 | 139 | ais->type27.status = UBITS(40, 4); |
1336 | 139 | ais->type27.lon = SBITS(44, 18); |
1337 | 139 | ais->type27.lat = SBITS(62, 17); |
1338 | 139 | ais->type27.speed = UBITS(79, 6); |
1339 | 139 | ais->type27.course = UBITS(85, 9); |
1340 | 139 | ais->type27.gnss = (bool)UBITS(94, 1); |
1341 | 139 | break; |
1342 | 213 | default: |
1343 | 213 | GPSD_LOG(LOG_ERROR, errout, |
1344 | 213 | "Unparsed AIVDM message type %d.\n",ais->type); |
1345 | 213 | return false; |
1346 | 16.4k | } |
1347 | 7.59k | #undef UCHARS |
1348 | 7.59k | #undef SBITS |
1349 | 7.59k | #undef UBITS |
1350 | | |
1351 | | // data is fully decoded |
1352 | 7.59k | return true; |
1353 | 16.4k | } |
1354 | | // vim: set expandtab shiftwidth=4 |