mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-28 01:01:12 -07:00
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:
+56
-1
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user