Find a legacy tower's Leonardo and its old launcher, and refuse to install while the old program holds the port
This commit is contained in:
parent
4b73199e8e
commit
2d2b498ff2
|
|
@ -69,12 +69,15 @@ probe_board() {
|
||||||
# RP2040 running the gimbal firmware (arduino-pico) : "Raspberry_Pi_Pico"
|
# RP2040 running the gimbal firmware (arduino-pico) : "Raspberry_Pi_Pico"
|
||||||
# RP2040 as shipped, still on MicroPython : "MicroPython_Board"
|
# RP2040 as shipped, still on MicroPython : "MicroPython_Board"
|
||||||
# ATmega32U4 (Delta fleet) : "Arduino_LLC_Arduino_Leonardo"
|
# ATmega32U4 (Delta fleet) : "Arduino_LLC_Arduino_Leonardo"
|
||||||
|
# the same, running a legacy tower's firmware : "Unknown_LattePanda_Leonardo"
|
||||||
probe_mcu() {
|
probe_mcu() {
|
||||||
local d found=()
|
local d found=()
|
||||||
for d in /dev/serial/by-id/*; do
|
for d in /dev/serial/by-id/*; do
|
||||||
[[ -e $d ]] || continue
|
[[ -e $d ]] || continue
|
||||||
case "$d" in
|
case "$d" in
|
||||||
*Raspberry_Pi_Pico*|*MicroPython_Board*|*Arduino_LLC_Arduino*|*Pico*) found+=("$d") ;;
|
*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
|
esac
|
||||||
done
|
done
|
||||||
(( ${#found[@]} == 1 )) && { echo "${found[0]}"; return; }
|
(( ${#found[@]} == 1 )) && { echo "${found[0]}"; return; }
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,21 @@ set -euo pipefail
|
||||||
|
|
||||||
S_MCU="$(probe_mcu)"
|
S_MCU="$(probe_mcu)"
|
||||||
S_MCU_N=$(grep -c . <<< "$S_MCU" || true)
|
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_CAM="$(probe_camera_id)"
|
||||||
S_LPM="$(probe_camera_lpm_path)"
|
S_LPM="$(probe_camera_lpm_path)"
|
||||||
S_USBFS="$(cat /sys/module/usbcore/parameters/usbfs_memory_mb 2>/dev/null || echo '?')"
|
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
|
case "$S_MCU" in
|
||||||
*MicroPython*) S_MODE="factory MicroPython image" ;;
|
*MicroPython*) S_MODE="factory MicroPython image" ;;
|
||||||
*Raspberry_Pi_Pico*|*Pico*) S_MODE="gimbal firmware" ;;
|
*Raspberry_Pi_Pico*|*Pico*) S_MODE="gimbal firmware" ;;
|
||||||
*Arduino*) S_MODE="gimbal firmware (Leonardo)" ;;
|
*Arduino*|*Leonardo*) S_MODE="firmware on the Leonardo" ;;
|
||||||
esac
|
esac
|
||||||
lsusb -d 2e8a:0003 >/dev/null 2>&1 && S_MODE="in its bootloader"
|
lsusb -d 2e8a:0003 >/dev/null 2>&1 && S_MODE="in its bootloader"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
# bash survey-legacy-tower the machine, the old install, the camera
|
# bash survey-legacy-tower the machine, the old install, the camera
|
||||||
# bash survey-legacy-tower --firmware also ask the old firmware for its
|
# bash survey-legacy-tower --firmware also ask the old firmware for its
|
||||||
# registers, travel and north calibration:
|
# 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-<date>.txt.
|
# The report is printed and saved to ~/legacy-survey-<date>.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)"
|
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"
|
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/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"
|
hr "Vimba X and the camera"
|
||||||
ls -d /opt/VimbaX* 2>/dev/null || echo "no /opt/VimbaX*"
|
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
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
hr "the old install"
|
hr "the old install - how it runs"
|
||||||
systemctl is-enabled fire-gimbal-control 2>/dev/null | sed 's/^/service enabled: /'
|
echo "-- systemd units that look like it (system and user):"
|
||||||
systemctl is-active fire-gimbal-control 2>/dev/null | sed 's/^/service active : /'
|
{ systemctl list-unit-files --no-legend 2>/dev/null; systemctl --user list-unit-files --no-legend 2>/dev/null; } |
|
||||||
systemctl cat fire-gimbal-control 2>/dev/null | grep -E '^(ExecStart|WorkingDirectory|User|Environment)=' | sed 's/^/ /'
|
grep -iE 'gimbal|fire[-_]|fwt|tower|camera|zkms' | sed 's/^/ /' || echo " (none)"
|
||||||
for c in /opt/fire_gimbal_control/config.ini "$HOME"/*/config.ini; do
|
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
|
[[ -r $c ]] || continue
|
||||||
echo "-- $c (passwords masked)"
|
echo "-- $c (passwords masked)"
|
||||||
grep -vE '^[[:space:]]*(;|#|$)' "$c" | sed -E 's/^(mqtt_pw[[:space:]]*=).*/\1 *****/' | sed 's/^/ /'
|
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; }
|
[[ $FIRMWARE -eq 1 ]] || { hr "firmware"; echo "not asked (run with --firmware)"; echo; echo "saved: $OUT"; exit 0; }
|
||||||
|
|
||||||
hr "the old firmware"
|
hr "the old firmware"
|
||||||
PORT="$(ls /dev/serial/by-id/*Arduino* 2>/dev/null | head -1)"
|
# The Leonardo by name: an Arduino-branded one, or the LattePanda's own ("Unknown_LattePanda_Leonardo").
|
||||||
[[ -n $PORT ]] || { echo "no Arduino on /dev/serial/by-id"; exit 1; }
|
PORT="$(ls /dev/serial/by-id/*Leonardo* /dev/serial/by-id/*Arduino* 2>/dev/null | head -1)"
|
||||||
WAS_ACTIVE="$(systemctl is-active fire-gimbal-control 2>/dev/null || true)"
|
[[ -n $PORT ]] || { echo "no Leonardo on /dev/serial/by-id - see the USB section above"; exit 1; }
|
||||||
if [[ $WAS_ACTIVE == active ]]; then
|
echo "port: $PORT"
|
||||||
echo "pausing the old service (it holds the port)"
|
# Something may hold it: the old program. The two units known to start it are
|
||||||
sudo systemctl stop fire-gimbal-control
|
# paused here and started again at the end - start_gimbal.service (the legacy
|
||||||
trap 'echo "restarting the old service"; sudo systemctl start fire-gimbal-control' EXIT
|
# 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
|
sleep 2
|
||||||
fi
|
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'
|
python3 - "$PORT" <<'PYEOF'
|
||||||
import os, sys, termios, time, math
|
import os, sys, termios, time, math
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue