mirror of
https://github.com/openglow-org/forgefirm.git
synced 2026-09-28 09:11:11 -07:00
Laser safety write-up (docs/SAFETY.md + diagram); bump pin: forgectrl a451e7c
docs/SAFETY.md documents the control board's laser safing chain as reverse-engineered and bench-verified - parts, every net with its SoC pin, Linux exposure and polarity, the logic, and the software layers ForgeFIRM stacks on it - with docs/img/safety-chain.svg. Linked from the README. BRINGUP: Next work item 11 records the interlock-latch finding (an open loop never tripped the latch; the kernel now drives INTERLOCK_LATCH_RESET) and the charge-pump watchdog readback, both code-complete and pinned, bench validation on the next image.
This commit is contained in:
@@ -9,6 +9,7 @@ panel, and a standard Grbl interface.
|
|||||||
* [Installation Instructions](https://github.com/ScottW514/forgefirm/blob/master/INSTALL.md)
|
* [Installation Instructions](https://github.com/ScottW514/forgefirm/blob/master/INSTALL.md)
|
||||||
* [Build Instructions](https://github.com/ScottW514/forgefirm/blob/master/BUILD.md)
|
* [Build Instructions](https://github.com/ScottW514/forgefirm/blob/master/BUILD.md)
|
||||||
* [Connecting LightBurn](https://github.com/ScottW514/forgefirm/blob/master/docs/LIGHTBURN.md)
|
* [Connecting LightBurn](https://github.com/ScottW514/forgefirm/blob/master/docs/LIGHTBURN.md)
|
||||||
|
* [How the laser safing works](https://github.com/ScottW514/forgefirm/blob/master/docs/SAFETY.md)
|
||||||
* [Community Support](https://community.openglow.org)
|
* [Community Support](https://community.openglow.org)
|
||||||
|
|
||||||
## What it does
|
## What it does
|
||||||
@@ -67,7 +68,8 @@ running job unattended — keep a fire extinguisher within reach. Read
|
|||||||
[Before you cut — safety](docs/LIGHTBURN.md#before-you-cut--safety-read-this-first)
|
[Before you cut — safety](docs/LIGHTBURN.md#before-you-cut--safety-read-this-first)
|
||||||
before your first job, and the
|
before your first job, and the
|
||||||
[Regulatory and legal](INSTALL.md#regulatory-and-legal) section before
|
[Regulatory and legal](INSTALL.md#regulatory-and-legal) section before
|
||||||
installing.
|
installing. [How the laser safing works](docs/SAFETY.md) describes the hardware
|
||||||
|
safety chain and the software gates ForgeFIRM stacks on it.
|
||||||
|
|
||||||
**A very important warning: this is experimental software. Use of this software
|
**A very important warning: this is experimental software. Use of this software
|
||||||
could seriously maim or kill you or others, and voids your warranty. It is not
|
could seriously maim or kill you or others, and voids your warranty. It is not
|
||||||
|
|||||||
+42
-1
@@ -2091,7 +2091,10 @@ accordingly ("Automatic — AP country, else World").
|
|||||||
Interlock-trip recovery was exercised in commissioning runs without
|
Interlock-trip recovery was exercised in commissioning runs without
|
||||||
one — the chain recovers when the condition clears. `cnc/laser_latch`
|
one — the chain recovers when the condition clears. `cnc/laser_latch`
|
||||||
stays write-only (1 = lock), the driver's arm flow unlocks per job,
|
stays write-only (1 = lock), the driver's arm flow unlocks per job,
|
||||||
and `interlock_latch_reset` remains a readback.
|
and `interlock_latch_reset` remains a readback. **Amended 2026-08-15:**
|
||||||
|
the *interlock* latch never trips at all in ForgeFIRM — see Next work
|
||||||
|
item 11; the "recovery" seen in commissioning was the software
|
||||||
|
safety-door path, not the hardware latch.
|
||||||
**Bench items:** open the lid mid-job (expect `Door` at the sender,
|
**Bench items:** open the lid mid-job (expect `Door` at the sender,
|
||||||
motion parked, resume on close); jog and `$H` with the lid open
|
motion parked, resume on close); jog and `$H` with the lid open
|
||||||
(refused); a Pro with an unjumpered interlock connector (expect the
|
(refused); a Pro with an unjumpered interlock connector (expect the
|
||||||
@@ -2351,3 +2354,41 @@ accordingly ("Automatic — AP country, else World").
|
|||||||
after an underrun cuts at the stale origin unless homing is
|
after an underrun cuts at the stale origin unless homing is
|
||||||
required (GRBL mode permits unhomed cutting; the underrun itself
|
required (GRBL mode permits unhomed cutting; the underrun itself
|
||||||
alarms and unlinks the anchor).
|
alarms and unlinks the anchor).
|
||||||
|
11. **Interlock latch has no hardware trip path in ForgeFIRM (found
|
||||||
|
2026-08-15, bench-verified).** With the interlock connector unjumpered
|
||||||
|
at idle: EV_SW `interlock`=1 (loop open), `interlock_latch`=0 (not
|
||||||
|
tripped), `cnc/interlock_circuit`=13 (b4 INTERLOCK_RESET=0),
|
||||||
|
`interlock_latch_reset`=0. This matches the safing schematic: the
|
||||||
|
interlock latch (U23-2, CD4043B) has RESET = loop-closed and
|
||||||
|
SET = INTERLOCK_RESET (GPIO4_05) — an open loop only *releases* the
|
||||||
|
reset, and nothing in ForgeFIRM drives INTERLOCK_RESET (the driver
|
||||||
|
exposes it as a read-only readback, initialized low; the former
|
||||||
|
`interlock_reset` LED node that let userspace drive it is gone). So on
|
||||||
|
a machine with a real external lockout (Pro), an open loop does **not**
|
||||||
|
cut LASER_ON in hardware; enforcement is the GRBL safety-door hold on
|
||||||
|
switch code 5 and the cloud client's motion gate. Basic/Plus ship the
|
||||||
|
loop jumpered. **Decision + fix needed:** drive INTERLOCK_RESET high
|
||||||
|
whenever the loop is open and hold it until the loop closes, so Q2
|
||||||
|
blocks the LASER_ON gate in hardware (the CD4043B is set-dominant, so
|
||||||
|
the latch stays blocked until the SoC releases SET *and* the loop is
|
||||||
|
closed). **IMPLEMENTED 2026-08-15 (kernel-module, code-complete, bench
|
||||||
|
validation pending; kernel-module 015913b, meta-openglow 92d6e20 DTS +
|
||||||
|
897c175 pin, forgectrl a451e7c docs, all pushed and pins bumped
|
||||||
|
2026-08-15):** `src/cnc_interlock.{c,h}` — an in-kernel input
|
||||||
|
handler on the gpio-keys switch device (no DT change, GPIO stays with
|
||||||
|
gpio-keys) drives INTERLOCK_RESET high while EV_SW code 5 reads open,
|
||||||
|
from probe until the switch device attaches, and if it detaches
|
||||||
|
(unobservable = open); low only while an attached device reports the
|
||||||
|
loop closed. Pin init changed to `GPIOF_OUT_INIT_HIGH`. Proof so far:
|
||||||
|
host test `tests/interlock_test.c` (8 cases, `make -C tests check`,
|
||||||
|
new CI job `host-tests`) green; module cross-compiled clean against
|
||||||
|
the staged 6.12.20-fslc kernel with `KCFLAGS=-Werror`, MODPOST silent.
|
||||||
|
Ships with the next image flash (kernel changes are never hot-swapped);
|
||||||
|
bench re-run of this exact reading then expects `interlock_latch`=1 /
|
||||||
|
`interlock_circuit` b4=1 with the loop open, both clearing after it is
|
||||||
|
closed. Same batch: the charge-pump watchdog readback (`cnc/charge_pump_alive`,
|
||||||
|
`interlock_circuit` b5; GPIO1_08 = inverted one-shot Q, new
|
||||||
|
`charge-pump-alive-gpio` + GPIO_8 pad in the linux-fslc DTS — kernel
|
||||||
|
module and DTB must ship together, the pin is required at probe; DTB
|
||||||
|
compile-checked with cpp+dtc against the staged kernel). Full write-up
|
||||||
|
of the chain: `docs/SAFETY.md` (+ `docs/img/safety-chain.svg`).
|
||||||
|
|||||||
+267
@@ -0,0 +1,267 @@
|
|||||||
|
# Laser safety: how the machine is kept from firing
|
||||||
|
|
||||||
|
This document describes the laser-safing design of a stock Glowforge running
|
||||||
|
ForgeFIRM: the discrete hardware chain on the factory control board, what the
|
||||||
|
i.MX6 can see and drive, and the software layers ForgeFIRM stacks on top. The
|
||||||
|
hardware chain is the safety boundary; software only ever adds gates in front
|
||||||
|
of it and never bypasses it.
|
||||||
|
|
||||||
|
Signal names follow the factory board's nets. `GPIOx_yy` is the i.MX6 GPIO;
|
||||||
|
the Linux name in parentheses is how ForgeFIRM exposes it (device-tree
|
||||||
|
`gpio-keys` switch, or `glowforge.ko` `/sys/glowforge/cnc` attribute).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Principle
|
||||||
|
|
||||||
|
```
|
||||||
|
lid closed (both switches) ─┐
|
||||||
|
SoC alive (charge pump) ──┴─▶ HV_ENABLE ─────────────────▶ PSU: HV supply may run
|
||||||
|
│
|
||||||
|
FIRE (per-tick stream bit) ─┐ ▼
|
||||||
|
button latch cleared ──┼─▶ LASER_ON ──▶ PSU: tube fires only when BOTH are true
|
||||||
|
interlock latch cleared ──┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Two independent hardware outputs go to the laser power supply on J1:
|
||||||
|
|
||||||
|
- **HV_ENABLE (J1_16)** — high only while the lid is closed *and* the SoC is
|
||||||
|
actively retriggering a hardware one-shot ("charge pump"). A hung SoC, a
|
||||||
|
stuck GPIO or an open lid drops it in hardware.
|
||||||
|
- **LASER_ON (J1_12)** — the SoC's per-tick FIRE request, AND-gated behind
|
||||||
|
two hardware latches: the *button latch* (lid state + SoC lock, cleared only
|
||||||
|
by a physical button press) and the *interlock latch* (set by the SoC,
|
||||||
|
cleared only while the remote-interlock loop is closed — see §5 for what
|
||||||
|
that means in ForgeFIRM today).
|
||||||
|
|
||||||
|
The SoC cannot fire the tube by driving one pin. It has to keep the one-shot
|
||||||
|
alive, release its own lock, wait for a human to press the button while the
|
||||||
|
lid is closed, and then stream FIRE bits — and any of those conditions going
|
||||||
|
away kills emission in hardware, not in software.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. The hardware chain
|
||||||
|
|
||||||
|
### 2.1 Parts on the control board
|
||||||
|
|
||||||
|
| Ref | Part | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| U1 | SN74AHC123A dual retriggerable monostable, R ≈ 499 kΩ / C ≈ 1 µF (t_w ≈ 0.45–0.5 s) | Charge-pump watchdog: Q stays high only while CHG_PUMP keeps arriving; times out ~0.5 s after the last pulse |
|
||||||
|
| U5, U6 | SN74AHC14 hex Schmitt-trigger inverters | Level inversion / conditioning for every switch line and SoC readback |
|
||||||
|
| U17 | SN74AHC08 quad 2-input AND | The four gates: DOORS, HV_ENABLE, and the two-stage LASER_ON gate |
|
||||||
|
| U23 | CD4043B quad R/S latch (NOR type, active-high S/R, output enable tied high) | Latch 1 = button latch, latch 2 = interlock latch |
|
||||||
|
| U32 | 74AHC1G32 single 2-input OR | Lid-open OR SoC lock → button latch SET |
|
||||||
|
| U24 | 74AHC1G04 single inverter | E-STOP sense line = ¬HV_ENABLE |
|
||||||
|
| U18 | i.MX6 Solo | The SoC: drives CHG_PUMP, LATCH_RESET, INTERLOCK_RESET, FIRE; reads everything else |
|
||||||
|
|
||||||
|
### 2.2 Inputs
|
||||||
|
|
||||||
|
| Net | Source | Conditioning | SoC pin | Linux exposure | Meaning |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| DOOR_SW1 (L) | J4_13, lid switch pulled to 3.3 V when closed | U5-1 inverts | GPIO4_14 (ball T6) | `gpio-keys` code 0 `door1`, active low → **active = closed** | Left lid switch |
|
||||||
|
| DOOR_SW2 (R) | J4_12 | U5-2 inverts | GPIO1_06 (T3) | code 1 `door2`, active low → **active = closed** | Right lid switch |
|
||||||
|
| DOORS | U17-1 = DOOR_SW1 · DOOR_SW2 | U5-3 inverts | GPIO1_00 (T5) | code 3 `doors`, active low → **active = both closed** | The lid term the chain actually uses |
|
||||||
|
| BUTTON | J5_5, 12 V through the button, 27 kΩ / 8.7 kΩ divider (≈ 2.9 V when pressed) | U5-5 inverts | GPIO4_09 (U6) | code 2 `button`, active low → **active = pressed** | Big front button. Also the RESET input of the button latch |
|
||||||
|
| INTERLOCK_SW | J8, 12 V through the remote-interlock loop, 432 Ω / 165 Ω divider (≈ 3.3 V when the loop is closed); factory-jumpered on Basic/Plus, brought out on Pro | U6-2 inverts | GPIO1_09 (T2) | code 5 `interlock`, active high → **active = loop OPEN** | Also the RESET input of the interlock latch |
|
||||||
|
| CHG_PUMP watchdog Q | U1-1 Q (pin 13): /A = GND, /CLR = 3.3 V, B = CHG_PUMP; each rising edge retriggers | U6-6 inverts | GPIO1_08 (R5) | `cnc/charge_pump_alive` (logical), `interlock_circuit` bit 5 (raw, 0 = alive) | watchdog alive |
|
||||||
|
| Button latch state | U23-1 Q → U5-6 → U6-1 | double inversion | GPIO1_03 (R7) | `cnc/button_latch`, `interlock_circuit` bit 2 | 1 = latch SET (fire blocked / not armed), 0 = armed |
|
||||||
|
| Interlock latch state | U23-2 Q → U6-3 → U6-4 | double inversion | GPIO1_02 (T1) | code 6 `interlock_latch`, active high → **active = latch SET** | 1 = interlock latch blocking |
|
||||||
|
| LASER_ON readback | J1_12 net (U17-3 output) | U6-5 inverts | GPIO1_05 (R4) | `cnc/laser_on`, `laser_on_sampled`, `interlock_circuit` bit 0 (raw, active low) | The gated output — the only software-visible proof of emission permission |
|
||||||
|
| E-STOP | U24 = ¬HV_ENABLE | — | GPIO4_06 (W5) | code 4 `estop`, active high | Sense line, **not** an input: high whenever HV_ENABLE is low (idle), low while HV_ENABLE is alive |
|
||||||
|
| LASER_PGOOD | J1_14 (the supply's HV_OK line) | — | GPIO4_21 (P24) | `cnc/laser_pgood`, `laser_pgood_sampled` (active low) | Read as "power good" from the laser supply; what the supply actually signals on it is not fully characterized |
|
||||||
|
|
||||||
|
### 2.3 SoC outputs into the chain
|
||||||
|
|
||||||
|
| Net | SoC pin | Driven by | Effect |
|
||||||
|
|---|---|---|---|
|
||||||
|
| CHG_PUMP | GPIO3_24 (F22, `charge-pump-gpio`) | `glowforge.ko`: one 0→1→0 pulse at run start, then every 200 ms from a soft hrtimer **only while `state == running`**; forced low on stop, disable, unload and kernel panic | Retriggers U1-1 (t_w ≈ 0.45–0.5 s, so a 200 ms feed holds Q solidly high). No edges → Q falls within ~0.5 s → HV_ENABLE drops |
|
||||||
|
| LATCH_RESET | GPIO1_07 (R3, `latch-reset-gpio`, init HIGH) | `cnc/laser_latch` (1 = lock). Also drives the FIRE line to high impedance while locked | Into U32 with lid-open; SETs the button latch → LASER_ON blocked until the next button press |
|
||||||
|
| INTERLOCK_RESET | GPIO4_05 (P5, `interlock-latch-reset-gpio`, init HIGH) | `glowforge.ko`: high whenever the remote-interlock loop reads open, or until a switch device reporting the loop has attached; low only while an attached device reports it closed (in-kernel input handler on the gpio-keys switch, EV_SW code 5). Read back as `interlock_latch_reset` / `interlock_circuit` bit 4 | SET input of the interlock latch → LASER_ON blocked in hardware while the loop is open |
|
||||||
|
| FIRE (LASER_ENABLE) | GPIO2_30 (E22, `laser-enable-gpio`) | The SDMA script, from bit 4 of each pulse byte; Hi-Z whenever the latch is locked or no run is in flight | One input of the final LASER_ON AND gate |
|
||||||
|
|
||||||
|
Laser *power* (PWM2 on J1_13) is not part of the chain: it sets the tube
|
||||||
|
current setpoint and is not gated. Emission permission is FIRE ∧ chain; the
|
||||||
|
laser-off guarantee rests on FIRE, and the kernel drops FIRE within one tick
|
||||||
|
on end-of-data or underrun.
|
||||||
|
|
||||||
|
### 2.4 Logic
|
||||||
|
|
||||||
|
```
|
||||||
|
DOORS_OK = DOOR_SW1 · DOOR_SW2 (U17-1)
|
||||||
|
WDOG_ALIVE = U1-1 Q, retriggered by every CHG_PUMP rising edge
|
||||||
|
HV_ENABLE = DOORS_OK · WDOG_ALIVE (U17-4) → J1_16
|
||||||
|
E_STOP = ¬HV_ENABLE (U24 inverter) → GPIO4_06
|
||||||
|
|
||||||
|
Button latch (U23-1):
|
||||||
|
SET = ¬DOORS_OK + LATCH_RESET (U32 OR)
|
||||||
|
RESET = BUTTON pressed
|
||||||
|
Q1 = 1 → fire blocked; 0 → armed
|
||||||
|
|
||||||
|
Interlock latch (U23-2):
|
||||||
|
SET = INTERLOCK_RESET (SoC: high while the loop reads open or is unobservable)
|
||||||
|
RESET = interlock loop closed
|
||||||
|
Q2 = 1 → fire blocked
|
||||||
|
|
||||||
|
LASER_ON = FIRE · ¬Q1 · ¬Q2 (U17-2, U17-3) → J1_12
|
||||||
|
```
|
||||||
|
|
||||||
|
The CD4043B is set-dominant: while SET is high the latch cannot be cleared.
|
||||||
|
That ordering is what makes the button meaningful — a press only arms the
|
||||||
|
machine when the lid is closed *and* the SoC has already released its lock.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### 2.5 What each condition does, in hardware alone
|
||||||
|
|
||||||
|
| Event | HV_ENABLE | LASER_ON | Recovery |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Lid opens (either switch) | drops (DOORS_OK low) | drops immediately: ¬DOORS_OK SETs the button latch | close the lid, SoC lock released, **press the button** |
|
||||||
|
| SoC asserts LATCH_RESET (kernel `laser_latch=1`) | unchanged | blocked: button latch SET; FIRE line is also Hi-Z | `laser_latch=0`, then a button press |
|
||||||
|
| SoC stops toggling CHG_PUMP (hang, panic, stop, fault, underrun) | drops within one one-shot period | FIRE is parked by the same paths | next run restarts the feed |
|
||||||
|
| Button pressed with lid closed and lock released | — | armed (Q1 cleared) | — |
|
||||||
|
| Button pressed while lid open or lock held | — | stays blocked (SET is dominant) | — |
|
||||||
|
| Remote-interlock loop opens (Pro) | unchanged | blocked: the kernel drives INTERLOCK_RESET high on the switch edge, setting the interlock latch. Opening the loop by itself only releases the latch's RESET — the board has no direct trip path — so this SoC drive is what makes the interlock a hardware cut (see §3.1); software additionally parks the job on `interlock` | close the loop: the kernel releases INTERLOCK_RESET and the closed loop resets the latch |
|
||||||
|
| Interlock latch already SET | unchanged | blocked | closing the loop clears it |
|
||||||
|
|
||||||
|
Note the *E-STOP* line: despite the factory name it is an output of this
|
||||||
|
chain — the inverse of HV_ENABLE. It reads active on a healthy idle machine and
|
||||||
|
drops for the whole duration of any kernel run, the window in which the charge
|
||||||
|
pump is fed and HV_ENABLE is alive. Nothing in ForgeFIRM gates on it unless a
|
||||||
|
machine settings key opts in for a retrofitted circuit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Software layers on top
|
||||||
|
|
||||||
|
Every layer below sits *in front of* the chain: it can only withhold FIRE, hold
|
||||||
|
the lock, or starve the charge pump. None can produce emission the hardware
|
||||||
|
would not allow.
|
||||||
|
|
||||||
|
### 3.1 `glowforge.ko` (kernel)
|
||||||
|
|
||||||
|
- **Laser latch** (`cnc/laser_latch`, write-only): 1 = lock. Locking drives
|
||||||
|
LATCH_RESET high (button latch SETs) *and* puts the FIRE line in high
|
||||||
|
impedance so the SDMA stream physically cannot raise it. **Locked by
|
||||||
|
default; every close of `/dev/glowforge` relocks.** Unlocking never restores
|
||||||
|
the FIRE drive while a run or ramp is in flight — only run start and the
|
||||||
|
resume waypoint do, and only if the latch is unlocked at that moment.
|
||||||
|
- **Charge pump only while running.** The 200 ms retrigger starts with the
|
||||||
|
run and the callback returns without rearming as soon as the state leaves
|
||||||
|
`running` (stop, halt, fault, underrun). Stop/disable/unload pin sets force
|
||||||
|
CHG_PUMP low.
|
||||||
|
- **FIRE backstop.** At end-of-data and on underrun the SDMA script drops FIRE
|
||||||
|
and the step lines within one tick; the FIRE line is parked Hi-Z at every
|
||||||
|
run end and only a latch unlock plus a new run restores it.
|
||||||
|
- **Interlock latch drive.** The board's interlock latch is reset by a closed
|
||||||
|
loop but can only be *set* by the SoC's INTERLOCK_RESET line; an open loop
|
||||||
|
alone does not trip it. The driver owns that line through an in-kernel
|
||||||
|
input handler on the gpio-keys switch device: it is high (latch set,
|
||||||
|
LASER_ON blocked) from probe until the switch device attaches, whenever the
|
||||||
|
loop reads open, and again if the switch device goes away — an
|
||||||
|
unobservable loop counts as open. Only an attached device reporting the
|
||||||
|
loop closed releases it, and the set-dominant latch then clears through
|
||||||
|
its own RESET. The policy is host-tested (`tests/interlock_test.c`).
|
||||||
|
- **Dead man's switch.** A feeder holds `/dev/glowforge` open with `flock
|
||||||
|
LOCK_EX`; if that fd closes while a program runs, the driver performs an
|
||||||
|
emergency stop, puts the head in its safe state and de-energizes the
|
||||||
|
thermal-loop heat sources.
|
||||||
|
- **Panic handler.** On a kernel panic the driver stops the EPIT and drives
|
||||||
|
the pins safe directly: FIRE Hi-Z, CHG_PUMP low, LATCH_RESET asserted,
|
||||||
|
steppers de-energized — because SDMA and EPIT would otherwise keep playing
|
||||||
|
the ring with no kernel alive.
|
||||||
|
- **Readbacks** (`interlock_circuit` bits 0–5, `laser_on[_sampled]`,
|
||||||
|
`laser_pgood[_sampled]`, `button_latch`, `charge_pump_alive`,
|
||||||
|
`interlock_latch_reset`) are
|
||||||
|
monitoring only; the driver enforces nothing from them. Bits 1, 3 and 4 are
|
||||||
|
driven outputs read back from the data register — bit 3 says what the
|
||||||
|
driver *commanded*, `laser_on` says what the chain *did*.
|
||||||
|
|
||||||
|
### 3.2 grblHAL controller (`grblHAL-glowforge`)
|
||||||
|
|
||||||
|
- **Operator-armed window.** The first laser-on of a job runs the arm flow on
|
||||||
|
the protocol thread: coolant fire verdict must be OK, a head must be present
|
||||||
|
(lens, air assist and beam detector live on it and the chain has no head
|
||||||
|
term), fans go to the run profile, the latch is unlocked, and the controller
|
||||||
|
then waits for the physical button (`laser_button_timeout_s`, default 300 s;
|
||||||
|
a timeout or soft reset relocks and aborts). The hardware button latch is
|
||||||
|
what the press clears — the software wait exists so the job does not start
|
||||||
|
streaming FIRE bits into a blocked gate.
|
||||||
|
- **Disarm.** After `laser_disarm_s` (default 60 s) of no laser use, or on
|
||||||
|
program end/abort, the controller relocks the latch, turns the button LED
|
||||||
|
off and stands the cooling profile down. The relock waits for the kernel to
|
||||||
|
finish the queue tail so a controlled stop can never leave FIRE driven.
|
||||||
|
- **Coolant fire gates.** The armed window requires a fresh `fire_ok` verdict
|
||||||
|
from the cooling engine (flow verification, over-temperature, lid-IR
|
||||||
|
emission witness); a stale or failed verdict relocks in-process.
|
||||||
|
- **Safety door.** `doors` (lid) and `interlock` (loop open) are the core's
|
||||||
|
safety-door signal: a running job parks and resumes on close. This is a
|
||||||
|
motion/UX gate; the lid is *also* cut in hardware by the button latch.
|
||||||
|
- **Head/motion witnesses.** Position counters are not proof of motion (the
|
||||||
|
step-stream drives are open loop); the head accelerometer is the motion
|
||||||
|
witness, and `beam_detect_analog` on the head is the live emission witness.
|
||||||
|
|
||||||
|
### 3.3 forgectrl (machine services)
|
||||||
|
|
||||||
|
- Holds `/dev/glowforge` for its lifetime (pulse-device broker) so controller
|
||||||
|
handovers never close the device, and **relocks the latch (`cnc/stop` +
|
||||||
|
`cnc/laser_latch=1`) on every transition out of a running child** —
|
||||||
|
unexpected death, mode switch, restart.
|
||||||
|
- The **cooling engine** is the sole owner of the thermal hardware and
|
||||||
|
publishes the fire verdict the controllers enforce; on a FIRE-class verdict
|
||||||
|
it writes `cnc/stop` + `cnc/laser_latch=1` itself.
|
||||||
|
- The **motion-liveness gate** refuses to hand a controller a machine whose
|
||||||
|
drivers may have wedged (counters running, motors dead) — a laser-safety
|
||||||
|
corollary of "counters are not motion".
|
||||||
|
- `/status` reports the switch map and `laser_locked` (`interlock_circuit`
|
||||||
|
bit 3) for the panel and telemetry; nothing in forgectrl reads the Grbl
|
||||||
|
socket for machine state.
|
||||||
|
|
||||||
|
### 3.4 Cloud mode
|
||||||
|
|
||||||
|
The factory-experience client runs behind the same kernel latch, charge-pump,
|
||||||
|
backstop and dead-man rules; the precomputed pulse file it loads is subject to
|
||||||
|
the same FIRE gating as the live stream.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. What is proven, and how
|
||||||
|
|
||||||
|
Verified on the bench with a probe on the PSU-connector LASER_ON pin and the
|
||||||
|
kernel readbacks (the runbook `BRINGUP.md` holds the drill records):
|
||||||
|
|
||||||
|
- Latch **locked**: 40,000 streamed FIRE bits → PSU pin flat, `laser_enable`
|
||||||
|
0 — the lock severs the FIRE drive entirely.
|
||||||
|
- Latch **unlocked, chain unarmed** (no button press): `laser_enable` 1
|
||||||
|
mid-window, PSU pin flat, `laser_on` 0 — the AND gate holds.
|
||||||
|
- FIRE drop at end-of-data and at true underrun: ≤ 1 tick, both termination
|
||||||
|
paths.
|
||||||
|
- A latch unlock inside an acceleration ramp does not restore the FIRE drive
|
||||||
|
for the in-flight run; a locked latch survives a stop + resume replay.
|
||||||
|
- Armed kill mid-FIRE: emission tail equals the ring in-flight only
|
||||||
|
(15–171 ms), the latch relocks, the burn line ends abruptly.
|
||||||
|
- Switch bits 0–3, 5, 6 verified against physical state; bit 4 (`estop`)
|
||||||
|
characterized live: high at idle, low through any run.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Not yet established
|
||||||
|
|
||||||
|
Present gaps in the hardware picture. None of them changes the safety
|
||||||
|
argument (every gap is on the readback/sense side or is a "which part" question),
|
||||||
|
but each is worth closing:
|
||||||
|
|
||||||
|
- **`estop` toggles seen inside motion windows.** With the one-shot's
|
||||||
|
measured R/C (≈ 499 kΩ, ≈ 1 µF → t_w ≈ 0.45–0.5 s against a 200 ms feed)
|
||||||
|
the one-shot cannot gap during a healthy run, so those toggles are most
|
||||||
|
likely run boundaries (homing and jogs are several short runs) or a feed
|
||||||
|
late by more than ~250 ms; `charge_pump_alive` sampled through a run
|
||||||
|
settles it.
|
||||||
|
- **Interlock latch drive: bench validation pending.** The board itself has
|
||||||
|
no trip path from the loop to the latch's SET input (bench-verified with the
|
||||||
|
connector unjumpered: `interlock` open, `interlock_latch` clear while
|
||||||
|
INTERLOCK_RESET was held low). The kernel drive described in §3.1 closes
|
||||||
|
that gap; its host test is green and it ships with the next image, where the
|
||||||
|
expected reading with the loop open is `interlock_latch` set,
|
||||||
|
`interlock_circuit` bit 4 set, clearing after the loop is closed.
|
||||||
|
- **`laser_pgood` (HV_OK, J1_14) semantics** are not fully characterized.
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1500 860" width="1500" height="860" font-family="Segoe UI, Helvetica, Arial, sans-serif" font-size="13">
|
||||||
|
<title>Glowforge laser safing chain as run by ForgeFIRM</title>
|
||||||
|
<desc>Lid switches, the charge-pump watchdog, the button latch, the interlock latch and the FIRE line combine on the factory control board into HV_ENABLE and LASER_ON for the laser power supply; the SoC drives four lines and reads back the rest.</desc>
|
||||||
|
<defs>
|
||||||
|
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto-start-reverse">
|
||||||
|
<path d="M0 0 L10 5 L0 10 z" fill="#222"/>
|
||||||
|
</marker>
|
||||||
|
<style>
|
||||||
|
.wire { fill: none; stroke: #222; stroke-width: 2; }
|
||||||
|
.wire-out { fill: none; stroke: #222; stroke-width: 2; marker-end: url(#arr); }
|
||||||
|
.dot { fill: #222; }
|
||||||
|
.gate { fill: #ffffff; stroke: #222; stroke-width: 1.6; }
|
||||||
|
.gate-l { font-weight: 700; font-size: 13px; text-anchor: middle; fill: #111; }
|
||||||
|
.gate-s { font-size: 10px; text-anchor: middle; fill: #555; }
|
||||||
|
.pin { font-size: 10px; fill: #444; }
|
||||||
|
.in-tag { fill: #e9ebee; stroke: #6b7280; stroke-width: 1.2; }
|
||||||
|
.out-tag { fill: #dbeafe; stroke: #2563eb; stroke-width: 1.2; }
|
||||||
|
.rb-tag { fill: #fef3c7; stroke: #d97706; stroke-width: 1.2; }
|
||||||
|
.psu-tag { fill: #fee2e2; stroke: #dc2626; stroke-width: 1.2; }
|
||||||
|
.tag-t { font-size: 12px; font-weight: 700; fill: #111; }
|
||||||
|
.tag-s { font-size: 10px; fill: #444; }
|
||||||
|
.region { fill: #f6f7f9; stroke: #b8bec8; stroke-width: 1; stroke-dasharray: 5 4; }
|
||||||
|
.region-l { font-size: 12px; font-weight: 700; fill: #4b5563; letter-spacing: 0.4px; }
|
||||||
|
.net { font-size: 11px; font-style: italic; fill: #333; }
|
||||||
|
.note { font-size: 12px; fill: #222; }
|
||||||
|
.title { font-size: 18px; font-weight: 700; fill: #111; }
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<rect width="1500" height="860" fill="#ffffff"/>
|
||||||
|
<text x="20" y="30" class="title">Glowforge control board — laser safing chain, as run by ForgeFIRM</text>
|
||||||
|
|
||||||
|
<!-- regions -->
|
||||||
|
<rect x="20" y="52" width="212" height="640" class="region"/>
|
||||||
|
<text x="30" y="70" class="region-l">PHYSICAL INPUTS</text>
|
||||||
|
<rect x="250" y="52" width="1010" height="640" class="region"/>
|
||||||
|
<text x="260" y="70" class="region-l">CONTROL-BOARD SAFING LOGIC (hardware)</text>
|
||||||
|
<rect x="1290" y="52" width="192" height="640" class="region"/>
|
||||||
|
<text x="1300" y="70" class="region-l">LASER POWER SUPPLY (J1)</text>
|
||||||
|
|
||||||
|
<!-- ===================== Row A: lid switches ===================== -->
|
||||||
|
<rect x="40" y="90" width="172" height="28" rx="5" class="in-tag"/>
|
||||||
|
<text x="50" y="109" class="tag-t">LID_SW1</text><text x="122" y="109" class="tag-s">J4_13 · closed = 1</text>
|
||||||
|
<rect x="40" y="130" width="172" height="28" rx="5" class="in-tag"/>
|
||||||
|
<text x="50" y="149" class="tag-t">LID_SW2</text><text x="122" y="149" class="tag-s">J4_12 · closed = 1</text>
|
||||||
|
<path class="wire" d="M212 104 H330"/>
|
||||||
|
<path class="wire" d="M212 144 H310 V116 H330"/>
|
||||||
|
<rect x="330" y="84" width="64" height="44" rx="6" class="gate"/>
|
||||||
|
<text x="362" y="103" class="gate-l">AND</text><text x="362" y="118" class="gate-s">U17-1</text>
|
||||||
|
<path class="wire" d="M394 106 H740 V136 H760"/>
|
||||||
|
<circle cx="470" cy="106" r="3.5" class="dot"/>
|
||||||
|
<text x="480" y="98" class="net">DOORS_OK (both lid switches closed)</text>
|
||||||
|
<!-- doors readback -->
|
||||||
|
<path class="wire" d="M560 106 V126"/>
|
||||||
|
<rect x="500" y="126" width="150" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="508" y="142" class="tag-t">doors</text><text x="552" y="142" class="tag-s">EV_SW 3 · GPIO1_00</text>
|
||||||
|
|
||||||
|
<!-- ===================== Row B: charge-pump watchdog / HV_ENABLE ===================== -->
|
||||||
|
<rect x="262" y="176" width="190" height="40" rx="5" class="out-tag"/>
|
||||||
|
<text x="270" y="192" class="tag-t">CHG_PUMP</text><text x="352" y="192" class="tag-s">GPIO3_24</text>
|
||||||
|
<text x="270" y="207" class="tag-s">200 ms pulses, only while running</text>
|
||||||
|
<path class="wire" d="M452 196 H500"/>
|
||||||
|
<rect x="500" y="174" width="90" height="44" rx="6" class="gate"/>
|
||||||
|
<text x="545" y="192" class="gate-l">one-shot</text><text x="545" y="207" class="gate-s">U1-1 · t_w ≈ 0.45 s</text>
|
||||||
|
<path class="wire" d="M590 196 H620 V156 H760"/>
|
||||||
|
<circle cx="620" cy="196" r="3.5" class="dot"/>
|
||||||
|
<text x="630" y="190" class="net">WDOG_ALIVE</text>
|
||||||
|
<!-- charge_pump_alive readback -->
|
||||||
|
<path class="wire" d="M620 196 V222"/>
|
||||||
|
<rect x="540" y="222" width="212" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="548" y="238" class="tag-t">charge_pump_alive</text><text x="672" y="238" class="tag-s">GPIO1_08 (¬Q)</text>
|
||||||
|
<!-- AND U17-4 -->
|
||||||
|
<rect x="760" y="124" width="64" height="44" rx="6" class="gate"/>
|
||||||
|
<text x="792" y="143" class="gate-l">AND</text><text x="792" y="158" class="gate-s">U17-4</text>
|
||||||
|
<path class="wire-out" d="M824 146 H1300"/>
|
||||||
|
<circle cx="880" cy="146" r="3.5" class="dot"/>
|
||||||
|
<text x="900" y="166" class="net">HV_ENABLE</text>
|
||||||
|
<!-- U24 inverter -> estop -->
|
||||||
|
<path class="wire" d="M880 146 V88 H930"/>
|
||||||
|
<rect x="930" y="70" width="64" height="36" rx="6" class="gate"/>
|
||||||
|
<text x="962" y="86" class="gate-l">NOT</text><text x="962" y="99" class="gate-s">U24</text>
|
||||||
|
<path class="wire" d="M994 88 H1010"/>
|
||||||
|
<rect x="1010" y="76" width="236" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="1018" y="92" class="tag-t">estop</text><text x="1060" y="92" class="tag-s">EV_SW 4 · GPIO4_06 · = ¬HV_ENABLE</text>
|
||||||
|
<!-- PSU tag HV_ENABLE -->
|
||||||
|
<rect x="1300" y="132" width="172" height="28" rx="5" class="psu-tag"/>
|
||||||
|
<text x="1308" y="151" class="tag-t">J1_16</text><text x="1354" y="151" class="tag-s">HV_ENABLE</text>
|
||||||
|
<text x="1300" y="180" class="note">HV runs only while this</text>
|
||||||
|
<text x="1300" y="196" class="note">line is alive (pulsed).</text>
|
||||||
|
|
||||||
|
<!-- ===================== Row C: button latch ===================== -->
|
||||||
|
<!-- ¬DOORS_OK -->
|
||||||
|
<path class="wire" d="M470 106 V190 A6 6 0 0 1 470 202 V288 H500"/>
|
||||||
|
<rect x="500" y="270" width="64" height="36" rx="6" class="gate"/>
|
||||||
|
<text x="532" y="286" class="gate-l">NOT</text><text x="532" y="299" class="gate-s">U5-4</text>
|
||||||
|
<path class="wire" d="M564 288 H584 V280 H600"/>
|
||||||
|
<text x="565" y="266" class="net">lid open</text>
|
||||||
|
<!-- LATCH_RESET -->
|
||||||
|
<rect x="262" y="296" width="190" height="40" rx="5" class="out-tag"/>
|
||||||
|
<text x="270" y="312" class="tag-t">LATCH_RESET</text><text x="366" y="312" class="tag-s">GPIO1_07</text>
|
||||||
|
<text x="270" y="327" class="tag-s">cnc/laser_latch: 1 = lock (FIRE also Hi-Z)</text>
|
||||||
|
<path class="wire" d="M452 316 H584 V300 H600"/>
|
||||||
|
<!-- OR U32 -->
|
||||||
|
<rect x="600" y="268" width="64" height="44" rx="6" class="gate"/>
|
||||||
|
<text x="632" y="287" class="gate-l">OR</text><text x="632" y="302" class="gate-s">U32</text>
|
||||||
|
<path class="wire" d="M664 290 H720"/>
|
||||||
|
<!-- button latch -->
|
||||||
|
<rect x="720" y="272" width="124" height="76" rx="6" class="gate"/>
|
||||||
|
<text x="782" y="292" class="gate-l">Button latch</text>
|
||||||
|
<text x="782" y="306" class="gate-s">U23-1 · CD4043B</text>
|
||||||
|
<text x="782" y="320" class="gate-s">set-dominant</text>
|
||||||
|
<text x="726" y="294" class="pin">S</text>
|
||||||
|
<text x="726" y="336" class="pin">R</text>
|
||||||
|
<text x="832" y="314" class="pin">Q</text>
|
||||||
|
<!-- BUTTON -->
|
||||||
|
<rect x="40" y="332" width="172" height="28" rx="5" class="in-tag"/>
|
||||||
|
<text x="50" y="351" class="tag-t">BUTTON</text><text x="118" y="351" class="tag-s">J5 · pressed = 1</text>
|
||||||
|
<path class="wire" d="M212 346 H700 V332 H720"/>
|
||||||
|
<path class="wire" d="M330 346 V356"/>
|
||||||
|
<rect x="270" y="356" width="150" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="278" y="372" class="tag-t">button</text><text x="326" y="372" class="tag-s">EV_SW 2 · GPIO4_09</text>
|
||||||
|
<!-- Q1 -> NOT -> AND2 -->
|
||||||
|
<path class="wire" d="M844 311 H890"/>
|
||||||
|
<circle cx="868" cy="311" r="3.5" class="dot"/>
|
||||||
|
<rect x="890" y="293" width="64" height="36" rx="6" class="gate"/>
|
||||||
|
<text x="922" y="309" class="gate-l">NOT</text><text x="922" y="322" class="gate-s">U5-6</text>
|
||||||
|
<path class="wire" d="M954 311 H975 V380 H1000"/>
|
||||||
|
<text x="958" y="345" class="net">¬Q1</text>
|
||||||
|
<!-- button_latch readback -->
|
||||||
|
<path class="wire" d="M868 311 V262"/>
|
||||||
|
<rect x="770" y="238" width="222" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="778" y="254" class="tag-t">button_latch</text><text x="864" y="254" class="tag-s">GPIO1_03 · = Q1 · 1 = set</text>
|
||||||
|
|
||||||
|
<!-- ===================== Row D: interlock latch ===================== -->
|
||||||
|
<rect x="262" y="462" width="190" height="40" rx="5" class="out-tag"/>
|
||||||
|
<text x="270" y="478" class="tag-t">INTERLOCK_RESET</text><text x="386" y="478" class="tag-s">GPIO4_05</text>
|
||||||
|
<text x="270" y="493" class="tag-s">1 while loop open or unobserved</text>
|
||||||
|
<path class="wire" d="M452 476 H720"/>
|
||||||
|
<rect x="720" y="458" width="124" height="76" rx="6" class="gate"/>
|
||||||
|
<text x="782" y="478" class="gate-l">Interlock latch</text>
|
||||||
|
<text x="782" y="492" class="gate-s">U23-2 · CD4043B</text>
|
||||||
|
<text x="782" y="506" class="gate-s">set-dominant</text>
|
||||||
|
<text x="726" y="480" class="pin">S</text>
|
||||||
|
<text x="726" y="522" class="pin">R</text>
|
||||||
|
<text x="832" y="500" class="pin">Q</text>
|
||||||
|
<!-- INTERLOCK loop -->
|
||||||
|
<rect x="40" y="504" width="172" height="40" rx="5" class="in-tag"/>
|
||||||
|
<text x="50" y="520" class="tag-t">INTERLOCK loop</text><text x="160" y="520" class="tag-s">J8</text>
|
||||||
|
<text x="50" y="535" class="tag-s">jumpered on Basic/Plus · closed = 1</text>
|
||||||
|
<path class="wire" d="M212 518 H720"/>
|
||||||
|
<path class="wire" d="M330 518 V540"/>
|
||||||
|
<rect x="270" y="540" width="262" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="278" y="556" class="tag-t">interlock</text><text x="340" y="556" class="tag-s">EV_SW 5 · GPIO1_09 · active = open</text>
|
||||||
|
<!-- Q2 -> NOT -> AND2 -->
|
||||||
|
<path class="wire" d="M844 497 H890"/>
|
||||||
|
<circle cx="868" cy="497" r="3.5" class="dot"/>
|
||||||
|
<rect x="890" y="479" width="64" height="36" rx="6" class="gate"/>
|
||||||
|
<text x="922" y="495" class="gate-l">NOT</text><text x="922" y="508" class="gate-s">U6-3</text>
|
||||||
|
<path class="wire" d="M954 497 H985 V400 H1000"/>
|
||||||
|
<text x="958" y="470" class="net">¬Q2</text>
|
||||||
|
<!-- interlock_latch readback -->
|
||||||
|
<path class="wire" d="M868 497 V546"/>
|
||||||
|
<rect x="770" y="546" width="236" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="778" y="562" class="tag-t">interlock_latch</text><text x="878" y="562" class="tag-s">EV_SW 6 · GPIO1_02 · = Q2</text>
|
||||||
|
|
||||||
|
<!-- ===================== Row E: LASER_ON ===================== -->
|
||||||
|
<rect x="1000" y="368" width="64" height="44" rx="6" class="gate"/>
|
||||||
|
<text x="1032" y="387" class="gate-l">AND</text><text x="1032" y="402" class="gate-s">U17-2</text>
|
||||||
|
<path class="wire" d="M1064 390 H1110"/>
|
||||||
|
<rect x="1110" y="378" width="64" height="44" rx="6" class="gate"/>
|
||||||
|
<text x="1142" y="397" class="gate-l">AND</text><text x="1142" y="412" class="gate-s">U17-3</text>
|
||||||
|
<!-- FIRE -->
|
||||||
|
<rect x="850" y="600" width="232" height="40" rx="5" class="out-tag"/>
|
||||||
|
<text x="858" y="616" class="tag-t">FIRE</text><text x="896" y="616" class="tag-s">GPIO2_30 (laser_enable)</text>
|
||||||
|
<text x="858" y="631" class="tag-s">SDMA pulse-byte bit 4 · Hi-Z when locked or idle</text>
|
||||||
|
<path class="wire" d="M1082 620 H1094 V410 H1110"/>
|
||||||
|
<!-- LASER_ON out -->
|
||||||
|
<path class="wire-out" d="M1174 400 H1300"/>
|
||||||
|
<circle cx="1210" cy="400" r="3.5" class="dot"/>
|
||||||
|
<text x="1182" y="392" class="net">LASER_ON</text>
|
||||||
|
<path class="wire" d="M1210 400 V446"/>
|
||||||
|
<rect x="1112" y="446" width="146" height="24" rx="5" class="rb-tag"/>
|
||||||
|
<text x="1120" y="462" class="tag-t">laser_on</text><text x="1182" y="462" class="tag-s">GPIO1_05</text>
|
||||||
|
<!-- PSU tag LASER_ON -->
|
||||||
|
<rect x="1300" y="386" width="172" height="28" rx="5" class="psu-tag"/>
|
||||||
|
<text x="1308" y="405" class="tag-t">J1_12</text><text x="1354" y="405" class="tag-s">LASER_ON</text>
|
||||||
|
<text x="1300" y="434" class="note">The tube fires only while</text>
|
||||||
|
<text x="1300" y="450" class="note">this line is high (and HV</text>
|
||||||
|
<text x="1300" y="466" class="note">is enabled). Power comes</text>
|
||||||
|
<text x="1300" y="482" class="note">from PWM on J1_13, which</text>
|
||||||
|
<text x="1300" y="498" class="note">is not part of the chain.</text>
|
||||||
|
|
||||||
|
<!-- ===================== equations ===================== -->
|
||||||
|
<text x="262" y="612" class="note" font-weight="700">HV_ENABLE = DOORS_OK · WDOG_ALIVE</text>
|
||||||
|
<text x="262" y="630" class="note" font-weight="700">LASER_ON = FIRE · ¬Q1 · ¬Q2</text>
|
||||||
|
<text x="262" y="652" class="note">Button latch: SET = lid open OR LATCH_RESET; RESET = button pressed. Cleared only by a press while the lid is closed and the lock released.</text>
|
||||||
|
<text x="262" y="670" class="note">Interlock latch: SET = INTERLOCK_RESET (driven by glowforge.ko while the loop reads open); RESET = loop closed. Both latches are set-dominant.</text>
|
||||||
|
|
||||||
|
<!-- ===================== legend ===================== -->
|
||||||
|
<rect x="20" y="712" width="1462" height="128" rx="6" fill="#ffffff" stroke="#b8bec8"/>
|
||||||
|
<text x="34" y="734" class="region-l">LEGEND</text>
|
||||||
|
<rect x="34" y="746" width="26" height="16" rx="3" class="in-tag"/>
|
||||||
|
<text x="68" y="759" class="note">physical switch or loop, wired to the board</text>
|
||||||
|
<rect x="34" y="770" width="26" height="16" rx="3" class="out-tag"/>
|
||||||
|
<text x="68" y="783" class="note">line driven by the SoC (glowforge.ko)</text>
|
||||||
|
<rect x="34" y="794" width="26" height="16" rx="3" class="rb-tag"/>
|
||||||
|
<text x="68" y="807" class="note">line read by the SoC — gpio-keys switch (EV_SW code) or /sys/glowforge/cnc attribute; monitoring only</text>
|
||||||
|
<rect x="34" y="818" width="26" height="16" rx="3" class="psu-tag"/>
|
||||||
|
<text x="68" y="831" class="note">output to the laser power supply</text>
|
||||||
|
<text x="760" y="759" class="note">Boxes are logic functions on the control board (part reference below each). Wires carry logic levels: 1 = true as named.</text>
|
||||||
|
<text x="760" y="777" class="note">Software can only withhold FIRE, hold LATCH_RESET, drive INTERLOCK_RESET, or stop feeding CHG_PUMP —</text>
|
||||||
|
<text x="760" y="795" class="note">every one of those makes the hardware block emission. Nothing on the SoC side can add an emission path.</text>
|
||||||
|
<text x="760" y="817" class="note">Also read: door1 / door2 (EV_SW 0 / 1, GPIO4_14 / GPIO1_06), the two lid switches individually;</text>
|
||||||
|
<text x="760" y="833" class="note">laser_pgood (GPIO4_21), the supply's HV_OK line on J1_14.</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 14 KiB |
@@ -9,7 +9,7 @@ PV = "0.1.0"
|
|||||||
|
|
||||||
SRC_URI = "git://github.com/ScottW514/forgectrl.git;protocol=https;branch=main"
|
SRC_URI = "git://github.com/ScottW514/forgectrl.git;protocol=https;branch=main"
|
||||||
# Pinned; bump deliberately after pushing forgectrl changes.
|
# Pinned; bump deliberately after pushing forgectrl changes.
|
||||||
SRCREV = "73eda9a5a47c4a94c6df40fa039226129f53d2f9"
|
SRCREV = "a451e7cd6e6d41cb5ef1d640badca0e8b4b5724b"
|
||||||
|
|
||||||
S = "${WORKDIR}/git"
|
S = "${WORKDIR}/git"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user