klipper-flash: support can bus flashing, support flashing avr mcus (#524434)

This commit is contained in:
Cabia Rangris
2026-06-01 16:11:37 +00:00
committed by GitHub
5 changed files with 97 additions and 28 deletions

View File

@@ -40,11 +40,27 @@ let
'';
serial = lib.mkOption {
type = lib.types.nullOr lib.types.path;
description = "Path to serial port this printer is connected to. Derived from `service.klipper.settings` by default.";
description = "Path to serial port this mcu is connected to. Derived from `service.klipper.settings` by default.";
defaultText = lib.literalExpression "config.services.klipper.settings.<name>.serial";
default =
if lib.hasAttrByPath [ "${mcu}" "serial" ] cfg.settings then cfg.settings."${mcu}".serial else null;
};
canbus_uuid = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "CAN bus uuid of this mcu. Derived from `service.klipper.settings` by default.";
defaultText = lib.literalExpression "config.services.klipper.settings.<name>.canbus_uuid";
default =
if lib.hasAttrByPath [ "${mcu}" "canbus_uuid" ] cfg.settings then
cfg.settings."${mcu}".canbus_uuid
else
null;
};
canbusNetwork = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "CAN bus network this mcu is connected to. Defaults to can0 if canbus_uuid is set.";
defaultText = lib.literalExpression ''if canbus_uuid != null then "can0" else null'';
default = if subcfg.canbus_uuid != null then "can0" else null;
};
configFile = lib.mkOption {
type = lib.types.path;
description = "Path to firmware config which is generated using `klipper-genconf`";
@@ -78,6 +94,8 @@ let
klipper-firmware = subcfg.package;
mcu = lib.strings.sanitizeDerivationName mcu;
flashDevice = subcfg.serial;
canbusDevice = subcfg.canbus_uuid;
canbusNetwork = subcfg.canbusNetwork;
firmwareConfig = subcfg.configFile;
}
else
@@ -224,12 +242,15 @@ in
}
]
++ lib.mapAttrsToList (mcu: firmware: {
assertion = firmware.enableKlipperFlash -> firmware.serial != null;
assertion =
firmware.enableKlipperFlash -> (firmware.serial != null || firmware.canbus_uuid != null);
message = ''
Unable to determine the serial connection for services.klipper.firmwares."${mcu}". Please set one of the following:
Unable to determine the serial or canbus connection for services.klipper.firmwares."${mcu}". Please set one of the following:
- services.klipper.firmwares."${mcu}".serial
- services.klipper.firmwares."${mcu}".canbus_uuid
- services.klipper.settings."${mcu}".serial
- services.klipper.settings."${mcu}".canbus_uuid
'';
}) cfg.firmwares;
@@ -308,7 +329,6 @@ in
environment.systemPackages =
let
default = a: b: if a != null then a else b;
genconf = pkgs.klipper-genconf.override {
klipper = cfg.package;
};

View File

