Highlights
PipeDecoder: reject CRC-lucky phantoms
CRC-24 alone isn't enough — ~1-in-16M random 1090 MHz FRUIT survives
CRC with a plausible ICAO but garbage payload. This release adds four
plausibility cross-checks layered on top of CRC, each reusing a
per-ICAO anchor updated only from CRC-valid frames that pass their
own check:
- DF17/18 BDS 0,5 (airborne position) — altitude vs ADS-B anchor.
- DF17/18 TC=19 (airborne velocity) — groundspeed/track vs anchor,
plus a|VR| > 10 000 fpmguard that fires even without an anchor. - DF20/21 BDS 5,0 (track & turn) — groundspeed/true-track vs the
ADS-B velocity anchor. - DF20/21 BDS 6,0 (heading & speed) — magnetic_heading vs ADS-B
track (wider tolerance to absorb magnetic variation + wind-correction
angle).
Rejected frames keep their header fields so callers can see what
happened, but the velocity / position fields are scrubbed and the
anchor isn't updated. A new velocity_mismatch stats counter joins
the existing altitude_mismatch.
PipeDecoder: preserve paired frames
Two structural fixes to stop legitimate positions from being dropped:
_pending_even/_pending_oddare now per-parity deques so two
same-parity frames arriving before an opposite don't silently
discard the earlier one — orphan halves pair against the arriving
frame and each gets its own resolved position.- Bootstrap entries hold a list of result dicts so both halves
of a resolved CPR pair get theirlatitude/longituderetroactively
filled when the bootstrap cluster locks.
Docs
- New Interesting messages
reference page — a growing catalogue of real-world messages
exhibiting edge cases (CRC-lucky phantoms, FRUIT, BDS ambiguity,
malformed payloads) to use when debugging or writing new checks.
Dev
- Repo now ships a pre-commit config running
ruff-format+ruff-check.
After cloning:uv sync && uv run pre-commit install.
Full Changelog: v3.2.0...v3.3.0