Merge pull request #165151 from vtuan10/klipper-firmware

nixos/klipper: Add Klipper firmware options
This commit is contained in:
Bernardo Meurer 2022-08-01 14:07:26 -07:00 committed by GitHub
commit 6f435e54b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 215 additions and 22 deletions

View File

@ -5,9 +5,9 @@ let
format = pkgs.formats.ini {
# https://github.com/NixOS/nixpkgs/pull/121613#issuecomment-885241996
listToValue = l:
if builtins.length l == 1 then generators.mkValueStringDefault {} (head l)
if builtins.length l == 1 then generators.mkValueStringDefault { } (head l)
else lib.concatMapStrings (s: "\n ${generators.mkValueStringDefault {} s}") l;
mkKeyValue = generators.mkKeyValueDefault {} ":";
mkKeyValue = generators.mkKeyValueDefault { } ":";
};
in
{
@ -69,6 +69,24 @@ in
for supported values.
'';
};
firmwares = mkOption {
description = "Firmwares klipper should manage";
default = { };
type = with types; attrsOf
(submodule {
options = {
enable = mkEnableOption ''
building of firmware and addition of klipper-flash tools for manual flashing.
This will add `klipper-flash-$mcu` scripts to your environment which can be called to flash the firmware.
'';
configFile = mkOption {
type = path;
description = "Path to firmware config which is generated using `klipper-genconf`";
};
};
});
};
};
};
@ -83,6 +101,10 @@ in
assertion = cfg.user != null -> cfg.group != null;
message = "Option klipper.group is not set when a user is specified.";
}
{
assertion = foldl (a: b: a && b) true (mapAttrsToList (mcu: _: mcu != null -> (hasAttrByPath [ "${mcu}" "serial" ] cfg.settings)) cfg.firmwares);
message = "Option klipper.settings.$mcu.serial must be set when klipper.firmware.$mcu is specified";
}
];
environment.etc."klipper.cfg".source = format.generate "klipper.cfg" cfg.settings;
@ -92,26 +114,48 @@ in
group = config.services.octoprint.group;
};
systemd.services.klipper = let
klippyArgs = "--input-tty=${cfg.inputTTY}"
+ optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}";
in {
description = "Klipper 3D Printer Firmware";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
systemd.services.klipper =
let
klippyArgs = "--input-tty=${cfg.inputTTY}"
+ optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}";
in
{
description = "Klipper 3D Printer Firmware";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecStart = "${cfg.package}/lib/klipper/klippy.py ${klippyArgs} /etc/klipper.cfg";
RuntimeDirectory = "klipper";
SupplementaryGroups = [ "dialout" ];
WorkingDirectory = "${cfg.package}/lib";
} // (if cfg.user != null then {
Group = cfg.group;
User = cfg.user;
} else {
DynamicUser = true;
User = "klipper";
});
};
serviceConfig = {
ExecStart = "${cfg.package}/lib/klipper/klippy.py ${klippyArgs} /etc/klipper.cfg";
RuntimeDirectory = "klipper";
SupplementaryGroups = [ "dialout" ];
WorkingDirectory = "${cfg.package}/lib";
} // (if cfg.user != null then {
Group = cfg.group;
User = cfg.user;
} else {
DynamicUser = true;
User = "klipper";
});
};
environment.systemPackages =
with pkgs;
let
firmwares = filterAttrs (n: v: v!= null) (mapAttrs
(mcu: { enable, configFile }: if enable then pkgs.klipper-firmware.override {
mcu = lib.strings.sanitizeDerivationName mcu;
firmwareConfig = configFile;
} else null)
cfg.firmwares);
firmwareFlasher = mapAttrsToList
(mcu: firmware: pkgs.klipper-flash.override {
mcu = lib.strings.sanitizeDerivationName mcu;
klipper-firmware = firmware;
flashDevice = cfg.settings."${mcu}".serial;
firmwareConfig = cfg.firmwares."${mcu}".configFile;
})
firmwares;
in
[ klipper-genconf ] ++ firmwareFlasher ++ attrValues firmwares;
};
}

View File

