{ config, lib, pkgs, paths, self, keys, ... }: let # Backlight fallback for CM5 display quirk # The kernel driver usually handles this, but some boots need a kick backlightFixScript = pkgs.writeShellScript "backlight-fix" '' # Try sysfs backlight control for bl in /sys/class/backlight/*/brightness; do if [ -f "$bl" ]; then max=$(cat "$(dirname "$bl")/max_brightness" 2>/dev/null || echo 100) echo "$max" > "$bl" 2>/dev/null || true fi done ''; in { # Basic Host Info networking.hostName = "uConsole"; time.timeZone = "America/Montreal"; i18n.defaultLocale = "en_CA.UTF-8"; # System State system.stateVersion = "25.05"; # Boot & Hardware (migrated to kernel bootloader per nixos-raspberrypi deprecation notice) boot.loader.raspberry-pi.bootloader = "kernel"; # kernel managed by nixos-raspberrypi module — don't override, patches are version-specific # boot.kernelPackages = pkgs.linuxPackages_latest; # Use kernel built-in console font — ter-v24n from nixos-uconsole is garbled on CM5 console.font = lib.mkForce "Lat2-Terminus16"; console.packages = lib.mkForce [ ]; # Networking networking.networkmanager.enable = true; services.openssh = { enable = true; # TODO: lock down after first deployment settings.PermitRootLogin = lib.mkForce "yes"; settings.PasswordAuthentication = lib.mkForce true; }; # User users.users.gortium = { isNormalUser = true; extraGroups = [ "wheel" "networkmanager" "video" "dialout" "kismet" ]; openssh.authorizedKeys.keys = [ keys.users.gortium.main keys.users.gortium.gitea ]; }; security.sudo.extraRules = [ { users = [ "gortium" ]; commands = [ { command = "ALL"; options = [ "NOPASSWD" ]; } ]; } ]; # ============================================================ # Package groups # ============================================================ environment.systemPackages = with pkgs; [ # ===== Base ===== emacs-pgtk git ripgrep fd htop tmux neovim libgpiod # GPIO control (for internal USB hub, AIO modules) # ===== HAM Radio ===== js8call wsjtx fldigi pat # Winlink client direwolf # AX.25 packet modem chirp # Radio programming tool hamlib # Ham radio control libraries trustedqsl # Logbook of the World (LoTW) # ===== SDR / RF ===== sdrpp # SDR++ spectrum analyzer gqrx # SDR receiver GUI rtl-sdr # RTL-SDR drivers & utilities inspectrum # Offline signal analysis soapysdr-with-plugins # SoapySDR + hardware support plugins # ===== Mesh / LoRa ===== # meshtastic not available in nixpkgs 25.11 stable; install manually: # nix shell nixpkgs#meshtastic -c meshtastic reticulumStack # Reticulum Network Stack (rnsd, rnsh, rncp, rnx, rnpath, etc.) lxmf # LXMF messaging protocol nomadnet # Nomad Network client # ===== Security ===== nmap aircrack-ng kismet # Wi-Fi monitor / IDS bettercap # MITM/network attack framework wireshark # Packet analyzer hashcat # GPU password cracker john # John the Ripper sqlmap # SQL injection tool # ===== GPS / Maps ===== foxtrotgps viking # GPS map editor gpsbabel # GPS data conversion ]; # Packages noted but not in unstable nixpkgs: # - metasploit: unfree; install manually via Git clone # - burpsuite: unfree Java app (Community Edition available for download) # - sidechannel: not a distinct PyPI package; functionality covered by # the Reticulum stack. For LXMF GUI client, install Sideband manually # from github.com/markqvist/Sideband # ============================================================ # Reticulum Service (rnsd) # ============================================================ systemd.services.rnsd = { description = "Reticulum Network Stack Daemon"; wants = [ "network-online.target" ]; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { User = "gortium"; Group = "gortium"; ExecStart = "${pkgs.reticulumStack}/bin/rnsd"; Restart = "always"; RestartSec = "10s"; LimitNOFILE = 65536; }; }; # ============================================================ # Kismet Service (Wi-Fi monitoring / mesh node) # ============================================================ systemd.services.kismet = { description = "Kismet Wi-Fi Monitor & IDS"; wants = [ "network-online.target" ]; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { User = "gortium"; Group = "kismet"; ExecStart = "${pkgs.kismet}/bin/kismet -c wlan0 --log-base=/home/gortium/kismet_logs --no-nc-ui"; Restart = "always"; RestartSec = "10s"; }; }; # ============================================================ # Kernel modules for SDR, radio, and WiFi # ============================================================ boot.kernelModules = [ "mt7921u" # MediaTek MT7921 USB WiFi (uConsole AC1200) "88x2bu" # Realtek 8812/8821BU USB WiFi (common adapter) "rtl8xxxu" # RTL8188/8192/8723 USB WiFi "rtl2832_sdr" # RTL-SDR kernel module "dvb_usb_rtl28xxu" # RTL-SDR DVB-T ]; boot.blacklistedKernelModules = [ ]; # ============================================================ # Extra udev rules for SDR and HAM radio devices # ============================================================ services.udev.packages = with pkgs; [ rtl-sdr ]; # ============================================================ # Enable IPv6 for Reticulum mesh # ============================================================ networking.enableIPv6 = true; # ============================================================ # Firewall: open ports for Reticulum (optional) # ============================================================ networking.firewall.allowedTCPPorts = [ 22 ]; # SSH only networking.firewall.allowedUDPPorts = [ ]; # Reticulum uses its own encryption and doesn't need open ports # for basic mesh operations (peer-to-peer discovery). # For TCP interfaces, open additional ports as needed. # ============================================================ # Display & Desktop (Hyprland Wayland compositor) # ============================================================ programs.hyprland = { enable = true; xwayland.enable = true; }; services.displayManager.sddm = { enable = true; wayland.enable = true; }; # ============================================================ # CM5 Display Backlight Fix # The kernel driver initializes backlight, but some boots fail. # This service kicks it after boot as a reliable fallback. # ============================================================ systemd.services.cm5-backlight-fix = { description = "CM5 Display Backlight Fix"; after = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; ExecStart = "${backlightFixScript}"; }; }; # ============================================================ # Internal USB Hub Enable (GPIO 23) — DISABLED # This service freeze the CM5 because gpioset 0 23=1 writes # to the wrong GPIO chip (BCM2712 native, not RP1). # Enable manually after boot once the correct chip is confirmed: # gpioset 0 23=1 # on chip 0 (BCM2712, CORE_VOLT or critical) # gpioset 512 23=1 # on chip 512 (RP1, likely correct) # ============================================================ # systemd.services.enable-gpio23-usb-hub = { # description = "Enable Internal USB Hub (GPIO 23)"; # before = [ "network.target" ]; # wantedBy = [ "multi-user.target" ]; # serviceConfig = { # Type = "oneshot"; # RemainAfterExit = true; # ExecStart = "${pkgs.libgpiod}/bin/gpioset 0 23=1"; # ExecStop = "${pkgs.libgpiod}/bin/gpioset 0 23=0"; # }; # }; }