Skip to content
sirsjgPublic

About

A standalone, cross-platform ADS-B receiver in a single Go binary.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

squitter

A standalone, cross-platform ADS-B receiver in a single Go binary.

Go License Platform

Plug in an RTL-SDR dongle, run one command, and watch aircraft on a live map — or stream the data to Virtual Radar Server, an aggregator, or your own code.

No dump1090. No readsb. No librtlsdr. No Python. One binary, no setup.

squitter -location 51.4775,-0.4614 -map carto -enrich

The web view, with a map background and database enrichment


Try it without hardware

squitter -demo -location 51.4775,-0.4614

Then open http://localhost:8080.

That synthesises real 1090 MHz signals, pushes them through the actual demodulator, and decodes them back — the same code path a real dongle uses. It is the fastest way to tell whether a silent screen is your antenna or your build.

Why

Existing ADS-B software is excellent but fragmented and mostly Windows- or Linux-first: a C decoder here, a Python multilateration client there, a web UI somewhere else, and a stack of setup steps before anything appears on screen. squitter is one program that does the whole chain — radio to screen to feed — and runs the same way everywhere.

How it works

 RTL-SDR ──▶ demodulator ──▶ Mode S decode ──▶ tracker ──┬──▶ web UI
  1090 MHz    2.4 MSPS        CRC + CPR         aircraft │    terminal view
                                                  state  ├──▶ Beast   :30005
                                                         ├──▶ AVR     :30002
                                                         └──▶ SBS-1   :30003

Everything from raw samples onward is implemented here: the pulse-position demodulator, the 24-bit CRC with single-bit error correction, Compact Position Reporting, altitude decoding including the legacy Gillham code, and the output encoders.


The web view

By default it is a radar scope: range rings drawn about your antenna, no network, nothing to configure.

The default radar scope

Input Action
scroll zoom
drag pan
click select an aircraft, and put it in the URL so it can be linked to
m toggle the map background
c return to the antenna and refit the range
Esc clear the selection

Setting -location is worth doing. Without it, a position needs a matched pair of even/odd frames; with it, single frames can be resolved against your known location, which roughly doubles the usable position rate and lets obviously wrong decodes be rejected.

Map backgrounds

Pass -map to put real geography under the traffic.

squitter -location 51.4775,-0.4614 -map carto
-map Key needed Notes
carto — Dark basemap; the one that suits the display
carto-light — The same, light
osm — Standard OpenStreetMap raster
mapbox -map-key -map-style takes a style ID, default dark-v11
google -map-key -map-style takes roadmap, satellite or terrain
a URL template — Anything containing {z}, {x} and {y}
squitter -map mapbox -map-key pk.eyJ1... -map-style satellite-v9
squitter -map google -map-key AIza... -map-style terrain
squitter -map 'https://tiles.example.com/{z}/{x}/{y}.png'

Tiles are fetched by squitter, not by your browser. That keeps the key on the machine you control rather than shipping it to every client, lets one cache serve every browser and every pan back over ground already covered, and is the only way Google's tiles work at all, since they need a session token minted with the key.

Enrichment

The radio carries an ICAO address and, sometimes, a callsign. It never says what the aircraft is, who operates it, or where the flight is going.

squitter -location 51.4775,-0.4614 -enrich

That fills in registration, ICAO type, manufacturer, operator, country and a photograph, plus the airline, the origin and destination airports, and the IATA flight number a passenger would recognise — BA547 rather than the BAW547 the transponder actually transmits.

The data comes from adsbdb, which is free, needs no account, and is open source if you would rather run your own:

squitter -enrich -enrich-url http://localhost:8008

It is off by default, and deliberately so. A receiver that quietly reports every aircraft it hears to a third party is not what you get from a program that otherwise only listens. Turning it on tells adsbdb which aircraft you can see.

Lookups never touch the receive path: nothing blocks on the network, results and misses are both cached, failures back off, and a database that is slow or unreachable costs you the labels rather than the decoder. Registration and type travel in the feed under readsb's own field names (r, t, desc, ownOp), so tar1090 pointed at squitter picks them up without changes.

In demo mode the invented callsigns resolve to real routes, but the invented ICAO addresses are random, so registrations mostly come back unknown — and the occasional coincidental hit will pair an airline callsign with an entirely unrelated airframe.


Outputs

Format Default port Who reads it
Beast binary 30005 ADS-B Exchange, adsb.lol, airplanes.live, FR24 — the only format aggregators accept
AVR hex 30002 Anything line-oriented; easiest to pipe into your own code
SBS-1 BaseStation CSV 30003 Virtual Radar Server, PlanePlotter, adsbSCOPE
JSON 8080 /data/aircraft.json in the tar1090/SkyAware schema

All four run at once. Each is a plain TCP or HTTP server — connect as many clients as you like.

Feeding an aggregator is then just:

nc localhost 30005 | nc feed.adsbexchange.com 30004

