Подэтап 3a реализован
This commit is contained in:
140
scripts/test_arq.sh
Executable file
140
scripts/test_arq.sh
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
# test_arq.sh — e2e-тест ARQ и EOF-хендшейка (этап 3, §10 п.7, техдолг #6).
|
||||
#
|
||||
# Отличие от test_fdd_fwd.sh: там успех = md5 совпал, а завершение обеих сторон
|
||||
# организует скрипт (killall + сторожевой kill). Здесь проверяется сам ПРОТОКОЛ:
|
||||
# • B, собрав файл целиком, поднимает FB_FLAG_COMPLETE в STATUS и выходит САМ;
|
||||
# • A ждёт этот COMPLETE и возвращает 0; не дождался за 10 с → exit 2.
|
||||
# Поэтому сторожевой kill приёмника = провал (B не смог завершиться сам), а
|
||||
# ненулевой код A — не аварийная ситуация, а штатный отчёт «файл не подтверждён».
|
||||
#
|
||||
# Использование: scripts/test_arq.sh [ipA] [ipB] [размер_КБ]
|
||||
# SIZE_KB=10240 — длинный прогон (или третьим позиционным аргументом)
|
||||
# TXGAIN=-45 — стресс: высокий PER, ARQ обязан вытянуть md5
|
||||
# NEGATIVE=1 FBGAIN=-89 — обратный канал заглушён: успех = A НЕ подтвердил
|
||||
# FBGAIN (деф. −15) — середина рабочего окна −20…−10 (README §12.8)
|
||||
# FBFREQ, PAUSE, TXGAIN, FEC, GROUPFEC — как в test_fdd_fwd.sh
|
||||
# ВНИМАНИЕ: сначала кабель + аттенюатор 30–40 дБ!
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../toolchain.env"
|
||||
|
||||
A="${1:-$PLUTO_A}" # передатчик данных (TX 915 / fb-RX 868)
|
||||
B="${2:-$PLUTO_B}" # приёмник данных (RX 915 / fb-TX 868)
|
||||
SIZE_KB="${3:-${SIZE_KB:-1024}}"
|
||||
|
||||
FREQ=915000000
|
||||
FBFREQ="${FBFREQ:-868000000}"
|
||||
RATE=1920000 # НЕ поднимать: бюджет CPU, docs/BENCHMARK.md
|
||||
BW=1500000
|
||||
TXGAIN="${TXGAIN:--30}"
|
||||
FBGAIN="${FBGAIN:--15}" # штатный обратный канал; −89 ≈ выкл (NEGATIVE)
|
||||
FEC="${FEC:-rs8}"
|
||||
PAUSE="${PAUSE:-4000}" # §12.7: соук/маргинальный канал — только 4000, не 3000
|
||||
GROUPFEC="${GROUPFEC:-1}"
|
||||
NEGATIVE="${NEGATIVE:-0}"
|
||||
[ "$GROUPFEC" = 1 ] && GFLAG="-G" || GFLAG=""
|
||||
# +40 (против +20 у test_fdd_fwd): END-фаза до 10 с плюс запас на ретрансмиты.
|
||||
TIMEOUT=$(( SIZE_KB / 85 + 40 ))
|
||||
|
||||
if command -v sshpass >/dev/null; then
|
||||
SSH=(sshpass -p "$PLUTO_PASS" ssh -o StrictHostKeyChecking=no)
|
||||
SCP=(sshpass -p "$PLUTO_PASS" scp -O -o StrictHostKeyChecking=no)
|
||||
else
|
||||
SSH=(ssh); SCP=(scp -O)
|
||||
echo "подсказка: apt install sshpass — и пароль вводить не придётся"
|
||||
fi
|
||||
|
||||
echo "=== ARQ e2e: A=$A (TX $((FREQ/1000000))/fb-RX $((FBFREQ/1000000))) → B=$B ==="
|
||||
echo " ${SIZE_KB} КБ TXGAIN=$TXGAIN FBGAIN=$FBGAIN PAUSE=$PAUSE GROUPFEC=$GROUPFEC NEGATIVE=$NEGATIVE"
|
||||
|
||||
echo "=== [1/6] Тестовый файл ${SIZE_KB} КБ ==="
|
||||
dd if=/dev/urandom of=/tmp/arq_test.bin bs=1024 count="$SIZE_KB" status=none
|
||||
MD5_SRC=$(md5sum /tmp/arq_test.bin | cut -d' ' -f1)
|
||||
echo "md5: $MD5_SRC"
|
||||
|
||||
echo "=== [2/6] Зачистка хвостов на обеих платах ==="
|
||||
# Остаточный процесс держит RX-DMA → пустой out.bin (грабля из README §12.6).
|
||||
"${SSH[@]}" "root@$A" "killall -9 transmitter receiver 2>/dev/null || true"
|
||||
"${SSH[@]}" "root@$B" "killall -9 transmitter receiver 2>/dev/null || true"
|
||||
|
||||
echo "=== [3/6] Заливка файла на Pluto A ($A) ==="
|
||||
"${SCP[@]}" /tmp/arq_test.bin "root@$A:/tmp/"
|
||||
|
||||
echo "=== [4/6] Старт приёмника на Pluto B ($B), сторож ${TIMEOUT}с ==="
|
||||
# busybox без `timeout` → сторожевой sleep+kill на плате. Штатно B выходит САМ по
|
||||
# COMPLETE задолго до сторожа; сторож снимается сразу после выхода B, иначе ssh
|
||||
# висел бы до конца sleep и скрывал реальное время завершения.
|
||||
"${SSH[@]}" "root@$B" \
|
||||
"rm -f /tmp/out.bin; /tmp/receiver -f $FREQ -r $RATE -b $BW -c $FEC \
|
||||
-F $FBFREQ -g $FBGAIN -u local: > /tmp/out.bin 2>/tmp/rx_arq.log & \
|
||||
RXP=\$!; (sleep $TIMEOUT; kill \$RXP 2>/dev/null) & WDP=\$!; \
|
||||
wait \$RXP; RC=\$?; kill \$WDP 2>/dev/null; exit \$RC" &
|
||||
RX_PID=$!
|
||||
sleep 4 # дать RX прогреться (FDD-инициализация двух трактов дольше)
|
||||
|
||||
echo "=== [5/6] Передача с Pluto A + EOF-хендшейк ==="
|
||||
TX_RC=0
|
||||
"${SSH[@]}" "root@$A" \
|
||||
"cat /tmp/arq_test.bin | /tmp/transmitter -f $FREQ -r $RATE -b $BW \
|
||||
-g $TXGAIN -p $PAUSE -c $FEC $GFLAG -F $FBFREQ -u local: 2>/tmp/tx_arq.log" \
|
||||
|| TX_RC=$?
|
||||
echo "код возврата передатчика: $TX_RC (0 = COMPLETE подтверждён, 2 = таймаут)"
|
||||
|
||||
wait "$RX_PID" 2>/dev/null || true # B выходит сам либо снимается сторожем
|
||||
"${SSH[@]}" "root@$B" "killall receiver 2>/dev/null || true" # страховка
|
||||
|
||||
echo "=== [6/6] Сверка ==="
|
||||
MD5_DST=$("${SSH[@]}" "root@$B" "md5sum /tmp/out.bin 2>/dev/null | cut -d' ' -f1" || echo "нет_файла")
|
||||
SIZE_DST=$("${SSH[@]}" "root@$B" "wc -c < /tmp/out.bin 2>/dev/null" || echo 0)
|
||||
echo "источник: $MD5_SRC ($((SIZE_KB*1024)) байт)"
|
||||
echo "приёмник: $MD5_DST ($SIZE_DST байт)"
|
||||
|
||||
# Самозавершение B: маркер печатается ТОЛЬКО когда COMPLETE ушёл в эфир и B
|
||||
# закрывается штатно. Нет маркера → B досидел до сторожевого kill = провал 3a.
|
||||
SELF_DONE=0
|
||||
"${SSH[@]}" "root@$B" "grep -q 'завершаю приём' /tmp/rx_arq.log 2>/dev/null" && SELF_DONE=1 || true
|
||||
|
||||
echo "--- Хендшейк ---"
|
||||
"${SSH[@]}" "root@$B" "grep ARQ /tmp/rx_arq.log 2>/dev/null | sed 's/^/B: /'" || true
|
||||
"${SSH[@]}" "root@$A" "grep ARQ /tmp/tx_arq.log 2>/dev/null | sed 's/^/A: /'" || true
|
||||
echo "B самозавершился: $([ "$SELF_DONE" = 1 ] && echo да || echo 'НЕТ (снят сторожем)')"
|
||||
|
||||
echo "--- Обратный канал STATUS (B→A) ---"
|
||||
SENT=$("${SSH[@]}" "root@$B" "grep -o 'отправлено STATUS: [0-9]*' /tmp/rx_arq.log 2>/dev/null | grep -o '[0-9]*'" || echo "")
|
||||
RECV=$("${SSH[@]}" "root@$A" "grep -o 'принято STATUS: [0-9]*' /tmp/tx_arq.log 2>/dev/null | grep -o '[0-9]*'" || echo "")
|
||||
SENT=${SENT:-0}; RECV=${RECV:-0}
|
||||
if [ "$SENT" -gt 0 ]; then
|
||||
echo "B отправил: $SENT | A принял: $RECV | доставка ≈ $(( RECV * 100 / SENT ))%"
|
||||
else
|
||||
echo "B отправил: $SENT | A принял: $RECV"
|
||||
fi
|
||||
|
||||
echo "--- RX-статистика (PER) ---"
|
||||
"${SSH[@]}" "root@$B" "grep '^Кадров:' /tmp/rx_arq.log 2>/dev/null | tail -1" || true
|
||||
|
||||
echo "=== РЕЗУЛЬТАТ ==="
|
||||
if [ "$NEGATIVE" = 1 ]; then
|
||||
# Обратный канал заглушён: B файл соберёт и выйдет сам, но подтвердить A
|
||||
# некому. Проверяем именно честность отказа — раньше A рапортовал успех.
|
||||
if [ "$TX_RC" != 0 ]; then
|
||||
echo "OK (негатив) — A не получил COMPLETE и честно вышел с кодом $TX_RC"
|
||||
else
|
||||
echo "FAIL (негатив) — A вернул 0 без обратного канала: хендшейк фиктивен"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [ "$MD5_SRC" = "$MD5_DST" ] && [ "$SELF_DONE" = 1 ] && [ "$TX_RC" = 0 ]; then
|
||||
echo "OK — md5 совпал, B завершился по COMPLETE, A подтвердил"
|
||||
else
|
||||
echo "FAIL: md5 $([ "$MD5_SRC" = "$MD5_DST" ] && echo ок || echo РАСХОЖДЕНИЕ) |" \
|
||||
"самозавершение $([ "$SELF_DONE" = 1 ] && echo ок || echo НЕТ) | код A $TX_RC"
|
||||
echo "Диагностика:"
|
||||
echo " - md5 разошёлся при коде A=0 → COMPLETE поднят рано (проверь miss/next_out)."
|
||||
echo " - код A=2 при целом md5 → COMPLETE не долетел: подними FBGAIN к −10."
|
||||
echo " - размер 0 → RX не декодит: остаточный процесс на B или самоглушение."
|
||||
echo " - на этапе 3a ретрансмитов ещё нет: любая потеря кадра → код A=2 ОЖИДАЕМО."
|
||||
echo "--- хвост rx_arq.log (B) ---"
|
||||
"${SSH[@]}" "root@$B" "tail -8 /tmp/rx_arq.log" || true
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user