fwt_software/scripts/survey-legacy-tower

148 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# survey-legacy-tower - read what a legacy tower (the old host program and the
# TMC-API Arduino sketch) is running, BEFORE it is migrated, so its
# hardware.ini is written from its own values rather than another tower's.
# Run it ON the legacy tower. Changes nothing on disk.
#
# 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
#
# The report is printed and saved to ~/legacy-survey-<date>.txt.
#
# The firmware part talks the old sketch's own serial protocol:
# ? endstop positions and the travel between them (set by its last home)
# y its north calibration from EEPROM (the same `y` the old host sends
# after every home - it reloads the stored value, it stores nothing)
# id<n> read TMC5160 register n (write-only ones answer from the library's copy)
#
set -uo pipefail
FIRMWARE=0
[[ ${1:-} == --firmware ]] && FIRMWARE=1
OUT="$HOME/legacy-survey-$(date +%Y%m%d-%H%M%S).txt"
exec > >(tee "$OUT") 2>&1
hr() { printf '\n== %s ==\n' "$*"; }
reach() { timeout 6 bash -c "</dev/tcp/$1/$2" 2>/dev/null && echo "ok" || echo "NO"; }
hr "machine"
echo "board : $(tr -d '\0' < /sys/class/dmi/id/product_name 2>/dev/null || echo '?')"
echo "os : $(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME") ($(uname -r))"
echo "user : $USER groups: $(id -nG)"
echo "disk / : $(df -h / | awk 'NR==2 {print $4 " free of " $2}')"
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)"
ls /dev/serial/by-id/ 2>/dev/null | sed 's/^/by-id: /'
hr "Vimba X and the camera"
ls -d /opt/VimbaX* 2>/dev/null || echo "no /opt/VimbaX*"
for tool in /opt/VimbaX*/bin/ListCameras_VmbC /opt/VimbaX*/bin/ListCameras; do
[[ -x $tool ]] || continue
cti="$(dirname "$(dirname "$tool")")/cti"
GENICAM_GENTL64_PATH="$cti" "$tool" 2>/dev/null | grep -E 'Camera (ID|Name)|Model|Transport Layer Path' | sed 's/^/ /'
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
[[ -r $c ]] || continue
echo "-- $c (passwords masked)"
grep -vE '^[[:space:]]*(;|#|$)' "$c" | sed -E 's/^(mqtt_pw[[:space:]]*=).*/\1 *****/' | sed 's/^/ /'
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
sleep 2
fi
python3 - "$PORT" <<'PYEOF'
import os, sys, termios, time, math
port = sys.argv[1]
fd = os.open(port, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
a = termios.tcgetattr(fd)
a[0] = 0; a[1] = 0; a[2] = termios.CS8 | termios.CREAD | termios.CLOCAL; a[3] = 0
a[4] = a[5] = termios.B115200
termios.tcsetattr(fd, termios.TCSANOW, a)
buf = b""
def lines_for(seconds):
global buf
out, end = [], time.time() + seconds
while time.time() < end:
try:
buf += os.read(fd, 4096)
except BlockingIOError:
time.sleep(0.02)
while b"\n" in buf:
line, buf = buf.split(b"\n", 1)
out.append(line.decode(errors="replace").strip())
return out
def ask(cmd, seconds=0.8):
lines_for(0.2) # drop what was already streaming
os.write(fd, cmd.encode() + b"\n")
got = lines_for(seconds)
return [l for l in got if l and not l.startswith("$")], [l for l in got if l.startswith("$")]
_, status = ask("", 1.0)
print("status line :", status[-1] if status else "(none - is this the legacy firmware?)")
reply, _ = ask("?")
print("? (endstops) :", " | ".join(reply) or "(no answer)")
nums = [int(x) for x in reply if x.lstrip("-").isdigit()]
if len(nums) >= 3:
r, l = nums[0], nums[1]
print(f" right {r} left {l} travel {abs(l - r)} counts = {abs(l - r) / 528.253966:.1f} deg at 528.25 counts/deg")
reply, _ = ask("y")
print("y (north) :", " | ".join(reply) or "(no answer)")
REGS = [("GCONF", 0x00), ("GLOBALSCALER", 0x0B), ("IHOLD_IRUN", 0x10), ("TPOWERDOWN", 0x11),
("XACTUAL", 0x21), ("AMAX", 0x26), ("VMAX", 0x27), ("DMAX", 0x28), ("SW_MODE", 0x34),
("ENCMODE", 0x38), ("X_ENC", 0x39), ("ENC_CONST", 0x3A), ("ENC_DEVIATION", 0x3D),
("CHOPCONF", 0x6C), ("COOLCONF", 0x6D), ("PWMCONF", 0x70)]
vals = {}
print("registers :")
for name, n in REGS:
reply, _ = ask(f"id{n}")
v = None
for x in reply:
if x.startswith("READ"):
try: v = int(x.split(",")[-1])
except ValueError: pass
vals[name] = v
shown = "(no answer)" if v is None else f"{v} = 0x{v & 0xFFFFFFFF:08X}"
print(f" {name:14s} 0x{n:02X} {shown}")
gs, ii = vals.get("GLOBALSCALER"), vals.get("IHOLD_IRUN")
if ii is not None:
irun, ihold = (ii >> 8) & 0x1F, ii & 0x1F
scale = (gs or 256) / 256.0
print(f"current : IRUN {irun}, IHOLD {ihold}, GLOBALSCALER {gs if gs else '0 (=256, full)'}")
for rs in (0.075, 0.05):
i_run = scale * (irun + 1) / 32 * 0.325 / rs / math.sqrt(2) * 1000
print(f" with a {rs * 1000:.0f} mOhm sense resistor: run {i_run:.0f} mA RMS"
" (read the resistor off the board before trusting either)")
os.close(fd)
PYEOF
echo
echo "saved: $OUT"