Or point an existing viewer at the JSON:

curl -s localhost:8080/data/aircraft.json | jq '.aircraft[] | {flight, alt_baro, r_dst}'

HTTP endpoints

Path What it serves
/ The web view
/data/aircraft.json Current traffic, readsb schema
/data/receiver.json Receiver position and version
/data/map.json Whether a map is configured, and its attribution
/tiles/{z}/{x}/{y} Map tiles, proxied and cached

Options

Receiver

Flag Default Description
-location lat,lon — Antenna position; enables distance, range checks and single-frame decoding
-device n 0 SDR device index
-gain dB -1 Tuner gain; -1 selects automatic
-sample-rate hz 2400000 Sample rate
-frequency hz 1090000000 Centre frequency
-list — List attached dongles and exit

Display

Flag Default Description
-web addr :8080 Web interface; "" disables
-map provider — Map background; see the table above
-map-key key — API key, for mapbox and google
-map-style s — Mapbox style ID, or Google map type
-enrich off Look up registration, type, operator and route
-enrich-url url adsbdb.com An adsbdb-compatible service of your own
-quiet — No terminal display

Outputs

Flag Default Description
-beast addr :30005 Beast binary; "" disables
-avr addr :30002 AVR hex; "" disables
-avr-timestamps off Use the @ timestamped AVR variant
-sbs addr :30003 SBS-1 CSV; "" disables

Demo and diagnostics

Flag Default Description
-demo — Simulate traffic instead of using a radio
-demo-aircraft n 14 How many aircraft to simulate
-demo-noise f 0.02 Noise floor, 0 to 1
-log level warn debug, info, warn, error

Installing

go install github.com/sirsjg/squitter/cmd/squitter@latest

Or from a clone:

git clone https://github.com/sirsjg/squitter.git
cd squitter
go build ./cmd/squitter

Go 1.24 or newer. No C toolchain needed on Linux or Windows. On macOS the USB backend links against IOKit, which ships with the OS — still nothing to install.

Everything except macOS is pure Go, so release binaries cross-compile from any machine:

GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o squitter-pi ./cmd/squitter
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -o squitter.exe ./cmd/squitter

Status

Working and tested: demodulator, Mode S and ADS-B decoding, aircraft tracking, all four output formats, both user interfaces, the map and enrichment layers, and the simulator.

squitter -list shows attached dongles.

The decoders are validated against captured reference transmissions and by round-tripping through the encoder — position decoding is exact to within CPR's own 5 metre quantisation everywhere on the globe.

The demodulator decodes every frame down to about 20 dB SNR, degrades from there, and runs around 11× faster than real time on one modern desktop core (comfortable on a Raspberry Pi, with room to spare on anything larger). Improving weak-signal performance is the most worthwhile next piece of work: dump1090 squeezes more out of marginal aircraft than this does.

The USB driver is the newest and least proven part: it has never run against a real dongle. It is a from-scratch port of librtlsdr's register sequences, with a fake USB transport in the tests that asserts the whole open sequence produces the expected register trace. That catches transcription errors, not reality-contact errors.

If a dongle behaves oddly, start there. A good bring-up sequence that isolates USB from everything else:

squitter -list          # does enumeration work at all?

then confirm streaming works before trusting any tuner register, since the chip's test mode emits an incrementing byte counter instead of samples.

Known suspects, in order: the macOS asynchronous transfer plumbing; the Linux usbfs ioctl numbers, which were derived from first principles rather than checked against a running kernel; the whole Windows backend; and the sign convention on the intermediate frequency, which would give a mirrored spectrum that still looks like a live noise floor.

Google's tile session handling is the other path never exercised against a real account. The keyless providers and Mapbox have been.

Notes on hardware

  • A 1090 MHz filtered dongle with an LNA roughly doubles useful range over a bare RTL-SDR. The antenna matters more than any of this software.
  • The RTL-SDR Blog V4 uses a different crystal frequency from earlier models. squitter detects it; a decoder that does not will tune 1.8× off frequency and hear nothing while appearing to work.
  • On Windows you still need Zadig to bind the WinUSB driver. That is a driver binding requirement, not a library dependency.

Not yet implemented

  • MLAT. Beast timestamps are emitted at the correct reference point (end of bit 56) so the data is usable, but there is no multilateration client.
  • ASTERIX CAT021, the Eurocontrol surveillance format used by ATC systems.
  • UAT (978 MHz), used by smaller aircraft in the US.
  • Mode S formats that carry no address of their own (DF0/4/5/16/20/21) are decoded only for aircraft already identified from a self-validating frame, since a corrupted frame otherwise conjures a plausible but fictitious aircraft.

Credits

Aircraft and route data from adsbdb. Map tiles from OpenStreetMap, CARTO, Mapbox or Google, depending on what you configure — each is displayed with its own attribution.

License

MIT.

About

A standalone, cross-platform ADS-B receiver in a single Go binary.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages