From 4fbf14195b98af9abd5ecb590a24981df6010b30 Mon Sep 17 00:00:00 2001 From: ScottW514 Date: Thu, 10 Sep 2026 11:59:47 -0400 Subject: [PATCH] Wait for the purge fan's draw, do not read it in the same second The airflow check reads the purge fan's off current with the fan off, and the stand-down that follows commands it back on. The guard that proves the machine was handed back whole read the draw immediately, so what it got back was the off current the check had just measured: on the bench reference, 74 against a 300 floor, with the fan drawing 631 a moment later. The check failed for having worked. The current follows the command; it does not arrive with it. The guard now waits for the draw to reach the floor, up to PURGE_SPINUP_S, the way the controller below it is already waited for, and logs how long it took. It is no weaker: a fan that never reaches its floor still fails the check, and the message now says how long it was given. Pin: forgectrl 0.1.17 (a9e7073, the air assist and the purge in the diagnostic run posture - the reason that check measured an idle fan and wrote a floor from it). --- forgetest/forgetest/suite/commission_dark.py | 30 ++++++++++++++----- .../forgectrl/forgectrl-pin.inc | 4 +-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/forgetest/forgetest/suite/commission_dark.py b/forgetest/forgetest/suite/commission_dark.py index 4609500..8f1a809 100644 --- a/forgetest/forgetest/suite/commission_dark.py +++ b/forgetest/forgetest/suite/commission_dark.py @@ -17,6 +17,10 @@ from .commission import wiz, Restore # noqa: F401 - Restore is re-exported for POLL_S = 1.0 # What the machine's own press prompt says, used when it sends no text. PRESS_TEXT = "The button is lit white. Press it now: the laser fires after your press." +# How long the purge fan's current is given to come up after the airflow +# check switches it back on. The bench reference draws its off current +# (74) for the first seconds and settles near 630. +PURGE_SPINUP_S = 30 DARK_COVERS = [("forgectrl", "src/wizdark.*"), ("forgectrl", "src/wizcalc.*"), ("forgectrl", "src/wiz.*"), ("forgectrl", "src/commission.*"), ("forgectrl", "src/main.c"), ("forgectrl", "src/ui/wizard.*")] @@ -202,13 +206,25 @@ def check_airflow(ctx): # duties. Prove the machine is whole, not just measured. purge_on = ctx.sysfs("head/purge_air") ctx.check(purge_on == "1", "purge air reads %r after the check, expected 1 (on)", purge_on) - gate = ((ctx.forgectrl.get("/cool/status")[1] or {}).get("fan_gates") or {}).get("purge") or {} - ctx.evidence["purge_after"] = {"purge_air": purge_on, "gate": gate} - ctx.log("purge after the check: commanded %s, drawing %s against the %s floor", - purge_on, gate.get("reading"), gate.get("floor")) - ctx.check((gate.get("reading") or 0) >= (gate.get("floor") or 0), - "purge draws %s, under the %s floor the check just wrote: the next job would be held", - gate.get("reading"), gate.get("floor")) + + def purge_gate(): + return ((ctx.forgectrl.get("/cool/status")[1] or {}).get("fan_gates") or {}).get("purge") or {} + + # The check read its off current with the fan off, and the stand-down + # commands it back on. The current follows the command, it does not + # arrive with it: read in the same second and what comes back is the + # off current the check just measured. Wait for the draw the way the + # controller below is waited for. + took = ctx.wait_for(lambda: (purge_gate().get("reading") or 0) >= (purge_gate().get("floor") or 0), + PURGE_SPINUP_S) + gate = purge_gate() + ctx.evidence["purge_after"] = {"purge_air": purge_on, "gate": gate, "took_s": took} + ctx.log("purge after the check: commanded %s, drawing %s against the %s floor (%s)", + purge_on, gate.get("reading"), gate.get("floor"), + "after %.1f s" % took if took is not None else "never reached the floor") + ctx.check(took is not None, + "purge draws %s after %d s, under the %s floor the check just wrote: the next job " + "would be held", gate.get("reading"), PURGE_SPINUP_S, gate.get("floor")) ok = ctx.wait_for(lambda: (ctx.forgectrl.get("/mode")[1] or {}).get("controller") == "running", 60) ctx.check(ok is not None, "the controller did not come back after the check") diff --git a/meta-forgefirm/recipes-forgefirm/forgectrl/forgectrl-pin.inc b/meta-forgefirm/recipes-forgefirm/forgectrl/forgectrl-pin.inc index a5dba8f..c0fd75b 100644 --- a/meta-forgefirm/recipes-forgefirm/forgectrl/forgectrl-pin.inc +++ b/meta-forgefirm/recipes-forgefirm/forgectrl/forgectrl-pin.inc @@ -2,5 +2,5 @@ # only SRCREV and PV here - the image manifest leaves *-pin.inc out of the # layer content hash because the component entry already identifies the # pinned source (forgefirm-image-manifest.bbclass). -SRCREV = "e58aa8a5ad8b91c75896f0c53add8a72095b01d2" -PV = "0.1.16" +SRCREV = "a9e7073b2325c8c9d89d490fe6d067abfac22da5" +PV = "0.1.17"