mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-28 09:11:11 -07:00
forgetest: the lid lamp idles at forgectrl's lid_lamp_idle; the liveness test masks and restarts
The lid lamp now has a resting policy in forgectrl (lid_lamp_idle, default 236, asserted at start and at every spawn), so the baseline expects it there instead of preserving whatever level a boot left, and forgectrl.settings-bounds proves it: resting at the setting, 256 / -1 / 'bright' refused, a new level applied to the lamp at once, the cleared key back to the default. Clearing a key goes through the query-string form (an empty JSON value reads as no setting). motion.liveness-probe adds the regression the bench needed: with every axis masked (cnc/motor_lock=15, as a bench tool may leave it) forgectrl is restarted and its fresh probe must read MOTION OK on the first try - the probe unmasks the axes itself - and the controller comes up with the mask cleared. Bench 2026-08-16: MOTION OK at p2p 2047/1341 against the 800 threshold, no ladder. The baseline's settle no longer counts 'probe verified, spawn pending' as settled (the post pass ran between the probe's own writes and the controller's init writes and mis-flagged motor_lock/step_freq): it waits for the controller to be running, with a bounded allowance for a respawn backoff.
This commit is contained in:
@@ -9,9 +9,12 @@ restores it after (on every exit path), so a test cannot hand the next one
|
||||
the GRBL controller's init writes. Verified against the value,
|
||||
restored by writing it back.
|
||||
preserved state with no resting policy that a run must hand back as it
|
||||
found it: the lid lamp level, the position counters, the
|
||||
settings map, the controller mode. Captured before the run,
|
||||
compared after, restored where the interface allows.
|
||||
found it: the position counters, the settings map, the
|
||||
controller mode. Captured before the run, compared after,
|
||||
restored where the interface allows.
|
||||
|
||||
The lid lamp is fixed too, at forgectrl's `lid_lamp_idle` setting (unset =
|
||||
236): the daemon asserts it at start and at every controller spawn.
|
||||
|
||||
Everything found off-baseline is a "leftover": logged, kept in the run's
|
||||
evidence, and surfaced on the page. The pre-run pass attributes leftovers
|
||||
@@ -63,7 +66,10 @@ LATCH_BIT = 0x08 # interlock_circuit bit 3: latch locked
|
||||
|
||||
BUTTON_LEDS = ("button_led_1", "button_led_2", "button_led_3")
|
||||
|
||||
PRESERVED_SYSFS = ["pic/lid_led"] # captured before, restored after
|
||||
PRESERVED_SYSFS = [] # sysfs attrs captured before, restored after
|
||||
|
||||
LID_LAMP_ATTR = "pic/lid_led"
|
||||
LID_LAMP_DEFAULT = "236" # forgectrl's lid_lamp_idle default
|
||||
|
||||
BOOT_MAX_AGE_S = 600 # a boot reference is taken only this soon after boot
|
||||
SETTLE_S = 150 # the supervisor's probe + rail-off ladder
|
||||
@@ -165,6 +171,7 @@ class Baseline:
|
||||
t0 = time.time()
|
||||
deadline = t0 + timeout
|
||||
last = seen = heard = None
|
||||
pending_since = None # verified but not running: the spawn follows
|
||||
while time.time() < deadline and not self.abort():
|
||||
try:
|
||||
st, body = self.fc().get("/mode")
|
||||
@@ -181,12 +188,20 @@ class Baseline:
|
||||
if key != seen:
|
||||
seen = key
|
||||
self.log("/mode controller=%s motion=%s" % key)
|
||||
if (body.get("motion") == "verified"
|
||||
or body.get("controller") in ("motion-fault", "standby")):
|
||||
if body.get("controller") == "motion-fault":
|
||||
ctl = body.get("controller")
|
||||
if ctl in ("motion-fault", "standby") or (ctl == "running" and body.get("motion") == "verified"):
|
||||
if ctl == "motion-fault":
|
||||
self.log("WARNING - motion liveness ladder failed, controllers are "
|
||||
"down (motion-fault); retry via POST /mode")
|
||||
return body
|
||||
if body.get("motion") == "verified":
|
||||
# the probe passed; the spawn (or a respawn backoff of up to
|
||||
# 30 s) is in flight - give it a bounded moment
|
||||
pending_since = pending_since or time.time()
|
||||
if time.time() - pending_since > 35:
|
||||
return body
|
||||
else:
|
||||
pending_since = None
|
||||
time.sleep(1.0)
|
||||
self.log("WARNING - forgectrl did not settle within %d s (last /mode: %s)" % (timeout, last))
|
||||
return last
|
||||
@@ -214,6 +229,7 @@ class Baseline:
|
||||
left = []
|
||||
self._forgectrl_side(left)
|
||||
self._kernel_side(left)
|
||||
self._lamp_side(left)
|
||||
self._preserved(left, captured)
|
||||
if left:
|
||||
self.log("%s: %d leftover(s): %s" % (phase, len(left), "; ".join(str(x) for x in left)))
|
||||
@@ -305,6 +321,23 @@ class Baseline:
|
||||
left.append(Leftover("cool", found, "idle/unarmed/no hold",
|
||||
"waited" if w is not None else "failed: still %s" % found))
|
||||
|
||||
def _lamp_side(self, left):
|
||||
"""The lid lamp at forgectrl's idle level (the lid_lamp_idle setting)."""
|
||||
st, body = self.fc_get("/settings")
|
||||
if st != 200 or not isinstance(body, dict):
|
||||
return
|
||||
want = (body.get("lid_lamp_idle") or "").strip() or LID_LAMP_DEFAULT
|
||||
got = hw.sysfs_read(LID_LAMP_ATTR)
|
||||
if got is None or got == want:
|
||||
return
|
||||
try:
|
||||
hw.sysfs_write(LID_LAMP_ATTR, want)
|
||||
back = hw.sysfs_read(LID_LAMP_ATTR)
|
||||
act = "restored" if back == want else "failed: reads %s" % back
|
||||
except OSError as e:
|
||||
act = "failed: %s" % e
|
||||
left.append(Leftover(LID_LAMP_ATTR, got, want, act))
|
||||
|
||||
def _kernel_side(self, left):
|
||||
if hw.sysfs_read("cnc/state") is None:
|
||||
self.log("kernel sysfs not present - kernel-side checks skipped")
|
||||
@@ -414,7 +447,8 @@ class Baseline:
|
||||
for k, v in was.items():
|
||||
if body.get(k) == v:
|
||||
continue
|
||||
st2, b2 = self.fc_post("/settings", data={k: v})
|
||||
st2, b2 = (self.fc_post("/settings", params={k: ""}) if v == ""
|
||||
else self.fc_post("/settings", data={k: v}))
|
||||
left.append(Leftover("settings." + k, body.get(k), v,
|
||||
"restored" if st2 == 200 else "failed: %s %s" % (st2, b2)))
|
||||
|
||||
@@ -514,8 +548,8 @@ def boot_reference(log, data_dir):
|
||||
pass
|
||||
up = uptime_s()
|
||||
if up is None or up > BOOT_MAX_AGE_S:
|
||||
log("baseline: no fresh-boot reference for this boot (uptime %s s > %d s) - "
|
||||
"the lid lamp resting level is unknown; reboot to take one" % (up, BOOT_MAX_AGE_S))
|
||||
log("baseline: no fresh-boot reference for this boot (uptime %s s > %d s); "
|
||||
"power-cycle to take one" % (up, BOOT_MAX_AGE_S))
|
||||
return None
|
||||
bl = Baseline(log)
|
||||
bl.wait_settled()
|
||||
|
||||
Reference in New Issue
Block a user