aivdm
A no_std, allocation-free parser and encoder for AIS (Automatic
Identification System) messages, per ITU-R M.1371, as carried over NMEA
0183 !AIVDM/!AIVDO sentences.
- All 27 message types, decode and encode, verified against a corpus of real, independently-decoded AIS captures (not just synthetic round trips).
no_std, noalloc: works on bare-metal targets with no allocator. Multi-fragment sentence reassembly uses a fixed-capacity, caller-sized buffer instead of a growable one.- Zero mandatory dependencies. The bit-level codec is hand-rolled: AIS's irregular field widths (6, 12, 22, 27, 28, 30, 38 bits, ...) and spec-fixed sentinel values don't map cleanly onto byte-aligned derive macros.
#![forbid(unsafe_code)]. AIS messages are small (well under 1100 bits); there's no meaningful performance case for unsafe here.- A C FFI (
aivdm-ffi) for calling the decoder from C or any language with a C FFI, with a CI-checked header and a linked, running smoke test.
Crates
| Crate | Description |
|---|---|
aivdm |
The no_std, no-alloc parser/encoder library. |
aivdm-cli |
A small command-line decoder (installs as aivdm). |
aivdm-ffi |
Decode-only C FFI bindings. |
Quick start
let msg = decode_line?;
let PositionReportClassA = msg else ;
println!;
decode_line handles single-fragment sentences, which cover the large
majority of AIS traffic. For multi-part messages, parse each line with
Sentence::parse
and feed the fragments through a
FragmentAssembler
(a fixed-capacity buffer sized by you, so it works without an allocator),
then decode the reassembled payload with decode_payload.
Encoding mirrors decoding:
let mut buf = ;
let = encode_payload?;
Add it to a project with:
From C
AivdmError err;
AivdmMessage *msg = ;
if
See crates/aivdm-ffi for the full API and
crates/aivdm-ffi/tests/smoke.c for a
complete, working example. cargo build -p aivdm-ffi produces
libaivdm_ffi.{a,so} alongside the checked-in
crates/aivdm-ffi/include/aivdm.h; consumers who want a polished,
pkg-config-discoverable libaivdm can instead use
cargo-c (cargo capi build).
Message type coverage
All 27 ITU-R M.1371 message types are implemented, decode and encode:
| Types | What |
|---|---|
| 1, 2, 3 | Position Report Class A |
| 4, 11 | Base Station Report / UTC and Date Response |
| 5 | Static and Voyage Related Data |
| 6, 8, 25, 26 | Binary Addressed/Broadcast Messages |
| 7, 13 | Binary / Safety Related Acknowledge |
| 9 | Standard SAR Aircraft Position Report |
| 10 | UTC and Date Inquiry |
| 12, 14 | Addressed / Broadcast Safety Related Message |
| 15 | Interrogation |
| 16 | Assignment Mode Command |
| 17 | DGNSS Broadcast Binary Message |
| 18, 19 | Standard / Extended Class B Position Report |
| 20 | Data Link Management Message |
| 21 | Aid-to-Navigation Report |
| 22 | Channel Management |
| 23 | Group Assignment Command |
| 24 | Static Data Report (Class B, Parts A/B) |
| 27 | Long Range AIS Broadcast |
Position reports, static/voyage data, base station reports, and the Class B
variants were checked against real captured sentences with hand-verified
field values. The rarer control/management types were additionally
cross-referenced against libais's
well-tested decoder and its real-world test corpus — see
crates/aivdm/tests/real_world_corpus.rs.
Building
This project is built and checked with Nix:
# cross-compile verification, FFI header-diff, FFI smoke test
CI runs the identical nix flake check -L, so there is one source of truth
for what "passing" means, locally and in GitHub Actions.
Without Nix, a standard cargo build / cargo test from the workspace root
also works with a recent stable Rust toolchain (edition 2024, MSRV tracked
in Cargo.toml).
License
MIT. See LICENSE.