Documentation
¶
Overview ¶
Package agw implements a minimal AGWPE-compatible TCP server for APRS use. The wire format matches direwolf's server.c so existing clients (APRSIS32, UI-View, YAAC, Xastir) interoperate without modification.
Only the frame types needed for APRS are implemented:
Client → server: 'R' query AGW version 'G' query port information (list of radio ports) 'g' query port capabilities 'X' register callsign 'x' unregister callsign 'm' start monitoring (enable 'U'-type rx packets) 'k' transmit raw AX.25 frame 'M' transmit UNPROTO (UI) frame — server must build the AX.25 header Server → client: 'R' version response 'G' port info response 'g' port capability response 'X' callsign registered ack 'U' monitored UI frame from RF
Connected-mode frame types ('C', 'D', 'd', 'v', 'V', 'c', ...) are accepted and logged but not implemented, matching the "AX.25 UI only" constraint for graywolf Phase 2.
Index ¶
Constants ¶
const ( KindVersion byte = 'R' KindPortInfo byte = 'G' KindPortCaps byte = 'g' KindRegisterCallsign byte = 'X' KindUnregisterCallsign byte = 'x' KindMonitorOn byte = 'm' KindSendUnproto byte = 'M' // client → server: send UI frame KindSendUnprotoVia byte = 'V' // client → server: send UI frame via digipeaters KindSendRaw byte = 'K' // both directions: raw AX.25 KindMonitoredUI byte = 'U' // server → client: rx UI frame )
Data kinds as single ASCII bytes. Direction is context-dependent (some kinds appear in both directions).
const HeaderSize = 36
HeaderSize is the fixed AGW frame header length.
Variables ¶
This section is empty.
Functions ¶
func EncodeHeader ¶
EncodeHeader writes h into a 36-byte buffer.
Types ¶
type Header ¶
type Header struct {
Port uint8
DataKind byte
PID uint8
CallFrom string // 10-char NUL-padded
CallTo string // 10-char NUL-padded
DataLen uint32 // little-endian on the wire
User uint32
}
Header is the 36-byte AGWPE frame header.
func DecodeHeader ¶
DecodeHeader parses a 36-byte header.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a multi-client AGWPE-compatible TCP server.
func NewServer ¶
func NewServer(cfg ServerConfig) *Server
NewServer builds an AGW server. Does not listen until ListenAndServe.
func (*Server) ActiveClients ¶
ActiveClients returns the current client count.
func (*Server) BroadcastMonitoredUI ¶
BroadcastMonitoredUI sends a received UI frame to every connected monitoring client as an AGW 'U' record.
func (*Server) ListenAndServe ¶
ListenAndServe binds and serves until ctx is cancelled or Shutdown is called. Blocks. When it returns, the listener is closed and the bound port is free.
func (*Server) LocalAddr ¶
LocalAddr returns the actual bound listener address. Returns nil until ListenAndServe has successfully bound. Useful for tests that pass ":0" and want the OS-assigned port.
func (*Server) Shutdown ¶
Shutdown triggers an orderly exit of ListenAndServe without requiring the caller's context to be cancelled. It closes the listener (breaking Accept) and closes every live client connection to unblock their readers, then waits for all tracked goroutines up to ctx's deadline. Safe to call more than once; subsequent calls are no-ops.
type ServerConfig ¶
type ServerConfig struct {
ListenAddr string
// PortCallsigns lists the mycall of each radio port, in AGWPE port
// order (index 0 = port 0). Used in the 'G' response.
PortCallsigns []string
// PortToChannel maps an AGW port number to a graywolf channel. If a
// port isn't listed it defaults to PortToChannel[0] or channel 1.
PortToChannel map[uint8]uint32
// Sink receives parsed AX.25 frames for transmission. Typically
// *txgovernor.Governor in production.
Sink txgovernor.TxSink
// Logger is optional.
Logger *slog.Logger
// OnClientChange is invoked with the new total-client count on connect
// and disconnect. Optional.
OnClientChange func(active int)
// OnDecodeError is invoked for each raw-frame decoding attempt that
// fails, with stage == "initial" when the first ax25.Decode fails (and
// the skip-byte fallback is about to be tried) or stage == "fallback"
// when both attempts fail and the frame is dropped. Optional.
OnDecodeError func(stage string)
}
ServerConfig configures the AGW TCP server.