diff --git a/hardware/common/kit.sh b/hardware/common/kit.sh index 8885f7f..00e814b 100644 --- a/hardware/common/kit.sh +++ b/hardware/common/kit.sh @@ -69,12 +69,15 @@ probe_board() { # RP2040 running the gimbal firmware (arduino-pico) : "Raspberry_Pi_Pico" # RP2040 as shipped, still on MicroPython : "MicroPython_Board" # ATmega32U4 (Delta fleet) : "Arduino_LLC_Arduino_Leonardo" +# the same, running a legacy tower's firmware : "Unknown_LattePanda_Leonardo" probe_mcu() { local d found=() for d in /dev/serial/by-id/*; do [[ -e $d ]] || continue case "$d" in *Raspberry_Pi_Pico*|*MicroPython_Board*|*Arduino_LLC_Arduino*|*Pico*) found+=("$d") ;; + # The Delta's onboard Leonardo, as a legacy tower's firmware names it. + *LattePanda_Leonardo*) found+=("$d") ;; esac done (( ${#found[@]} == 1 )) && { echo "${found[0]}"; return; } diff --git a/scripts/install-tower b/scripts/install-tower index d234b76..a15e627 100755 --- a/scripts/install-tower +++ b/scripts/install-tower @@ -307,6 +307,21 @@ set -euo pipefail S_MCU="$(probe_mcu)" S_MCU_N=$(grep -c . <<< "$S_MCU" || true) +# Another program on the motor MCU's port - a legacy tower's old program, started +# by start_gimbal.service - would fight this one for it, and the flash would +# fail half-way. Our own program is fine: it is stopped before anything needs +# the port. +if (( S_MCU_N == 1 )) && [[ -e $S_MCU ]]; then + for pid in $(fuser "$(readlink -f "$S_MCU")" 2>/dev/null); do + args="$(ps -o args= -p "$pid" 2>/dev/null)" + [[ $args == */fire_gimbal_control* ]] && continue + die "the motor MCU's port is held by another program: pid $pid ($args). +Stop it for good before installing. On a legacy tower it is started by +start_gimbal.service from ~/scripts/startup_gimbal.sh, which also runs the picture +transfer: comment out the old program's line there, keep the transfer, then + sudo systemctl restart start_gimbal" + done +fi S_CAM="$(probe_camera_id)" S_LPM="$(probe_camera_lpm_path)" S_USBFS="$(cat /sys/module/usbcore/parameters/usbfs_memory_mb 2>/dev/null || echo '?')" @@ -326,7 +341,7 @@ S_MODE="none" case "$S_MCU" in *MicroPython*) S_MODE="factory MicroPython image" ;; *Raspberry_Pi_Pico*|*Pico*) S_MODE="gimbal firmware" ;; - *Arduino*) S_MODE="gimbal firmware (Leonardo)" ;; + *Arduino*|*Leonardo*) S_MODE="firmware on the Leonardo" ;; esac lsusb -d 2e8a:0003 >/dev/null 2>&1 && S_MODE="in its bootloader" diff --git a/scripts/survey-legacy-tower b/scripts/survey-legacy-tower index 047a22f..f777e2d 100755 --- a/scripts/survey-legacy-tower +++ b/scripts/survey-legacy-tower @@ -8,7 +8,7 @@ # bash survey-legacy-tower the machine, the old install, the camera # bash survey-legacy-tower --firmware also ask the old firmware for its # registers, travel and north calibration: -# pauses the old service for ~20 s +# pauses the old program for ~20 s # # The report is printed and saved to ~/legacy-survey-.txt. # @@ -37,8 +37,9 @@ echo "memory : $(free -h | awk '/^Mem/ {print $2}')" echo "internet : gitea:2222 $(reach git.ggs-solutions.eu 2222) github $(reach github.com 443) pypi $(reach pypi.org 443) platformio $(reach dl.registry.platformio.org 443)" hr "USB" -lsusb 2>/dev/null | grep -Ei '1ab2|2341|arduino|allied' || echo "(no Alvium or Arduino on lsusb)" +lsusb 2>/dev/null | grep -viE 'root hub' | sed 's/^/ /' ls /dev/serial/by-id/ 2>/dev/null | sed 's/^/by-id: /' +ls /dev/ttyACM* 2>/dev/null | sed 's/^/acm : /' hr "Vimba X and the camera" ls -d /opt/VimbaX* 2>/dev/null || echo "no /opt/VimbaX*" @@ -49,11 +50,44 @@ for tool in /opt/VimbaX*/bin/ListCameras_VmbC /opt/VimbaX*/bin/ListCameras; do break done -hr "the old install" -systemctl is-enabled fire-gimbal-control 2>/dev/null | sed 's/^/service enabled: /' -systemctl is-active fire-gimbal-control 2>/dev/null | sed 's/^/service active : /' -systemctl cat fire-gimbal-control 2>/dev/null | grep -E '^(ExecStart|WorkingDirectory|User|Environment)=' | sed 's/^/ /' -for c in /opt/fire_gimbal_control/config.ini "$HOME"/*/config.ini; do +hr "the old install - how it runs" +echo "-- systemd units that look like it (system and user):" +{ systemctl list-unit-files --no-legend 2>/dev/null; systemctl --user list-unit-files --no-legend 2>/dev/null; } | + grep -iE 'gimbal|fire[-_]|fwt|tower|camera|zkms' | sed 's/^/ /' || echo " (none)" +for u in $(systemctl list-unit-files --no-legend 2>/dev/null | awk '{print $1}' | grep -iE 'gimbal|fire[-_]|fwt|tower'); do + echo " -- $u: $(systemctl is-active "$u" 2>/dev/null)" + systemctl cat "$u" 2>/dev/null | grep -E '^(ExecStart|WorkingDirectory|User)=' | sed 's/^/ /' + # The script a legacy unit runs (start_gimbal.service -> startup_gimbal.sh): + # it starts the old program AND the picture transfer, so it matters which. + for f in $(systemctl cat "$u" 2>/dev/null | sed -n 's/^ExecStart=//p' | tr ' ' '\n' | grep -E '\.sh$'); do + [[ -r $f ]] || continue + echo " --- $f:" + grep -vE '^[[:space:]]*$' "$f" | head -25 | sed -E 's/(pass(word)?|pw)([=: ]).*/\1\3*****/I' | sed 's/^/ /' + for g in $(grep -oE '/[^ #&;]+\.sh' "$f" | sort -u); do + [[ -r $g && $g != "$f" ]] || continue + echo " --- $g (first lines):" + grep -vE '^[[:space:]]*$' "$g" | head -8 | sed -E 's/(pass(word)?|pw)([=: ]).*/\1\3*****/I' | sed 's/^/ /' + done + done +done +echo "-- processes that look like it:" +ps -eo pid,user,etime,args 2>/dev/null | grep -iE 'gimbal|fire_|fwt|vimba|zkms|tower|inotifywait' | grep -vE 'grep|survey-legacy|avahi' | sed 's/^/ /' || echo " (none)" +echo "-- what holds the serial ports:" +for d in /dev/ttyACM*; do + [[ -e $d ]] || continue + pids="$(fuser "$d" 2>/dev/null | tr -s ' ')" + if [[ -n ${pids// /} ]]; then for p in $pids; do echo " $d: pid $p $(ps -o args= -p "$p" 2>/dev/null)"; done + else echo " $d: free"; fi +done +echo "-- other ways it could start:" +crontab -l 2>/dev/null | grep -v '^#' | sed 's/^/ cron: /' +ls ~/.config/autostart/ 2>/dev/null | sed 's/^/ autostart: /' +tmux ls 2>/dev/null | sed 's/^/ tmux: /' +screen -ls 2>/dev/null | grep -E '^\s+[0-9]' | sed 's/^/ screen: /' +docker ps --format '{{.Names}} {{.Image}} {{.Status}}' 2>/dev/null | sed 's/^/ docker: /' +echo "-- home directory:" +ls -1 "$HOME" 2>/dev/null | sed 's/^/ /' +for c in /opt/fire_gimbal_control/config.ini "$HOME"/*/config.ini "$HOME"/*/*/config.ini; do [[ -r $c ]] || continue echo "-- $c (passwords masked)" grep -vE '^[[:space:]]*(;|#|$)' "$c" | sed -E 's/^(mqtt_pw[[:space:]]*=).*/\1 *****/' | sed 's/^/ /' @@ -62,15 +96,31 @@ done [[ $FIRMWARE -eq 1 ]] || { hr "firmware"; echo "not asked (run with --firmware)"; echo; echo "saved: $OUT"; exit 0; } hr "the old firmware" -PORT="$(ls /dev/serial/by-id/*Arduino* 2>/dev/null | head -1)" -[[ -n $PORT ]] || { echo "no Arduino on /dev/serial/by-id"; exit 1; } -WAS_ACTIVE="$(systemctl is-active fire-gimbal-control 2>/dev/null || true)" -if [[ $WAS_ACTIVE == active ]]; then - echo "pausing the old service (it holds the port)" - sudo systemctl stop fire-gimbal-control - trap 'echo "restarting the old service"; sudo systemctl start fire-gimbal-control' EXIT +# The Leonardo by name: an Arduino-branded one, or the LattePanda's own ("Unknown_LattePanda_Leonardo"). +PORT="$(ls /dev/serial/by-id/*Leonardo* /dev/serial/by-id/*Arduino* 2>/dev/null | head -1)" +[[ -n $PORT ]] || { echo "no Leonardo on /dev/serial/by-id - see the USB section above"; exit 1; } +echo "port: $PORT" +# Something may hold it: the old program. The two units known to start it are +# paused here and started again at the end - start_gimbal.service (the legacy +# towers' launcher, which also runs the picture transfer) and +# fire-gimbal-control. Anything else is named, and left for a person to stop. +PAUSED=() +for u in start_gimbal fire-gimbal-control; do + [[ $(systemctl is-active "$u" 2>/dev/null) == active ]] || continue + echo "pausing $u.service (it runs the program that holds the port)" + sudo systemctl stop "$u" && PAUSED+=("$u") +done +if (( ${#PAUSED[@]} )); then + trap 'for u in "${PAUSED[@]}"; do echo "restarting $u.service"; sudo systemctl start "$u"; done' EXIT sleep 2 fi +holders="$(fuser "$(readlink -f "$PORT")" 2>/dev/null | tr -s ' ')" +if [[ -n ${holders// /} ]]; then + echo "the port is in use by:" + for p in $holders; do echo " pid $p $(ps -o args= -p "$p" 2>/dev/null)"; done + echo "stop that program first (it is the old one, reading the same port), then run this again." + exit 1 +fi python3 - "$PORT" <<'PYEOF' import os, sys, termios, time, math