isoImage.isoName was renamed to image.fileName in 25.11 (unified image module). Split the rename out — the rest of isoImage.* stays put (makeEfiBootable, makeBiosBootable, squashfsCompression). All 8 nixosConfigurations evaluate clean on 25.11 with zero deprecation warnings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
263 lines
9.8 KiB
Nix
263 lines
9.8 KiB
Nix
# Lamassu ATM Live USB Configuration
|
|
# Bootable ISO for testing on physical hardware without installing to disk.
|
|
#
|
|
# Parameterized by machineModel (passed via specialArgs from flake.nix):
|
|
# "douro" - Bay Trail Atom, kernel 5.15 (i915 regression in newer kernels), eDP panel
|
|
# "tejo" - UP4000/UPBoard, default kernel 6.6, standard Intel GPU
|
|
#
|
|
# Builds with: nix build .#iso-douro or nix build .#iso-tejo
|
|
#
|
|
# Does NOT import hardware/upboard.nix (its fileSystems conflict with live boot).
|
|
# Instead, duplicates only the hardware-relevant kernel modules and GPU config.
|
|
|
|
{ config, lib, pkgs, pkgs-unstable, nixpkgs, machineModel ? "douro", atm-app, ... }:
|
|
|
|
let
|
|
# Fiat code per machine model (for envTemplate display only)
|
|
fiatCodeForModel = {
|
|
douro = "GTQ";
|
|
tejo = "GTQ";
|
|
sintra = "EUR";
|
|
batm3 = "USD";
|
|
}.${machineModel} or "USD";
|
|
|
|
# .env template — runtime secrets are provisioned later via provision-atm.sh.
|
|
# Only non-secret defaults and display vars go here.
|
|
envTemplate = pkgs.writeText "bitspire-env" ''
|
|
VITE_RELAY_URL=
|
|
VITE_LIGHTNING_PUB_PUBKEY=
|
|
VITE_LIGHTNING_PUB_API_URL=
|
|
VITE_ADMIN_TOKEN=
|
|
VITE_ATM_PRIVATE_KEY=
|
|
VITE_EXTENSION_API_URL=
|
|
VITE_APP_ID=
|
|
VITE_LNDCONNECT_URL=
|
|
VITE_LAMASSU_MACHINE_MODEL=${machineModel}
|
|
VITE_LAMASSU_FIAT_CODE=${fiatCodeForModel}
|
|
ELECTRON_FORCE_PROD=1
|
|
DISPLAY=:0
|
|
'';
|
|
in
|
|
{
|
|
imports = [
|
|
# NixOS ISO image builder (nixpkgs path passed via specialArgs from flake.nix)
|
|
"${nixpkgs}/nixos/modules/installer/cd-dvd/iso-image.nix"
|
|
"${nixpkgs}/nixos/modules/profiles/all-hardware.nix"
|
|
|
|
# Reuse kiosk config (X11, openbox, users, networking)
|
|
./configuration.nix
|
|
|
|
# Reuse ATM systemd service module
|
|
./bitspire-atm.nix
|
|
];
|
|
|
|
# ISO image settings
|
|
image.fileName = "bitspire-${machineModel}-live.iso";
|
|
isoImage = {
|
|
makeEfiBootable = true;
|
|
makeBiosBootable = true;
|
|
squashfsCompression = "zstd -Xcompression-level 6";
|
|
};
|
|
|
|
# No fileSystems override needed — iso-image.nix handles squashfs + tmpfs root.
|
|
# We don't import hardware/upboard.nix, so there are no conflicting disk mounts.
|
|
|
|
# Kernel: Douro Bay Trail needs 5.15 LTS (i915 eDP regression in 6.x kernels)
|
|
boot.kernelPackages = lib.mkIf (machineModel == "douro") pkgs.linuxPackages_5_15;
|
|
|
|
# Boot: kernel modules and parameters (model-specific)
|
|
boot = {
|
|
initrd.availableKernelModules = [
|
|
"xhci_pci"
|
|
"ahci"
|
|
"usb_storage"
|
|
"sd_mod"
|
|
"sdhci_pci"
|
|
"i915"
|
|
"squashfs"
|
|
"iso9660"
|
|
"loop"
|
|
];
|
|
|
|
kernelModules = [
|
|
"kvm-intel"
|
|
"i2c-dev"
|
|
"spi-dev"
|
|
] ++ lib.optionals (machineModel == "tejo") [
|
|
"usbserial" # USB-to-serial adapters (ttyUSB0/1 for validator/printer)
|
|
"ftdi_sio" # FTDI USB serial (common in ATM peripherals)
|
|
"cp210x" # CP210x USB serial (alternative adapter)
|
|
] ++ lib.optionals (machineModel == "batm3") [
|
|
"cdc_acm" # USB CDC ACM for MEI BNR Advance validator
|
|
"usbserial" # USB-to-serial for F56 dispenser adapter
|
|
"ftdi_sio" # FTDI USB serial (common RS232 adapter)
|
|
"cp210x" # CP210x USB serial (alternative adapter)
|
|
];
|
|
|
|
kernelParams = [
|
|
"i915.enable_psr=0"
|
|
"quiet"
|
|
"splash"
|
|
] ++ lib.optionals (machineModel == "douro") [
|
|
# Bay Trail: preserve BIOS display init (matches working kernel 5.4 config)
|
|
"vt.handoff=7"
|
|
] ++ lib.optionals (machineModel == "tejo") [
|
|
# UP Board debug UART for serial console
|
|
"console=ttyS4,115200n8"
|
|
"console=tty0"
|
|
];
|
|
};
|
|
|
|
# Intel GPU support
|
|
hardware = {
|
|
graphics = {
|
|
enable = true;
|
|
extraPackages = with pkgs; [
|
|
intel-media-driver
|
|
libva-vdpau-driver
|
|
libvdpau-va-gl
|
|
];
|
|
};
|
|
enableRedistributableFirmware = true;
|
|
cpu.intel.updateMicrocode = true;
|
|
};
|
|
|
|
# Performance governor for responsive kiosk
|
|
powerManagement = {
|
|
enable = true;
|
|
cpuFreqGovernor = "performance";
|
|
};
|
|
|
|
# Disable suspend/hibernate
|
|
systemd.targets = {
|
|
sleep.enable = false;
|
|
suspend.enable = false;
|
|
hibernate.enable = false;
|
|
hybrid-sleep.enable = false;
|
|
};
|
|
|
|
# Enable the ATM service with live USB paths
|
|
services.bitspire = {
|
|
enable = true;
|
|
appDir = "${atm-app}";
|
|
};
|
|
|
|
# Allow unprivileged user namespaces (Electron sandbox needs this)
|
|
boot.kernel.sysctl."kernel.unprivileged_userns_clone" = 1;
|
|
|
|
# Override the systemd service for live USB environment
|
|
systemd.services.bitspire = {
|
|
serviceConfig = {
|
|
EnvironmentFile = lib.mkForce "/var/lib/bitspire/.env";
|
|
# Native modules need libstdc++ on NixOS
|
|
Environment = "LD_LIBRARY_PATH=${pkgs.stdenv.cc.cc.lib}/lib";
|
|
# Electron needs --no-sandbox in the live/testing environment
|
|
# --enable-logging makes renderer console.log visible in journalctl
|
|
ExecStart = lib.mkForce "${pkgs-unstable.electron}/bin/electron --no-sandbox --disable-gpu-sandbox --disable-gpu --disable-software-rasterizer --enable-logging ${atm-app}";
|
|
# Prevent Electron from consuming all RAM on memory-constrained ATMs
|
|
MemoryMax = lib.mkForce "1G";
|
|
# Disable all security hardening that conflicts with Electron
|
|
NoNewPrivileges = lib.mkForce false;
|
|
ProtectSystem = lib.mkForce false;
|
|
ProtectHome = lib.mkForce false;
|
|
PrivateTmp = lib.mkForce false;
|
|
# Allow access to all character devices (serial ports for HAL hardware)
|
|
DevicePolicy = lib.mkForce "auto";
|
|
DeviceAllow = lib.mkForce [ "char-* rw" ];
|
|
};
|
|
};
|
|
|
|
# Install the .env on first boot
|
|
system.activationScripts.bitspire-env = ''
|
|
mkdir -p /var/lib/bitspire
|
|
if [ ! -f /var/lib/bitspire/.env ]; then
|
|
cp ${envTemplate} /var/lib/bitspire/.env
|
|
chmod 600 /var/lib/bitspire/.env
|
|
chown bitspire:bitspire /var/lib/bitspire/.env
|
|
fi
|
|
'';
|
|
|
|
# Reset display output after X starts (required for kexec boots where
|
|
# the GPU wasn't reinitialized by BIOS firmware)
|
|
systemd.services.display-reset = {
|
|
description = "Reset eDP display output";
|
|
after = [ "display-manager.service" ];
|
|
requires = [ "display-manager.service" ];
|
|
wantedBy = [ "graphical.target" ];
|
|
before = [ "bitspire.service" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = "bitspire";
|
|
Environment = "DISPLAY=:0";
|
|
ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.xorg.xrandr}/bin/xrandr --output eDP-1 --off; sleep 1; ${pkgs.xorg.xrandr}/bin/xrandr --output eDP-1 --auto'";
|
|
};
|
|
};
|
|
|
|
# Swap file — Douro/Tejo have only 2GB RAM; without swap the system
|
|
# hard-freezes under memory pressure instead of gracefully OOM-killing.
|
|
swapDevices = [{
|
|
device = "/var/swapfile";
|
|
size = 1024; # MB
|
|
}];
|
|
|
|
# Clean /tmp on boot to prevent stale Nix build artifacts from filling disk
|
|
boot.tmp.cleanOnBoot = true;
|
|
|
|
# SSH password auth disabled — machines are provisioned with SSH keys.
|
|
# Base configuration.nix sets PasswordAuthentication = false.
|
|
|
|
# Serial port udev rules — generic permissions for all models
|
|
services.udev.extraRules = lib.mkAfter (''
|
|
KERNEL=="ttyS[0-9]*", MODE="0666"
|
|
KERNEL=="ttyUSB[0-9]*", MODE="0666"
|
|
KERNEL=="ttyACM[0-9]*", MODE="0666"
|
|
'' + lib.optionalString (machineModel == "batm3") ''
|
|
|
|
# ── BATM3 MEI BNR Advance USB CDC ACM ──────────────────────────────
|
|
# Stable symlink for the bill validator (vendor 0x0bed = MEI)
|
|
SUBSYSTEM=="tty", ATTRS{idVendor}=="0bed", SYMLINK+="ttyValidator"
|
|
'' + lib.optionalString (machineModel == "tejo") ''
|
|
|
|
# ── Tejo serial port symlinks ──────────────────────────────────────
|
|
# Both UP Board and UP4000 rules are included so one ISO works on either.
|
|
# Rules match different kernel paths so they don't conflict.
|
|
|
|
# Printer (ttyJ4): UP Board via USB hub path, UP4000 via ttyUSB0
|
|
KERNELS=="1-7.2:1.0", SYMLINK+="ttyJ4"
|
|
KERNEL=="ttyUSB0", SYMLINK+="ttyJ4"
|
|
|
|
# Validator (ttyJ5): UP Board via USB hub path, UP4000 via ttyUSB1
|
|
KERNELS=="1-7.3:1.0", SYMLINK+="ttyJ5"
|
|
KERNEL=="ttyUSB1", SYMLINK+="ttyJ5"
|
|
|
|
# Dispenser (ttyJ7): UP Board uses ttyS1, UP4000 uses ttyS5
|
|
KERNEL=="ttyS1", SYMLINK+="ttyJ7"
|
|
KERNEL=="ttyS5", SYMLINK+="ttyJ7"
|
|
|
|
# Legacy ttyAMA0 alias
|
|
SUBSYSTEM=="tty", KERNEL=="ttyS1", SYMLINK+="ttyAMA0", GROUP="dialout"
|
|
|
|
# ── Camera devices ─────────────────────────────────────────────────
|
|
# QR scanner camera (A4tech USB, vendor 0ac8:0345)
|
|
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"
|
|
|
|
# Front-facing camera
|
|
SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-6", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-front"
|
|
SUBSYSTEM=="video4linux", ATTR{index}=="0", KERNELS=="1-3", ATTRS{idVendor}=="0ac8", ATTRS{idProduct}=="0345", SYMLINK+="video-front"
|
|
|
|
# ── LED SPI / peripherals ──────────────────────────────────────────
|
|
KERNEL=="spidev1.0", SYMLINK+="ledspi"
|
|
KERNEL=="spidev2.0", SYMLINK+="ledspi"
|
|
|
|
# SPI and I2C group permissions
|
|
SUBSYSTEM=="spidev", GROUP="spi", MODE="0660"
|
|
SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660"
|
|
|
|
# UP Board FPGA LED permissions
|
|
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"
|
|
'');
|
|
}
|