Skip to content

Tag Programmer (Rust)

tagprogram-rs is the Rust port of qtprogram. It does the same job: it programs and tests a batch of tags through a USB base and records each one. It has the same window, checks, texts and record file. The difference is underneath. It programs through probe-rs and needs no STM32CubeProgrammer, and its UI is a web page drawn by Tauri.

Layout

Directory What it is
core/ tagprogram-core: the model (model/: ELF, flash plan, identity record, image, release catalog, record CSV, settings) and the engine (engine/: station, session, view state). No UI toolkit; unit tests run without hardware.
ui/ The page: app.js renders the view state with Preact and the UI kit's components into index.html, laid out by app.css; mock-engine.js stands in for the engine in a plain browser; screenshots.sh captures the user manual's pictures from the two.
app/ The Tauri shell: starts the engine, forwards commands and queries, emits its events, and finds the user guide. build.rs stages the page from ui/ and host/ui-kit under cargo's OUT_DIR.
design/ The engine (threads, loop, station, session, hazards), building and packaging, the UI/engine contract, and qtprogram's specification, the behaviour this port reproduces. Why it was built this way: decision 0035.

The engine owns every rule and all state; the page holds none. That split is what lets the same kit and pattern serve qtmonitor and qtcalibrate later.

In the host build and the packages

The top-level CMake build builds it with cargo (BUILD_RUST_APPS, on where cargo is installed; the release workflow turns it on) and installs it beside the Qt applications: tag_tools/tagprogram.app on macOS, signed with them; tag_tools/tagprogram.exe on Windows; tag_tools/bin/tagprogram on Linux, where it needs the system's WebKitGTK 4.1. See CMakeLists.txt.

Nothing else needs installing to build it: libusb is built from source and linked in, and protoc comes from the protoc-bin-vendored crate. The build writes nothing into the source tree; app/build.rs stages the page, the configuration and Tauri's generated files under cargo's OUT_DIR.

The crates it ships are listed, with their licenses, in LICENSES/host/tagprogram-THIRD-PARTY-NOTICES.txt. Regenerate that file with LICENSES/tools/generate_rust_notices.py whenever Cargo.lock changes.

Building and running

cd host/applications/tagprogram-rs
cargo build -p tagprogram          # the app
./target/debug/tagprogram
cargo test -p tagprogram-core      # model and view tests, no hardware

To work on the page without the app or hardware, open ui/index.html in a browser. The mock engine supplies canned states, and a switcher in the corner changes between them.

cargo run -p tagprogram-core --example smoke -- <scratch-dir> runs the engine headless with scratch settings. It answers the first-run question with automatic attach off, so it lists and identifies the base but never attaches to the tag.

cargo run -p tagprogram-core --example bench -- <scratch-dir> <release> <label> [--retest] is qtprogram's --bench-program. It attaches (resetting the tag), programs or retests one tag, prints each step and the record row, and exits 0 for a written OK row.

Settings live in the platform config directory (settings.json, qtprogram's keys). Downloaded releases go in the platform data directory under firmware/. The record defaults to Documents/Tag Programmer/programmed-tags.csv, as in qtprogram.

Programming path

  • The base is identified with the F6 99 command (Identifying a Base).
  • A base that answers is driven by probe-rs's own ST-LINK driver. One that does not (older field firmware) is driven by tagprobe's field-safe driver.
  • tagprobe::program erases as the image's flash plan says, then programs and verifies in one session. It clears FLASH_SR.PEMPTY on an STM32L432, then starts the image as -g 0x08000000 did.
  • The read-back for Retest uses tagprobe::read_memory.

The probe driver and part are reported on the Programmer and SWD rows, and probe-rs's progress goes to the log pane.

Status

  • Program and Retest have passed on a BitTag (bittag-base-v7, stock driver) with fw-v0.6, through the bench runner: mass erase, program, verify, ALL_PASSED in 13 s (with the final start, stop and erase since removed), and the flash read back matching the image.
  • Retest has passed on an IMUTagNandBmp581 (U375, tag-breakout-base-l432-u375-1v8, stock driver): the flash read back matching fw-v0.6, and ALL_PASSED. Programming a U375 through the engine has not been run yet.
  • Program has passed on a UIUCTag (STM32L432KB) through a field base with the field-safe driver. The tagcore monitor's debug-register reads failed in a burst (status 0x81) while reconnecting after probe-rs, then recovered; tagcore now logs only the first and a count.
  • Retest and Program have passed on the BitTag through a "BitTag Base V5C", the oldest base on the bench, with the field-safe driver.
  • A batch of PresTags has been programmed, tag after tag, in one session.
  • Built into the host packages, and built and package-tested on all three platforms by the release workflow.