mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 16:51:12 -07:00
forgetest: the air-assist offset calibration runs before the heater tools
A queue runs the catalog in registration order among tests with the same prerequisites, and cooling.aa-offset-calibrate followed cooling.flow-verify. A flow-verify trial heats the tube water (a no-flow trial by 17 C on the bench) and the warm slug circulates past the coolant sensors for minutes afterward; the calibration's stationary gate passed 44 s after the trial on image 20260902144848 and the edges read the wave as disagreement. The calibration is registered first now, with the reason beside it, and tests/test_cooling_order.py holds the order. Catalog consequence: the cooling.* implementation hashes move (the suite file changed).
This commit is contained in:
@@ -20,61 +20,9 @@ _COOL_COVERS = [("forgectrl", "src/cool.*"), ("forgectrl", "src/coolfmt.*"), ("f
|
|||||||
("kernel-module-glowforge", "src/pic*")]
|
("kernel-module-glowforge", "src/pic*")]
|
||||||
|
|
||||||
|
|
||||||
@test("cooling.flow-verify", title="Coolant flow check separates flow from no-flow",
|
# Registered before the heater tools: a queue runs the catalog in this
|
||||||
subsystem="cooling", kind="auto", est_min=4,
|
# order, and a heater trial leaves a warm slug circulating past the
|
||||||
covers=_COOL_COVERS, requires=["kernel.latch-locked-idle"],
|
# coolant sensors for minutes, which the tool's edges read as disagreement.
|
||||||
steps=["Coolant loop normal (pump on); the machine idle. The controller is suspended by "
|
|
||||||
"forgectrl for the duration (about 3 minutes)."],
|
|
||||||
description="forgectrl's flow-verify diagnostic: one heater window with the pump on and "
|
|
||||||
"one with it commanded off, judged against the configured threshold. PASS = "
|
|
||||||
"the threshold separates the two readings with the margins forgectrl reports; "
|
|
||||||
"a thin margin is recorded as a warning.")
|
|
||||||
def flow_verify(ctx):
|
|
||||||
fc = ctx.forgectrl
|
|
||||||
ev = ctx.evidence
|
|
||||||
st, body = fc.get("/diag/status")
|
|
||||||
ctx.check(st == 200 and isinstance(body, dict), "GET /diag/status -> %s", st)
|
|
||||||
ctx.check(not body.get("running"), "a diagnostic is already running (%s)", body.get("tool"))
|
|
||||||
st, body = fc.post("/diag/flow-verify")
|
|
||||||
ctx.log("POST /diag/flow-verify -> %s %s", st, body if isinstance(body, dict) else "")
|
|
||||||
ctx.check(st == 202 and isinstance(body, dict) and body.get("started") is True,
|
|
||||||
"could not start flow-verify (%s %s)", st, body)
|
|
||||||
last_phase = None
|
|
||||||
result = None
|
|
||||||
t0 = time.time()
|
|
||||||
try:
|
|
||||||
while time.time() - t0 < 900:
|
|
||||||
ctx.checkpoint()
|
|
||||||
st, d = fc.get("/diag/status")
|
|
||||||
if st == 200 and isinstance(d, dict):
|
|
||||||
if d.get("phase") != last_phase:
|
|
||||||
last_phase = d.get("phase")
|
|
||||||
ctx.log("phase: %s (down %.1f C, up %.1f C)", last_phase, d.get("down_c", 0), d.get("up_c", 0))
|
|
||||||
if not d.get("running") and d.get("result") is not None:
|
|
||||||
result = d.get("result")
|
|
||||||
for line in d.get("log", [])[-12:]:
|
|
||||||
ctx.log(" diag: %s", line)
|
|
||||||
break
|
|
||||||
time.sleep(2)
|
|
||||||
except BaseException:
|
|
||||||
fc.post("/diag/abort")
|
|
||||||
raise
|
|
||||||
ctx.check(result is not None, "flow-verify did not finish within 15 minutes")
|
|
||||||
ev["result"] = result
|
|
||||||
ctx.check("error" not in result, "flow-verify error: %s", result.get("error"))
|
|
||||||
ctx.log("verdict: pass=%s threshold=%s flow_rise=%s noflow_rise=%s margins %s/%s thin=%s",
|
|
||||||
result.get("pass"), result.get("threshold"), result.get("flow_rise"),
|
|
||||||
result.get("noflow_rise"), result.get("margin_flow"), result.get("margin_noflow"),
|
|
||||||
result.get("thin_margin"))
|
|
||||||
ctx.check(result.get("pass") is True, "the threshold does not separate flow from no-flow: %s", result)
|
|
||||||
if result.get("thin_margin"):
|
|
||||||
ctx.log("WARNING: thin margin - run flow-calibrate")
|
|
||||||
ctx.check(fc.wait_idle(120, abort=ctx.aborted), "machine did not return to idle after the diagnostic")
|
|
||||||
|
|
||||||
|
|
||||||
AA_CAL_TIMEOUT_S = 540 # the tool's 420 s settle limit plus its six edges
|
|
||||||
|
|
||||||
|
|
||||||
@test("cooling.aa-offset-calibrate", title="The air-assist ground shift on the coolant readings measures cleanly",
|
@test("cooling.aa-offset-calibrate", title="The air-assist ground shift on the coolant readings measures cleanly",
|
||||||
subsystem="cooling", kind="auto", est_min=6,
|
subsystem="cooling", kind="auto", est_min=6,
|
||||||
covers=_COOL_COVERS, requires=["kernel.latch-locked-idle"],
|
covers=_COOL_COVERS, requires=["kernel.latch-locked-idle"],
|
||||||
@@ -137,6 +85,61 @@ IDLE_REF_TIMEOUT_S = 180 # a previous test's cooldown + spin-down
|
|||||||
COOLDOWN_TIMEOUT_S = 240 # the engine's smoke phase + idle drop + spin-down
|
COOLDOWN_TIMEOUT_S = 240 # the engine's smoke phase + idle drop + spin-down
|
||||||
|
|
||||||
|
|
||||||
|
@test("cooling.flow-verify", title="Coolant flow check separates flow from no-flow",
|
||||||
|
subsystem="cooling", kind="auto", est_min=4,
|
||||||
|
covers=_COOL_COVERS, requires=["kernel.latch-locked-idle"],
|
||||||
|
steps=["Coolant loop normal (pump on); the machine idle. The controller is suspended by "
|
||||||
|
"forgectrl for the duration (about 3 minutes)."],
|
||||||
|
description="forgectrl's flow-verify diagnostic: one heater window with the pump on and "
|
||||||
|
"one with it commanded off, judged against the configured threshold. PASS = "
|
||||||
|
"the threshold separates the two readings with the margins forgectrl reports; "
|
||||||
|
"a thin margin is recorded as a warning.")
|
||||||
|
def flow_verify(ctx):
|
||||||
|
fc = ctx.forgectrl
|
||||||
|
ev = ctx.evidence
|
||||||
|
st, body = fc.get("/diag/status")
|
||||||
|
ctx.check(st == 200 and isinstance(body, dict), "GET /diag/status -> %s", st)
|
||||||
|
ctx.check(not body.get("running"), "a diagnostic is already running (%s)", body.get("tool"))
|
||||||
|
st, body = fc.post("/diag/flow-verify")
|
||||||
|
ctx.log("POST /diag/flow-verify -> %s %s", st, body if isinstance(body, dict) else "")
|
||||||
|
ctx.check(st == 202 and isinstance(body, dict) and body.get("started") is True,
|
||||||
|
"could not start flow-verify (%s %s)", st, body)
|
||||||
|
last_phase = None
|
||||||
|
result = None
|
||||||
|
t0 = time.time()
|
||||||
|
try:
|
||||||
|
while time.time() - t0 < 900:
|
||||||
|
ctx.checkpoint()
|
||||||
|
st, d = fc.get("/diag/status")
|
||||||
|
if st == 200 and isinstance(d, dict):
|
||||||
|
if d.get("phase") != last_phase:
|
||||||
|
last_phase = d.get("phase")
|
||||||
|
ctx.log("phase: %s (down %.1f C, up %.1f C)", last_phase, d.get("down_c", 0), d.get("up_c", 0))
|
||||||
|
if not d.get("running") and d.get("result") is not None:
|
||||||
|
result = d.get("result")
|
||||||
|
for line in d.get("log", [])[-12:]:
|
||||||
|
ctx.log(" diag: %s", line)
|
||||||
|
break
|
||||||
|
time.sleep(2)
|
||||||
|
except BaseException:
|
||||||
|
fc.post("/diag/abort")
|
||||||
|
raise
|
||||||
|
ctx.check(result is not None, "flow-verify did not finish within 15 minutes")
|
||||||
|
ev["result"] = result
|
||||||
|
ctx.check("error" not in result, "flow-verify error: %s", result.get("error"))
|
||||||
|
ctx.log("verdict: pass=%s threshold=%s flow_rise=%s noflow_rise=%s margins %s/%s thin=%s",
|
||||||
|
result.get("pass"), result.get("threshold"), result.get("flow_rise"),
|
||||||
|
result.get("noflow_rise"), result.get("margin_flow"), result.get("margin_noflow"),
|
||||||
|
result.get("thin_margin"))
|
||||||
|
ctx.check(result.get("pass") is True, "the threshold does not separate flow from no-flow: %s", result)
|
||||||
|
if result.get("thin_margin"):
|
||||||
|
ctx.log("WARNING: thin margin - run flow-calibrate")
|
||||||
|
ctx.check(fc.wait_idle(120, abort=ctx.aborted), "machine did not return to idle after the diagnostic")
|
||||||
|
|
||||||
|
|
||||||
|
AA_CAL_TIMEOUT_S = 540 # the tool's 420 s settle limit plus its six edges
|
||||||
|
|
||||||
|
|
||||||
def _duties():
|
def _duties():
|
||||||
return {k: hw.sysfs_int(k) for k in IDLE_DUTY}
|
return {k: hw.sysfs_int(k) for k in IDLE_DUTY}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
"""cooling.aa-offset-calibrate is registered before the heater tools, so
|
||||||
|
a queue runs it first: a heater trial leaves a warm slug circulating past
|
||||||
|
the coolant sensors for minutes, and the tool's edges read it as
|
||||||
|
disagreement."""
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from forgetest import catalog
|
||||||
|
|
||||||
|
|
||||||
|
class CoolingOrderTests(unittest.TestCase):
|
||||||
|
def test_aa_offset_precedes_flow_verify(self):
|
||||||
|
reg = catalog.load_suite()
|
||||||
|
tests = catalog.all_tests(reg)
|
||||||
|
order = catalog.order_by_requires(tests, [t.id for t in tests])
|
||||||
|
self.assertLess(order.index("cooling.aa-offset-calibrate"), order.index("cooling.flow-verify"))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user