aethersdr / aethersdr/AetherSDR
Add APRS Digipeater tab to AetherModem TNC (MVP: WIDE1-1 fill-in)
Nobody has claimed this yet.
- 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 = 1 → replace 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)
- Duplicate suppression — compare
source-SSID + destination + info payload, ignoring the via path, over a ~30 s window (Dire WolfDEDUPE 30, KPC-3+UIDUPE 30). Not optional —RELAYis obsolete precisely because it lacked dupe-elimination. (Caveat: 30 s is the convention but imperfect; delayed packets can exceed it.) - Hop exhaustion — never retransmit a field at
N=0. - 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, andax25::Frame.via—src/core/tnc/Ax25.h:22/:62. Encode/decode preserve H bits (Ax25.cpp:53,:124). - RX hook:
AetherAx25LibmodemShim::frameDecoded→ distributed inAx25HfPacketDecodeDialog.cpp:889. A newAprsDigipeaterslot taps the same signal alongside PMS/terminal/MQTT. - TX hook: emit
transmitFrame(QByteArray rawNoFcs)→ shared KISS TX queue (m_kissTxQueue, depth-capped) →buildTransmitAudioFromFrame(). Same contractAprsMessengeruses (AprsMessenger.cpp:168). - Dedupe helper exists:
AprsStationListalready does ~30 s source+payload suppression — reuse/generalize it. - Tab pattern: add a 5th button to
tabGroup+ abuildDigipeaterPage()intom_tabStack(Ax25HfPacketDecodeDialog.cpp:670–755). - Settings: new
DigipeaterSettingsunder key"AetherModemDigipeater", mirroringAprsSettings(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.
DigipeaterSettingspersistence ("AetherModemDigipeater").- Safety: no RF TX without explicit enable and a visible "Digi TX active" indicator. Default off.
Phase 2 — wide-area + polish
WIDEn-Ntrace +SSn-Nflood 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
- New-N paradigm / WIDE1-1 settings (Bruninga) — https://www.aprs.org/newN/WIDE1-1settings.txt
- Digi beacon rates + HID-off — https://www.aprs.org/digis/digi-rates.txt
- KPC-3+ WIDEn-N (UITRACE/UIFLOOD/UIDUPE/UIDWAIT) — https://www.aprs.org/kpc3/kpc3+WIDEn.txt
- Dire Wolf digipeater + DEDUPE — https://github.com/wb2osz/direwolf/blob/master/digipeater.c · User-Guide.pdf
- aprx digipeater + viscous-delay/relay-modes — https://github.com/PhirePhly/aprx/blob/master/digipeater.c · https://manpages.debian.org/testing/aprx/aprx.8.en.html
- On duplicate & delayed packets (aprs.fi) — https://blog.aprs.fi/2008/03/on-duplicate-and-delayed-packets.html
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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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