This file provides guidance to coding agents (Claude Code, etc.) when working with code in this repository.
Stratux turns a Raspberry Pi + RTL-SDR dongles into a multi-band aviation receiver (1090 ADS-B, 978 UAT, OGN/FLARM on 868MHz, AIS) and broadcasts the fused traffic, weather, GPS and AHRS data to Electronic Flight Bags (ForeFlight, etc.) as GDL90 over Wi-Fi. It is a single long-running Go daemon plus several bundled C programs, served alongside a web configuration UI. This repo is the EU-flavored community fork (originally cyoung/Stratux) that also targets the US and rest of world.
Stratux mixes Go and C and pulls C sources in via git submodules. Always init submodules first or the build fails:
git submodule update --init --recursiveCommon targets (see Makefile):
| Command | Result |
|---|---|
make / make all |
Builds everything: libdump978.so, dump1090, rtl_ais, the main stratuxrun binary, and fancontrol |
make stratuxrun |
Just the main Go daemon (needs libdump978.so present) |
make www |
Copies the web UI into $STRATUX_HOME/www (default /opt/stratux) |
make optinstall |
Installs binaries/libs/web/config into /opt/stratux (needed before running on a dev machine so it can find dump1090, ogn-rx, etc.) |
make dpkg |
Builds the .deb. Only works on the target OS/arch (Debian 12 Bookworm, arm64) |
make dall / make ddpkg |
Runs make all / make dpkg inside Docker (docker_run.sh) — use this to produce target-arch artifacts from any host |
make test |
Compiles the standalone diagnostic utilities in test/ (see Testing) |
make clean |
Cleans Go output and the C submodule builds |
Notes:
- The Go build needs CGO and the locally-built shared lib: the Makefile sets
LIBRARY_PATH=$(CURDIR)andCGO_CFLAGS_ALLOW="-L$(CURDIR)". Replicate these env vars if buildingstratuxrunby hand. make debug=true ...adds-gcflags '-N -l'for delve debugging.- Version comes from the latest git tag (
scripts/getversion.sh); arch fromuname -mnormalized byscripts/getarch.sh(x86_64→amd64,aarch64→arm64). The chosenogn-rx-euprebuilt binary depends on arch. - There is no separate lint step; rely on
go vet/gofmtand the CI build (.github/workflows/ci.yml).
- On the Pi, Stratux runs as the systemd
stratuxservice. Aliases (fromimage_build/.../stxAliases.txt, available in the image shell):stxstart,stxstop,stxrestart. Typical dev loop:stxstopthenmake && make install && stxrestart. - Not running as root (i.e. local desktop dev),
main()remaps the web dir to./web/next to the binary and config to~/.stratux.confinstead of/opt/stratuxand/boot/firmware/stratux.conf. - The binary is
stratuxrun. Useful flags (parsed inmain/gen_gdl90.go):-replay -uatlog <file>(replay a UAT log),-trace <file> -traceSpeed -traceFilter(replay a recorded trace; filter contexts:ais,nmea,aprs,ogn-rx,dump1090,godump978,lowpower_uat),-port <n>,-cpuprofile <file>,-write-network-config. - There are no Go unit tests (
*_test.go). Thetest/directory is a collection of independentpackage maindiagnostic tools (e.g.icao2reg.go,uat_read.go,nexrad_annunciator.go);make -C testjust compiles each one. Sample input lives intest-data/. - VSCode has preconfigured Build + debug tasks (
.vscode/tasks.json,launch.json).⚠️ These still reference an oldergen_gdl90binary/target; the current Makefile producesstratuxrun. If using them, expect to update the program/target name.
main/gen_gdl90.go holds func main() and the central shared state. Everything else in
main/ is a feature module that main() wires together by launching goroutines. Key shared
globals (all defined in gen_gdl90.go, guarded by mutexes):
globalSettings— the user config, serialized tostratux.conf. Adding a setting means adding a struct field here; it is automatically exposed via the/getSettings//setSettingsAPI and the web UI reads it by field name.globalStatus— runtime status (message counts, device state, CPU temp, errors), exposed via/getStatus.mySituation— current GPS/AHRS fix and attitude.
Understanding these three patterns is the key to the codebase:
- 978 UAT → linked C library.
dump978/is compiled intolibdump978.soand bound into Go through thegodump978package via cgo (#cgo LDFLAGS: -ldump978). Raw UAT frames are decoded in-process, then parsed by theuatparsepackage (FIS-B weather, NEXRAD, etc.). - 1090 ES, OGN, AIS → external subprocesses.
main/sdr.golaunchesdump1090(FlightAware fork, submodule) and pipes its output over TCP:30006;ogn-rx-eu(prebuilt binary inogn/) for 868MHz; andrtl_ais(submodule) for AIS. Each is spawned withexec.Command, monitored, and auto-restarted on crash. OGN APRS parsing is inmain/ogn.go/main/ogn-aprs.go; AIS inmain/ais.go. - GPS / baro / IMU → direct hardware.
main/gps.go(serial GPS, large file with chip autodetect for various u-blox/SiRF modules),main/sensors.go, and thesensors/package (BMP280/388 baro, ICM20948/MPU9250 IMU drivers).
SDR dongles are assigned to bands by EEPROM serial prefix (stx:1090, stx:978, etc.);
main/sdr.go owns this assignment and reconfiguration when settings change.
main/traffic.go is the heart: it merges traffic targets from all sources, dedupes,
extrapolates positions between updates, and estimates Mode-S target distance. Outputs:
- GDL90 binary messages —
gen_gdl90.gobuilds them; sent over UDP :4000 to EFB clients (main/network.go,clientconnection.go) and mirrored over the/gdl90WebSocket. - FLARM / NMEA (PFLAA/PFLAU) —
main/flarm-nmea.go, over TCP :2000 and serial. - Bluetooth LE traffic output, Cursor-on-Target (
cot-in.go), X-Plane (xplane.go). - Traffic/situation history logged to SQLite via
main/datalog.go.
managementInterface() is the HTTP server. It serves the web UI and the JSON/WebSocket API
documented in docs/http-api.md (e.g. GET /getStatus, /getSituation, POST /setSettings, WebSocket /gdl90, /situation, /traffic, /weather). No auth — it's a
local AP network. The frontend (web/) is an AngularJS single-page app (mobile-angular-ui +
OpenLayers for maps). Each screen is a "plate": HTML in web/plates/*.html with its controller
in web/plates/js/*.js, talking to the API above.
fancontrol_main/→fancontrolbinary (PID-controlled cooling fan), its own systemd service.common/holds code shared betweenmainandfancontrol(CPU temp, aviation equations, helpers).
main/— the daemon (Go).common/— shared Go helpers.dump978/(C lib, built locally),godump978/(cgo wrapper),uatparse/(UAT/FIS-B parser).dump1090/,rtl-ais/,ogn/ogn-tracker/,image_build/pi-gen/— git submodules.sensors/— baro/IMU hardware drivers.web/— AngularJS UI and assets.debian/— systemd units, udev rules,.debpackaging scripts, boot/network templates.image_build/— pi-gen stages that produce the Raspberry Pi SD-card image.test/— standalone diagnostic tools.test-data/— sample logs.notes/— design notes.docs/— developer docs: architecture, building, dev setup, the HTTP/WebSocket API (http-api.md), the integration guide (integration/), the settings reference, and hardware support (hardware/). Index indocs/README.md.
Semantic MAJOR.MINOR (e.g. 3.6). OTA updates work only between minor versions. Two OTA
mechanisms run through the same boot-time path (debian/stratux-pre-start.sh): a .deb for the
Stratux app, and a legacy update script (US) for system-level changes. Full flow in
docs/building.md.
- Match the style of the file/area you are editing (project guidance in
docs/building.md). - User-facing docs live in the GitHub wiki; developer docs that track the code live in
docs/in this repo (so they're reviewed in PRs alongside code changes). - Keep the image small: the target is to fit the SD-card image on a 4GB card.