digipeater

package
v0.13.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 9, 2026 License: GPL-2.0 Imports: 14 Imported by: 0

Documentation

Overview

Package digipeater implements a WIDEn-N / TRACEn-N APRS digipeater with preemptive digipeating and cross-channel routing driven by per-channel rules stored in the configstore.

The engine is a pure function of (rules, mycall, rx frame). It does not own the RX frame source or the TX sink; cmd/graywolf wires it in:

digi := digipeater.New(digipeater.Config{...})
// on RX:
digi.Handle(ctx, rxChannel, frame, ingress.Modem())

Handle walks the path looking for the first unconsumed (H-bit clear) entry that matches a rule and, if it finds one, submits a cloned frame with the appropriate path mutation to the txgovernor at PriorityDigipeated. The RX frame is never mutated.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// MyCall is the per-digipeater callsign override. Empty string means
	// "inherit from StationCallsign". A non-empty value wins (e.g. a
	// mountaintop digi running under MTNTOP-1 distinct from the operator's
	// personal call). The resolved callsign is used for preemptive digi
	// (if a path slot equals it, the frame is repeated regardless of
	// WIDEn-N rules) and for TRACEn-N insertion.
	MyCall string

	// StationCallsign is the resolved station callsign fallback used when
	// MyCall is empty. The wiring layer resolves this once per
	// start/reload from StationConfig and hands it in; the digipeater
	// package does not read configstore directly.
	StationCallsign string

	// DedupeWindow is the time window within which an identical frame
	// will be dropped. Default 30s if zero.
	DedupeWindow time.Duration

	// Rules lists all digipeater rules (across all channels). The
	// engine filters by FromChannel on each call. The slice may be
	// replaced via SetRules for live reconfig.
	Rules []Rule

	// Submit is the TX sink. Required. Typically
	// func(ctx, ch, f, src) error { return gov.Submit(...) }.
	Submit func(ctx context.Context, channel uint32, frame *ax25.Frame, src txgovernor.SubmitSource) error

	// Logger is optional.
	Logger *slog.Logger

	// OnPacket is an optional hook invoked after a successful digipeat,
	// carrying a short human-readable note. Used by packetlog to
	// annotate entries.
	OnPacket func(note string, fromChan, toChan uint32, f *ax25.Frame)

	// OnDedup is an optional hook invoked when a frame is dropped as a
	// duplicate within the dedup window.
	OnDedup func()

	// ChannelModes resolves Channel.Mode at RX time. Rules whose RX
	// channel is "packet" cause Handle to short-circuit; rules whose
	// ToChannel is "packet" are skipped per-rule. Nil = treat every
	// channel as ChannelModeAPRS (preserves the legacy any-channel-
	// does-anything behavior). Lookup errors are silently ignored
	// (fail-open).
	ChannelModes configstore.ChannelModeLookup
}

Config configures a Digipeater.

type Digipeater

type Digipeater struct {
	// contains filtered or unexported fields
}

Digipeater is the engine.

func New

func New(cfg Config) (*Digipeater, error)

New builds a Digipeater. Resolves cfg.MyCall (override) against cfg.StationCallsign (fallback) via callsign.Resolve. An empty/N0CALL result is not fatal at construction — the engine starts disabled and Handle short-circuits when mycall is empty, so a freshly-wired digipeater with no station callsign yet simply no-ops until a valid callsign arrives via SetMyCall + SetEnabled on reload.

func (*Digipeater) Handle

func (d *Digipeater) Handle(ctx context.Context, rxChannel uint32, frame *ax25.Frame, src ingress.Source) bool

Handle evaluates frame arriving on rxChannel against the rules. If a rule matches and Action is "repeat", a cloned+mutated frame is submitted to the TX sink. The RX frame is never mutated. Returns true if the frame was digipeated.

src identifies where the frame entered graywolf. Phase 1 threads it through without affecting behavior; later phases may use it to tighten dedup or suppress self-feedback for KISS-TNC-sourced frames.

func (*Digipeater) SetDedupeWindow

func (d *Digipeater) SetDedupeWindow(w time.Duration)

SetDedupeWindow updates the dedupe window. A non-positive duration is ignored to preserve a sane default. Existing entries stay in the cache and are re-evaluated against the new window on their next touch, matching the previous in-place update behavior.

func (*Digipeater) SetEnabled

func (d *Digipeater) SetEnabled(on bool)

SetEnabled toggles the engine on or off for live reconfig. When disabled, Handle short-circuits and returns false without touching the dedup map or rules.

func (*Digipeater) SetMyCall

func (d *Digipeater) SetMyCall(a ax25.Address)

SetMyCall updates the local callsign for preemptive digi.

func (*Digipeater) SetRules

func (d *Digipeater) SetRules(rules []Rule)

SetRules replaces the rule set under the lock. Safe for live reconfig.

func (*Digipeater) Stats

func (d *Digipeater) Stats() Stats

Stats returns a snapshot.

type Rule

type Rule struct {
	FromChannel uint32
	ToChannel   uint32
	Alias       string // "WIDE", "TRACE", or an exact callsign for AliasTypeExact
	AliasType   string // "widen"|"trace"|"exact"
	MaxHops     uint32
	Action      string // "repeat"|"drop"
	Priority    uint32
}

Rule is a digipeater-local form of configstore.DigipeaterRule, decoupled from GORM.

func RulesFromStore

func RulesFromStore(rows []configstore.DigipeaterRule) []Rule

RulesFromStore converts configstore rows to local Rule values.

type Stats

type Stats struct {
	Packets uint64 // successfully digipeated
	Deduped uint64 // dropped as duplicate
}

Stats exposes counters.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL