diff --git a/firmware/update_fw.sh b/firmware/update_fw.sh index 29199ff..62d5074 100755 --- a/firmware/update_fw.sh +++ b/firmware/update_fw.sh @@ -5,9 +5,10 @@ # toolhead — EBB SB2209 (rp2040; прошивается по CAN через katapult) # # Использование: -# update_fw.sh [-h] [--build-only] [--force] [host|mcu|toolhead ...] +# update_fw.sh [-h] [--build-only|--no-build] [--force] [host|mcu|toolhead ...] # без целей — все три # --build-only — только собрать прошивки в ~/firmware, ничего не прошивать +# --no-build — не собирать, прошить уже собранные ~/firmware/<цель>_klipper.{bin,elf} # --force — не останавливаться, если Moonraker недоступен для проверки печати # # Исходники Klipper НЕ обновляются (это делает Moonraker Update Manager). @@ -50,18 +51,21 @@ ALL_TARGETS=(host mcu toolhead) # ---------- Разбор аргументов ---------- BUILD_ONLY=0 +NO_BUILD=0 FORCE=0 TARGETS=() for arg in "$@"; do case "$arg" in - -h|--help) sed -n '2,15p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0 ;; + -h|--help) sed -n '2,16p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'; exit 0 ;; --build-only) BUILD_ONLY=1 ;; + --no-build) NO_BUILD=1 ;; --force) FORCE=1 ;; host|mcu|toolhead) TARGETS+=("$arg") ;; *) echo "Неизвестный аргумент: $arg (см. -h)" >&2; exit 2 ;; esac done [ ${#TARGETS[@]} -eq 0 ] && TARGETS=("${ALL_TARGETS[@]}") +[ "$BUILD_ONLY" = 1 ] && [ "$NO_BUILD" = 1 ] && { echo "--build-only и --no-build несовместимы" >&2; exit 2; } want() { local t; for t in "${TARGETS[@]}"; do [ "$t" = "$1" ] && return 0; done; return 1; } # ---------- Лог и трапы ---------- @@ -119,7 +123,7 @@ mcu_versions() { # ---------- Preflight ---------- STAGE="предварительные проверки" section "Preflight" -echo "Цели: ${TARGETS[*]} build-only=$BUILD_ONLY лог: $LOG" +echo "Цели: ${TARGETS[*]} build-only=$BUILD_ONLY no-build=$NO_BUILD лог: $LOG" [ -d "$KLIPPER" ] || die "Нет исходников Klipper: $KLIPPER" [ -f "$KATAPULT" ] || die "Нет katapult flashtool: $KATAPULT" @@ -130,6 +134,23 @@ want toolhead && { [ -f "$CONFIG_DIR/$TOOLHEAD_CFG" ] || die "Нет конфи KLIPPER_VER=$(git -C "$KLIPPER" describe --always --tags --long --dirty 2>/dev/null || echo unknown) echo "Klipper в $KLIPPER: $KLIPPER_VER" +# Артефакт цели: ~/firmware/<цель>_klipper. (симлинк на <цель>-<версия>.) +artifact() { case "$1" in host) echo "$OUT_DIR/host_klipper.elf" ;; *) echo "$OUT_DIR/$1_klipper.bin" ;; esac; } + +if [ "$NO_BUILD" = 1 ]; then + echo "Без сборки — используются готовые прошивки:" + for t in "${TARGETS[@]}"; do + f=$(artifact "$t") + [ -s "$f" ] || die "Нет готовой прошивки $f (соберите: $0 --build-only $t)" + real=$(readlink -f "$f") + echo " $t: $(basename "$real") ($(stat -c %s "$real") байт)" + case "$(basename "$real")" in + *"-${KLIPPER_VER}."*) ;; + *) echo " !!! $t: прошивка собрана не из текущего $KLIPPER_VER" ;; + esac + done +fi + BEFORE="" if [ "$BUILD_ONLY" = 0 ]; then if want mcu || want toolhead; then @@ -179,14 +200,15 @@ build() { # build <цель> <конфиг> <артефакт: bin|elf> [ -s "$src" ] || die "Сборка $name не дала $src" local dst="$OUT_DIR/${name}-${KLIPPER_VER}.$ext" cp "$src" "$dst" - ln -sfn "$(basename "$dst")" "$OUT_DIR/${name}_klipper.$ext" + ln -sfn "$(basename "$dst")" "$(artifact "$name")" echo "-> $dst ($(stat -c %s "$dst") байт)" } -# host собирается последним: его out/ нужен для make flash -want mcu && build mcu "$MCU_CFG" bin -want toolhead && build toolhead "$TOOLHEAD_CFG" bin -want host && build host "$HOST_CFG" elf +if [ "$NO_BUILD" = 0 ]; then + want mcu && build mcu "$MCU_CFG" bin + want toolhead && build toolhead "$TOOLHEAD_CFG" bin + want host && build host "$HOST_CFG" elf +fi if [ "$BUILD_ONLY" = 1 ]; then section "Готово (только сборка)" @@ -203,9 +225,12 @@ KLIPPER_STOPPED=1 if want host; then STAGE="прошивка host MCU" section "Прошивка host (klipper-mcu)" - # flash-linux.sh копирует out/klipper.elf в /usr/local/bin/klipper_mcu и перезапускает klipper-mcu + # flash-linux.sh копирует /klipper.elf в /usr/local/bin/klipper_mcu и перезапускает klipper-mcu. + # Подсовываем ему каталог с артефактом из ~/firmware, а не out/ (там может быть сборка другой цели) + mkdir -p "$BUILD_TMP/host" + cp "$(artifact host)" "$BUILD_TMP/host/klipper.elf" HOST_PID_OLD=$(systemctl show -p ExecMainPID --value klipper-mcu) - make -C "$KLIPPER" flash KCONFIG_CONFIG="$BUILD_TMP/$HOST_CFG" + sudo "$KLIPPER/scripts/flash-linux.sh" "$BUILD_TMP/host" [ "$(stat -c %Y "$HOST_BIN")" -ge "$START_TS" ] || die "$HOST_BIN не обновился" host_restarted() { [ "$(systemctl show -p ExecMainPID --value klipper-mcu)" != "$HOST_PID_OLD" ] \ @@ -230,7 +255,7 @@ if want mcu; then DEV=$(katapult_serial) echo "katapult serial: $DEV" sleep 1 # порт может быть ещё не готов сразу после появления симлинка - python3 "$KATAPULT" -d "$DEV" -f "$OUT_DIR/mcu_klipper.bin" + python3 "$KATAPULT" -d "$DEV" -f "$(artifact mcu)" # После прошивки плата перезагружается в Klipper и снова поднимает USB-CAN мост wait_for 30 "Octopus не вернулся на $CAN_IF после прошивки" can_has_uuid "$MCU_UUID" echo "Octopus снова на $CAN_IF" @@ -240,7 +265,7 @@ if want toolhead; then STAGE="прошивка тулхеда" section "Прошивка toolhead (EBB SB2209, uuid $TOOLHEAD_UUID)" # flashtool сам отправляет запрос бутлоадера по UUID и заливает прошивку - python3 "$KATAPULT" -i "$CAN_IF" -u "$TOOLHEAD_UUID" -f "$OUT_DIR/toolhead_klipper.bin" + python3 "$KATAPULT" -i "$CAN_IF" -u "$TOOLHEAD_UUID" -f "$(artifact toolhead)" wait_for 30 "тулхед не вернулся на $CAN_IF после прошивки" can_has_uuid "$TOOLHEAD_UUID" echo "Тулхед снова на $CAN_IF" fi