Add deployment infrastructure and TUI showcase guide
Dockerfile (multi-stage: base/dev/build/prod with caddy:2-alpine), docker-compose.yml with caddy-docker-proxy labels for birdcage.warehack.ing, Caddyfile, Makefile (up/down/dev/prod/clean), and .env. TUI guide page with 4 screenshots (F1 position, F2 signal, F4 system, F5 console), demo mode docs, and project backstory crediting Gabe Emerson (KL1FI) and Chris Davidson.
This commit is contained in:
parent
088c1a5ace
commit
9c9b69c733
10 changed files with 275 additions and 0 deletions
176
src/content/docs/guides/tui.mdx
Normal file
176
src/content/docs/guides/tui.mdx
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
---
|
||||
title: "The Birdcage TUI"
|
||||
description: A five-screen terminal interface for controlling Winegard satellite dishes — from a $75 RV salvage find to something that looks like it belongs in a ground station.
|
||||
sidebar:
|
||||
order: 8
|
||||
badge:
|
||||
text: New
|
||||
variant: tip
|
||||
---
|
||||
|
||||
import { Aside, Steps, Tabs, TabItem } from '@astrojs/starlight/components';
|
||||
|
||||
Mission control for less than dinner for two.
|
||||
|
||||
Somewhere inside every Winegard Carryout G2 is a 2013-vintage NXP Cortex-M4 running firmware 02.02.48,
|
||||
driving two Allegro A3981 stepper motors and a Broadcom BCM4515 DVB-S2 tuner through 12 submenus
|
||||
and over 100 undocumented commands. In 2026, it takes commands from a Python TUI built on
|
||||
[Textual](https://textual.textualize.io/) and doesn't seem to mind.
|
||||
|
||||
Gabe Emerson ([KL1FI](https://github.com/saveitforparts)) went first — publishing control scripts
|
||||
for five different Winegard variants, proving that a $50–200 RV salvage yard dish could replace
|
||||
a $500–2000 commercial amateur radio rotator. Chris Davidson ([cdavidson0522](https://github.com/cdavidson0522/winegard-sky-scan))
|
||||
figured out the G2's RS-422 wiring and discovered `azscanwxp` — the firmware's built-in radio telescope mode.
|
||||
Birdcage is what happens when you take all of that and give it a proper interface.
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Steps>
|
||||
1. **Clone and install** (from the `tui/` directory inside the Birdcage repo):
|
||||
|
||||
```bash
|
||||
cd tui/
|
||||
uv sync
|
||||
```
|
||||
|
||||
2. **Run in demo mode** (no hardware required):
|
||||
|
||||
```bash
|
||||
uv run birdcage-tui --demo
|
||||
```
|
||||
|
||||
3. **Connect to a real dish:**
|
||||
|
||||
```bash
|
||||
uv run birdcage-tui --port /dev/ttyUSB0 --firmware g2
|
||||
```
|
||||
</Steps>
|
||||
|
||||
<Aside type="tip">
|
||||
Demo mode simulates a complete Carryout G2 — motor physics at 10°/s with settling noise,
|
||||
a Gaussian RSSI signal model, and all 12 firmware submenus. Every screen works, every button
|
||||
does something. You don't need a dish on the roof to try it.
|
||||
</Aside>
|
||||
|
||||
## Five Screens
|
||||
|
||||
Navigate between screens with **F1**–**F5** keys or click the sidebar buttons.
|
||||
The device status bar at the bottom persists across all screens — connection state,
|
||||
serial port, firmware version, and current menu prompt are always visible.
|
||||
|
||||
### F1 — Position
|
||||
|
||||

|
||||
|
||||
The position screen is where you point the dish. A compass rose shows current azimuth
|
||||
with a bearing indicator, while AZ and EL sparklines track movement history over time.
|
||||
The numeric readout at top shows position to hundredths of a degree — the G2's stepper
|
||||
resolution is 0.009° azimuth (40,000 steps/rev) and 0.014° elevation (24,960 steps/rev).
|
||||
|
||||
The AZ and EL sparklines give you immediate visual feedback: flat lines mean the dish
|
||||
is parked, slopes mean it's slewing, and the amplitude of the noise floor after arrival
|
||||
tells you how much stepper backlash you're dealing with.
|
||||
|
||||
### F2 — Signal
|
||||
|
||||

|
||||
|
||||
Signal strength from two sources: the BCM4515 DVB tuner's RSSI (bounded, averaged)
|
||||
and the raw ADC reading (single-shot). The gauge uses sub-character Unicode block elements
|
||||
(▏▎▍▌▋▊▉█) for smooth visual resolution. Below the gauge, DVB RSSI and ADC RSSI
|
||||
sparklines show signal trends over time — useful for peaking during manual dish adjustment.
|
||||
|
||||
The sample counter and iteration display at bottom track measurement throughput. On a
|
||||
live dish with the LNA enabled (`lnbdc odu`), you'll see the noise floor sit around
|
||||
RSSI 500 (ADC) or 230–490 (DVB, polarity-dependent).
|
||||
|
||||
### F3 — Scan
|
||||
|
||||
The scan screen wraps the firmware's `azscanwxp` command — Davidson's radio telescope
|
||||
mode. Define an AZ×EL grid, set the step resolution, and watch the sky heatmap fill
|
||||
in with RSSI-colored cells as the dish sweeps. Results export to CSV for post-processing
|
||||
into proper sky maps.
|
||||
|
||||
<Aside>
|
||||
No screenshot for this one yet — the scan screen needs a live dish or a long-running demo
|
||||
sweep to produce interesting output. It exists, it works, and it's waiting for first light.
|
||||
</Aside>
|
||||
|
||||
### F4 — System
|
||||
|
||||

|
||||
|
||||
The system dashboard. Top row shows the firmware identity banner: version 02.02.48,
|
||||
K60 MCU at 96 MHz, antenna ID "12-IN G2". Below that, two side-by-side panels:
|
||||
|
||||
- **A3981 Diagnostics** — fault pin status for both stepper drivers (AZ/EL DIAG: OK or FAULT),
|
||||
plus step size mode (AUTO means the driver handles microstepping transitions automatically).
|
||||
- **Motor Dynamics** — max velocity and acceleration for each axis. The G2 defaults to
|
||||
65.0°/s azimuth, 45.0°/s elevation, with 400.0°/s² acceleration — fast enough to track
|
||||
LEO satellites at medium altitudes.
|
||||
|
||||
The NVS Table at the bottom is a scrollable browser of all 134 non-volatile storage values.
|
||||
Current, saved, and default columns let you see what's been modified. The "Refresh NVS"
|
||||
and "Export NVS JSON" buttons at the bottom do what you'd expect.
|
||||
|
||||
### F5 — Console
|
||||
|
||||

|
||||
|
||||
Raw firmware console access with guardrails. Type commands directly to the dish's serial
|
||||
interface, see responses with color-coded prompt tracking (`TRK>`, `MOT>`, `DVB>`, `NVS>`,
|
||||
etc.). Command history with up/down arrows.
|
||||
|
||||
The safety gates matter here: the console warns before sending `q` at root level (which
|
||||
kills the firmware shell — requires power cycle to recover), before `reboot`, and before
|
||||
NVS writes. The firmware doesn't have an "are you sure?" prompt. Birdcage does.
|
||||
|
||||
## Demo Mode
|
||||
|
||||
Pass `--demo` and Birdcage substitutes a `DemoDevice` for the serial bridge. The simulator models:
|
||||
|
||||
- **Motor physics** — position changes at ~10°/s with configurable settling noise
|
||||
(±0.05° random perturbation to simulate stepper backlash)
|
||||
- **RSSI signal** — Gaussian model centered on a target position, so signal strength
|
||||
increases as you point closer to the simulated source
|
||||
- **All 12 submenus** — `TRK>`, `MOT>`, `DVB>`, `NVS>`, `A3981>`, `ADC>`, `OS>`, `STEP>`,
|
||||
`PEAK>`, `EE>`, `GPIO>`, `LATLON>`, `DIPSWITCH>`. Menu navigation with `mot`, `dvb`, `nvs`,
|
||||
etc. and `q` to go back all work correctly
|
||||
- **Full NVS dump** — the complete 134-entry table from firmware 02.02.48, captured from a
|
||||
live unit on 2026-02-12
|
||||
|
||||
Every screen, every widget, every button works in demo mode. It's the same code path —
|
||||
the only difference is what's on the other end of the bridge.
|
||||
|
||||
## The Story
|
||||
|
||||
The hardware was never the hard part. RV satellite dishes show up at salvage yards for
|
||||
$50–200 because the RV got totaled or the owner switched to Starlink. The mechanicals are
|
||||
built to survive highway speeds and hailstorms. The motors are Allegro A3981 stepper drivers
|
||||
with 1/16 microstepping — more precise than most amateur radio rotators at ten times the price.
|
||||
|
||||
The gap was always software.
|
||||
|
||||
Gabe Emerson (KL1FI) bridged it first. Five repositories for five Winegard variants — the
|
||||
Trav'ler (HAL 0.0.00 and HAL 2.05), the Trav'ler Pro, the original Carryout, and the
|
||||
Carryout G2. Python scripts that send `a 0 180` to point azimuth south and `a 1 45` to tilt
|
||||
elevation to 45°. A rotctld bridge so Gpredict could drive the dish. Proof that the idea
|
||||
worked.
|
||||
|
||||
Chris Davidson took the G2 further — mapped the RS-422 wiring (four wires, not two, and
|
||||
polarity matters or you get garbled data at the correct baud rate), discovered the `azscanwxp`
|
||||
command buried in the motor submenu, and turned a TV satellite dish into an RF imager.
|
||||
|
||||
Birdcage picks up where they left off. We reverse-engineered over 100 commands across
|
||||
12 firmware submenus using automated probing and interactive exploration. We documented
|
||||
the full NVS table (134 entries), the GPIO pin map, the SPI bus layout (4 MHz to the motor
|
||||
drivers, 6.857 MHz to the DVB tuner), the DiSEqC 2.x interface, and the boot sequence from
|
||||
bootloader through motor calibration to prompt.
|
||||
|
||||
The TUI is what ties it together. Not because a terminal interface is fashionable, but because
|
||||
when you're on a roof with a laptop and a USB-to-RS422 adapter, you want something that runs
|
||||
over SSH and shows you everything at once.
|
||||
|
||||
A 2013 microcontroller. A 2026 terminal. A dish that costs less than the cable to connect it.
|
||||
|
||||
That's the project.
|
||||
Loading…
Add table
Add a link
Reference in a new issue