diff --git a/docs/BRINGUP.md b/docs/BRINGUP.md index c99b6c4..37bae06 100644 --- a/docs/BRINGUP.md +++ b/docs/BRINGUP.md @@ -151,12 +151,12 @@ core mutex stands in for interrupt masking. `GFSINK` unset = null-sink mode second. 3. Standalone start (bench/debug only - requires forgectrl stopped, since the broker's exclusive hold on `/dev/glowforge` makes any self-open fail EBUSY): - `cd /data && GFSINK=/dev/glowforge grblHAL_glowforge -p 23 -e - /data/EEPROM-glowforge.DAT`. Env knobs: `GFSINK_RATE` (machine tick, default - 28160 Hz = factory travel tick), `GFSINK_DEPTH_MS` (queue depth = feed-hold - latency, default 200). Standalone, the driver opens the device itself and - every takeover runs the `rail_settle_s` off-period; under the broker it - inherits the fd and skips the settle (the rail never dropped). The driver + `cd /data/forgefirm && GFSINK=/dev/glowforge grblHAL_glowforge -p 23 -e + /data/forgefirm/EEPROM-glowforge.DAT`. Env knobs: `GFSINK_RATE` (machine + tick, default 28160 Hz = factory travel tick), `GFSINK_DEPTH_MS` (queue + depth = feed-hold latency, default 200). Standalone, the driver opens the + device itself and every takeover runs the `rail_settle_s` off-period; under + the broker it inherits the fd and skips the settle (the rail never dropped). The driver applies the full analog machine config at init either way (×8 modes, decay 1, motor_lock 0 with every axis in the pulse path and the Z soft limit always on, laser latched, PIC hold currents) and swaps PIC run/hold @@ -184,7 +184,7 @@ runtime `$35=0` the shipped duties stay floored. **Stored `$`-settings beat freshly baked defaults** - after changing `GLOWFORGE_DEFAULTS` values, run `$RST=$` once on the board (settings persist -in the eeprom file in `/data`). +in `/data/forgefirm/EEPROM-glowforge.DAT`). **Protocol-loop pacing is fd-blocking.** `serial_wait()` drains TX then `ppoll()`s the listen/client fds with a state-dependent timeout: idle and alarm diff --git a/forgetest/forgetest/suite/forgectrl.py b/forgetest/forgetest/suite/forgectrl.py index fcdb15e..1d638af 100644 --- a/forgetest/forgetest/suite/forgectrl.py +++ b/forgetest/forgetest/suite/forgectrl.py @@ -1,5 +1,6 @@ """forgectrl.* - the machine-services daemon's API, access control, and panel.""" import json +import os import socket import time @@ -283,8 +284,10 @@ def settings_bounds(ctx): "interval since the previous read, memory used percent), and /cam/status " "answers. In GRBL mode with a live controller, /status also echoes the " "controller's published state file as the grbl block (fresh age, machine " - "state, sender session, laser window and dose model, modal report) and " - "GET /grbl/settings serves the published $$ view.") + "state, sender session, laser window and dose model, modal report), " + "GET /grbl/settings serves the published $$ view, and the controller's " + "settings store is /data/forgefirm/EEPROM-glowforge.DAT with nothing of " + "it at the top of /data.") def panel_serves(ctx): fc = ctx.forgectrl ev = ctx.evidence @@ -350,6 +353,12 @@ def panel_serves(ctx): ev["grbl_settings_status"] = st ctx.check(st == 200 and b"$35=" in (text or b""), "GET /grbl/settings -> %s without the $$ view", st) + # The $-settings persist in the data directory, never loose in /data. + nvs = "/data/forgefirm/EEPROM-glowforge.DAT" + ev["grbl_nvs"] = os.path.isfile(nvs) + ctx.check(os.path.isfile(nvs), "the controller's settings store is not at %s", nvs) + ctx.check(not os.path.exists("/data/EEPROM-glowforge.DAT"), + "a settings store remains at the top of /data") else: ctx.log("no live GRBL controller (%s); grbl block checks skipped", mode)