diff --git a/deploy/nixos/configuration.nix b/deploy/nixos/configuration.nix index 2306f5a..d473a42 100644 --- a/deploy/nixos/configuration.nix +++ b/deploy/nixos/configuration.nix @@ -7,16 +7,6 @@ # System basics system.stateVersion = "24.05"; - # ── Image slimming (bitspire#70 sizing) ────────────────────────────── - # This is a single-purpose Electron kiosk; strip the desktop/multimedia - # baggage NixOS pulls in by default so the disk image stays lean. - # - speechd: text-to-speech (speech-dispatcher → espeak-ng → mbrola, ~1GB). - # An ATM does not talk. - # - documentation: man/info/NixOS manual — no one reads them on a kiosk. - services.speechd.enable = lib.mkForce false; - documentation.enable = false; - documentation.nixos.enable = false; - # Networking networking = { hostName = "bitspire"; @@ -131,10 +121,8 @@ # Node.js for the application pkgs-unstable.nodejs_22 - # Camera support. v4l-utils' default build drags in the whole Qt6 stack - # for its qv4l2 GUI (~0.5GB) — we only ever use the v4l2-ctl CLI, so drop - # the GUI. - (v4l-utils.override { withGUI = false; }) + # Camera support + v4l-utils fswebcam # ATM operations diff --git a/deploy/nixos/hardware/upboard-serial.nix b/deploy/nixos/hardware/upboard-serial.nix deleted file mode 100644 index dfbf947..0000000 --- a/deploy/nixos/hardware/upboard-serial.nix +++ /dev/null @@ -1,61 +0,0 @@ -# UP Board serial peripherals — the validator / dispenser / printer wiring -# shared by the INSTALLED configs (hardware/upboard.nix, used by both -# tejo-installed and sintra-installed) AND the sintra live ISO (live.nix). -# Single source of truth so the two artifacts can't drift — the earlier bug -# was exactly this drift (the sintra live ISO lacked ftdi_sio + the ttyJ7 -# symlink, so the F56 dispenser failed while the installed image worked). -# -# Sintra IS a UP Board, so these are the UP Board rules; ttyS1/ttyS5 cover the -# older UP Board / UP4000 (Tejo) dispenser nodes and ttyS4 covers the Sintra -# (Apollo Lake) where the F56 is on the SoC MMIO UART. Only the device that -# actually exists at runtime gets the symlink, so all three coexist safely. -# -# Serial port mapping: -# ttyJ4 = Printer (Nippon NP-2511D-2) -# ttyJ5 = Validator (iVIZION, ID003) -# ttyJ7 = Dispenser (Fujitsu F53/F56) -{ lib, ... }: - -{ - boot.kernelModules = [ - "usbserial" # USB-to-serial adapters - "ftdi_sio" # FTDI USB serial (the iVIZION validator bridge) - "cp210x" # CP210x USB serial (alternative adapter) - ]; - - boot.kernelParams = [ - # Do NOT route the kernel console through ttyS4 on Sintra. ttyS4 is the - # SoC's MMIO 16550A (the only real UART besides the legacy ttyS0 at I/O - # 0x3f8) and is wired to the Fujitsu F56 dispenser's RS-232 header. Holding - # it as console prevents userspace opening it at 9600 baud and HAL fails - # with "Input/output error setting custom baud rate of 9600". For serial - # debug, point console at ttyS0 instead. - "console=tty0" - ]; - - services.udev.extraRules = lib.mkAfter '' - # Generic serial port permissions (so the non-root HAL user can open them) - KERNEL=="ttyS[0-9]*", MODE="0666" - KERNEL=="ttyUSB[0-9]*", MODE="0666" - KERNEL=="ttyACM[0-9]*", MODE="0666" - - # Printer (ttyJ4) - KERNELS=="1-7.2:1.0", SYMLINK+="ttyJ4" - KERNEL=="ttyUSB0", SYMLINK+="ttyJ4" - - # Validator (ttyJ5) - KERNELS=="1-7.3:1.0", SYMLINK+="ttyJ5" - KERNEL=="ttyUSB1", SYMLINK+="ttyJ5" - - # Dispenser (ttyJ7). ttyS1/ttyS5 = older UP Board / UP4000; ttyS4 = Sintra. - KERNEL=="ttyS1", SYMLINK+="ttyJ7" - KERNEL=="ttyS4", SYMLINK+="ttyJ7" - KERNEL=="ttyS5", SYMLINK+="ttyJ7" - - # Legacy ttyAMA0 alias - SUBSYSTEM=="tty", KERNEL=="ttyS1", SYMLINK+="ttyAMA0", GROUP="dialout" - - # Disable USB autosuspend (prevents serial adapters from sleeping) - ACTION=="add", SUBSYSTEM=="usb", TEST=="power/control", ATTR{power/control}="on" - ''; -} diff --git a/deploy/nixos/hardware/upboard.nix b/deploy/nixos/hardware/upboard.nix index d213ff7..b3fe1f3 100644 --- a/deploy/nixos/hardware/upboard.nix +++ b/deploy/nixos/hardware/upboard.nix @@ -11,10 +11,6 @@ { config, lib, pkgs, ... }: { - # Serial peripherals (validator/dispenser/printer modules + udev symlinks + - # console=tty0) are shared with the live ISO via ./upboard-serial.nix. - imports = [ ./upboard-serial.nix ]; - boot = { loader = { systemd-boot.enable = true; @@ -46,12 +42,21 @@ "kvm-intel" "i2c-dev" "spi-dev" - # Serial modules (usbserial/ftdi_sio/cp210x) → ./upboard-serial.nix. + "usbserial" # USB-to-serial adapters + "ftdi_sio" # FTDI USB serial + "cp210x" # CP210x USB serial ]; kernelParams = [ "i915.enable_psr=0" - # console=tty0 (keeps ttyS4 free for the F56) → ./upboard-serial.nix. + # NOTE: do NOT route the kernel console through ttyS4 on Sintra. + # ttyS4 is the SoC's MMIO 16550A (the only real UART besides the + # legacy ttyS0 at I/O 0x3f8) and is wired to the Fujitsu F56 + # dispenser's RS-232 header on Sintra. Holding it as console + # prevents userspace from opening it at 9600 baud and HAL fails + # with "Input/output error setting custom baud rate of 9600". + # If you want serial debug, point console at ttyS0 instead. + "console=tty0" "quiet" "splash" ]; @@ -99,9 +104,37 @@ hybrid-sleep.enable = false; }; - # Camera + LED/SPI peripherals. The serial rules (validator/dispenser/printer - # symlinks + permissions) are shared with the live ISO in ./upboard-serial.nix. + # Serial port permissions + tejo-specific symlinks services.udev.extraRules = lib.mkAfter '' + # Generic serial port permissions + KERNEL=="ttyS[0-9]*", MODE="0666" + KERNEL=="ttyUSB[0-9]*", MODE="0666" + KERNEL=="ttyACM[0-9]*", MODE="0666" + + # ── Tejo serial port symlinks ────────────────────────────────────── + # Both UP Board and UP4000 rules included (match different kernel paths) + + # Printer (ttyJ4) + KERNELS=="1-7.2:1.0", SYMLINK+="ttyJ4" + KERNEL=="ttyUSB0", SYMLINK+="ttyJ4" + + # Validator (ttyJ5) + KERNELS=="1-7.3:1.0", SYMLINK+="ttyJ5" + KERNEL=="ttyUSB1", SYMLINK+="ttyJ5" + + # Dispenser (ttyJ7). + # ttyS1 / ttyS5 cover earlier UP Board variants where the dispenser + # lands on those kernel-enumerated serial nodes; ttyS4 covers the + # Sintra (UP Board Atom/Apollo Lake) where the dispenser is wired + # to the SoC's MMIO UART. Whichever device actually exists at + # runtime gets the ttyJ7 symlink. + KERNEL=="ttyS1", SYMLINK+="ttyJ7" + KERNEL=="ttyS4", SYMLINK+="ttyJ7" + KERNEL=="ttyS5", SYMLINK+="ttyJ7" + + # Legacy ttyAMA0 alias + SUBSYSTEM=="tty", KERNEL=="ttyS1", SYMLINK+="ttyAMA0", GROUP="dialout" + # ── Camera devices ───────────────────────────────────────────────── SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-5", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-scan" SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-2", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-scan" @@ -114,5 +147,8 @@ SUBSYSTEM=="spidev", GROUP="spi", MODE="0660" SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" SUBSYSTEM=="leds", KERNEL=="upboard:*", ACTION=="add|change", RUN+="${pkgs.findutils}/bin/find /sys$devpath -type f -exec ${pkgs.coreutils}/bin/chmod g+u {} + -exec ${pkgs.coreutils}/bin/chown :leds {} +" + + # Disable USB autosuspend (prevents serial adapters from sleeping) + ACTION=="add", SUBSYSTEM=="usb", TEST=="power/control", ATTR{power/control}="on" ''; } diff --git a/deploy/nixos/live.nix b/deploy/nixos/live.nix index 7c5682f..698e0bb 100644 --- a/deploy/nixos/live.nix +++ b/deploy/nixos/live.nix @@ -47,12 +47,7 @@ in # Reuse ATM systemd service module ./bitspire-atm.nix - ] - # Sintra: share the UP Board serial hardware (validator/dispenser/printer - # modules + udev symlinks + console=tty0) with the installed image so the - # live ISO drives the same hardware. Safe to import here — unlike upboard.nix - # it declares no fileSystems, so there's no live-boot mount conflict. - ++ lib.optionals (machineModel == "sintra") [ ./hardware/upboard-serial.nix ]; + ]; # ISO image settings image.fileName = "bitspire-${machineModel}-live.iso"; diff --git a/flake.nix b/flake.nix index 63296c0..9305991 100644 --- a/flake.nix +++ b/flake.nix @@ -347,25 +347,6 @@ fileSystems."/".device = lib.mkForce "/dev/disk/by-label/nixos-usb"; fileSystems."/boot".device = lib.mkForce "/dev/disk/by-label/ESP-USB"; system.autoUpgrade.enable = lib.mkForce false; - - # The Sintra's Aaeon firmware USB-boots in Legacy/BIOS mode — it - # boots the live ISO via its isolinux (BIOS) El Torito image, not - # the UEFI ESP. systemd-boot is UEFI-only, so a dd'd systemd-boot - # image isn't recognised as bootable. Switch THIS USB image to - # GRUB with BOTH BIOS (MBR + bios_grub partition, via the "hybrid" - # table below) and UEFI (removable /EFI/BOOT/BOOTX64.EFI) — mirroring - # the live ISO's dual boot — so it boots on Legacy and UEFI alike. - # Scoped to the USB image; the eMMC install keeps systemd-boot. - boot.loader.systemd-boot.enable = lib.mkForce false; - boot.loader.efi.canTouchEfiVariables = lib.mkForce false; - boot.loader.grub = { - enable = lib.mkForce true; - efiSupport = true; - efiInstallAsRemovable = true; - # make-disk-image's build VM exposes the image as /dev/vda; - # GRUB installs its BIOS stage to that disk's MBR. - devices = lib.mkForce [ "/dev/vda" ]; - }; }) ]; }; @@ -373,8 +354,7 @@ inherit pkgs lib; config = cfg.config; format = "raw"; - # hybrid = GPT + bios_grub partition + ESP → BIOS + UEFI bootable. - partitionTableType = "hybrid"; + partitionTableType = "efi"; diskSize = "auto"; label = "nixos-usb"; # ext4 root label (make-disk-image -L) };