aethersdr / aethersdr/AetherSDR

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

Open
#3,571 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

GUI maintainer-review New Feature priority: low protocol
Dominant language
C++
Stars
221
Forks
117
Avg merge
2d 7h
Merged PRs (30d)
299

Description

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Ax25HfPacketDecodeDialog.cpp, especially frameDecoded, the tab-building code, and the AprsMessenger TX contract; inspect Ax25.h/Ax25.cpp for via addresses and H-bit handling. Reuse or generalize AprsStationList's duplicate suppression. Done means an explicitly enabled, visibly active WIDE1-1 fill-in path with MYCALL, 30-second deduplication, hop and H-bit checks, persistence, counters, and a repeat log.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
desktop, networking
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.