Compare commits

..

1 Commits

5 changed files with 92 additions and 285 deletions

32
flake.nix Executable file → Normal file
View File

@@ -2,34 +2,28 @@
description = "Gortium infra flake"; description = "Gortium infra flake";
inputs = { inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=25.11"; nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
agenix = { agenix = {
url = "github:ryantm/agenix"; url = "github:ryantm/agenix";
inputs.darwin.follows = ""; inputs.darwin.follows = "";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
lix = { lix = {
url = "git+https://git.lix.systems/lix-project/lix?ref=main"; url = "git+https://git.lix.systems/lix-project/lix?ref=main";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nixpkgs-uconsole = {
url = "github:nixos/nixpkgs/54170c54449ea4d6725efd30d719c5e505f1c10e";
};
nixos-uconsole = { nixos-uconsole = {
url = "github:nixos-uconsole/nixos-uconsole/v1.1.0"; url = "github:nixos-uconsole/nixos-uconsole";
inputs.nixpkgs.follows = "nixpkgs-uconsole"; inputs.nixpkgs.follows = "nixpkgs";
}; };
nixos-raspberrypi = { nixos-raspberrypi = {
url = "github:nvmd/nixos-raspberrypi/v1.20260317.0"; url = "github:nvmd/nixos-raspberrypi/v1.20260517.0";
inputs.nixpkgs.follows = "nixos-uconsole/nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
self.submodules = true;
}; };
outputs = { self, nixpkgs, agenix, disko, lix, nixos-uconsole, nixos-raspberrypi, ... }@inputs: outputs = { self, nixpkgs, agenix, lix, nixos-uconsole, nixos-raspberrypi, ... }@inputs:
let let
system = "x86_64-linux"; system = "x86_64-linux";
keys = import ./lib/keys.nix; keys = import ./lib/keys.nix;
@@ -95,21 +89,19 @@
]; ];
}; };
uConsole = nixos-uconsole.lib.mkUConsoleSystem { uConsole = nixos-raspberrypi.lib.nixosSystem {
variant = "cm5";
specialArgs = { inherit self keys paths inputs nixos-raspberrypi; }; specialArgs = { inherit self keys paths inputs nixos-raspberrypi; };
modules = [ modules = [
{ {
nixpkgs.overlays = overlays; nixpkgs.overlays = overlays;
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
nixpkgs.config.permittedInsecurePackages = [ nixpkgs.hostPlatform = "aarch64-linux";
"openclaw-2026.3.12" nix.package = lix.packages."aarch64-linux".default;
];
} }
disko.nixosModules.disko nixos-raspberrypi.nixosModules.raspberry-pi-5.base
nixos-uconsole.nixosModules.uconsole-cm5
./hosts/uConsole/configuration.nix ./hosts/uConsole/configuration.nix
./hosts/uConsole/hardware-configuration.nix ./hosts/uConsole/hardware-configuration.nix
./hosts/uConsole/disko-config.nix
]; ];
}; };
}; };

125
hosts/uConsole/configuration.nix Executable file → Normal file
View File

