mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-27 16:51:12 -07:00
gfhome: derive the service hostname from the effective serial
The gf_hostname override is gone (the forgectrl UI no longer offers it): the hostname is a pure derivation of the serial - base 23 over the factory consonant alphabet - so a gf_serial override re-derives MACHINE.HOSTNAME and the fuse derivation stands otherwise. BRINGUP records the panel rework (units, fuse identity, always-on position) as offline-verified; board deploy and pin bumps held during the firmware-upgrade bench testing.
This commit is contained in:
+35
-3
@@ -215,13 +215,30 @@ cameras as MJPEG over the mainline imx-media pipeline:
|
||||
GF Cloud / GRBL / Diagnostics; ui.c): status page with the
|
||||
controller-mode selector (GRBL active; factory cloud disabled until
|
||||
implemented), the operational dashboard, a scaled lid snapshot +
|
||||
on-demand live stream, and the settings forms for homing method,
|
||||
home-position calibration, the nine cooling tunables, identity
|
||||
overrides, and the session timeout. All
|
||||
on-demand live stream, and the settings forms for display units,
|
||||
homing method, home-position calibration, the nine cooling
|
||||
tunables, identity overrides, and the session timeout. All
|
||||
settings controls disable (with a banner) while the machine is not
|
||||
idle **or a diagnostic is running**. `/?action=stream|snapshot`
|
||||
remain the mjpg-streamer-
|
||||
compatible aliases (lid camera; LightBurn uses the stream one).
|
||||
**Panel conventions (2026-08-08, operator-directed):** the header
|
||||
identifies the machine by its **fuse identity** — the factory
|
||||
hostname derived from the OCOTP serial (HW_OCOTP_MAC0 base-23 over
|
||||
`BCDFGHJKMQRTVWXY2346789`, XXX-YYY; the C implementation matches
|
||||
gfhardware id.py over 200k random serials) — regardless of any
|
||||
cloud identity override; the `gf_hostname` override is REMOVED
|
||||
(the service hostname always derives from whichever serial is in
|
||||
effect — gfhome.py re-derives it from an overridden gf_serial);
|
||||
**units** are a display-only preference (`ui_units` metric |
|
||||
imperial): the backend stores metric, lengths convert mm↔in,
|
||||
absolute temps °C↔°F, temperature DELTAS (the flow-rise family)
|
||||
scale by 1.8 with no offset, and saves post **only fields whose
|
||||
display string changed** (dirty tracking — unit round-trips never
|
||||
masquerade as edits); **position always shows**, counters-only and
|
||||
painted red while unreferenced (the machine moves fine unhomed —
|
||||
relative to wherever it started), normal once anchored; sender
|
||||
hints are unopinionated (no named Grbl clients).
|
||||
- `GET/POST /settings` — the shared machine settings store
|
||||
(/data/forgefirm.conf, validated keys incl. controller_mode and the
|
||||
cool_* cooling tunables,
|
||||
@@ -413,6 +430,21 @@ browser-verified: the click wrote `cool_flow_rise = 14.8` to the
|
||||
conf (cleared after; the compiled default stands until the operator
|
||||
chooses otherwise).
|
||||
|
||||
**Units/identity/position panel rework (2026-08-08, later):
|
||||
OFFLINE-VERIFIED ONLY — board deploy + bump HELD during the
|
||||
operator's firmware-upgrade bench testing.** Verified against the
|
||||
`tools/mock.py` harness in forgectrl (serves the ui.c panel with
|
||||
mock endpoints; POSTs logged): fuse-identity header (XXX-XXX), red
|
||||
unreferenced position (needed the `.kv>span:first-child` selector
|
||||
fix — the old descendant selector out-specified `.b-bad` on nested
|
||||
value spans), imperial placeholders 14.4→25.9 (delta) / 33→91.4
|
||||
(absolute), position 12.34 mm→0.486 in, dirty-save posting exactly
|
||||
one changed key converted back (27 °F→15 °C), diag bands ×1.8 with
|
||||
Apply still posting metric, and a units round-trip leaving nothing
|
||||
dirty. The C serial→hostname derivation matches gfhardware id.py on
|
||||
200k random 32-bit serials (host-side cross-check). Pending on
|
||||
go-ahead: deploy both binaries, live re-check, then SRCREV bumps.
|
||||
|
||||
## Hardware facts bank (measured)
|
||||
|
||||
- SDMA pulse engine: ring size = the `ring_mb` module parameter
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# gfhome - Glowforge web-service homing configuration.
|
||||
# Copied to /data/etc/gfhome.conf on first run; edit the copy.
|
||||
# Machine identity (serial/password) is read from the OCOTP fuses;
|
||||
# gf_serial / gf_password / gf_hostname in /data/forgefirm.conf (the
|
||||
# forgectrl UI, GF Cloud tab) override it.
|
||||
# gf_serial / gf_password in /data/forgefirm.conf (the forgectrl UI,
|
||||
# GF Cloud tab) override it. The service hostname always derives from
|
||||
# whichever serial is in effect.
|
||||
|
||||
[SERVICE]
|
||||
server_url: https://app.glowforge.com
|
||||
|
||||
@@ -14,8 +14,9 @@ homing_mode = gfcloud is set in /data/forgefirm.conf, releasing
|
||||
/dev/glowforge for the duration of the run. It can also be run by hand
|
||||
(with the controller stopped or its homing session active). The same
|
||||
shared config supplies optional identity overrides (gf_serial /
|
||||
gf_password / gf_hostname; the fuse identity is the fallback), managed
|
||||
from the forgectrl UI.
|
||||
gf_password; the fuse identity is the fallback), managed from the
|
||||
forgectrl UI. The service hostname is always derived from whichever
|
||||
serial is in effect - it is never set independently.
|
||||
|
||||
The service ends the sequence silently - there is no completion
|
||||
message - so the run is considered homed once a hunt and at least one
|
||||
@@ -75,11 +76,25 @@ def load_config(path: str) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
def _hostname_for(serial):
|
||||
"""The factory serial -> hostname encoding (base 23 over the
|
||||
consonant alphabet, up to six characters, split XXX-YYY) - the
|
||||
same derivation gfhardware applies to the fuse serial."""
|
||||
enc = ''
|
||||
serial = int(serial)
|
||||
while serial > 0 and len(enc) < 6:
|
||||
enc = 'BCDFGHJKMQRTVWXY2346789'[serial % 23] + enc
|
||||
serial //= 23
|
||||
return '{}-{}'.format(enc[:3], enc[3:])
|
||||
|
||||
|
||||
def apply_identity_overrides():
|
||||
"""Identity overrides from the shared machine config (set in the
|
||||
forgectrl UI): non-empty gf_serial / gf_password / gf_hostname beat
|
||||
the OCOTP fuse identity - Machine.__init__ sets its fuse values
|
||||
with keep_value, so whatever is in the config store first wins."""
|
||||
forgectrl UI): non-empty gf_serial / gf_password beat the OCOTP
|
||||
fuse identity - Machine.__init__ sets its fuse values with
|
||||
keep_value, so whatever is in the config store first wins. The
|
||||
hostname is never overridden independently: it derives from the
|
||||
serial, so a serial override re-derives it."""
|
||||
keys = {}
|
||||
try:
|
||||
with open(MACHINE_CONF) as f:
|
||||
@@ -92,11 +107,18 @@ def apply_identity_overrides():
|
||||
except OSError:
|
||||
return
|
||||
for key, cfg in (('gf_serial', 'MACHINE.SERIAL'),
|
||||
('gf_password', 'MACHINE.PASSWORD'),
|
||||
('gf_hostname', 'MACHINE.HOSTNAME')):
|
||||
('gf_password', 'MACHINE.PASSWORD')):
|
||||
if keys.get(key):
|
||||
set_cfg(cfg, keys[key])
|
||||
logger.info('identity override: %s from %s', cfg, MACHINE_CONF)
|
||||
if keys.get('gf_serial'):
|
||||
try:
|
||||
set_cfg('MACHINE.HOSTNAME', _hostname_for(keys['gf_serial']))
|
||||
logger.info('identity override: MACHINE.HOSTNAME derived '
|
||||
'from gf_serial')
|
||||
except ValueError:
|
||||
logger.warning('gf_serial is not numeric; hostname left '
|
||||
'at the fuse derivation')
|
||||
|
||||
|
||||
def make_machine():
|
||||
|
||||
Reference in New Issue
Block a user