← Projects

SnePRS - AX.25 / APRS I-Gate

Running as K2MOW-10

A from-scratch AX.25 and APRS stack in Kotlin, running as the software side of my I-Gate. Rather than wrapping an existing TNC, it does the whole chain itself: a Bell 202 AFSK demodulator and modulator, HDLC framing, and CRC-CCITT, taking audio straight off a soundcard fed by the radio.

On top of the AX.25 layer sits an APRS parser with handlers for Mic-E, position reports with and without timestamps, compressed positions, messages, objects and items, telemetry, and weather.

It runs as a systemd service on the gate as K2MOW-10.

Kotlin · Ktor · Koin · ESP32 · systemd

Modules

The application is a set of modules configured from a single HOCON file and wired together with Koin. A soundcard module owns the radio audio and the AX.25 layer. An I-Gate module connects to APRS-IS, beacons on an interval, and gates RF packets to the network. A digipeater module responds to the WIDE, TRACE, and RELAY aliases. A system monitor collects host metrics, and a Ktor web module serves the control panel.

Each module declares whether it is enabled and whether it is required, so a failure in something optional does not take the application down. Modules register themselves through an annotation rather than a central list, which means adding one is a single new file.

Metrics and control panel

Modules publish typed metrics at runtime - packets decoded, decode errors, packets gated, APRS-IS connection state, signal level, CPU and memory - and the web module streams them to the control panel over server-sent events. Because registration is dynamic, a new module's metrics appear in the interface without any change to the frontend.

SnepCtrl PTT controller

Keying the radio is handled by SnepCtrl, an ESP32 running custom firmware that speaks a small binary protocol over serial. Commands and responses are fixed-length frames, with the high bit of the type byte distinguishing an unsolicited event from a reply.

The firmware runs the hardware watchdog over its main loop and a separate software timer over the maximum PTT hold time, so a crash or a hang on the host side cannot leave the transmitter stuck keyed.

Still to do

AX.25 transmit is the large remaining piece, along with offline gating for events where there is no uplink, better packet caching so something already on APRS-IS is not gated twice, and authentication on the control panel so it can be handed to someone read-only.