@@ -90,6 +90,7 @@ stdenv.mkDerivation rec {
p: with p; [
numpy
matplotlib
python-can
]
)).interpreter;
@@ -109,8 +110,10 @@ stdenv.mkDerivation rec {
# under `klipper_path`
cp -r $src/docs $out/lib/docs
cp -r $src/config $out/lib/config
cp -r $src/scripts $out/lib/scripts
cp -r $src/klippy $out/lib/klippy
mkdir -p $out/lib/scripts
cp -r $src/scripts/* $out/lib/scripts
cp $src/lib/katapult/flashtool.py $out/lib/scripts/flash_can.py
# Add version information. For the normal procedure see https://www.klipper3d.org/Packaging.html#versioning
# This is done like this because scripts/make_version.py is not available when sourceRoot is set to "${src.name}/klippy"
@@ -125,6 +128,11 @@ stdenv.mkDerivation rec {
--subst-var-by "script" "calibrate_shaper.py"
chmod 755 "$out/bin/klipper-calibrate-shaper"
substitute "$pythonScriptWrapper" "$out/bin/klipper-canbus-query" \
--subst-var "out" \
--subst-var-by "script" "canbus_query.py"
chmod 755 "$out/bin/klipper-canbus-query"
runHook postInstall
'';

View File

@@ -72,6 +72,7 @@ stdenv.mkDerivation {
cp ./.config $out/config
cp out/klipper.bin $out/ || true
cp out/klipper.elf $out/ || true
cp out/klipper.elf.hex $out/ || true
cp out/klipper.uf2 $out/ || true
mkdir -p $out/lib/
@@ -95,7 +96,11 @@ stdenv.mkDerivation {
passthru = {
makeFlasher =
{ flashDevice }:
{
flashDevice ? null,
canbusNetwork ? null,
canbusDevice ? null,
}:
klipper-flash.override {
klipper-firmware = klipper-firmware.override args;
inherit
@@ -103,6 +108,8 @@ stdenv.mkDerivation {
firmwareConfig
mcu
flashDevice
canbusNetwork
canbusDevice
;
};
};

View File

@@ -7,7 +7,9 @@
dfu-util,
stm32flash,
mcu ? "mcu",
flashDevice ? "/dev/null",
flashDevice ? null,
canbusNetwork ? null,
canbusDevice ? null,
firmwareConfig ? ./simulator.cfg,
}:
let
@@ -20,34 +22,66 @@ let
if matches != null then head matches else null;
matchPlatform = getConfigField "CONFIG_BOARD_DIRECTORY";
matchBoard = getConfigField "CONFIG_MCU";
matchAvrdudeProtocol = getConfigField "CONFIG_AVRDUDE_PROTOCOL";
flashUsbSupportedBoards = [
"sam3"
"sam4"
"same70"
"samd"
"same5"
"lpc176"
"stm32f103"
"stm32f4"
"stm32f042"
"stm32f070"
"stm32f072"
"stm32g0b1"
"stm32f7"
"stm32h7"
"stm32l4"
"stm32g4"
"rp2"
];
in
assert lib.assertMsg (
(flashDevice != null) != (canbusNetwork != null && canbusDevice != null)
&& ((canbusNetwork != null) == (canbusDevice != null))
) "Either set flashDevice or both canbusNetwork and canbusDevice";
writeShellApplication {
name = "klipper-flash-${mcu}";
runtimeInputs =
[ ]
++ lib.optionals (matchPlatform == "avr") [ avrdude ]
++ lib.optionals (matchPlatform == "stm32") [
stm32flash
dfu-util
]
++ lib.optionals (matchPlatform == "lpc176x") [ dfu-util ]
# bossac, hid-flash and RP2040 flash binaries are built by klipper-firmware
;
++ lib.optionals (flashDevice != null) (
lib.optionals (matchPlatform == "avr") [ avrdude ]
++ lib.optionals (matchPlatform == "stm32") [
stm32flash
dfu-util
]
++ lib.optionals (matchPlatform == "lpc176x") [ dfu-util ]
# bossac, hid-flash and RP2040 flash binaries are built by klipper-firmware
);
text =
# generic USB script for most things with serial and bootloader (see MCU_TYPES in scripts/flash_usb.py)
if matchBoard != null && matchPlatform != null then
''
pushd ${klipper-firmware}
${klipper}/lib/scripts/flash_usb.py -t ${matchBoard} -d ${flashDevice} ${klipper-firmware}/klipper.bin "$@"
popd
''
if flashDevice != null then
if (builtins.elem matchBoard flashUsbSupportedBoards) && matchPlatform != null then
''
${klipper}/lib/scripts/flash_usb.py -t ${matchBoard} -d ${flashDevice} ${klipper-firmware}/klipper.bin "$@"
''
else if matchPlatform == "avr" && matchAvrdudeProtocol != null && matchBoard != null then
''
avrdude -p${matchBoard} -c${matchAvrdudeProtocol} -P"${flashDevice}" -D -U"flash:w:${klipper-firmware}/klipper.elf.hex:i"
''
else
''
cat <<EOF
Board pair ${toString matchBoard}/${toString matchPlatform} (config ${firmwareConfig}) is not supported in NixOS auto flashing script.
Please manually flash the firmware using the appropriate tool for your board.
Built firmware is located here:
${klipper-firmware}
EOF
''
else
''
cat <<EOF
Board pair ${toString matchBoard}/${toString matchPlatform} (config ${firmwareConfig}) is not supported in NixOS auto flashing script.
Please manually flash the firmware using the appropriate tool for your board.
Built firmware is located here:
${klipper-firmware}
EOF
${klipper}/lib/scripts/flash_can.py -i ${canbusNetwork} -f ${klipper-firmware}/klipper.bin -u ${canbusDevice} "$@"
'';
}

View File

@@ -1772,7 +1772,7 @@ with pkgs;
klipper-firmware = callPackage ../servers/klipper/klipper-firmware.nix { };
klipper-flash = callPackage ../servers/klipper/klipper-flash.nix { };
klipper-flash = callPackage ../servers/klipper/klipper-flash.nix { flashDevice = "/dev/null"; };
klipper-genconf = callPackage ../servers/klipper/klipper-genconf.nix { };