diff --git a/.gitignore b/.gitignore index c84fa27..3fc98d3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ languages_builder # Generated docs site website/_build/ + +# Screenshot tool venv + scratch output +MDUV380_firmware/tools/.venv/ +screenshots/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ff9be8..e91175f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ single running list until the first versioned release. ## Unreleased -_Nothing yet._ +- **`screenshot.sh`** — a one-command wrapper around the OpenGD77 screen grabber + that auto-detects the serial port and sets up a self-contained Python venv + (pyserial + pillow) on first run. Saves to `screenshots/`. ## 0.5.0 diff --git a/TOOLS.md b/TOOLS.md index 5e3bc6f..516dfdf 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -87,9 +87,19 @@ Models: `MD-UV380`, `DM-1701`, `MD-9600`, `MD-2017`, `MD-380`. grabber (the "gd-77" name is historical). It talks over the USB **CDC serial port**, auto-detects the radio model and reads the MD-UV380's 160×128 RGB565 framebuffer into a PNG. -1. Power the radio on **normally** (not DFU mode) and navigate to the screen you want. - Connect USB. -2. Run it (`-o` takes the filename **without** `.png`): +Power the radio on **normally** (not DFU mode), navigate to the screen you want, and +connect USB. + +**Easiest — the `./screenshot.sh` helper** (auto-detects the serial port and sets up a +self-contained Python venv with `pyserial` + `pillow` on first run): + +```bash +./screenshot.sh # -> screenshots/screenshot-.png +./screenshot.sh vfo-7seg # -> screenshots/vfo-7seg.png +./screenshot.sh -d /dev/cu.usbmodemXXXX [name] # explicit port +``` + +**Or call the grabber directly** (`-o` takes the filename **without** `.png`): ```bash python3 MDUV380_firmware/tools/gd-77_screen_grabber.py \ diff --git a/screenshot.sh b/screenshot.sh new file mode 100644 index 0000000..0232b67 --- /dev/null +++ b/screenshot.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# Grab a screenshot from the radio over USB (CDC serial), using the OpenGD77 +# screen grabber. Runs natively (USB serial is not available inside Docker) and +# sets up a self-contained Python venv (pyserial + pillow) on first use. +# +# The radio must be powered on, running the firmware, and connected via USB. +# +# Usage: +# ./screenshot.sh # auto-detect port -> screenshots/screenshot-.png +# ./screenshot.sh vfo-7seg # -> screenshots/vfo-7seg.png +# ./screenshot.sh -d /dev/cu.usbmodem1234 [name] # explicit serial port +set -euo pipefail + +REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +GRABBER="$REPO_DIR/MDUV380_firmware/tools/gd-77_screen_grabber.py" +VENV="$REPO_DIR/MDUV380_firmware/tools/.venv" +OUT_DIR="$REPO_DIR/screenshots" + +# ---- optional explicit device (-d /dev/...) ------------------------------- +DEVICE="" +if [[ "${1:-}" == "-d" ]]; then + DEVICE="${2:-}"; shift 2 || true +fi + +# ---- auto-detect the radio's serial port ---------------------------------- +if [[ -z "$DEVICE" ]]; then + case "$(uname -s)" in + Darwin) DEVICE="$(ls /dev/cu.usbmodem* 2>/dev/null | head -1 || true)" ;; + *) DEVICE="$(ls /dev/ttyACM* 2>/dev/null | head -1 || true)" ;; + esac +fi +if [[ -z "$DEVICE" ]]; then + echo "!! No radio serial port found." >&2 + echo " Connect the radio via USB (powered on, running firmware) and retry, or pass one:" >&2 + echo " ./screenshot.sh -d /dev/cu.usbmodemXXXX" >&2 + exit 1 +fi + +# ---- one-time Python venv with the grabber's dependencies ------------------ +if [[ ! -x "$VENV/bin/python" ]]; then + echo "==> First run: creating Python venv with pyserial + pillow..." + python3 -m venv "$VENV" + "$VENV/bin/pip" install --quiet --upgrade pip + "$VENV/bin/pip" install --quiet pyserial pillow +fi + +# ---- output name ----------------------------------------------------------- +mkdir -p "$OUT_DIR" +NAME="${1:-screenshot-$(date +%Y%m%d-%H%M%S)}" +OUT="$OUT_DIR/$NAME" + +echo "==> Grabbing from $DEVICE" +"$VENV/bin/python" "$GRABBER" -d "$DEVICE" -o "$OUT" +echo "==> Saved: $OUT.png"