mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-28 09:11:11 -07:00
Let a test declare the controller mode it needs; the runner switches to it
The cloud job tests enter cloud mode and stay there, by design, so a queue (or an operator) that goes on to a motion test reaches it with gfcloud as the controller and no grblHAL process to find: motion.step-timing-under-load failed on exactly that, before it touched the machine. Nothing in the runner put the machine into the mode a test needed; the baseline only preserved the mode it found. A test now declares `mode="grbl"` (or "cloud") in @test. The runner's pre pass, after the leftovers are handled and before the preserved state is captured, switches through POST /mode, waits for the supervisor to settle (controller running, motion verified) and for the Grbl port to answer, and fails the test with the reason when the mode cannot be established. Capturing after the switch means the post pass keeps the mode the test asked for, so the machine changes mode only where the next test asks for it and never between tests of the same mode. The cloud job tests keep managing their own entry (enter_cloud also waits for the service session) and declare nothing. Tagged: every motion.* test but the mode-agnostic liveness probe, the six laser.* tests, cooling.fans-quiet-after-motion, cloud.mode-switch and cloud.gfhome-homing (both start in GRBL mode). controller_pid() now says what mode forgectrl reports when the process is missing. The page shows the declared mode as a badge; the Grbl port probe moved to hw. Proof: tests/test_mode.py (switch_mode against the fake forgectrl, including a refused switch, a controller that never comes up and a port that never opens; the runner end to end from cloud mode, from grbl mode, an undeclared test, and a failed switch). 151 unit tests pass; the coverage lint is clean. No catalog consequence beyond the suite modules' own source hashes: the change is to how a test is started, not to what it proves.
This commit is contained in:
@@ -101,6 +101,7 @@ SETTLE_S = 150 # the supervisor's probe + rail-off ladder
|
||||
CAM_IDLE_S = 20 # camera engine idle stop is 10 s
|
||||
COOL_IDLE_S = 120 # cooldown after motion
|
||||
IDLE_S = 30 # cnc/state back to idle after a job
|
||||
GRBL_PORT_S = 30 # the Grbl port after the supervisor reports grblHAL running
|
||||
|
||||
XY_STEPS_PER_MM = 53.333 # boards/glowforge.h (x8 microstepping)
|
||||
RETURN_MAX_MM = 100.0 # a displaced head is jogged back at most this far
|
||||
@@ -259,6 +260,35 @@ class Baseline:
|
||||
self.log("WARNING - forgectrl did not settle within %d s (last /mode: %s)" % (timeout, last))
|
||||
return last
|
||||
|
||||
# -- the mode a test needs -------------------------------------------
|
||||
def switch_mode(self, want, timeout=SETTLE_S):
|
||||
"""Put the machine in controller mode `want` through the supervisor
|
||||
and wait for it to settle there: the controller running, motion
|
||||
verified, and in GRBL mode the Grbl port answering. Returns (ok,
|
||||
detail). Used by the runner for a test that declares a mode, before
|
||||
the preserved state is captured - so the baseline keeps the mode
|
||||
the test asked for, not the one the run found."""
|
||||
st, mode = self.fc_get("/mode")
|
||||
if st != 200 or not isinstance(mode, dict):
|
||||
return False, "forgectrl not answering (/mode -> %s)" % st
|
||||
if mode.get("mode") == want and mode.get("controller") == "running":
|
||||
self.mode = want
|
||||
return True, "already in %s mode" % want
|
||||
self.log("switching to %s mode (found %s, controller %s)"
|
||||
% (want, mode.get("mode"), mode.get("controller")))
|
||||
st, body = self.fc_post("/mode", data={"controller": want})
|
||||
if st != 200:
|
||||
return False, "POST /mode controller=%s -> %s %s" % (want, st, body)
|
||||
mode = self.wait_settled(timeout=timeout) or {}
|
||||
self.mode = mode.get("mode")
|
||||
if mode.get("mode") != want or mode.get("controller") != "running":
|
||||
return False, "%s mode did not come up: %s" % (want, mode)
|
||||
if want == "grbl":
|
||||
w = self._wait("Grbl port", lambda: hw.grbl_port_open(2), GRBL_PORT_S)
|
||||
if w is None:
|
||||
return False, "grbl controller is running but the Grbl port never opened"
|
||||
return True, "%s mode up" % want
|
||||
|
||||
# -- capture -------------------------------------------------------
|
||||
def capture(self):
|
||||
"""Record the preserved state before a run."""
|
||||
|
||||
Reference in New Issue
Block a user