Carefree, observable plotting of HP-GL files on HP pen plotters over RS-232.
Project description
hpgl-buddy
Carefree, observable plotting of HP-GL files on HP pen plotters over RS-232.
It does not just shove a file at the plotter: it validates the file, splits it to fit the device buffer, feeds it so the buffer never overflows and an inked pen never stalls mid-stroke, watches the device for faults the whole time, and logs every exchange so a run can be understood and troubleshooted from the log alone.
Supported device: HP 7475A (RS-232). New devices are added as declarative profiles (see Extending); HP-IB is planned.
Install
Requires Python 3.13 and a USB-serial adapter (macOS: use the /dev/cu.* device).
pip install -e . # editable, for development
# or build a wheel:
python -m build --wheel # -> dist/hpgl_buddy-*.whl (or: tox -e build)
pyserial is the only runtime dependency.
Quick start
# 1. Validate a file offline (no plotter needed)
hpgl-buddy check drawing.hpgl
# 2. Check the plotter is alive and interpret its status
hpgl-buddy status --port /dev/cu.usbserial-XXXX
# 3. Plot it (verbose shows every byte/ESC exchange)
hpgl-buddy -v plot drawing.hpgl --port /dev/cu.usbserial-XXXX
# 4. Generate and plot a built-in demo
hpgl-buddy demo --pens 6 --out demo.hpgl
hpgl-buddy plot demo.hpgl --port /dev/cu.usbserial-XXXX
Serial defaults: 9600 8N1, no flow control (configurable). Flow control is off by
default because XON/XOFF corrupted the exchange on the on-site adapter; enable it with
--xonxoff if your cabling needs it.
Commands
| Command | What it does |
|---|---|
check FILE |
Offline HP-GL syntax check. No device. Exit non-zero on errors. |
status |
Ad-hoc healthcheck: identification, buffer, status byte, errors, limits - all interpreted. |
plot FILE |
Safe, buffer-aware plotting with progress + end-of-run report. |
monitor on|off|watch |
Switch monitor mode (computer port) or stream the echoed bytes (terminal port). |
demo |
Generate demo HP-GL (--scene card shapes/fills/labels/colours, or --scene house a continuous one-line drawing). |
Global: -v/--verbose (DEBUG, incl. raw ASCII+hex wire dumps), --version.
Serial options (on status/plot/monitor): --port, --model (default hp7475a),
--baud, --framing (e.g. 8N1), --timeout, --xonxoff, --rtscts.
plot options
--on-error abort|prompt|continue- on a reported error: stop and park the pen (default), ask interactively, or auto-recover (ESC.Kdiscard ->IN-> replay the tracked state preamble -> carry on).--live-hpgl-verify off|chunk|pu- optional on-device HP-GL error checking (see Verification). Defaultoff.--ignore-syntax-errors- plot even if the offline check found errors.--stats-json PATH- write run statistics as JSON (-for stdout).
monitor (two ports)
The 7475A enables monitor mode via an ESC sequence on the computer (data) port, then echoes received bytes out a separate terminal port. So:
# stream the echo on the terminal port, enabling monitor on the computer port first
hpgl-buddy monitor watch --port /dev/cu.TERMINAL --command-port /dev/cu.COMPUTER --enable
watch prints every byte as binary, hex, decimal, and ASCII/control-name.
How plotting works
file -> parse -> offline syntax check -> plan into chunks -> stream to device -> report
- Parse the bytes into instructions, each tagged with its source line and sequence index (so any error names the exact command).
- Syntax check offline;
plotrefuses a file with errors unless--ignore-syntax-errors. - Plan into chunks of <=256 bytes, split only at instruction boundaries (never inside a command), each tagged whether it ends with the pen up.
- Stream: a chunk is sent only when
ESC.Breports enough free buffer space. This one gate both prevents overflow and keeps the buffer fed, so a long pen-down stroke spanning several chunks never underruns (an underrun would park an inked pen and blot). - Watch (always on, after each chunk):
ESC.Efor I/O faults (overflow / framing / data loss) andESC.Ofor environmental faults (paper lever or pinch wheels raised -> abort; VIEW pressed -> warn). Both are immediate and never stall the pen. - Confirm: a final
OS;OE;OI;tailgate waits for the pen to physically finish and reports the end status / any HP-GL error. - Report instructions/chunks/bytes sent, elapsed time, recovered errors, and warnings
(and the same as JSON via
--stats-json).
Verification
HP-GL/syntax errors are a property of the file (already validated offline), so on-device
HP-GL error checking is optional and off by default. When enabled it never stalls the
pen - it uses a one-deep tailgate: the OS;OE;OI; query is prefixed to the chunk after a
pen-up, so its verdict reports the previous chunk while the current one is already drawing.
chunk- check at pen-up chunk boundaries.pu- break a chunk at every pen-up so each completed stroke is checked (more, smaller chunks).
Either way you learn a chunk is clean within ~1 chunk, and a reported error names the span of chunks it could belong to with all candidate instructions.
Limits to know
- No pen sensing on the 7475A: a missing or fallen pen plots dry and is not detectable
by any status query. Pre-load the pens your file uses. (
plotwarns about this.)
Architecture
Thoroughly separated layers, each replaceable on its own:
hpgl/ parse HP-GL bytes into a Program; offline syntax check
devices/ declarative TOML profiles + abstract Device base (registry)
interface/ Transport abstraction + pyserial RS-232 implementation
status/ ESC + HP-GL command builders, response parsers, status interpretation, monitor
execution/ planner (Program -> chunks) + flow control + executor + progress/report
demo/ demo HP-GL generators
The authoritative design rationale (with HP manual citations) lives in DESIGN.md; the
running decision log is the "Follow-up steering" section of TASK-1-BASIC-IMPLEMENTATION.md.
Extending
Add a simple device by dropping a <model>.toml into devices/profiles/ (buffer size,
pen count, serial defaults, capabilities, pen_sensing). A device with unusual behavior
can subclass Device and register it. The interface layer is transport-agnostic, so HP-IB
can be added as another Transport without touching the rest.
Development
tox # run the test suite (Python 3.13)
tox -e build # build the wheel
Dependencies are managed two-file style: requirements-rough.txt (hand-maintained,
loose top-level) is frozen into a fully-pinned requirements.txt by the
dependencies_update GitHub Actions workflow. A Dockerfile provides a reproducible
build/test image (not for serial I/O - hardware is not reachable from a container).
Conventions: extensive logging (no print), ASCII-only output, descriptive names, and
errors that state what happened, where, and why.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file hpgl_buddy-1.0.0.tar.gz.
File metadata
- Download URL: hpgl_buddy-1.0.0.tar.gz
- Upload date:
- Size: 52.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45e9ad5edfe66445b4a3c67cf0e0d27367500197b88206d28225d50ddadb1eea
|
|
| MD5 |
2f87718c33ba2964ceeb2ab58103517c
|
|
| BLAKE2b-256 |
97bbec31b027268a41ed9febb8c0710fe70de3fa46cc8b6e856cabe998f3d5d2
|
Provenance
The following attestation bundles were made for hpgl_buddy-1.0.0.tar.gz:
Publisher:
release.yml on hpgl-buddy/hpgl-buddy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hpgl_buddy-1.0.0.tar.gz -
Subject digest:
45e9ad5edfe66445b4a3c67cf0e0d27367500197b88206d28225d50ddadb1eea - Sigstore transparency entry: 1874537880
- Sigstore integration time:
-
Permalink:
hpgl-buddy/hpgl-buddy@30bc45ab298e35a1183680625e00467a0642b4dd -
Branch / Tag:
refs/heads/master - Owner: https://github.com/hpgl-buddy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@30bc45ab298e35a1183680625e00467a0642b4dd -
Trigger Event:
push
-
Statement type:
File details
Details for the file hpgl_buddy-1.0.0-py3-none-any.whl.
File metadata
- Download URL: hpgl_buddy-1.0.0-py3-none-any.whl
- Upload date:
- Size: 55.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d9624f1b7e07a38615fe0ff1cebdb353b2bea4d5602c3579a20eaf7a5e9b253f
|
|
| MD5 |
1ad155f3eb09b8029ca3cdd3d7f1a25c
|
|
| BLAKE2b-256 |
64734775d253cce1bb2953c8f462193e8968e02a056d028c4e6827334fe7c38e
|
Provenance
The following attestation bundles were made for hpgl_buddy-1.0.0-py3-none-any.whl:
Publisher:
release.yml on hpgl-buddy/hpgl-buddy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
hpgl_buddy-1.0.0-py3-none-any.whl -
Subject digest:
d9624f1b7e07a38615fe0ff1cebdb353b2bea4d5602c3579a20eaf7a5e9b253f - Sigstore transparency entry: 1874537935
- Sigstore integration time:
-
Permalink:
hpgl-buddy/hpgl-buddy@30bc45ab298e35a1183680625e00467a0642b4dd -
Branch / Tag:
refs/heads/master - Owner: https://github.com/hpgl-buddy
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@30bc45ab298e35a1183680625e00467a0642b4dd -
Trigger Event:
push
-
Statement type: