mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 16:51:12 -07:00
forgectrl: implement the camera MJPEG service
Persistent imx-media capture engine (lid/head via the shared video-mux, 409 arbitration, 10 s idle teardown), 1296x972 MJPEG stream via 2x2 Bayer superpixel, full-resolution bilinear snapshots, mjpg-streamer-compatible aliases, sysvinit script; installed in both images. Bench-verified: 3.2 fps stream, clamped 0 during simultaneous motion.
This commit is contained in:
+56
-5
@@ -1,8 +1,9 @@
|
||||
# ForgeFIRM bring-up status & cold-start runbook
|
||||
|
||||
Last updated: **2026-08-02** — milestone 2 (factory-true motion tuning)
|
||||
bench-verified, and the controller promoted to a canonical grblHAL driver
|
||||
repo (**grblHAL-glowforge**) with bench parity re-proven on hardware.
|
||||
Last updated: **2026-08-03** — camera service (forgectrl MJPEG on :8080)
|
||||
implemented and bench-verified, including motion-coexistence (clamped 0
|
||||
while streaming). Previous milestone: factory-true motion tuning +
|
||||
promotion to the canonical grblHAL driver repo (**grblHAL-glowforge**).
|
||||
Read together with `AUDIT_ACTION_PLAN.md` in the project root (sibling of
|
||||
this repo; per-finding status of the 2026-07-03 audit) and
|
||||
`kernel-module-glowforge/UAPI.md` (the pulse-stream feeder contract).
|
||||
@@ -121,6 +122,47 @@ hardware I/O — host testing).
|
||||
(controlled decel) and raises an alarm; TCP disconnects never kill the
|
||||
process (the deadman fd stays held).
|
||||
|
||||
## The camera service (forgectrl, port 8080)
|
||||
|
||||
Source: `meta-forgefirm/recipes-forgefirm/forgectrl/` (recipe-local C,
|
||||
MIT; built by the `forgectrl` recipe, installed in both images with a
|
||||
sysvinit script). One ulfius daemon exposes both OV5648 cameras as MJPEG
|
||||
over the mainline imx-media pipeline:
|
||||
|
||||
- `GET /` — index page with a live view; `/?action=stream|snapshot` are
|
||||
the mjpg-streamer-compatible aliases (lid camera).
|
||||
- `GET /cam/stream?cam=lid|head` — multipart MJPEG at 1296×972 (2×2
|
||||
Bayer-superpixel demosaic, JPEG q75; `FORGECTRL_STREAM_Q` overrides).
|
||||
- `GET /cam/snapshot?cam=lid|head&res=full|half&q=1..100` — single JPEG,
|
||||
default full 2592×1944 (own MIT bilinear demosaic, output verified
|
||||
against the gfhardware reference grab).
|
||||
- `GET /cam/status` — JSON (running/cam/clients/frames/fps).
|
||||
|
||||
Engine model: one worker owns the V4L2 node persistently (media-ctl /
|
||||
v4l2-ctl configure sequences identical to gfhardware/cam.py, factory
|
||||
exposure/gain/WB, software hflip in the demosaic); starts on demand,
|
||||
full teardown after 10 s idle so gfhardware one-shot grabs still work.
|
||||
The cameras share the hardware video-mux, so stream clients pin the
|
||||
selection — requests for the other camera return 409 until they leave.
|
||||
The per-camera lamp (`pic/lid_led` / `head/white_led`) is raised to
|
||||
`FORGECTRL_LAMP` (default 132) while capturing and restored on idle.
|
||||
|
||||
Bench (2026-08-03, on the board): stream 3.2 fps sustained at 1296×972;
|
||||
full-res snapshot 2.4 s warm / 2.7 s cold (cold includes the pipeline
|
||||
bring-up); camera switch works both ways; two parallel clients share the
|
||||
frame rate; idle teardown observed. **Motion coexistence proven**: X
|
||||
round-trip jogs at F1200 with an active stream — producer stats
|
||||
`clamped 0`, max behind 4.5 ms (the daemon runs at nice +5, single
|
||||
core). Run by hand: `/usr/bin/forgectrl >> /data/forgectrl.log 2>&1 &`
|
||||
(kill before scp when redeploying, text-file-busy).
|
||||
|
||||
Not yet done: LightBurn-side camera consumption (needs an operator
|
||||
session — LightBurn desktop takes USB webcams; the mjpg-streamer alias
|
||||
is the standard bridge-style interface, so test whether the overlay can
|
||||
use it directly or needs a relay), lens calibration / bed alignment, and
|
||||
the deferred 5.6 emulator homing-image smoke (the cloud emulator can now
|
||||
be pointed at live snapshots).
|
||||
|
||||
## Hardware facts bank (measured)
|
||||
|
||||
- SDMA pulse engine: ring free = 128 MiB − 32 KiB gap; script effective
|
||||
@@ -293,6 +335,13 @@ hardware I/O — host testing).
|
||||
the dependence is weak — with forced flow ΔT = P/(ṁ·c), which
|
||||
carries no absolute-temperature term — but that is reasoning,
|
||||
not measurement.
|
||||
- **OBSERVED 2026-08-03 (needs triage):** `/data/glowforge.log`
|
||||
carries, from a prior controller run, a passing check (rise
|
||||
11.4 °C) followed by TWO `COOLANT FLOW FAULT` lines (rise
|
||||
16.5 / 15.9 °C vs the 14.4 limit, dT 11.6). Undated (raw
|
||||
stderr log). Either the pump genuinely faltered or this is the
|
||||
warm-baseline false-positive mode above — check the pump and
|
||||
re-run a supervised verification before trusting the loop.
|
||||
|
||||
*(Superseded earlier text kept below for context.)*
|
||||
**Coolant flow verification (first attempt, live-verified both ways).**
|
||||
@@ -347,8 +396,10 @@ hardware I/O — host testing).
|
||||
hall-supervised only.
|
||||
4. **6.5 safety mapping**: door/estop evdev → feed-hold/halt in the
|
||||
backend; underrun → grblHAL alarm; interlock-trip recovery check.
|
||||
5. **6.6 camera service**: persistent MJPEG (ulfius, forgectrl) — also the
|
||||
natural time for the deferred 5.6 emulator smoke (homing images).
|
||||
5. **6.6 camera service: DONE 2026-08-03, bench-verified** (see "The
|
||||
camera service" section above). Remaining camera work: LightBurn
|
||||
consumption test (operator), lens calibration / bed alignment, the
|
||||
deferred 5.6 emulator homing-image smoke.
|
||||
6. **Housekeeping**: ~~pick the controller's remote home~~ **DONE
|
||||
2026-08-02** — the controller is now the canonical driver repo
|
||||
`github.com/ScottW514/grblHAL-glowforge` (+ `ScottW514/core` fork;
|
||||
|
||||
Reference in New Issue
Block a user