@@ -1,19 +1,5 @@
{ config, lib, pkgs, paths, self, keys, ... }: { 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 # Basic Host Info
networking.hostName = "uConsole"; networking.hostName = "uConsole";
@@ -21,37 +7,19 @@ in
i18n.defaultLocale = "en_CA.UTF-8"; i18n.defaultLocale = "en_CA.UTF-8";
# System State # System State
system.stateVersion = "25.11"; system.stateVersion = "25.05";
# Boot & Hardware (migrated to kernel bootloader per nixos-raspberrypi deprecation notice) # Boot & Hardware (migrated to kernel bootloader per nixos-raspberrypi deprecation notice)
boot.loader.raspberry-pi.bootloader = "kernel"; boot.loader.raspberry-pi.bootloader = "kernel";
# kernel managed by nixos-raspberrypi module — don't override, patches are version-specific # kernel managed by nixos-raspberrypi module — don't override, patches are version-specific
# boot.kernelPackages = pkgs.linuxPackages_latest; # boot.kernelPackages = pkgs.linuxPackages_latest;
# Kernel parameters matching nixos-uconsole CM5 module
# console=tty1 is critical — without it, console output goes to ttyAMA0 not fb0
boot.kernelParams = [
"8250.nr_uarts=1"
"console=tty1"
];
# Enable Mesa GPU drivers — REQUIRED for VC4 display pipeline to initialize
hardware.graphics.enable = true;
# Console font sized for the 5" 720x1280 display (from nixos-uconsole base module)
console = {
earlySetup = true;
font = "ter-v24n";
packages = with pkgs; [ terminus_font ];
};
# Networking # Networking
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
services.openssh = { services.openssh = {
enable = true; enable = true;
# TODO: lock down after first deployment settings.PermitRootLogin = lib.mkForce "prohibit-password";
settings.PermitRootLogin = lib.mkForce "yes"; settings.PasswordAuthentication = lib.mkForce false;
settings.PasswordAuthentication = lib.mkForce true;
}; };
# User # User
@@ -88,7 +56,6 @@ in
htop htop
tmux tmux
neovim neovim
libgpiod # GPIO control (for internal USB hub, AIO modules)
# ===== HAM Radio ===== # ===== HAM Radio =====
js8call js8call
@@ -108,8 +75,7 @@ in
soapysdr-with-plugins # SoapySDR + hardware support plugins soapysdr-with-plugins # SoapySDR + hardware support plugins
# ===== Mesh / LoRa ===== # ===== Mesh / LoRa =====
# meshtastic not available in nixpkgs 25.11 stable; install manually: meshtastic # Python CLI for Meshtastic devices
# nix shell nixpkgs#meshtastic -c meshtastic
reticulumStack # Reticulum Network Stack (rnsd, rnsh, rncp, rnx, rnpath, etc.) reticulumStack # Reticulum Network Stack (rnsd, rnsh, rncp, rnx, rnpath, etc.)
lxmf # LXMF messaging protocol lxmf # LXMF messaging protocol
nomadnet # Nomad Network client nomadnet # Nomad Network client
@@ -173,33 +139,22 @@ in
}; };
# ============================================================ # ============================================================
# Kernel modules for SDR, radio, and WiFi # Kernel modules for SDR and radio
# ============================================================ # ============================================================
boot.kernelModules = [ boot.kernelModules = [
"mt7921u" # MediaTek MT7921 USB WiFi (uConsole AC1200)
"88x2bu" # Realtek 8812/8821BU USB WiFi (common adapter) "88x2bu" # Realtek 8812/8821BU USB WiFi (common adapter)
"rtl8xxxu" # RTL8188/8192/8723 USB WiFi "rtl8xxxu" # RTL8188/8192/8723 USB WiFi
"rtl2832_sdr" # RTL-SDR kernel module "rtl2832_sdr" # RTL-SDR kernel module
"dvb_usb_rtl28xxu" # RTL-SDR DVB-T "dvb_usb_rtl28xxu" # RTL-SDR DVB-T
# Display drivers — loaded AFTER RP1 PCIe southbridge init (~12s)
# NOTHING in initrd — ALL RP1 hardware is behind PCIe
"panel_cwu50" # uConsole DSI panel driver
"vc4" # VideoCore 4 KMS GPU driver
"rp1_dsi" # RP1 DSI bridge driver
]; ];
boot.blacklistedKernelModules = [ ]; boot.blacklistedKernelModules = [ ];
# Rien dans initrd pour le display — tout RP1 est derrière PCIe
boot.initrd.kernelModules = lib.mkForce [ ];
# ============================================================ # ============================================================
# Extra udev rules for SDR and HAM radio devices # Extra udev rules for SDR and HAM radio devices
# ============================================================ # ============================================================
services.udev.packages = with pkgs; [ rtl-sdr ]; services.udev.packages = with pkgs; [ rtl-sdr ];
# ============================================================ # ============================================================
# Enable IPv6 for Reticulum mesh # Enable IPv6 for Reticulum mesh
# ============================================================ # ============================================================
@@ -213,74 +168,4 @@ in
# Reticulum uses its own encryption and doesn't need open ports # Reticulum uses its own encryption and doesn't need open ports
# for basic mesh operations (peer-to-peer discovery). # for basic mesh operations (peer-to-peer discovery).
# For TCP interfaces, open additional ports as needed. # For TCP interfaces, open additional ports as needed.
# ============================================================
# Hyprland Wayland compositor (manual start)
# No SDDM — boot to console, user starts Hyprland with command
# Display modules (vc4/panel_cwu50) load late after RP1 PCIe init
# ============================================================
programs.hyprland = {
enable = true;
xwayland.enable = true;
};
# SDDM disabled — was blocking boot when display isn't ready
# services.displayManager.sddm = {
# enable = true;
# wayland.enable = true;
# };
# ============================================================
# CM5 Config.txt Fix: use [pi5] section (not [cm5])
# Rex's images use [pi5], the CM5 firmware may not detect [cm5]
# ============================================================
# Merge nixos-uconsole GPIO config with our [pi5] overrides
# GPIO 10/11 are from nixos-uconsole configtxt.nix (audio amplifier)
# [pi5] section fixes the CM5 detection issue — firmware matches [pi5] not [cm5]
hardware.raspberry-pi.extra-config = ''
[all]
gpio=10=ip,np
gpio=11=op,dh
[pi5]
dtparam=pciex1=off
dtoverlay=clockworkpi-uconsole-cm5
dtoverlay=dwc2,dr_mode=host
dtoverlay=vc4-kms-v3d-pi5,cma-384
dtparam=nohdmi1=off
'';
# ============================================================
# 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";
# };
# };
} }

