Skip to content

Iridium wave 2: native ring-alert/broadcast decode core#29

Merged
kevinelliott merged 1 commit into
masterfrom
iridium
Jun 10, 2026
Merged

Iridium wave 2: native ring-alert/broadcast decode core#29
kevinelliott merged 1 commit into
masterfrom
iridium

Conversation

@kevinelliott

@kevinelliott kevinelliott commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Wave 2 begins. New xng-mode-iridium crate decoding Iridium ring-alert (IRA) and broadcast frames on the fixed simplex channels — satellite id, beam, live ECEF→lat/lon/alt positions, and paging TMSIs — wired end-to-end: runtime, console (IRIDIUM ring-alert sat=75 beam=21 pos=48.14,169.44 pages=2), asf-2.0 protocol (new IridiumBody), and the scanner plan.

Sources (per the repo's sourcing policy)

  • iridium-toolkit (BSD-2, ported with attribution): access codes, the symbol-pair deinterleavers, BCH(31,21)+parity blocks (polys 1207/1897), FILL removal, classification, IRA field layout.
  • gr-iridium / iridium-sniffer (GPL-3, facts only): PHY parameters — 25 ksym/s DQPSK, tone preamble + 12-symbol UW, dqpsk_map=[0,2,3,1], burst limits. iridium-sniffer's ARCHITECTURE.md (thanks for the pointer — it's the best single pipeline reference) also documents the IDA/SBD→ACARS chain for the wideband follow-up.
  • The demodulator itself is original: power-boxcar burst gate, tone-DFT coarse CFO, and the coherent UW fit (joint timing/phase/CFO least squares) that this session developed for VDL2/HFDL, now proving itself on a third modulation.

Validation — oracle-grade

A generated ring-alert frame decodes bit-identically in iridium-toolkit's bitsparser.py (run offline as the reference oracle) and in this crate: IRA: sat:075 beam:21 xyz=(-1411,+0263,+1602) pos=(+48.14/+169.44) alt=2248 RAI:33 ?01 bc_sb:22 P02: PAGE(tmsi:cafed00d…) {OK} — every field agrees. The vector is vendored in tests, alongside an RF loopback through the full chain (CFO + noise). Interop note: gr-iridium RAW: lines carry each symbol's bits swapped; RWA: is the normalized form.

Scope and next

v1 targets the fixed simplex channels (ring alert 1626.270833 MHz — bursts every few seconds worldwide, decodable with one DDC channel). The wave-2 follow-ups documented in docs/notes/IRIDIUM.md: wideband burst hunting across the full band (gr-iridium-style channelizer), IDA/SBD→ACARS, and an off-air L-band capture validation.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added native Iridium satellite message decoding support, including ring alerts and broadcasts
    • Enabled Iridium mode in scan command with pre-configured frequency plan
    • Messages now display satellite/beam information and decoded position coordinates (ring alerts)
    • Signal strength metrics integrated into Iridium message output
  • Documentation

    • Added implementation notes and source attribution for Iridium decoding capabilities

New xng-mode-iridium crate, wired into the runtime, console, asf-2.0
protocol (IridiumBody, field 16), and the scanner plan (simplex
ring-alert + messaging channels).

Layer 2 ported from BSD-2 iridium-toolkit (attributed): access codes,
symbol-pair deinterleavers (2-way/3-way), BCH(31,21) blocks with even
parity and 1-2 bit repair (polys 1207/1897), FILL removal, frame
classification, and the full IRA ring-alert field layout (satellite,
beam, ECEF position -> lat/lon/alt, paging TMSIs). PHY facts from
gr-iridium/iridium-sniffer (GPL, facts only; iridium-sniffer's
ARCHITECTURE.md documents the whole pipeline incl. the IDA/SBD->ACARS
chain for the wideband follow-up).

The demodulator is original: 250 kHz channel (10 sps), power-boxcar
burst gate, tone-DFT coarse CFO, the coherent UW fit (joint
timing/phase/CFO over the 12 known UW symbols - the same technique
that fixed VDL2/HFDL acquisition), DQPSK with dqpsk_map=[0,2,3,1] and
a decision-directed phase trim. One war story: the DD residual must
round against the signed constellation index or a symbol at -pi slews
the PLL by -2pi.

Validation: a generated ring-alert frame decodes BIT-IDENTICALLY in
iridium-toolkit's bitsparser.py (run as an offline oracle) and in this
crate; the vector is vendored in tests. RF loopback covers the full
chain with CFO and noise. Interop note recorded: gr-iridium RAW lines
are symbol-bit-swapped (RWA: is the normalized form).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR adds native Iridium satellite signal decoding to xng, comprising a new xng-mode-iridium crate with DSP demodulation, Layer 2 frame codec (BCH/ECC/interleaving), ring-alert payload parsing, runtime integration, e2e RF loopback validation, and comprehensive implementation documentation and provenance.

