{"id":38101216,"url":"https://github.com/airframesio/xng","last_synced_at":"2026-06-11T12:00:16.566Z","repository":{"id":179773494,"uuid":"630328511","full_name":"airframesio/xng","owner":"airframesio","description":"Next-generation multi-mode decoder client (written w/ Rust)","archived":false,"fork":false,"pushed_at":"2026-06-10T09:04:36.000Z","size":2319,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-06-10T09:10:15.192Z","etag":null,"topics":["acars","aero","ais","decoder","feeding","hfdl","inmarsat","iridium","satcom","vdl"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/airframesio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-04-20T06:37:43.000Z","updated_at":"2026-06-10T09:03:01.000Z","dependencies_parsed_at":"2023-12-20T10:40:21.061Z","dependency_job_id":"8ccdd3c2-2620-4969-bd3d-d84bd3a89038","html_url":"https://github.com/airframesio/xng","commit_stats":null,"previous_names":["airframesio/xng"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/airframesio/xng","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airframesio%2Fxng","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airframesio%2Fxng/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airframesio%2Fxng/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airframesio%2Fxng/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/airframesio","download_url":"https://codeload.github.com/airframesio/xng/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/airframesio%2Fxng/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34197394,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["acars","aero","ais","decoder","feeding","hfdl","inmarsat","iridium","satcom","vdl"],"created_at":"2026-01-16T21:13:52.943Z","updated_at":"2026-06-11T12:00:16.506Z","avatar_url":"https://github.com/airframesio.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xng\n\n[![Rust](https://github.com/airframesio/xng/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/airframesio/xng/actions/workflows/rust.yml)\n[![Release](https://img.shields.io/github/v/release/airframesio/xng)](https://github.com/airframesio/xng/releases/latest)\n\n**One native SDR decoder for the whole aviation + maritime radio stack.**\n\nxng decodes **ACARS, VDL Mode 2, HFDL, Inmarsat Aero, Inmarsat STD-C/EGC,\nIridium, AIS, and Mode S/ADS-B** in a single Rust binary — replacing\nacarsdec, vdlm2dec, dumpvdl2, dumphfdl, JAERO, Scytale-C, gr-iridium, and\niridium-toolkit with consistent, tested decode cores that share one\ncapture, one message model, one application layer, and one set of outputs\n(including first-class [airframes.io](https://airframes.io) feeding).\nAll nine modes are implemented, validated, and merged — including the\ncomplete Iridium stack (ring alerts through ACARS-over-SBD with a\nwideband burst-hunting front end) — and shipped as tagged releases with\nbinaries for Linux (x86_64/arm64, tarball + .deb), macOS Apple Silicon,\nand multi-arch Docker images.\n\n```bash\n# Two ACARS channels from one RTL-SDR, fed to Airframes:\nxng listen --sdr driver=rtlsdr -r 2400000 -c 131.500M \\\n    --channels 131.550,131.725 \\\n    --feed-airframes --station-id XX-KSEA-ACARS1\n```\n\n```text\n12:01:13.402 [acars] 131.550 MHz ACARS N401UA UA1989 lbl=H1 ok | #M1B...\n12:01:14.118 [acars] 131.725 MHz ACARS N831UA UA0233 lbl=B6 ok [ADS-C 47.5512 -122.3052 34000 ft]\n```\n\n## Why xng\n\n| | Existing tools | xng |\n|---|---|---|\n| **Decoders** | One binary per mode (acarsdec, dumpvdl2, dumphfdl, JAERO, …), each with its own CLI, output format, and quirks | One binary, one CLI, every mode |\n| **SDR usage** | One SDR per decoder | Many channels of one mode from a single capture; one dongle can watch 12 ACARS channels |\n| **Validation** | Varies | Every decode core is validated against **real off-air recordings** or the reference implementation's own test vectors, with the captures vendored into CI so conventions can never silently regress |\n| **Application layer** | libacars bolted on, or nothing | Built-in ARINC 622 (ADS-C positions, **CPDLC rendered as readable text** — `REQUEST CLIMB TO FL360`), media advisory, H1 sublabels — shared by every ACARS carrier (VHF, VDL2, HFDL, Aero, Iridium SBD) |\n| **Outputs** | Per-tool formats | Pretty console, JSON/JSONL, acarsdec-compatible UDP, Airframes feeding, Prometheus metrics, and the multiplexed gRPC/QUIC **asf-2.0** protocol — identical across all modes |\n| **Tooling** | None | Interactive TUI (spectrum, waterfall, message browser), auto-scanner that proposes ready-to-run configs, site survey/soak reports with gain tuning, IQ-file inspection, built-in self-test |\n| **License** | Mostly GPL | MIT/Apache-2.0 dual license; cores are clean-room from public specs or ported from MIT/BSD projects with attribution |\n\nThe provenance discipline is part of the engineering: every core has a\n`PROVENANCE.md` recording exactly what came from where, and the off-air\nvalidation campaigns are documented finding-by-finding (several on-air\nconventions — invisible to loopback testing — were caught only this way).\n\n## Supported modes\n\n| Mode | `--mode` | Band | What you get | Validation |\n|---|---|---|---|---|\n| VHF ACARS (ARINC 618) | `acars` (default) | 118–137 MHz | ACARS + applications | Live off-air (RTL-SDR), CRC-verified, **fed to production Airframes end-to-end** |\n| VDL Mode 2 (ICAO Annex 10) | `vdl2` | 136.6–137 MHz | ACARS-over-AVLC, AVLC link events, XID handoff parameters (incl. ground-station lists), **ATN-B1: X.25/CLNP/COTP transport (+facilities, ES-IS, IDRP), protected-mode CPDLC with the full element tables and phraseology, CM logon and ground PDUs**, ground-station naming via `--gs-file` | Off-air capture vs dumpvdl2 ground truth |\n| HFDL (ARINC 635) | `hfdl` | 2.8–22 MHz | Squitters, logons, positions, ACARS, **over-the-air system table** | Off-air 21 931 kHz capture, field-exact vs dumphfdl |\n| Inmarsat Aero L (JAERO port) | `aero` | 1545–1547 MHz | P-channels 600/1200 bps + 10.5 kbps, ACARS/ADS-C/CPDLC; **C-channel voice circuits (8.4 kbps OQPSK): AMBE voice-frame extraction + call-progress/telephony signal units** | Real Inmarsat recordings: 600 bps + 10.5k both decode off-air; C-channel RF loopback |\n| Inmarsat Aero C bursts | `aero-c` | C-band | R/T-channel signal units | RF loopback |\n| Inmarsat STD-C / EGC | `std-c` | 1537–1542 MHz | NCS frames, EGC SafetyNET/FleetNET text, logical-channel messages | Off-air EGC capture, field-exact vs reference |\n| Iridium | `iridium` | 1616–1626.5 MHz | Ring alerts (live satellite positions), broadcasts, **ACARS over SBD**, **pager messages (IMS) with multi-part reassembly**, **voice-channel classification (VDA/VO6/VOD/VOZ/VOC) with AMBE extraction**, IP-data tagging, wideband burst hunting across the band | Every layer validated: bit-perfect demod of gr-iridium's reference burst (direct *and* via the wideband hunter) + field-identical decode vs the iridium-toolkit oracle |\n| AIS (ITU-R M.1371) | `ais` | 161.975/162.025 MHz | NMEA AIVDM | Canonical published test vector |\n| Mode S / ADS-B | `adsb` | 1090 MHz | **CPR positions** (airborne, surface via `--receiver-pos`), velocity, squawk, altitude replies, **Comm-B/BDS registers** (callsign, selected altitude, track/turn, heading/speed — pyModeS-validated), per-aircraft tracking, **SBS + Beast outputs** | Published vectors (1090 Riddle) + field-exact vs pyModeS |\n\nAll multi-channel modes decode any number of channels from one capture.\nWrapped external decoders (`xng extern`) remain available as a\nsecond-class path — they get every xng output and the application layer.\n\n## Supported hardware\n\n| Device | `--sdr` | Backend | Notes |\n|---|---|---|---|\n| RTL-SDR | `driver=rtlsdr` | SoapySDR | The budget workhorse for VHF (ACARS, VDL2, AIS) and — with an L-band antenna + LNA — Aero, STD-C, Iridium, ADS-B |\n| Airspy R2 / Mini | `driver=airspy` | **native** (libairspy, `--features airspy`) | 24 MHz–1.75 GHz, 12-bit; `serial=…` (hex) selects a unit, `bias=1` powers an LNA. Validated live (Mini: off-air ACARS at 6 MS/s) |\n| Airspy HF+ / Discovery | `driver=airspyhf` | **native** (libairspyhf, `--features airspyhf`) | The classic HFDL receiver; 768 kS/s divides cleanly into every xng HF/VHF channel rate |\n| SDRplay (RSP series) | `driver=sdrplay` | SoapySDR | The Soapy module wraps the proprietary API |\n| Anything else | per its Soapy module | SoapySDR | HackRF, LimeSDR, USRP, BladeRF, … |\n\n`--gain` is in dB everywhere, and omitting it selects hardware AGC. The\nnative Airspy backends map dB sensibly onto the actual hardware controls\n(R2/Mini: 22-step linearity gain; HF+: attenuator/preamp, bigger = more\ngain). With a native backend compiled in, its driver name routes to it\nautomatically; add `backend=soapy` to force SoapySDR instead. IQ-file\ninput (`xng decode`) needs no hardware or SDR libraries at all.\n\n## Installing\n\nGrab a [release](https://github.com/airframesio/xng/releases/latest) —\ntarballs for Linux x86_64/arm64 and macOS Apple Silicon, `.deb` packages\nfor Debian/Ubuntu (which declare the runtime libraries), and `SHA256SUMS`.\nThe binaries need `libsoapysdr` at runtime (plus `libairspy`/`libairspyhf`\nfor native Airspy):\n\n```bash\nsudo apt install ./xng_0.9.0_arm64.deb     # pulls runtime deps\n# or\ntar xzf xng-v0.9.0-x86_64-unknown-linux-gnu.tar.gz \u0026\u0026 sudo cp xng-*/xng /usr/local/bin/\n```\n\nMulti-arch Docker images (amd64/arm64/armv7) are published per tag:\n\n```bash\ndocker run --rm ghcr.io/airframesio/xng:latest --version\n```\n\n## Building\n\nRequirements: a stable [Rust](https://rustup.rs) toolchain, a **protobuf\ncompiler**, and (for live SDR use) **SoapySDR** with your vendor module.\n\n```bash\n# Debian / Ubuntu\nsudo apt install protobuf-compiler libsoapysdr-dev soapysdr-module-all\n\n# macOS\nbrew install protobuf soapysdr\n\n# Build (binary at ./target/release/xng)\ncargo build --release\n\n# Run the test suite (includes the vendored off-air captures)\ncargo test --workspace\n```\n\nAirspy owners can skip the SoapyAirspy shim: native backends for the\nR2/Mini (libairspy) and the HF+ / Discovery (libairspyhf) are built in\nwith feature flags:\n\n```bash\nsudo apt install libairspy-dev libairspyhf-dev   # or: brew install airspy airspyhf\ncargo build --release --features airspy,airspyhf\n```\n\nNo hardware? Everything works from IQ recordings (`xng decode`,\n`xng tui --file`), and `cargo build --no-default-features` skips SoapySDR\nentirely. A Dockerfile and a Debian packaging script are included.\n\n```bash\ndocker build -t xng . \u0026\u0026 docker run --rm xng --version\n```\n\n## Quick start\n\n```bash\nxng devices                       # what SDRs are attached?\nxng selftest                      # end-to-end pipeline sanity check\n\n# No idea what's receivable at your site? Let the scanner find out:\nxng scan --sdr driver=rtlsdr --gain 28 --modes acars,vdl2,ais --dwell 120 --out scan.json\n# → prints verdicts per channel and ready-to-paste `xng listen` command lines.\n#   For HFDL it even learns new frequencies from the over-the-air system table.\n\n# Then qualify the site properly: a 15-minute soak across the whole ACARS\n# plan, with an empirical gain sweep first, ending in a per-channel report\n# (frames, CRC rate, levels) plus reception advice:\nxng survey --sdr driver=rtlsdr --mode acars --tune-gain --out survey.json\n```\n\n## Examples\n\n### Live decoding\n\n```bash\n# VDL Mode 2: four channels including the worldwide CSC\nxng listen --sdr driver=rtlsdr --mode vdl2 -r 2400000 -c 136.800M \\\n    --channels 136.650,136.800,136.925,136.975\n\n# HFDL on an HF-capable SDR (channels per the public system table)\nxng listen --sdr driver=sdrplay --mode hfdl -r 768000 -c 10060.000k \\\n    --channels 10027k,10060k,10063k,10081k,10084k,10087k\n\n# Same, on an Airspy HF+ Discovery via the native backend (no Soapy\n# module needed; build with --features airspyhf). Hardware AGC unless\n# --gain is given; add serial=... to pick among several units.\nxng listen --sdr driver=airspyhf --mode hfdl -r 768000 -c 10060.000k \\\n    --channels 10027k,10060k,10063k,10081k,10084k,10087k\n\n# Inmarsat Aero L-band (patch antenna + LNA)\nxng listen --sdr driver=rtlsdr --mode aero -r 2400000 -c 1546.000M \\\n    --channels 1545.880,1546.045\n\n# Inmarsat STD-C: maritime safety broadcasts in plain text\nxng listen --sdr driver=rtlsdr --mode std-c -r 2400000 -c 1537.500M \\\n    --channels 1537.700,1537.100\n\n# Iridium, wideband: point at the band, get everything — bursts are\n# hunted across the whole capture (ring alerts, broadcasts, and the\n# duplex-hopping SBD/ACARS traffic). Triggered by --channels equal to\n# the capture center:\nxng listen --sdr driver=rtlsdr --mode iridium -r 2000000 -c 1626.000M \\\n    --channels 1626.000\n\n# Iridium, fixed channels: just the simplex ring-alert/messaging\n# frequencies (cheaper; live satellite positions every few seconds)\nxng listen --sdr driver=rtlsdr --mode iridium -r 2000000 -c 1626.250M \\\n    --channels 1626.271,1626.104\n\n# AIS: both channels from one capture\nxng listen --sdr driver=rtlsdr --mode ais -r 2400000 -c 162.000M \\\n    --channels 161.975,162.025\n\n# Mode S / ADS-B (consumes the whole capture)\nxng listen --sdr driver=rtlsdr --mode adsb -r 2000000 -c 1090.000M --channels 1090\n```\n\n### Site survey / soak test\n\n`xng survey` qualifies a site for one mode: it monitors every channel in\nthe mode's plan (rotating capture windows when the plan exceeds the SDR\nbandwidth), prints interim tables as it goes, and ends with per-channel\nstatistics — frames, CRC pass rate, frames/min, levels — plus reception\nadvice and a ready-to-run `listen` command. Ctrl-C ends early but still\nreports.\n\n```bash\n# 15-minute ACARS soak over the full plan, gain picked empirically\nxng survey --sdr driver=rtlsdr --mode acars --tune-gain --out survey.json\n\n# Scan first, then soak only active channels — plus the mode's core\n# worldwide channels, which short scans routinely undersell\nxng survey --sdr driver=rtlsdr --gain 28 --mode vdl2 --scan --duration 1800\n\n# Specific channels, live message output, messages archived to JSONL\nxng survey --sdr driver=rtlsdr --gain 28 --mode acars --duration 3600 \\\n    --channels 130.025,131.550,131.725 --show-messages --jsonl soak.jsonl\n```\n\n### Recordings\n\n```bash\nxng iq-info capture.cf32 -r 2000000 -c 131500000      # duration, power, spectral peaks\nxng decode capture.cf32 -r 2400000 -c 131.500M --channels 131.550,131.425\nxng decode vdl2.cf32 --mode vdl2 -r 50000 -c 136.975M --channels 136.975 --json\n```\n\n### Interactive TUI\n\nLive message browser with a detail pane (press `v` to flip between a\nhuman-readable rendering and raw JSON), per-channel statistics, spectrum\nwith channel markers, and a waterfall — over a live SDR or a replayed\nfile:\n\n```bash\n# Zero config: channels, center, and sample rate come from the mode's\n# built-in plan — as many channels as fit the capture width and CPU.\n# Native-backend devices are asked which rates they support (an Airspy\n# Mini gets 3 MS/s automatically, not the plan's 2.4):\nxng tui --sdr driver=rtlsdr\nxng tui --sdr driver=airspy --mode vdl2\n\n# Explicit tuning still works (and is required for --file replay)\nxng tui --sdr driver=rtlsdr -r 2400000 -c 131.500M --channels 131.550,131.125\nxng tui --file capture.cf32 -r 2400000 -c 131.500M --channels 131.550\n```\n\n### Feeding and outputs\n\nEvery mode and every command shares the same output options:\n\n```bash\n--feed-airframes --station-id XX-KSEA-ACARS1   # Airframes (feed.airframes.io)\n--udp host:5550                                # acarsdec-compatible JSON\n--json                                         # raw JSON to stdout\n--jsonl messages.jsonl                         # JSONL file\n--metrics 0.0.0.0:9090                         # Prometheus (frames, CRC, levels)\n--sbs 0.0.0.0:30003                            # SBS/BaseStation TCP (Mode S)\n--beast 0.0.0.0:30005                          # Beast binary TCP (Mode S)\n--nmea-tcp 0.0.0.0:10110                       # NMEA AIVDM TCP (AIS)\n--mqtt mqtt://user:pass@broker:1883            # MQTT (JSON to \u003cprefix\u003e/\u003cmode\u003e)\n--mqtt-topic xng                               # MQTT topic prefix\n--asf2-grpc http://ingest:6001                 # asf-2.0 over gRPC\n--asf2-quic ingest:6011                        # asf-2.0 over QUIC (TLS verified)\n```\n\nACARS traffic can be filtered by label before it reaches any output:\n`--filter-labels H1,Q0` passes only those labels; `--exclude-labels SQ`\ndrops the listed ones. Non-ACARS messages always pass. VDL2 console\nlines can name ground stations via `--gs-file stations.json` (a JSON\nobject mapping hex AVLC addresses to names).\n\n**asf-2.0** ([docs/ASF2.md](docs/ASF2.md)) is xng's multiplexed feeding\nprotocol: one protobuf schema carrying every channel/SDR/mode over a\nsingle gRPC or QUIC connection, with reconnect and backpressure handling.\n`xng ingest` is the reference server:\n\n```bash\nxng ingest --grpc 0.0.0.0:6001 --quic 0.0.0.0:6011\n```\n\n### Wrapped external decoders\n\nExisting decoder deployments can join the xng bus (and get asf-2.0,\nAirframes feeding, and the application layer — ADS-C and CPDLC decode\neven from wrapped ACARS):\n\n```bash\ndumpvdl2 ... | xng extern --format dumpvdl2 --asf2-grpc http://ingest:6001\nxng extern --format dumphfdl --feed-airframes --station-id XX-... \\\n    -- dumphfdl --soapysdr driver=sdrplay ...\n```\n\n## The application layer\n\nACARS from any carrier flows through one application layer\n(`xng-acars`, ported from MIT libacars):\n\n- **ADS-C** (ARINC 622): full decode — positions, altitudes, contract\n  tags — conformance-tested against real off-air messages.\n- **CPDLC, both dialects**: FANS-1/A (over ACARS) and ATN-B1\n  (over VDL2/CLNP) rendered as readable text with decoded arguments —\n  `REQUEST CLIMB TO FL360`, `AT 14:32 EXPECT M0.84`, free text,\n  vertical rates, headings, multi-element messages, and **route\n  clearances** (`ASSIGNED ROUTE DEST KSFO, ROUTE J501 OAK`).\n- **MIAM** (ARINC 841): single-transfer CORE PDUs decompressed\n  (DEFLATE), file-transfer signalling decoded.\n- **OHMA**: Boeing aircraft-health JSON unwrapped (base64 + zlib) into\n  structured output.\n- **Multi-block reassembly**: long messages spanning ACARS blocks are\n  stitched back together (libacars-equivalent keying and timeouts), and\n  the application layer re-runs over the complete text.\n- Media advisory, H1 sublabel/MFI handling.\n\n## Workspace layout\n\n| Crate | Role |\n|---|---|\n| `xng-types` | Normalized message model shared by everything |\n| `xng-dsp` | Channelizer, DDC, FIR/NCO, Viterbi, Reed-Solomon, CRCs, scramblers |\n| `xng-sdr` | SoapySDR, native Airspy (libairspy/libairspyhf), and IQ-file sample sources |\n| `xng-acars` | ACARS application layer (ARINC 622, ADS-C, CPDLC, media advisory) |\n| `xng-proto` | asf-2.0 protobuf schema + conversions |\n| `xng-mode-*` | One decode core per mode, each with a spec-faithful modulator for loopback tests, vendored validation fixtures, and a `PROVENANCE.md` |\n\nEach core also ships `examples/` harnesses (`offair`, `dumpbits`, …) used\nfor the validation campaigns — point them at your own captures.\n\nArchitecture, research notes, and the roadmap live in\n[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) and\n[`docs/notes/`](docs/notes/). The pre-rewrite xng (a dumphfdl session\nwrapper) is preserved in [`legacy/`](legacy/).\n\n## License\n\nDual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE), at\nyour option. Decode cores are implemented clean-room from public standards\n(ICAO, ARINC, ITU-R, ETSI) or ported from permissively licensed projects\n(libacars, JAERO, iridium-toolkit — MIT/BSD) with attribution; GPL\nprojects are used as *fact* references only, and the full sourcing record\nis in [`docs/REFERENCES.md`](docs/REFERENCES.md) plus per-crate\n`PROVENANCE.md` files.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fairframesio%2Fxng","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fairframesio%2Fxng","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fairframesio%2Fxng/lists"}