Acceptance catalog: the rest of the lid/button/interlock drills, and a pause/resume chain-timing tool

Catalog 34 -> 39. Every remaining bench drill of the lid/button parity work
is now a test, with drills that exercise the same path combined:

  motion.lid-cancel-home   also cancels from a hold - a job paused on the
                           button is ended by the lid, never resumed - so the
                           armed window and the hardware button latch stay in
                           agreement by construction.
  motion.cancel-abort      also asserts what a sender abort must NOT do: it
                           stops where it stopped and never returns home. The
                           return-to-start belongs to the lid policy alone.
  motion.interlock-cancel-park (new)  the interlock loop cancels like the lid,
                           and the lid opened during the return home does not
                           interrupt it.
  motion.lid-policy-hold (new)  the other policy: Door park, no cancel, no
                           return, and a cycle start finishes the move. The
                           setting is restored on the way out.
  laser.pause-resume-live (new)  the button pause/resume during a live cut:
                           emission stops, the latch stays UNLOCKED and the
                           armed window open (a pause is not a cancel), the
                           next press resumes and the job finishes.
  cloud.interlock-abort-park (new)  the same interlock/park pair in cloud mode.
  cloud.pause-cancel-paths (new)  the two non-finishing ends of a print, each
                           from the state the factory ends it in: paused on the
                           button then cancelled by the lid, and cancelled from
                           the app while running.

The shared cancel tail (reason reported, reset without an alarm, position
kept, head back at the job start with the KERNEL counters confirming it) is
now one helper, so every trigger is judged the same way.

scripts/bench/resume_dark_lead.py: samples LASER_ON, FIRE, HV_ENABLE, the
charge-pump watchdog, the button and the doors off the SoC pads at ~2 kHz
through /dev/mem, with motion dated from the kernel step counters, across a
pause and a resume. Levels are taken at idle and everything after is reported
as a change from that baseline, so no polarity assumption is baked in. Dry by
default, with --auto driving the pause and resume through ! / ~ for an
unattended rehearsal; --run live adds the dark lead between FIRE and LASER_ON,
in milliseconds and in millimeters at the job's feed.

Bench registry: argument specs can name a flag (--feed 600) instead of being
positional, and an optional argument with an empty default is left off the
command line entirely.

Host proof: 104 unit tests (20 in the cloud suite - the two new cloud tests
replay the machine's own lid-abort excerpt, with the interlock and the app
cancel substituted for the trigger, and fail for the right reasons), coverage
lint 0 uncovered across 39 tests.
This commit is contained in:
ScottW514
2026-08-17 07:54:47 -04:00
parent 86ce0419e5
commit 0870a835c4
8 changed files with 1105 additions and 45 deletions
+1
View File
@@ -52,6 +52,7 @@ page's takeover does that; from a host, stop them first.
| `build-feeder.sh` | Cross-compiles `feeder.c` the same way. |
| `puls_profile.py` | Decodes factory `.puls` streams (raw or GF1-headered) into velocity/accel profiles: peak speeds, ramp-slope fits, per-move segments, Z cadence. Runs anywhere (stdlib only). Source of the factory-true grblHAL defaults: 700/590 mm/s² accel, 200 mm/s max rate, 28160 Hz travel tick. |
| `cp_watchdog_timing.py` | HV charge-pump watchdog one-shot timing (runs on the board): latches every CHG_PUMP feed pulse in GPIO3's edge detector (pin 24 only, IMR untouched, ICR2 restored on exit) and polls the `!Q` (`charge_pump_alive`) and `!HV_ENABLE` (`hv_enable`) pads through /dev/mem in a tight loop while it commands short local jogs; prints per-run t_w (last pulse → Q fall), Q → HV_ENABLE delay, priming latency and the feed period, with the loop's worst gap as the resolution. Motion only, laser locked, no other Grbl client attached. |
| `resume_dark_lead.py` | Pause/resume safety-chain timing (runs on the board, as root): samples LASER_ON, FIRE, HV_ENABLE, the charge-pump watchdog, the button and the doors straight off the SoC pads through /dev/mem at ~2 kHz, with motion dated from the kernel step counters, across a pause and a resume driven by the operator's button presses. Reports how long HV_ENABLE survives the stream stopping, how fast the chain re-arms on the resume, and - on `--run live` - the dark lead between FIRE going back on and LASER_ON following it, in milliseconds and in millimeters at the job's feed. `--run dry` (default) commands no laser at all and `--auto P,R` drives the pause and resume with `!`/`~` for an unattended rehearsal; `--run live` needs the arm press, eye protection, fire watch, extinguisher and exhaust. GRBL mode, no other Grbl client attached. |
| `bench_m2.py` | Motion-quality bench, runs against the board over TCP:23: bounded round-trip jogs (sanity, max-rate, diagonal) + feed-hold/resume mid-move, reporting peak feed, state transitions, and position drift. |
Data files kept beside the tools: `flow_matrix_results.json` /