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
|
GF Cloud / GRBL / Diagnostics; ui.c): status page with the
|
||||||
controller-mode selector (GRBL active; factory cloud disabled until
|
controller-mode selector (GRBL active; factory cloud disabled until
|
||||||
implemented), the operational dashboard, a scaled lid snapshot +
|
implemented), the operational dashboard, a scaled lid snapshot +
|
||||||
on-demand live stream, and the settings forms for homing method,
|
on-demand live stream, and the settings forms for display units,
|
||||||
home-position calibration, the nine cooling tunables, identity
|
homing method, home-position calibration, the nine cooling
|
||||||
overrides, and the session timeout. All
|
tunables, identity overrides, and the session timeout. All
|
||||||
settings controls disable (with a banner) while the machine is not
|
settings controls disable (with a banner) while the machine is not
|
||||||
idle **or a diagnostic is running**. `/?action=stream|snapshot`
|
idle **or a diagnostic is running**. `/?action=stream|snapshot`
|
||||||
remain the mjpg-streamer-
|
remain the mjpg-streamer-
|
||||||
compatible aliases (lid camera; LightBurn uses the stream one).
|
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
|
- `GET/POST /settings` — the shared machine settings store
|
||||||
(/data/forgefirm.conf, validated keys incl. controller_mode and the
|
(/data/forgefirm.conf, validated keys incl. controller_mode and the
|
||||||
cool_* cooling tunables,
|
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
|
conf (cleared after; the compiled default stands until the operator
|
||||||
chooses otherwise).
|
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)
|
## Hardware facts bank (measured)
|
||||||
|
|
||||||
- SDMA pulse engine: ring size = the `ring_mb` module parameter
|
- SDMA pulse engine: ring size = the `ring_mb` module parameter
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
# gfhome - Glowforge web-service homing configuration.
|
# gfhome - Glowforge web-service homing configuration.
|
||||||
# Copied to /data/etc/gfhome.conf on first run; edit the copy.
|
# Copied to /data/etc/gfhome.conf on first run; edit the copy.
|
||||||
# Machine identity (serial/password) is read from the OCOTP fuses;
|
# Machine identity (serial/password) is read from the OCOTP fuses;
|
||||||
# gf_serial / gf_password / gf_hostname in /data/forgefirm.conf (the
|
# gf_serial / gf_password in /data/forgefirm.conf (the forgectrl UI,
|
||||||
# forgectrl UI, GF Cloud tab) override it.
|
# GF Cloud tab) override it. The service hostname always derives from
|
||||||
|
# whichever serial is in effect.
|
||||||
|
|
||||||
[SERVICE]
|
[SERVICE]
|
||||||
server_url: https://app.glowforge.com
|
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
|
/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
|
(with the controller stopped or its homing session active). The same
|
||||||
shared config supplies optional identity overrides (gf_serial /
|
shared config supplies optional identity overrides (gf_serial /
|
||||||
gf_password / gf_hostname; the fuse identity is the fallback), managed
|
gf_password; the fuse identity is the fallback), managed from the
|
||||||
from the forgectrl UI.
|
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
|
The service ends the sequence silently - there is no completion
|
||||||
message - so the run is considered homed once a hunt and at least one
|
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
|
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():
|
def apply_identity_overrides():
|
||||||
"""Identity overrides from the shared machine config (set in the
|
"""Identity overrides from the shared machine config (set in the
|
||||||
forgectrl UI): non-empty gf_serial / gf_password / gf_hostname beat
|
forgectrl UI): non-empty gf_serial / gf_password beat the OCOTP
|
||||||
the OCOTP fuse identity - Machine.__init__ sets its fuse values
|
fuse identity - Machine.__init__ sets its fuse values with
|
||||||
with keep_value, so whatever is in the config store first wins."""
|
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 = {}
|
keys = {}
|
||||||
try:
|
try:
|
||||||
with open(MACHINE_CONF) as f:
|
with open(MACHINE_CONF) as f:
|
||||||
@@ -92,11 +107,18 @@ def apply_identity_overrides():
|
|||||||
except OSError:
|
except OSError:
|
||||||
return
|
return
|
||||||
for key, cfg in (('gf_serial', 'MACHINE.SERIAL'),
|
for key, cfg in (('gf_serial', 'MACHINE.SERIAL'),
|
||||||
('gf_password', 'MACHINE.PASSWORD'),
|
('gf_password', 'MACHINE.PASSWORD')):
|
||||||
('gf_hostname', 'MACHINE.HOSTNAME')):
|
|
||||||
if keys.get(key):
|
if keys.get(key):
|
||||||
set_cfg(cfg, keys[key])
|
set_cfg(cfg, keys[key])
|
||||||
logger.info('identity override: %s from %s', cfg, MACHINE_CONF)
|
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():
|
def make_machine():
|
||||||
|
|||||||
Reference in New Issue
Block a user