#!/bin/bash
# daemon_fast_read.sh — Pi の mecharm_daemon.py の角度の読み直しを速くして起動し直す (2026-11-05)
#
#   tools/daemon_fast_read.sh
#
# なぜ: 動いている間は get_angles が空で返ることが多く, daemon は 0.2 秒待って 12 回まで読み直す (1 回最長約 2.6 秒).
#       送る命令のたびに記録用にも読むので, 送る命令の返事も遅れ, ゲームパッドが最長 15 秒受け付けなかった.
# 変えること: 読み直しの待ち 0.2 → 0.02 秒. 送ったあとの記録用の読み取りは 1 回だけ (読めなくても待たない).
#       ほかは 1 文字も変えない. AI の実機推論も同じ daemon を通る (送る命令の返りが速くなるだけ).
# 流れ:
#   1. Pi で今動いている /home/ubuntu/mecharm_daemon.py を Mac に持ち帰り, KIOXIA の archive/ に写しを残す
#   2. すでに書き換えてあれば何もしない. なければ書き換え, 構文を確かめる
#   3. Pi へ一時名で送ってから入れ替え, systemd で起動し直し, ping と get_angles が返事をするか確かめる
#      うまくいかなければ, 元に戻すコマンドを出して止まる
# 流す前に: ゲームパッドなど daemon を使うものを止め, アームを HOME など安全な姿勢にしておく
#           (daemon を起動し直すと MyCobot の初期化が走る)
# 書き足した daemon は tools/pi/mecharm_daemon.py にも置く (これからの手元の正. ルートの mecharm_daemon.py は古い版なので触らない)
set -u
PI=ubuntu@192.168.2.1
KEY="$HOME/.ssh/id_rsa_pi"
SSH=(ssh -n -i "$KEY" -o ConnectTimeout=5 "$PI")
UNIT=mecharm-daemon.service
HERE="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(dirname "$HERE")"
DATA_ROOT=/Volumes/KIOXIA/r2r2r-data
[ -d "$DATA_ROOT/archive" ] || { echo "ABORT: $DATA_ROOT/archive がない (KIOXIA がマウントされていない?)"; exit 1; }
STAMP=$(date +%Y%m%d_%H%M%S)
BK="$DATA_ROOT/archive/mecharm_daemon_premerge_fastread_$STAMP"
mkdir "$BK" || exit 1
WORK=$(mktemp -d)

scp -i "$KEY" -q -o ConnectTimeout=5 "$PI:/home/ubuntu/mecharm_daemon.py" "$WORK/before.py" || { echo "ABORT: Pi から持ち帰れない"; exit 1; }
cp "$WORK/before.py" "$BK/mecharm_daemon.py" || { echo "ABORT: 写しを残せない (Pi の daemon は変えていません)"; exit 1; }
echo "今の daemon の写し: $BK/mecharm_daemon.py"

python3 - "$WORK/before.py" "$WORK/after.py" <<'PY'
import re, sys
src = open(sys.argv[1], encoding="utf-8").read()
if "read_angles_once_for_log" in src:
    print("すでに書き換えてあります。書き換えません")
    open(sys.argv[2], "w", encoding="utf-8").write(src)
    sys.exit(0)
out = src
n = len(re.findall(r"^GET_ANGLES_INTERVAL_SEC = 0\.2$", out, flags=re.M))
assert n == 1, "GET_ANGLES_INTERVAL_SEC = 0.2 が 1 つに決まらない"
out = re.sub(r"^GET_ANGLES_INTERVAL_SEC = 0\.2$",
             "GET_ANGLES_INTERVAL_SEC = 0.02   # 2026-11-05: 0.2 → 0.02 (動いている間は空で返ることが多く, 1 回の読み取りに最長 2.6 秒かかっていた)",
             out, flags=re.M)
for label in ("send_angles_after", "send_angle_after"):
    old = f'read_angles_with_retry("{label}", log_fail=False)'
    assert out.count(old) == 1, f"{old} が 1 つに決まらない"
    out = out.replace(old, f'read_angles_once_for_log()')
anchor = "def handle_command(cmd_obj):"
assert out.count(anchor) == 1
helper = '''def read_angles_once_for_log():
    """送ったあとの記録用に 1 回だけ読む (2026-11-05). 読めなくても待たない.
    以前は読み直しつきで, 読めないと送る命令の返事が最長 2.6 秒遅れていた."""
    try:
        a = _mc.get_angles()
    except Exception:
        return None
    return a if isinstance(a, (list, tuple)) and len(a) == 6 else None


'''
out = out.replace(anchor, helper + anchor)
compile(out, "mecharm_daemon.py", "exec")
open(sys.argv[2], "w", encoding="utf-8").write(out)
print("読み取りを速くしました")
PY
[ $? = 0 ] || { echo "ABORT: 書き足せない (Pi の daemon は変えていません)"; exit 1; }
cp "$WORK/after.py" "$BK/mecharm_daemon_fast_read.py" || exit 1
cp "$WORK/after.py" "$HERE/pi/mecharm_daemon.py" || exit 1
RESTORE="scp -i $KEY $BK/mecharm_daemon.py $PI:/home/ubuntu/mecharm_daemon.py && ssh -i $KEY $PI sudo systemctl restart $UNIT"
fail() { echo "ABORT: $1"; echo "元に戻すには: $RESTORE"; exit 1; }
echo "--- 差分"
diff "$WORK/before.py" "$WORK/after.py"

scp -i "$KEY" -q -o ConnectTimeout=5 "$WORK/after.py" "$PI:/home/ubuntu/mecharm_daemon.py.new" || { echo "ABORT: Pi へ送れない (Pi の daemon は変えていません)"; exit 1; }
"${SSH[@]}" "python3 -m py_compile /home/ubuntu/mecharm_daemon.py.new && mv /home/ubuntu/mecharm_daemon.py.new /home/ubuntu/mecharm_daemon.py" \
    || { echo "ABORT: Pi で入れ替えられない (Pi の daemon は変えていません)"; exit 1; }
"${SSH[@]}" "sudo systemctl restart $UNIT" || fail "systemctl restart が失敗した"
UP=no
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
    sleep 2
    "${SSH[@]}" "ss -ltn | grep -q ':5555 '" && { UP=yes; break; }
done
[ "$UP" = yes ] || fail "30 秒たっても 5555 が開かない"
python3 - <<'PY'
import json, socket
s = socket.create_connection(("192.168.2.1", 5555), timeout=5)
f = s.makefile("rwb")
for c in ({"cmd": "ping"}, {"cmd": "get_angles"}):
    f.write((json.dumps(c) + "\n").encode()); f.flush()
    r = json.loads(f.readline().decode())
    print(c["cmd"], "→", r)
    assert r.get("ok"), c["cmd"] + " が ok を返さない"
s.close()
PY
[ $? = 0 ] || fail "ping か get_angles が ok を返さない"
echo "できました。記録: $BK"
