can you hear me now? good! (Part 11/12) 🕊️
Paul Tagliamonte 2026-09-08 diyIf you're looking for it, the intro to the Link (layer 2) that this belongs at a high level and listing of the parts that make it up (including this one) is on the link post.
Built-in to the pigeon link protocol is a message type called cal (short for,
you guessed it, calibration). A pigeon frame with a type of cal
(which is 0x02) carries a JSON encoded payload in the body, which can
either be a beacon, requesting signal reports in response,
or a report, describing the received beacons.
This serves a few interesting purposes – firstly, network operators can better understand the coverage footprint, propagation under different conditions, and how gain impacts reception when tuning for the lowest practical power levels. Secondly, this can be used (and I plan to eventually implement!) to construct a mapping of minimum power level and peer mac address to dynamically control the transmission power based on the destination station.
That being said, for now, all I’ve used this for is getting a rough sense for
what gain value(s) make sense between two nodes (manually). In the future,
beyond all the fancy neighbor gain stuff, I plan to wire this into the daemon
to happen automatically, “debouncing” for beacon and report messages, such
that transmitting stations only beacon, and receiving stations only report a
max of once over some time period for a given peer.
Version
Given all the above, I do intend to make some massive changes to this protocol
(I promise to blog all about it) when I get around to hacking on switching
Layer 2 frames within a network segment. Just to avoid having to dig myself out
of a hole later, I’m going to explicitly send (and check) the version field
to avoid having a big “flag day” switchover or needing to use a new link
type.
| Version ID | Description |
V1 | this version of the cal protocol |
Location
Both flavors of cal messages (beacon and report) may contain a location,
which is the location that the beacon was transmitted, or for or the location
where the beacon was heard for a response. This can be used to derive a
coverage map and to (operationally) better understand what stations should be
within range, and generally what gain level(s) are effective.
All fields assume WGS84 latitude and longitude values, and elevation is
distance, in meters, above the WGS84 ellipsoid – NOT height above
sea level, or altitude above the ground.
| Field | Description |
| lat | WGS84 Latitude |
| lon | WGS84 Longitude |
| elevation | height, in meters above the WGS84 ellipsoid |
Sequence
Each beacon contains a Sequence identifier, which is used to communicate
which message number is being heard, and how many total were transmitted
by the originating station. The current approach with Beacon messages is to
transmit some number of Beacon messages at different gain levels, each
with a unique Sequence identifier.
| Field | Description |
| number | beacon sequence number |
| total | total number of beacons transmitted |
Gains
Recorded gain setting(s). For a Beacon this indicates the gain settings
(which, in spite of its name, includes things like amplifiers, or attenuators).
Changing this over different Beacon frames enables a better understanding
of what an appropriate gain level is for the transmitting station over time.
| Field | Description |
| name | gain stage name |
| db | gain value, in dBm |
Cal
All messages contained in a cal frame are of this type. The type field
communicates if this is a Beacon or Report message type.
| Type | Description |
| beacon | sent intermittently by idle stations |
| report | reception report in response to a beacon |
Beacon
A beacon message may be sent periodically by pigeon nodes capable of
transmitting to announce their prescience to peers and, implicitly, to receive
signal reports from nearby listeners who are capable and configured to transmit
reports.
The beacon JSON message is made up of the following fields:
| Field | Description |
| version | version enum value |
| gains | gains object |
| sequence | sequence number |
| location | location object |
An example beacon looks, unsupprisingly, as follows:
{
"type": "beacon",
"version": "V1",
"sequence": {
"number": 2,
"total": 5
},
"gains": []
}
Report
A report message may be sent in response to a beacon message by
pigeon nodes capable of receiving and transmitting to assist with setting the
lowest usable gain value, and to better understand the area of coverage and
propagation.
The report JSON message is made up of the following fields:
| Field | Description |
| version | version object |
| location | location object |
An example report looks as follows:
{
"type": "report",
}
With all that out of the way