@ -0,0 +1,61 @@
{ stdenv
, lib
, pkg-config
, pkgsCross
, bintools-unwrapped
, libffi
, libusb1
, wxGTK
, python2
, python3
, gcc-arm-embedded
, klipper
, avrdude
, stm32flash
, mcu ? "mcu"
, firmwareConfig ? ./simulator.cfg
}: stdenv.mkDerivation rec {
name = "klipper-firmware-${mcu}-${version}";
version = klipper.version;
src = klipper.src;
nativeBuildInputs = [
python2
python3
pkgsCross.avr.stdenv.cc
gcc-arm-embedded
bintools-unwrapped
libffi
libusb1
avrdude
stm32flash
pkg-config
wxGTK # Required for bossac
];
preBuild = "cp ${firmwareConfig} ./.config";
postPatch = ''
patchShebangs .
'';
makeFlags = [
"V=1"
"KCONFIG_CONFIG=${firmwareConfig}"
];
installPhase = ''
mkdir -p $out
cp ./.config $out/config
cp -r out/* $out
'';
dontFixup = true;
meta = with lib; {
inherit (klipper.meta) homepage license;
description = "Firmware part of Klipper";
maintainers = with maintainers; [ vtuan10 ];
platforms = platforms.linux;
};
}

View File

@ -0,0 +1,38 @@
{ lib
, writeShellApplication
, gnumake
, pkgsCross
, klipper
, klipper-firmware
, python2
, avrdude
, stm32flash
, mcu ? "mcu"
, flashDevice ? "/dev/null"
, firmwareConfig ? ./simulator.cfg
}:
let
supportedArches = [ "avr" "stm32" "lpc176x" ];
matchBoard = with builtins; match ''^.*CONFIG_BOARD_DIRECTORY="([a-zA-Z0-9_]+)".*$'' (readFile firmwareConfig);
boardArch = if matchBoard == null then null else builtins.head matchBoard;
in
writeShellApplication {
name = "klipper-flash-${mcu}";
runtimeInputs = [
python2
pkgsCross.avr.stdenv.cc
gnumake
] ++ lib.optionals (boardArch == "avr") [ avrdude ] ++ lib.optionals (boardArch == "stm32") [ stm32flash ];
text = ''
if ${lib.boolToString (!builtins.elem boardArch supportedArches)}; then
printf "Flashing Klipper firmware to your board is not supported yet.\n"
printf "Please use the compiled firmware at ${klipper-firmware} and flash it using the tools provided for your microcontroller."
exit 1
fi
if ${lib.boolToString (boardArch == "stm32")}; then
make -C ${klipper.src} FLASH_DEVICE="${toString flashDevice}" OUT="${klipper-firmware}/" KCONFIG_CONFIG="${klipper-firmware}/config" serialflash
else
make -C ${klipper.src} FLASH_DEVICE="${toString flashDevice}" OUT="${klipper-firmware}/" KCONFIG_CONFIG="${klipper-firmware}/config" flash
fi
'';
}

View File

@ -0,0 +1,21 @@
{ writeShellApplication
, klipper
, python2
, gnumake
, pkgsCross
}: writeShellApplication {
name = "klipper-genconf";
runtimeInputs = [
python2
pkgsCross.avr.stdenv.cc
gnumake
];
text = ''
CURRENT_DIR=$(pwd)
TMP=$(mktemp -d)
make -C ${klipper.src} OUT="$TMP" KCONFIG_CONFIG="$CURRENT_DIR/config" menuconfig
rm -rf "$TMP" config.old
printf "\nYour firmware configuration for klipper:\n\n"
cat config
'';
}

View File

@ -0,0 +1,23 @@
# CONFIG_LOW_LEVEL_OPTIONS is not set
# CONFIG_MACH_AVR is not set
# CONFIG_MACH_ATSAM is not set
# CONFIG_MACH_ATSAMD is not set
# CONFIG_MACH_LPC176X is not set
# CONFIG_MACH_STM32 is not set
# CONFIG_MACH_RP2040 is not set
# CONFIG_MACH_PRU is not set
# CONFIG_MACH_LINUX is not set
CONFIG_MACH_SIMU=y
CONFIG_BOARD_DIRECTORY="simulator"
CONFIG_CLOCK_FREQ=20000000
CONFIG_SERIAL=y
CONFIG_SIMULATOR_SELECT=y
CONFIG_SERIAL_BAUD=250000
CONFIG_USB_VENDOR_ID=0x1d50
CONFIG_USB_DEVICE_ID=0x614e
CONFIG_USB_SERIAL_NUMBER="12345"
CONFIG_HAVE_GPIO=y
CONFIG_HAVE_GPIO_ADC=y
CONFIG_HAVE_GPIO_SPI=y
CONFIG_HAVE_GPIO_HARD_PWM=y
CONFIG_INLINE_STEPPER_HACK=y

View File

@ -4073,6 +4073,12 @@ with pkgs;
klipper = callPackage ../servers/klipper { };
klipper-firmware = callPackage ../servers/klipper/klipper-firmware.nix { };
klipper-flash = callPackage ../servers/klipper/klipper-flash.nix { };
klipper-genconf = callPackage ../servers/klipper/klipper-genconf.nix { };
klog = qt5.callPackage ../applications/radio/klog { };
krapslog = callPackage ../tools/misc/krapslog { };