bitspire/apps
Padreug ea4c1f406b fix(machine): make the dispenser optional, as the validator already was
initializeHal created and initialised the dispenser unconditionally, so a
missing dispenser device threw and aborted the WHOLE of HAL init — taking
the validator down with it, even when the validator was present and
working.

The Pi bring-up hit exactly that. With a Pyramid Apex correctly wired and
enumerated on /dev/ttyValidator0:

  [ATM] Validator device: /dev/ttyValidator0
  [ATM] Dispenser device: /dev/ttyDispenser-not-fitted
  [Electron] HAL init failed: cannot open /dev/ttyDispenser-not-fitted
  [Recovery] Reloading renderer to re-attempt initialization

and round again, forever, with a perfectly good acceptor attached.

The validator has been optional since it was written — it checks the
device exists, catches init failures, and logs "running dispenser-only".
The dispenser had no equivalent. That asymmetry was the bug, not the
placeholder device path that exposed it: a cash-in-only machine is a
legitimate configuration, and the Raspberry Pi reference build is one.

Mirrors the validator's handling exactly: existence check, try/catch,
null on failure, and a log line saying what the machine will do instead
("running cash-in only"). Three call sites then need guarding —
dispenseCash returns a clear "No dispenser fitted on this machine —
cash-out unavailable" rather than dereferencing null, setCassettes still
records the layout but skips the re-init, and cleanup uses an optional
call.

This also removes the sharp edge from the rpi4/rpi5 presets added in the
previous commit. Their dispenser block points at a path that does not
exist because DispenseType has no 'none' variant and DeviceConfig
requires the field. That is still worth fixing properly with a real
'none' variant, but the machine no longer has to care.
2026-09-29 18:16:41 +02:00
..
machine fix(machine): make the dispenser optional, as the validator already was 2026-09-29 18:16:41 +02:00