Lid/button parity: harness cases, acceptance tests, operator and safety docs, BRINGUP item 16

laser_lifecycle_test.py: the button toggle (press = Hold, press = Run;
the arming press is not a pause), lid and interlock cancel mid-job with
the return to the job start and no alarm, and lid_policy=hold.

Acceptance catalog: motion.button-hold-resume, motion.lid-cancel-home
(operator: travel job, lid open -> cancel message, banner, no alarm,
autonomous return, Idle at the start), laser.lid-cancel-mid-fire (live:
emission stops in hardware, cancelled, returned, armed=false, latch
locked, hardware button latch SET). covers name the switch and laser
sources explicitly.

LIGHTBURN.md: what the lid, Stop and the button now do; SAFETY.md: the
door policy and the button as a software layer; BRINGUP.md: item 16
records the whole parity change (host-proven, bench validation pending)
and items 4/12 point at it.
This commit is contained in:
ScottW514
2026-08-16 19:26:11 -04:00
parent c255b265c5
commit c4ea96127c
6 changed files with 474 additions and 22 deletions
+56 -1
View File
@@ -2386,7 +2386,10 @@ dev image (the confirmation campaign's image).**
approaches are near-silent** — belt compliance turns slow-speed
skipping into sub-threshold grinding — so any contact-sensing
scheme must strike fast.
4. **Controller safety mapping — IMPLEMENTED 2026-08-13, bench validation
4. **Controller safety mapping — IMPLEMENTED 2026-08-13; the mid-job
Door hold described here is superseded by the factory-parity policy of
item 16 (lid = cancel + return to the job start; Door hold only with
`lid_policy = hold`) — bench validation
pending** (`grblHAL-glowforge/src/glowforge_switches.c`). The
controller reads EV_SW with `EVIOCGSW` from the protocol thread's
realtime hook (no grab — forgectrl polls the same device) and maps:
@@ -2802,6 +2805,10 @@ dev image (the confirmation campaign's image).**
Resume path, Start-with-lid-open, or the sender's own handling of the
`Door` state, and what the controller reports at each step. Until
then the door change stands as partially validated (item 4).
**2026-08-16:** the default mid-job lid path is now the factory cancel
(item 16), so LightBurn no longer lives in `Door` at all; retest the
symptoms with the item-16 tests, and only chase what remains under
`lid_policy = hold`.
13. **uSDHC pad strength brought to the factory values (DTS change
2026-08-15, bench validation pending — ships with the next full image
flash, per the batched kernel/BSP rule).** Trigger: one
@@ -3001,3 +3008,51 @@ dev image (the confirmation campaign's image).**
the first release runs the full campaign and commits
`releases/v<version>/acceptance.json` - **not yet: no release is
cut.**
16. **Lid / button / interlock parity with the factory firmware — CODE-COMPLETE
and host-verified 2026-08-16, bench validation pending.** Both controller
modes now react to the lid, the interlock loop and the button the way the
factory daemon does (its behavior was decoded and then observed on the
bench machine booted into factory 2.6.0-2228 the same day: lid open
mid-print → `cnc/stop` 5 ms after the edge, immediate return to the job
start with the lid still open, `:cancelled`; app cancel the same path;
button → pause with a 2000-tick laser-off backtrack, resume with a
1950-tick laser-off lead; lid while paused → cancel + park).
- **GRBL mode** (`grblHAL-glowforge/src/glowforge_switches.c`,
`glowforge_laser.c`): the arm wait aborts on lid or interlock (relock,
alarm 3, reason reported; a press with the lid open never arms); the
button is the pause/resume toggle outside the arm wait (feed hold /
cycle start; the arming press is consumed and never a pause press);
lid or interlock mid-job → the core parks the job (planned decel) and
the driver cancels it — armed window closed, reason reported, soft
reset from the parked state (position kept, no alarm; the sender sees
the banner), then a driver-enqueued `G53 G0` back to the position the
job started from with the door hidden and the latch locked; the
`lid_policy` setting (`cancel` default / `hold` = stock door hold)
selects it. Job start = machine position at the Idle → Cycle
transition. Test hook: `GF_SWITCH_FILE` (file-backed EV_SW word for
null-sink builds).
- **Cloud mode** (`python3-gfhardware/gfhardware/machine.py`,
`Glowforge-Utilities` basemachine): interlock joins the lid in every
gate; the switch thread wakes the run loop on the edge (stop within
milliseconds, level read as backstop); the park ignores the lid and
the cancel flag; a hunt ignores the lid; a job refused at start ends
`:cancelled`; the button pauses/resumes a print exactly as the factory
(kernel `resume -2000` / `resume 1950`, `print:paused` / `print:resumed`;
`cloud_pause_backtrack_ticks` / `cloud_resume_lead_ticks` settings);
hunt honors the cancel flag; every job's terminal event is logged.
- **Proof so far (host):** `laser_arm_test` (17 new checks),
`laser_lifecycle_test.py` (button-wait, lid/interlock in the wait,
button toggle, lid/interlock cancel + return to X=0 without alarm,
`lid_policy=hold`), `python3-gfhardware/tests/test_machine_lid_button.py`
(22 cases), gfutilities tests (58), forgetest unit + coverage lint;
forgectrl builds clean with the three new settings and panel cards.
- **Bench validation pending (acceptance catalog):** `laser.arm-wait-lid`,
`motion.button-hold-resume`, `motion.lid-cancel-home`,
`laser.lid-cancel-mid-fire` (live), `cloud.lid-abort` (live),
`cloud.lid-during-button-wait`, `cloud.hunt-lid-open`,
`cloud.pause-resume` (live). Items 4 and 12 above are superseded by
this policy (the mid-job Door hold is no longer the default path);
close them with these tests. Still to observe once on the bench: the
~90 ms HV_ENABLE re-arm gap on a GRBL resume (whether a dark dwell
lead is wanted), the app's rendering of `print:paused`, and a lid open
during the return-to-start motion (should be ignored).
+19 -10
View File
@@ -19,9 +19,9 @@ roughly 45 W. **Jobs sent from LightBurn fire the laser.**
with some materials; sustained flame is not. Keep a fire extinguisher
(CO₂ preferred) within reach and know how you will open the lid and
smother a fire before you start.
- **Stop means stop.** The big button, LightBurn's Stop, and opening the
lid each halt the job. If anything looks wrong, stop first and diagnose
second.
- **Stop means stop.** Opening the lid cancels the job (the beam is cut by
the hardware the same instant); LightBurn's Stop aborts it; the big button
pauses it. If anything looks wrong, stop first and diagnose second.
The laser fires only inside an operator-armed window:
@@ -109,13 +109,22 @@ restart the controller with the head re-parked.)
- **Start** runs the job. Travels run up to 200 mm/s; anything faster
in a layer is clamped by the controller ($110/$111 = 12000 mm/min).
- **Pause** = grbl feed hold: motion parks within ~0.4 s (0.2 s stream
queue + deceleration); Resume continues exactly.
- **Opening the lid (or a Pro's interlock loop) during a job** parks it
the same way and LightBurn shows **Door**; close the lid and press
**Resume** (a cycle start) to continue. At idle, while jogging, or during
homing the lid is yours to open and close freely — the controller does
not enter Door there (the hardware blocks the beam anyway), so a lid
cycle while loading material never leaves LightBurn waiting.
queue + deceleration); Resume continues exactly. **The big button does
the same**: one press while a job runs pauses it (LightBurn shows Hold),
the next press resumes it — the factory's pause/resume, on the machine.
- **Opening the lid (or a Pro's interlock loop) during a job cancels it**,
as the factory firmware does: the head parks with a controlled
deceleration (the hardware cut the beam the instant the lid moved), the
console reports the reason, the job ends for LightBurn (the controller
resets — position is kept, no alarm), and the head returns on its own to
where the job started, lid open or not. Close the lid and start again
from LightBurn; the next job asks for the button, which is also what
re-arms the machine's hardware button latch. The `lid_policy` setting on
the control panel's GRBL tab can select the stock Grbl behavior instead
(Door hold, Resume once closed). At idle, while jogging, or during homing
the lid is yours to open and close freely — the controller does nothing
there (the hardware blocks the beam anyway), so a lid cycle while loading
material never leaves LightBurn waiting.
- **Stop** = soft reset: motion aborts with a controlled deceleration
and grblHAL raises an alarm with **position declared lost** (the
stream queue means up to ~40 mm of in-flight difference). Recovery:
+23 -9
View File
@@ -121,7 +121,7 @@ machine when the lid is closed *and* the SoC has already released its lock.
| SoC stops toggling CHG_PUMP (hang, panic, stop, fault, underrun) | drops within one one-shot period | FIRE is parked by the same paths | next run restarts the feed |
| Button pressed with lid closed and lock released | — | armed (Q1 cleared) | — |
| Button pressed while lid open or lock held | — | stays blocked (SET is dominant) | — |
| Remote-interlock loop opens (Pro) | unchanged | blocked: the kernel drives INTERLOCK_RESET high on the switch edge, setting the interlock latch. Opening the loop by itself only releases the latch's RESET — the board has no direct trip path — so this SoC drive is what makes the interlock a hardware cut (see §3.1); software additionally parks the job on `interlock` | close the loop: the kernel releases INTERLOCK_RESET and the closed loop resets the latch |
| Remote-interlock loop opens (Pro) | unchanged | blocked: the kernel drives INTERLOCK_RESET high on the switch edge, setting the interlock latch. Opening the loop by itself only releases the latch's RESET — the board has no direct trip path — so this SoC drive is what makes the interlock a hardware cut (see §3.1); software additionally cancels (or, with `lid_policy = hold`, parks) the job on `interlock` | close the loop: the kernel releases INTERLOCK_RESET and the closed loop resets the latch |
| Interlock latch already SET | unchanged | blocked | closing the loop clears it |
`hv_enable` (GPIO4_06) is a readback of this chain's own output, not an
@@ -198,14 +198,28 @@ would not allow.
emission witness); a stale or failed verdict relocks in-process.
- **Safety door.** `doors` (lid) and `interlock` (loop open) are the core's
safety-door signal, shown to the core only while it is in a job-time state
(cycle, hold, tool change, door): a running job parks; once the door/loop
closes the controller reports `Door:0` and a cycle start resumes it. While
idle, jogging or homing the signal is hidden — the lid is opened at idle
every time material is loaded and a door seen there would strand the
controller in Door — and it is delivered the moment the core leaves those
states, so a job started with the lid open parks on its first poll. This
is a motion/UX gate; the lid is *also* cut in hardware by the button latch,
and the interlock by the interlock latch (§3.1).
(cycle, hold, tool change, door): a running job parks with a planned
deceleration and — with `lid_policy = cancel`, the default and the factory
firmware's behavior — is then cancelled: the armed window closes, a soft
reset ends the sender's stream (from a fully parked state, so the position
is kept and no alarm is raised), and the head returns to where the job
started with the latch locked, lid open or not. The next job re-arms with a
fresh button press, which is also what clears the hardware button latch
the lid set — the software armed window and the hardware latch cannot
disagree. `lid_policy = hold` keeps the stock door hold (once the door/loop
closes the controller reports `Door:0` and a cycle start resumes it). During
the arm wait either opening cancels the job outright under both policies.
While idle, jogging or homing — and during the return-to-start motion after
a cancel — the signal is hidden: the lid is opened at idle every time
material is loaded and a door seen there would strand the controller in
Door; it is delivered the moment the core leaves those states, so a job
started with the lid open parks (and cancels) on its first poll. This is a
motion/UX gate; the lid is *also* cut in hardware by the button latch, and
the interlock by the interlock latch (§3.1).
- **Button.** Outside the arm wait the button is the job pause/resume toggle
in both controller modes (feed hold / cycle start in GRBL mode; the
factory's stop-backtrack-hold and lead-in resume in cloud mode); a held
button has no further meaning during a job.
- **Head/motion witnesses.** Position counters are not proof of motion (the
step-stream drives are open loop); the head accelerometer is the motion
witness, and `beam_detect_analog` on the head is the live emission witness.