kinavis-ais 0.1.1

AIS messages out of the KINAVIS NMEA 0183 encapsulation and into the KINAVIS navigation types: unarmouring, reassembly of fragments and the position reports, without an allocator.
Documentation
# kinavis-ais

AIS messages from NMEA 0183 encapsulation sentences to the
[kinavis-kernel](https://crates.io/crates/kinavis-kernel) value types.

AIS messages arrive as `!AIVDM` sentences, 6 bits per character, split across
sentences when long.
[kinavis-nmea0183](https://crates.io/crates/kinavis-nmea0183) validates each
sentence and yields the armoured payload; this crate unarmours it, reassembles
fragments and decodes the message into kernel types — `Position`, `Speed`,
`TrueCourse`, `TargetId` (MMSI), `Distance` (draught), `InlineStr` (names). "Not
available" is `None`, never zero.

- Position reports — messages 1, 2, 3 (class A), 18, 19 (class B) — as
  `PositionReport`; message 19 adds name, ship type and dimensions.
- Static and voyage data — message 5 — as `StaticAndVoyageData`: IMO, call sign,
  name, ship and cargo type, dimensions, draught, destination, ETA.
- Class B static data — message 24, part A or B — as `StaticDataReport`.
- Aids to navigation — message 21 — as `AidToNavigation`: mark type, name,
  off-position and virtual flags.
- Other types: `Message::Unsupported` with the type and raw bits.
- No allocation: fixed-capacity bit buffer; assembler with fixed slots and a
  timeout.
- No panics: every failure is an `AisError`.

```rust
use kinavis_ais::{Assembler, Message, StationClass};
use kinavis_kernel::{Instant, Utc};
use kinavis_nmea0183::{parse, Sentence};

let mut assembler = Assembler::new();
let now = Instant::<Utc>::from_unix_seconds(1_789_000_000);

let line = b"!AIVDM,1,1,,A,13aEOK?P00PD2wVMdLDRhgvL289?,0*26\r\n";
let Sentence::Vdm(vdm) = parse(line)? else { panic!("not an AIS sentence") };
let Some(bits) = assembler.push(&vdm, now)? else { panic!("in fragments") };
let Message::PositionReport(report) = Message::decode(&bits)? else { panic!("not a position") };

assert_eq!(report.station_class(), StationClass::A);
assert_eq!(report.mmsi.number(), 244_670_316);
assert_eq!(format!("{:.3}", report.position.unwrap()), "51°53.685'N 004°22.757'E");
assert_eq!(report.course.map(|c| c.degrees()), Some(70.6));
assert_eq!(report.heading, None);
# Ok::<(), Box<dyn std::error::Error>>(())
```

The navigation algorithms and the list of the other KINAVIS crates are in
[`kinavis`](https://crates.io/crates/kinavis).

## Feature flags

- `std` *(default)* — standard library maths in the kernel.
- `libm` — for `no_std` targets: `--no-default-features --features libm`.
- `serde` — serialisation of the messages.

## License

Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.