Commit f8de8add authored by Cabia Rangris's avatar Cabia Rangris Committed by Cabia Rangris
Browse files

klipper-flash: rewrite flasher script

This completely removes gcc/make from the update loop, and fixes it for
at least some boards.

Although only tested on some boards, and probably lacking support
for some, that's vastly better than sending avr-gcc to your RPi every
update, and not working afterwards.

This also introduces makeFlasher in firmware passthroughs. Use it like
so:
```
  firmware = klipper-firmware.override {
    mcu = "myprinter";
    firmwareConfig = ./config;
  };
  flasher = firmware.makeFlasher {
    flashDevice = "/dev/ttyACM0";
  };
```
parent 9d1eed54
Loading
Loading
Loading
Loading
+52 −3
Original line number Diff line number Diff line
{
args@{
  klipper-firmware,
  stdenv,
  lib,
  pkg-config,
@@ -12,9 +13,19 @@
  klipper,
  avrdude,
  stm32flash,
  klipper-flash,
  mcu ? "mcu",
  firmwareConfig ? ./simulator.cfg,
}:
# are used by flash scripts
# find those with `rg '\[\"lib'` inside of klipper repo
let
  flashBinaries = [
    "lib/bossac/bin/bossac"
    "lib/hidflash/hid-flash"
    "lib/rp2040_flash/rp2040_flash"
  ];
in
stdenv.mkDerivation rec {
  name = "klipper-firmware-${mcu}-${version}";
  version = klipper.version;
@@ -38,7 +49,7 @@ stdenv.mkDerivation rec {
    chmod +w ./.config
    echo qy | { make menuconfig >/dev/null || true; }
    if ! diff ${firmwareConfig} ./.config; then
      echo " !!! Menuconfig has changed. Please update your configuration."
      echo " !!! Klipper KConfig has changed. Please run klipper-genconf to update your configuration."
    fi
  '';

@@ -46,6 +57,11 @@ stdenv.mkDerivation rec {
    patchShebangs .
  '';

  postBuild = ''
    # build flash binaries
    ${with builtins; concatStringsSep "\n" (map (path: "make ${path} $out/bin/ || true") flashBinaries)}
  '';

  makeFlags = [
    "V=1"
    "WXVERSION=3.2"
@@ -57,14 +73,47 @@ stdenv.mkDerivation rec {
    cp out/klipper.bin $out/ || true
    cp out/klipper.elf $out/ || true
    cp out/klipper.uf2 $out/ || true

    mkdir -p $out/lib/

    ${
      with builtins;
      concatStringsSep "\n" (
        map (path: ''
          if [ -e ${path} ]; then
            mkdir -p $out/$(dirname ${path})
            cp -r ${path} $out/$(dirname ${path})
          fi
        '') flashBinaries
      )
    }
    rmdir $out/lib 2>/dev/null || echo "Flash binaries exist, not cleaning up lib/"

  '';

  dontFixup = true;

  passthru = {
    makeFlasher =
      { flashDevice }:
      klipper-flash.override {
        klipper-firmware = klipper-firmware.override args;
        inherit
          klipper
          firmwareConfig
          mcu
          flashDevice
          ;
      };
  };

  meta = with lib; {
    inherit (klipper.meta) homepage license;
    description = "Firmware part of Klipper";
    maintainers = with maintainers; [ vtuan10 cab404 ];
    maintainers = with maintainers; [
      vtuan10
      cab404
    ];
    platforms = platforms.linux;
  };
}
+35 −29
Original line number Diff line number Diff line
{
  lib,
  writeShellApplication,
  gnumake,
  pkgsCross,
  klipper,
  klipper-firmware,
  python3,
  avrdude,
  dfu-util,
  stm32flash,
  mcu ? "mcu",
  flashDevice ? "/dev/null",
  firmwareConfig ? ./simulator.cfg,
}:
let
  supportedArches = [
    "avr"
    "stm32"
    "lpc176x"
  ];
  matchBoard =
  getConfigField =
    field:
    with builtins;
    match ''^.*CONFIG_BOARD_DIRECTORY="([a-zA-Z0-9_]+)".*$'' (readFile firmwareConfig);
  boardArch = if matchBoard == null then null else builtins.head matchBoard;
    let
      matches = match ''^.*${field}="([a-zA-Z0-9_]+)".*$'' (readFile firmwareConfig);
    in
    if matches != null then head matches else null;
  matchPlatform = getConfigField "CONFIG_BOARD_DIRECTORY";
  matchBoard = getConfigField "CONFIG_MCU";
in
writeShellApplication {
  name = "klipper-flash-${mcu}";
  runtimeInputs = [
    python3
    pkgsCross.avr.stdenv.cc
    gnumake
  runtimeInputs =
    [ ]
    ++ lib.optionals (matchPlatform == "avr") [ avrdude ]
    ++ lib.optionals (matchPlatform == "stm32") [
      stm32flash
      dfu-util
    ]
  ++ 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
    ++ 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
      ''
    else
      make -C ${klipper.src} FLASH_DEVICE="${toString flashDevice}" OUT="${klipper-firmware}/" KCONFIG_CONFIG="${klipper-firmware}/config" flash
    fi
      ''
        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
      '';
}