View File

@@ -1,46 +0,0 @@
{ lib, ... }:
{
disko.devices.disk.main = {
type = "disk";
device = "/dev/mmcblk0";
content = {
type = "gpt";
partitions = {
boot = {
name = "FIRMWARE";
size = "1G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot/firmware";
mountOptions = [
"fmask=0022"
"dmask=0022"
];
};
};
root = {
name = "NIXOS_UCM5";
size = "30G";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
mountOptions = [ "noatime" ];
};
};
home = {
name = "NIXOS_HOME";
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/home";
mountOptions = [ "noatime" ];
};
};
};
};
};
}

View File

@@ -9,28 +9,15 @@
boot.initrd.kernelModules = [ ]; boot.initrd.kernelModules = [ ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
# Filesystems for NixOS install. # uConsole CM5 uses NVMe or eMMC for boot storage
# mkForce overrides disko's auto-generated paths so we can use # The uconsole-cm5 module sets up /boot/firmware and default /
# filesystem labels (by-label) which work with loop device installs. # Override device label here if using different storage
# Disko will set its own paths when nixos-anywhere is used. fileSystems."/" = lib.mkDefault {
fileSystems."/" = lib.mkForce {
device = "/dev/disk/by-label/NIXOS_UCM5"; device = "/dev/disk/by-label/NIXOS_UCM5";
fsType = "ext4"; fsType = "ext4";
options = [ "noatime" ]; options = [ "noatime" ];
}; };
fileSystems."/boot/firmware" = lib.mkForce {
device = "/dev/disk/by-label/FIRMWARE";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
fileSystems."/home" = lib.mkForce {
device = "/dev/disk/by-label/NIXOS_HOME";
fsType = "ext4";
options = [ "noatime" ];
};
swapDevices = [ ]; swapDevices = [ ];
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux"; nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";

13
overlays/reticulum.nix Executable file → Normal file
View File

@@ -1,8 +1,7 @@
final: prev: let final: prev: let
python3 = final.python3; python3 = final.python3;
pyPkgs = python3.pkgs; pyPkgs = python3.pkgs;
in in {
{
reticulumStack = python3.pkgs.buildPythonApplication rec { reticulumStack = python3.pkgs.buildPythonApplication rec {
pname = "reticulum"; pname = "reticulum";
version = "1.2.9"; version = "1.2.9";
@@ -12,12 +11,6 @@ in
inherit version; inherit version;
sha256 = "554814231c237b9caacf8df669312e57dd7d3f84b6d4810125087d1a79a75d75"; sha256 = "554814231c237b9caacf8df669312e57dd7d3f84b6d4810125087d1a79a75d75";
}; };
patchPhase = ''
# Fix license_files syntax: ("LICENSE") is a string not tuple
# Newer setuptools iterates over it char by char, fails on 'S'
substituteInPlace setup.py \
--replace-fail 'license_files = ("LICENSE")' 'license_files = ("LICENSE",)'
'';
propagatedBuildInputs = with pyPkgs; [ cryptography pyserial ]; propagatedBuildInputs = with pyPkgs; [ cryptography pyserial ];
doCheck = false; doCheck = false;
pythonImportsCheck = [ "RNS" ]; pythonImportsCheck = [ "RNS" ];
@@ -86,7 +79,3 @@ in
}; };
}; };
} }
# meshtastic may not exist in all nixpkgs versions (e.g. not in 25.11)
// prev.lib.optionalAttrs (prev ? meshtastic) {
inherit (prev) meshtastic;
}