update_fw.sh: флаг --no-build — прошивка готовых артефактов из ~/firmware

host прошивается через scripts/flash-linux.sh из ~/firmware/host_klipper.elf,
а не из out/, поэтому не зависит от порядка сборки.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 05:28:12 +03:00
parent 2209c0e1f9
commit f29dc7c6ad
+34 -9
View File
@@ -5,9 +5,10 @@
# toolhead — EBB SB2209 (rp2040; прошивается по CAN через katapult) # 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, ничего не прошивать # --build-only — только собрать прошивки в ~/firmware, ничего не прошивать
# --no-build — не собирать, прошить уже собранные ~/firmware/<цель>_klipper.{bin,elf}
# --force — не останавливаться, если Moonraker недоступен для проверки печати # --force — не останавливаться, если Moonraker недоступен для проверки печати
# #
# Исходники Klipper НЕ обновляются (это делает Moonraker Update Manager). # Исходники Klipper НЕ обновляются (это делает Moonraker Update Manager).
@@ -50,18 +51,21 @@ ALL_TARGETS=(host mcu toolhead)
# ---------- Разбор аргументов ---------- # ---------- Разбор аргументов ----------
BUILD_ONLY=0 BUILD_ONLY=0
NO_BUILD=0
FORCE=0 FORCE=0
TARGETS=() TARGETS=()
for arg in "$@"; do for arg in "$@"; do
case "$arg" in 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 ;; --build-only) BUILD_ONLY=1 ;;
--no-build) NO_BUILD=1 ;;
--force) FORCE=1 ;; --force) FORCE=1 ;;
host|mcu|toolhead) TARGETS+=("$arg") ;; host|mcu|toolhead) TARGETS+=("$arg") ;;
*) echo "Неизвестный аргумент: $arg (см. -h)" >&2; exit 2 ;; *) echo "Неизвестный аргумент: $arg (см. -h)" >&2; exit 2 ;;
esac esac
done done
[ ${#TARGETS[@]} -eq 0 ] && TARGETS=("${ALL_TARGETS[@]}") [ ${#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; } want() { local t; for t in "${TARGETS[@]}"; do [ "$t" = "$1" ] && return 0; done; return 1; }
# ---------- Лог и трапы ---------- # ---------- Лог и трапы ----------
@@ -119,7 +123,7 @@ mcu_versions() {
# ---------- Preflight ---------- # ---------- Preflight ----------
STAGE="предварительные проверки" STAGE="предварительные проверки"
section "Preflight" 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" [ -d "$KLIPPER" ] || die "Нет исходников Klipper: $KLIPPER"
[ -f "$KATAPULT" ] || die "Нет katapult flashtool: $KATAPULT" [ -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) KLIPPER_VER=$(git -C "$KLIPPER" describe --always --tags --long --dirty 2>/dev/null || echo unknown)
echo "Klipper в $KLIPPER: $KLIPPER_VER" echo "Klipper в $KLIPPER: $KLIPPER_VER"
# Артефакт цели: ~/firmware/<цель>_klipper.<bin|elf> (симлинк на <цель>-<версия>.<ext>)
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="" BEFORE=""
if [ "$BUILD_ONLY" = 0 ]; then if [ "$BUILD_ONLY" = 0 ]; then
if want mcu || want toolhead; then if want mcu || want toolhead; then
@@ -179,14 +200,15 @@ build() { # build <цель> <конфиг> <артефакт: bin|elf>
[ -s "$src" ] || die "Сборка $name не дала $src" [ -s "$src" ] || die "Сборка $name не дала $src"
local dst="$OUT_DIR/${name}-${KLIPPER_VER}.$ext" local dst="$OUT_DIR/${name}-${KLIPPER_VER}.$ext"
cp "$src" "$dst" cp "$src" "$dst"
ln -sfn "$(basename "$dst")" "$OUT_DIR/${name}_klipper.$ext" ln -sfn "$(basename "$dst")" "$(artifact "$name")"
echo "-> $dst ($(stat -c %s "$dst") байт)" echo "-> $dst ($(stat -c %s "$dst") байт)"
} }
# host собирается последним: его out/ нужен для make flash if [ "$NO_BUILD" = 0 ]; then
want mcu && build mcu "$MCU_CFG" bin want mcu && build mcu "$MCU_CFG" bin
want toolhead && build toolhead "$TOOLHEAD_CFG" bin want toolhead && build toolhead "$TOOLHEAD_CFG" bin
want host && build host "$HOST_CFG" elf want host && build host "$HOST_CFG" elf
fi
if [ "$BUILD_ONLY" = 1 ]; then if [ "$BUILD_ONLY" = 1 ]; then
section "Готово (только сборка)" section "Готово (только сборка)"
@@ -203,9 +225,12 @@ KLIPPER_STOPPED=1
if want host; then if want host; then
STAGE="прошивка host MCU" STAGE="прошивка host MCU"
section "Прошивка host (klipper-mcu)" section "Прошивка host (klipper-mcu)"
# flash-linux.sh копирует out/klipper.elf в /usr/local/bin/klipper_mcu и перезапускает klipper-mcu # flash-linux.sh <dir> копирует <dir>/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) 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 не обновился" [ "$(stat -c %Y "$HOST_BIN")" -ge "$START_TS" ] || die "$HOST_BIN не обновился"
host_restarted() { host_restarted() {
[ "$(systemctl show -p ExecMainPID --value klipper-mcu)" != "$HOST_PID_OLD" ] \ [ "$(systemctl show -p ExecMainPID --value klipper-mcu)" != "$HOST_PID_OLD" ] \
@@ -230,7 +255,7 @@ if want mcu; then
DEV=$(katapult_serial) DEV=$(katapult_serial)
echo "katapult serial: $DEV" echo "katapult serial: $DEV"
sleep 1 # порт может быть ещё не готов сразу после появления симлинка sleep 1 # порт может быть ещё не готов сразу после появления симлинка
python3 "$KATAPULT" -d "$DEV" -f "$OUT_DIR/mcu_klipper.bin" python3 "$KATAPULT" -d "$DEV" -f "$(artifact mcu)"
# После прошивки плата перезагружается в Klipper и снова поднимает USB-CAN мост # После прошивки плата перезагружается в Klipper и снова поднимает USB-CAN мост
wait_for 30 "Octopus не вернулся на $CAN_IF после прошивки" can_has_uuid "$MCU_UUID" wait_for 30 "Octopus не вернулся на $CAN_IF после прошивки" can_has_uuid "$MCU_UUID"
echo "Octopus снова на $CAN_IF" echo "Octopus снова на $CAN_IF"
@@ -240,7 +265,7 @@ if want toolhead; then
STAGE="прошивка тулхеда" STAGE="прошивка тулхеда"
section "Прошивка toolhead (EBB SB2209, uuid $TOOLHEAD_UUID)" section "Прошивка toolhead (EBB SB2209, uuid $TOOLHEAD_UUID)"
# flashtool сам отправляет запрос бутлоадера по 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" wait_for 30 "тулхед не вернулся на $CAN_IF после прошивки" can_has_uuid "$TOOLHEAD_UUID"
echo "Тулхед снова на $CAN_IF" echo "Тулхед снова на $CAN_IF"
fi fi