laser_stream_test: rule 18 reads $31 and the floor off the controller

Rule 18 proved a typed $35 is overwritten at the arm and the ladder
renders through the floor key, but took the shipped settings on faith:
the harness mirrors $31 = 0 and the board's 10 % floor as constants. The
catalog's laser.power-floor read them off the machine; it can leave the
catalog once the host does.

- The floor-derived session reads $$ on the fresh controller (no floor
  key: the shipped default) and again after the arm overwrote the typed
  $35. Both reads must show $31 = 0 (the floor, not $31, sets the bottom
  of the S range) and $35 = the board's floor, and that floor must land
  at PWMSAR_FLOOR_MIN (12) or above.
- A set floor key is laser_arm_test.c case J's (12.5 honored, an
  out-of-range key falling back to 10, 0 honored). forgectrl keeps no
  default for laser_floor_density: an absent key is the controller's
  own floor, so there is no second default to compare.

Proof: laser_stream_test passes whole on a null-sink build of the
grblHAL-glowforge working tree under Linux ("$31=0 and $35=10 (PWMSAR
12) fresh and after the arm"). A control session with a floor key of 5
reads back $35 = 5 both times through the same parse, which rule 18
would fail. pyflakes is clean.

Acceptance: none. The harness runs in grblHAL-glowforge's CI.
This commit is contained in:
ScottW514
2026-10-13 17:49:33 -04:00
parent 21f53e4e83
commit d7379d9fc0
+31 -6
View File
@@ -71,7 +71,10 @@ over TCP, then checks the dumps against the kernel feeder contract:
18. the floor is derived, never typed: $35 is loaded from the floor
key at every precompute, so a $35 typed by the sender is
overwritten - the ladder renders through the key's floor, and the
arm report names the model, the floor and the curve in force
arm report names the model, the floor and the curve in force;
read with $$ on the fresh controller and again after the arm, $31
is 0 (the floor, not $31, sets the bottom of the S range) and $35
is the board's floor, landing at PWMSAR_FLOOR_MIN or above
19. the dose curve bends S onto the density that delivers the
commanded light fraction: with the bench-default curve in force a
ladder of S rungs renders the curve's densities (half light lands
@@ -169,6 +172,9 @@ PWM_PERIOD = 127
PWM_MIN_PCT = 10.0
PWM_MIN = int(PWM_PERIOD * PWM_MIN_PCT / 100.0)
RPM_MAX = 1000.0
# The floor lands at this PWMSAR count or above: the level the tube needs
# for a nonzero S to emit at all (rule 18 reads it off the controller).
PWMSAR_FLOOR_MIN = 12
def duty_for(s):
@@ -1163,16 +1169,35 @@ def main():
# The same ladder with a $35=0 typed ahead of it, under the shipped
# density default (no floor key): the arm loads the board's floor and
# every rung renders through it.
floored = run_session("floor-derived", JOB_DENSITY, conf=DENSITY_CONF_FLOORED)
floored = run_session("floor-derived", ["$$"] + JOB_DENSITY + [WAIT_IDLE, "$$"],
conf=DENSITY_CONF_FLOORED)
text = run_session.text
expect_levels = tuple(duty_for(x) for x in LADDER_S)
check_density("floor-derived", floored, expect_levels, DENSITY_PERIOD_TICKS,
DENSITY_MIN_MACHINE_TICKS)
if "laser armed (density, floor %g %%, curve off)" % PWM_MIN_PCT not in run_session.text:
if "laser armed (density, floor %g %%, curve off)" % PWM_MIN_PCT not in text:
fail("[floor-derived] the arm report does not name the derived floor "
"(text: %r)" % run_session.text[-400:])
"(text: %r)" % text[-400:])
# The two $$ reads: the fresh controller's, and the one after the arm
# overwrote the typed $35. The typed line itself is not echoed.
reads = {k: [float(v) for v in re.findall(r"^\$%s=([-\d.]+)" % k, text, re.M)]
for k in ("31", "35")}
if len(reads["31"]) != 2 or len(reads["35"]) != 2:
fail("[floor-derived] expected two $$ reads of $31 and $35, got %s" % reads)
if reads["31"] != [0.0, 0.0]:
fail("[floor-derived] $31 reads %s, not 0: the bottom of the S range is no longer "
"the floor" % reads["31"])
if reads["35"] != [PWM_MIN_PCT, PWM_MIN_PCT]:
fail("[floor-derived] $35 reads %s (fresh, after the arm), expected the board's floor "
"%g both times" % (reads["35"], PWM_MIN_PCT))
counts = int(PWM_PERIOD * reads["35"][0] / 100.0)
if counts < PWMSAR_FLOOR_MIN:
fail("[floor-derived] the floor lands at PWMSAR %d, below the %d the tube needs"
% (counts, PWMSAR_FLOOR_MIN))
print("PASS [floor-derived]: a typed $35=0 is overwritten at the arm; the "
"ladder renders through the %g %% floor key, levels %s"
% (PWM_MIN_PCT, list(expect_levels)))
"ladder renders through the %g %% floor key, levels %s; $31=0 and $35=%g "
"(PWMSAR %d) fresh and after the arm"
% (PWM_MIN_PCT, list(expect_levels), PWM_MIN_PCT, counts))
# --- rule 20: the corner rolloff starves the accel head -------------
# One long M4 line from rest under the curve, at gamma 1 and the