From 9bfa0d74a2d4cbbcbb442ae1d67b9ba6b670923d Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Mon, 26 Jan 2026 23:20:34 -0500 Subject: [PATCH] docs: add ADR-001 for HAL architecture decisions Documents the decision to: - Use TypeScript HAL drivers extracted from lamassu-machine - Use Electron instead of Tauri for the kiosk app - Avoid Rust rewrite (adds complexity without benefit) Related issues: #18, #19, #20, #21 Co-Authored-By: Claude Opus 4.5 --- lamassu-next/docs/adr/001-hal-architecture.md | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 lamassu-next/docs/adr/001-hal-architecture.md diff --git a/lamassu-next/docs/adr/001-hal-architecture.md b/lamassu-next/docs/adr/001-hal-architecture.md new file mode 100644 index 0000000..c057c7d --- /dev/null +++ b/lamassu-next/docs/adr/001-hal-architecture.md @@ -0,0 +1,140 @@ +# ADR-001: Hardware Abstraction Layer Architecture + +**Status:** Accepted +**Date:** 2026-01-26 +**Context:** Lamassu Next ATM proof of concept + +## Decision + +We will use **TypeScript HAL drivers extracted from lamassu-machine** rather than rewriting in Rust, and use **Electron instead of Tauri** for the kiosk application. + +## Context + +The Lamassu Next project needs to control ATM hardware (bill validators, dispensers) on Lamassu Sintra machines. Initial plans considered: + +1. Rust HAL with Tauri backend +2. TypeScript HAL with Tauri (IPC bridge) +3. TypeScript HAL with Electron (direct integration) + +### Hardware Target: Lamassu Sintra + +- **Platform:** Aaeon UP Board (Intel Atom x5-Z8350, x86 Linux) +- **Bill Validator:** JCM iVIZION using ID003 protocol +- **Bill Dispenser:** Fujitsu F53/F56 +- **Serial:** `/dev/ttyJ5` (validator), `/dev/ttyJ7` (dispenser) +- **Protocol:** RS-232, 9600 baud, 8 data bits, even parity, 1 stop bit + +## Options Considered + +### Option 1: Rust HAL + Tauri + +**Pros:** + +- Native Tauri integration +- Memory safety guarantees +- Single backend language + +**Cons:** + +- Requires full protocol reimplementation +- Two debugging environments (Rust + TypeScript) +- Serial at 9600 baud doesn't benefit from Rust performance +- Significant time investment with uncertain payoff + +### Option 2: TypeScript HAL + Tauri + +**Pros:** + +- Reuse battle-tested lamassu-machine drivers +- TypeScript throughout application code + +**Cons:** + +- IPC boundary between Tauri (Rust) and HAL (Node.js) +- Serialization overhead and complexity +- Two processes to manage and debug + +### Option 3: TypeScript HAL + Electron (Selected) + +**Pros:** + +- Direct `serialport` npm access in main process +- Single debugging environment (Chrome DevTools) +- All packages run natively (state-machine, HAL, lightning, clink) +- Mature ecosystem, well-documented edge cases +- Fastest path to working proof of concept + +**Cons:** + +- Larger binary size (~150MB vs ~10MB) +- Higher memory usage than Tauri +- Bundles Chromium + +## Decision Rationale + +### Why not Rust? + +The JavaScript drivers in lamassu-machine have run in production for years. The complexity is in the protocol state machines (ID003 FSM, F56 DLE/STX framing), not raw performance. Serial communication at 9600 baud is trivial - Rust's performance benefits are irrelevant here. + +Adding Rust creates a language boundary that requires: + +- IPC serialization/deserialization +- Two build systems +- Two debugging environments +- Potential for bugs at the boundary + +For a proof of concept, minimizing unknowns is critical. + +### Why Electron over Tauri? + +Tauri's benefits (small binary, low RAM) optimize for end-user desktop apps where download size matters. An ATM is a single-purpose kiosk: + +- Binary size irrelevant - installed once on dedicated hardware +- RAM sufficient - Sintra has 2-4GB, not competing with other apps +- Development speed critical - proof of concept needs fast iteration + +Electron allows the Vue UI, state machine, HAL, and Lightning packages to all run in the same Node.js environment with unified debugging. + +## Implementation Status + +### Completed + +- `@lamassu/hal` package created with: + - ID003 bill validator driver (JCM iVIZION) + - F56 bill dispenser driver (Fujitsu F53/F56) + - TypeScript types for all interfaces + - Extracted from lamassu-machine, fully typed + +### Remaining Work + +1. Convert `apps/machine` from Tauri to Electron +2. Wire HAL to state machine services: + - `dispenseCash` → F56Dispenser.dispense() + - Bill events → state machine events +3. Add device configuration (serial port paths) +4. Test on physical Sintra hardware + +## Consequences + +### Positive + +- Faster proof of concept development +- Easier debugging during hardware integration +- Reuse of proven driver code +- Single language throughout + +### Negative + +- Larger deployment size (acceptable for kiosk) +- Cannot leverage Rust safety guarantees (mitigated by mature JS drivers) + +### Future Considerations + +If a compelling reason for Rust emerges (it likely won't), the HAL interface is abstracted - drivers could be reimplemented without changing the state machine integration. The Vue UI works with either Electron or Tauri. + +## References + +- `packages/hal/` - TypeScript HAL implementation +- `packages/state-machine/src/types.ts` - ATMServices interface +- `hardware/codebase/upboard/sintra/device_config.json` - Sintra device paths +- lamassu-machine `lib/id003/`, `lib/f56/` - Original JS drivers