Skip to content

Add APRS Digipeater tab to AetherModem TNC (MVP: WIDE1-1 fill-in) #3571

@jensenpat

Description

@jensenpat

Summary

Add an APRS Digipeater tab to the AetherModem TNC (Ax25HfPacketDecodeDialog). The codebase is already wired for it — several files carry // for the future APRS/AX.25 digipeater comments and the AX.25 model already tracks the has-been-repeated (H) bit and the via path. This issue scopes a minimum-viable WIDE1-1 fill-in digipeater first, then a full wide-area digi.

Follow-up to #3530 (AetherModem APRS client).

Background — what a digipeater does (researched + source-verified)

A digipeater receives an AX.25 UI frame, inspects its via path, and if addressed to an alias it handles, retransmits a modified copy. The modern New-N paradigm (Bob Bruninga, aprs.org/newN). Note the APRS Protocol Reference 1.01 deliberately does not specify digipeater behavior, which is why historical implementations diverged — so we follow the New-N docs + reference implementations, not the base spec.

Core algorithm (New-N), for a WIDEn-N via field

N is the SSID in the high bits of the last AX.25 address octet.

  • N ≥ 2 → decrement N; insert MYCALL ahead of the decremented entry (subject to the 8-address AX.25 limit); set the H bit only on the inserted MYCALL, leaving WIDEn-(N-1) unmarked so downstream digis keep relaying.
  • N = 1replace the field with MYCALL and set its H bit (avoids a useless WIDEn-0).
  • N = 0 → hop count exhausted → do not digipeat.

Two alias flavors:

  • TRACE (WIDEn-N): substitutes/inserts the transmitter callsign + sets H → full path traceability.
  • non-trace / FLOOD (state/section SSn-N): decrements but does not insert a callsign.

MVP vs full-featured

MVP — fill-in / home digi Full wide-area digi
Responds to WIDE1-1 + own MYCALL only + WIDEn-N (trace) + SSn-N state/section (flood)
Behavior one hop out of a dead zone, MYCALL implied, digipeat once full decrement/insert + N-trapping
Dire Wolf analog DIGIPEAT 0 0 ^WIDE1-1$ ^WIDE1-1$ DIGIPEAT + ^WIDE[3-7]-[1-7]$ trap

MVP target = WIDE1-1 fill-in. Genuinely useful, low network risk, exercises the full RX→modify→TX path.

Mandatory correctness features (required even for MVP)

  1. Duplicate suppression — compare source-SSID + destination + info payload, ignoring the via path, over a ~30 s window (Dire Wolf DEDUPE 30, KPC-3+ UIDUPE 30). Not optional — RELAY is obsolete precisely because it lacked dupe-elimination. (Caveat: 30 s is the convention but imperfect; delayed packets can exceed it.)
  2. Hop exhaustion — never retransmit a field at N=0.
  3. H-bit correctness — set H on the inserted/substituted MYCALL; never re-process a via field already marked H.

Network-friendliness features (full version / config knobs)

  • N-trapping — high-N paths (e.g. WIDE3-7) repeated once (replaced by MYCALL, no decrement) to kill abusive long paths. Trap boundary is a tunable, commonly N ≥ 3.
  • Viscous delay (aprx, 0–9 s; fill-in technique) — hold the packet; if the dupe detector sees another copy before the delay expires, discard (a stronger digi already covered it). Recommend 0 for normal digi, 5 for fill-in.
  • No stagger (UIDWAIT off) — let multiple digis transmit simultaneously ("fratricide"); this is the primary channel-load minimizer, not a bug.
  • Direct-only mode (aprx directonly) — fill-in repeats only directly-heard (not already-digipeated) packets.
  • Tiered self-beacon — direct posit every 10 min, 1-hop every 30 min, 2-hop every 60 min. Disable any non-APRS HID/ID packet.

Mapping onto AetherModem (architecture is ready)

  • AX.25 model already has what we need: ax25::Address.hasBeenRepeated (H bit) + ssid, and ax25::Frame.viasrc/core/tnc/Ax25.h:22 / :62. Encode/decode preserve H bits (Ax25.cpp:53, :124).
  • RX hook: AetherAx25LibmodemShim::frameDecoded → distributed in Ax25HfPacketDecodeDialog.cpp:889. A new AprsDigipeater slot taps the same signal alongside PMS/terminal/MQTT.
  • TX hook: emit transmitFrame(QByteArray rawNoFcs) → shared KISS TX queue (m_kissTxQueue, depth-capped) → buildTransmitAudioFromFrame(). Same contract AprsMessenger uses (AprsMessenger.cpp:168).
  • Dedupe helper exists: AprsStationList already does ~30 s source+payload suppression — reuse/generalize it.
  • Tab pattern: add a 5th button to tabGroup + a buildDigipeaterPage() into m_tabStack (Ax25HfPacketDecodeDialog.cpp:670–755).
  • Settings: new DigipeaterSettings under key "AetherModemDigipeater", mirroring AprsSettings (JSON blob).

Proposed scope

Phase 1 — MVP (this issue)

  • New class AprsDigipeater : public QObject — RX → decode → match alias → modify path → re-TX.
  • WIDE1-1 + MYCALL fill-in only; digipeat-once semantics.
  • 30 s dedupe (source+dest+payload, ignore path); hop-exhaustion + H-bit correctness.
  • New Digipeater tab: enable toggle, MYCALL field, live heard/repeated/dropped counters, recent-repeat log.
  • DigipeaterSettings persistence ("AetherModemDigipeater").
  • Safety: no RF TX without explicit enable and a visible "Digi TX active" indicator. Default off.

Phase 2 — wide-area + polish

  • WIDEn-N trace + SSn-N flood handling.
  • N-trapping (configurable boundary), viscous delay, direct-only mode.
  • Tiered self-beacon (10/30/60 min) + ensure no non-APRS HID.
  • Per-station digi statistics / map integration.

Open questions

  • Preemptive digipeating (Dire Wolf PREEMPT OFF/DROP/MARK/TRACE) — defer to Phase 2+? When is it network-friendly vs abusive?
  • Combined Tx-iGate + digi gating rules (third-party framing, avoid double-injecting RF back to APRS-IS) — out of scope here, but note the interaction.
  • HF vs VHF: digipeating convention is a VHF (1200 baud) practice; should the tab gate on the modem profile (Ax25DemodConfig) to avoid encouraging HF 300-baud digipeating?

References


Design researched via fan-out web search with 3-vote adversarial verification (24/25 claims confirmed). The one refuted claim: WIDEn-N dedup is per-digi, not a network-wide single copy — fratricide intentionally produces multiple simultaneous transmissions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GUIUser interfaceNew FeatureNew feature requestmaintainer-reviewRequires maintainer review before any action is takenprotocolSmartSDR protocolsafetyEquipment protection concern

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions