docs: cooling GUI + diagnostics; bump forgectrl and grblhal

BRINGUP: the conf-backed cooling tunables, the Diagnostics runner
model and both cooling tools, and the 2026-08-08 bench record
(conf re-read drill, takeover semantics, flow-verify PASS 2:42,
flow-calibrate 8:45 recommending 14.8 vs the hand-derived 14.4).
Pins: forgectrl -> 86ff78b (Machine-tab cooling card + Diagnostics
tab + diag runner), grblhal -> ae85682 (cool_* conf keys re-read
per flood start).
This commit is contained in:
ScottW514
2026-08-08 11:48:15 -04:00
parent 2aac59e0e4
commit b7eb5fdac5
3 changed files with 83 additions and 10 deletions
+81 -8
View File
@@ -212,19 +212,27 @@ pattern as build-glowforge.sh). One ulfius daemon exposes both OV5648
cameras as MJPEG over the mainline imx-media pipeline: cameras as MJPEG over the mainline imx-media pipeline:
- `GET /` — the tabbed machine control panel (Status / Machine / - `GET /` — the tabbed machine control panel (Status / Machine /
GF Cloud / GRBL; ui.c): status page with the controller-mode GF Cloud / GRBL / Diagnostics; ui.c): status page with the
selector (GRBL active; factory cloud disabled until implemented), controller-mode selector (GRBL active; factory cloud disabled until
the operational dashboard, a scaled lid snapshot + on-demand live implemented), the operational dashboard, a scaled lid snapshot +
stream, and the settings forms for homing method, home-position on-demand live stream, and the settings forms for homing method,
calibration, identity overrides, and the session timeout. All home-position calibration, the nine cooling tunables, identity
overrides, and the session timeout. All
settings controls disable (with a banner) while the machine is not settings controls disable (with a banner) while the machine is not
idle. `/?action=stream|snapshot` remain the mjpg-streamer- idle **or a diagnostic is running**. `/?action=stream|snapshot`
remain the mjpg-streamer-
compatible aliases (lid camera; LightBurn uses the stream one). compatible aliases (lid camera; LightBurn uses the stream one).
- `GET/POST /settings` — the shared machine settings store - `GET/POST /settings` — the shared machine settings store
(/data/forgefirm.conf, validated keys incl. controller_mode, (/data/forgefirm.conf, validated keys incl. controller_mode and the
cool_* cooling tunables,
empty-value-clears via query params; gf_password write-only). empty-value-clears via query params; gf_password write-only).
**Writes 409 unless cnc/state is idle** (the controller and homing **Writes 409 unless cnc/state is idle** (the controller and homing
runner read the file mid-run) — live-verified during a jog. runner read the file mid-run) — live-verified during a jog — **and
409 while a diagnostic owns the hardware**.
- `POST /diag/flow-verify`, `POST /diag/flow-calibrate`,
`POST /diag/abort`, `GET /diag/status` — the diagnostics runner
(own section below). `GET /status` carries a `diag` flag for the
UI lock.
- `GET /cam/stream?cam=lid|head` — multipart MJPEG at 1296×972 (2×2 - `GET /cam/stream?cam=lid|head` — multipart MJPEG at 1296×972 (2×2
Bayer-superpixel demosaic, JPEG q75; `FORGECTRL_STREAM_Q` overrides; Bayer-superpixel demosaic, JPEG q75; `FORGECTRL_STREAM_Q` overrides;
`FORGECTRL_STREAM_FPS` caps the frame rate, unset/0 = sensor max). `FORGECTRL_STREAM_FPS` caps the frame rate, unset/0 = sensor max).
@@ -343,6 +351,68 @@ relief valve if future CPU work needs headroom). Default stays sensor
max. Images from 20260807204056 carry forgectrl at the bumped SRCREV max. Images from 20260807204056 carry forgectrl at the bumped SRCREV
(73283b6), so a fresh burn ships the right daemon. (73283b6), so a fresh burn ships the right daemon.
## Diagnostics (forgectrl-owned hardware tests)
The Diagnostics tab runs tools that **take the hardware over**: the
runner (forgectrl diag.c, one slot) stops the `grblhal` service
(launch is gated on cnc idle + no diagnostic), drives the loop
directly through sysfs — the same model as the bench characterization
scripts — and restarts the service on every exit path (completion,
tool error, operator abort via `POST /diag/abort`, safety ceiling).
`/run/forgefirm-diag.active` marks the ownership; forgectrl startup
recovers a stale marker (stand-down + controller start), covering a
daemon crash mid-diagnostic. The laser is untouched throughout (latch
stays locked). While a diagnostic runs: settings POSTs 409, `/status`
reports `diag:true`, and the whole panel locks with a banner. Live
progress (phase, elapsed, both coolant temps, a scrolling log) streams
through `GET /diag/status` on a 2.5 s poll; results persist on the
page until the next run.
Cooling tools (both run at the *configured* duty/window/threshold so
the verdict applies to the check the driver actually runs; trials use
cut-profile chassis fans = the characterization condition; pump-off
windows hard-abort at 48 °C downstream):
- **flow-verify** (~3 min measured): one check with the pump on, one
with it commanded off, judged against `cool_flow_rise`. PASS =
threshold separates the readings; margins under 1.5 °C add a
run-calibration warning.
- **flow-calibrate** (~15-25 min): 3 trials per case, alternating,
with settle gates between; reports both bands and recommends
threshold = (flow max + no-flow min)/2 with an Apply button, or
refuses when the gap is under 3 °C (raise the duty and rerun) —
the per-machine path for replacement coolant or a swapped pump.
**Cooling tunables are conf-backed since 2026-08-08**: the nine
`cool_*` keys (flow_rise, flow_heater_pct, flow_check_s, recheck_s,
confirm_max_s, temp_max, temp_resume, cooldown_s, cooldown_max_s) live
in `/data/forgefirm.conf` (forgectrl Machine tab, validated ranges),
the driver re-reads them at **every flood start** (env `GFCOOL_*` >
conf > compiled default; env stays the bench-override path — it wins
for the process lifetime), and the conf parser now lives in
`glowforge_io.c` shared with homing.
Bench record 2026-08-08 (hot-deployed binaries, all through the HTTP
API): **conf plumbing** — `cool_flow_rise=8` posted, next M8's healthy
check read `limit 8.0` → SUSPECT; key cleared mid-session, next M8
re-read 14.4 and the confirming pass cleared the suspicion (also
proving episode continuity across M9/M8). **Takeover** — during a
running verify: grblHAL process gone, marker present, settings POST
409, second start 409. **flow-verify PASS** in 2:42: flow 11.4
(dT 9.7) / threshold 14.4 / no-flow 17.6 (dT 12.8), margins +3.0 and
+3.2; controller back (fresh pid), marker removed, heater 0, pump on
after. Validation ranges live-checked (rise 0.5 → 400, pct 101 → 400,
confirm 45 → 400). UI browser-verified mid-run: Diagnostics panel
streaming phase/temps/log with the lock banner up, Machine tab
Cooling card showing defaults as placeholders, inputs disabled.
**flow-calibrate COMPLETE in 8:45**: flow band 11.6/12.0/12.0
(max 12.0), no-flow band 17.6/17.7/18.1 (min 17.6), gap 5.7 →
**recommended 14.8 — within 0.4 °C of the hand-derived 14.4** from
the original 60-run matrix (the tool independently reproducing the
ground-truth calibration). Result panel + Apply button
browser-verified: the click wrote `cool_flow_rise = 14.8` to the
conf (cleared after; the compiled default stands until the operator
chooses otherwise).
## Hardware facts bank (measured) ## Hardware facts bank (measured)
- SDMA pulse engine: ring size = the `ring_mb` module parameter - SDMA pulse engine: ring size = the `ring_mb` module parameter
@@ -638,6 +708,9 @@ max. Images from 20260807204056 carry forgectrl at the bumped SRCREV
the FAULT state logs `coolant flow recovered`. Laser the FAULT state logs `coolant flow recovered`. Laser
milestone: safe posture (hold + laser off + forced cooling) milestone: safe posture (hold + laser off + forced cooling)
moves to the SUSPECT edge; FAULT stays the hard fire gate. moves to the SUSPECT edge; FAULT stays the hard fire gate.
Every threshold in this machinery is a `cool_*` conf key since
2026-08-08 (forgectrl Machine tab, re-read per flood start;
verification/calibration tools in the Diagnostics section).
Bench drill (`scripts/bench/flow_confirm_drill.py`, on-board, Bench drill (`scripts/bench/flow_confirm_drill.py`, on-board,
real pump-off transients through the production path, single real pump-off transients through the production path, single
M8 session): verified 11.6/9.4 → pump off SUSPECT 16.4/12.0 → M8 session): verified 11.6/9.4 → pump off SUSPECT 16.4/12.0 →
@@ -9,7 +9,7 @@ PV = "0.1.0"
SRC_URI = "git://github.com/ScottW514/forgectrl.git;protocol=https;branch=main" SRC_URI = "git://github.com/ScottW514/forgectrl.git;protocol=https;branch=main"
# Pinned; bump deliberately after pushing forgectrl changes. # Pinned; bump deliberately after pushing forgectrl changes.
SRCREV = "1ea3a227afd52afb02c6e5c0e8ba0961dc6ad156" SRCREV = "86ff78b52851134d752157e127cebe223973f73f"
S = "${WORKDIR}/git" S = "${WORKDIR}/git"
@@ -11,7 +11,7 @@ PV = "0.1.0"
# upstream). # upstream).
SRC_URI = "gitsm://github.com/ScottW514/grblHAL-glowforge.git;protocol=https;branch=main" SRC_URI = "gitsm://github.com/ScottW514/grblHAL-glowforge.git;protocol=https;branch=main"
# Pinned; bump deliberately after pushing grblHAL-glowforge changes. # Pinned; bump deliberately after pushing grblHAL-glowforge changes.
SRCREV = "22a7695ce60cdf8186e13049856b4a25d78dea2e" SRCREV = "ae8568218ed109362d399e88ae6612894d58a90f"
SRC_URI += "file://grblhal.init" SRC_URI += "file://grblhal.init"