Changes

Iridium Signal Decoding and Integration

Layer / File(s) Summary
Frame codec, protocols, and payload parsing
crates/xng-mode-iridium/src/frame.rs, crates/xng-mode-iridium/src/ira.rs
BCH(31,21) error correction with up-to-2-bit repair, GF(2) polynomial arithmetic, symbol-pair deinterleaving for RA/BC frames, frame classification (messaging/broadcast/ring-alert/unknown), IRA ring-alert payload parsing with position field extraction and geographic coordinate computation, transmit-side BCH encoding and inverse interleaving for loopback tests.
DSP burst demodulation and signal detection
crates/xng-mode-iridium/src/demod.rs
Asymmetric noise-floor estimation, power-triggered burst gating, coarse CFO estimation from tone preamble via brute-force DFT, UW (12-symbol) timing/phase coherent fitting over candidate offsets, hard-decision demodulation with PLL-style phase trimming, differential DQPSK decoding, and access-code validation.
Public API and decode orchestration
crates/xng-mode-iridium/src/lib.rs
IridiumChannelDecoder with optional Ddc downconversion stage, streaming demodulation, frame classification and payload parsing (RA: geometric field extraction and page iteration; BC: hex data chunking), message normalization with UTC timestamp, signal RSSI, and decode status.
Modulation and e2e validation
crates/xng-mode-iridium/src/modulate.rs, crates/xng-mode-iridium/tests/e2e.rs, crates/xng-mode-iridium/examples/genframe.rs
RRC FIR tap generation with unit-energy normalization, differential DQPSK symbol encoding, burst modulation with frequency offset for loopback; e2e tests validate bitstream encode/decode roundtrips, RF loopback with PRNG noise through full pipeline, and oracle-validated reference vectors with geographic tolerance checks.
Runtime mode integration and wiring
src/runtime.rs, src/commands/scan.rs, src/main.rs
ModeChannel::Iridium variant and per-channel decoder instantiation; frequency plan with center rate and known channel offsets; passband/sample-rate/signal-level parameter binding; decoding pipeline converts demodulated frames to bus messages with crc_ok parity flags.
Message type and protocol buffer support
crates/xng-types/src/message.rs, crates/xng-proto/src/lib.rs, proto/asf2.proto
MessageBody::Iridium { kind: String, details: serde_json::Value } variant for Serde union; protobuf IridiumBody message with kind and details_json fields; From<&Message> impl to convert to asf2::DecodedMessage::Iridium.
Console output formatting
src/outputs/console.rs
Display one-liner for Iridium frames with optional satellite/beam annotation, geographic position (when lat/lon present), and page array count.
Workspace, packaging, and documentation
Cargo.toml, crates/xng-mode-iridium/Cargo.toml, crates/xng-mode-iridium/PROVENANCE.md, docs/notes/IRIDIUM.md, docs/REFERENCES.md
Workspace dependency wiring for new crate; manifest with chrono/num-complex/rustfft/serde/xng-dsp/xng-types; provenance documentation attributing ported frame codec/interleaving/BCH to iridium-toolkit and PHY facts to gr-iridium/iridium-sniffer, original demodulation; detailed implementation notes covering frequency bands, DQPSK burst structure, Layer 2 classification, BCH/interleaving conventions, IRA field layout with geo formulas, and validation strategy (oracle + RF loopback + oracle vectors).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A satellite wakes from the RF sky,
DQPSK bursts demod, bits untie,
BCH repairs what noise did break,
Geo-fields compute for sky-alert's sake,
One more voice heard in the ether's dance. 📡✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: adding a native Iridium ring-alert and broadcast decode core as a new crate and runtime integration.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch iridium

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e18f88b0a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +196 to +198
if ndivide(RINGALERT_BCH_POLY, &b1[..31]) == 0
&& ndivide(RINGALERT_BCH_POLY, &b2[..31]) == 0
&& ndivide(RINGALERT_BCH_POLY, &b3[..31]) == 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow BCH repair before classifying ring alerts

For ring-alert bursts with any correctable bit flip in the first three BCH blocks, this exact zero-syndrome check returns Unknown, so decode_bits never reaches ecc_blocks where bch_repair is supposed to fix up to two bit errors. In real RF captures those BCH corrections are expected, so otherwise recoverable IRA frames are dropped instead of decoded; classify should tolerate/repair the candidate blocks on clones before deciding they are not RA.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant