Initial commit: OFDM-радиолиния на двух Pluto+ (PHY/link, код на ARM)
- src: transmitter, receiver, ofdm_bench, common (libiio local: + liquid-dsp) - scripts: кросс-сборка зависимостей, деплой scp -O, e2e-тест с md5 - docs: бенчмарк CPU (выбор rate 1.92 MSPS), грабли FDD/регуляторика - все текстовые файлы нормализованы в LF (.gitattributes принудительно): CRLF в toolchain.env/makefile ломал source и make на Linux - .vscode: IntelliSense в режиме linux-gcc-arm, заголовки из .xarm/include Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
85
scripts/build_deps.sh
Normal file
85
scripts/build_deps.sh
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# build_deps.sh — кросс-сборка статических armhf-зависимостей в $XARM
|
||||
# Собирает: FFTW 3.3.10 (single+NEON), liquid-dsp 1.8.0, libiio (local backend)
|
||||
# Запуск: scripts/build_deps.sh (один раз, ~15-20 мин на RPi4)
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../toolchain.env"
|
||||
|
||||
WORK="$HOME/src"
|
||||
mkdir -p "$WORK" "$XARM"
|
||||
cd "$WORK"
|
||||
|
||||
echo "=== [0/4] Проверка тулчейна ==="
|
||||
which "${CC}" >/dev/null || {
|
||||
echo "Нет ${CC}. Установи: sudo apt install gcc-arm-linux-gnueabihf"; exit 1; }
|
||||
sudo apt-get install -y build-essential autoconf automake libtool git wget cmake >/dev/null
|
||||
|
||||
echo "=== [1/4] FFTW 3.3.10 (float + NEON, static) ==="
|
||||
if [ ! -f "$XARM/lib/libfftw3f.a" ]; then
|
||||
[ -d fftw-3.3.10 ] || {
|
||||
wget -nc http://fftw.org/fftw-3.3.10.tar.gz
|
||||
tar xf fftw-3.3.10.tar.gz
|
||||
}
|
||||
cd fftw-3.3.10
|
||||
./configure --host=arm-linux-gnueabihf --prefix="$XARM" \
|
||||
--enable-single --enable-neon --enable-static --disable-shared \
|
||||
CC="$CC" CFLAGS="$XCFLAGS"
|
||||
make -j"$(nproc)" && make install
|
||||
cd "$WORK"
|
||||
else
|
||||
echo "уже собран, пропускаю"
|
||||
fi
|
||||
|
||||
echo "=== [2/4] liquid-dsp 1.8.0 (static, с FFTW) ==="
|
||||
if [ ! -f "$XARM/lib/libliquid.a" ]; then
|
||||
[ -d liquid-dsp ] || git clone --depth 1 --branch v1.8.0 \
|
||||
https://github.com/jgaeddert/liquid-dsp.git
|
||||
cd liquid-dsp
|
||||
./bootstrap.sh
|
||||
./configure --host=arm-linux-gnueabihf --prefix="$XARM" \
|
||||
CC="$CC" CFLAGS="$XCFLAGS -ffast-math" \
|
||||
CPPFLAGS="-I$XARM/include" LDFLAGS="-L$XARM/lib" \
|
||||
ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes
|
||||
# КРИТИЧНО: без FFTW liquid молча падает на медленный встроенный FFT,
|
||||
# и бюджет CPU из docs/BENCHMARK.md становится невалидным.
|
||||
grep -q "HAVE_LIBFFTW3F 1" config.log || {
|
||||
echo "ОШИБКА: liquid не нашёл кросс-FFTW — проверь \$XARM"; exit 1; }
|
||||
make -j"$(nproc)" && make install
|
||||
cd "$WORK"
|
||||
else
|
||||
echo "уже собран, пропускаю"
|
||||
fi
|
||||
|
||||
echo "=== [3/4] libiio v0.25 (static, только local backend) ==="
|
||||
if [ ! -f "$XARM/lib/libiio.a" ]; then
|
||||
[ -d libiio ] || git clone --depth 1 --branch v0.25 \
|
||||
https://github.com/analogdevicesinc/libiio.git
|
||||
cd libiio
|
||||
cat > toolchain-armhf.cmake <<EOF
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm)
|
||||
set(CMAKE_C_COMPILER ${CROSS}gcc)
|
||||
set(CMAKE_C_FLAGS_INIT "$XCFLAGS")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
EOF
|
||||
cmake -B build-armhf -DCMAKE_TOOLCHAIN_FILE=toolchain-armhf.cmake \
|
||||
-DCMAKE_INSTALL_PREFIX="$XARM" -DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DWITH_LOCAL_BACKEND=ON -DWITH_NETWORK_BACKEND=OFF \
|
||||
-DWITH_USB_BACKEND=OFF -DWITH_SERIAL_BACKEND=OFF \
|
||||
-DWITH_XML_BACKEND=OFF -DHAVE_DNS_SD=OFF \
|
||||
-DWITH_TESTS=OFF -DWITH_EXAMPLES=OFF -DWITH_DOC=OFF \
|
||||
-DCSHARP_BINDINGS=OFF -DPYTHON_BINDINGS=OFF
|
||||
cmake --build build-armhf -j"$(nproc)"
|
||||
cmake --install build-armhf
|
||||
cd "$WORK"
|
||||
# Если cmake ругается на libxml2: XML backend в этой версии отключается
|
||||
# флагом выше; если версия libiio его требует — собери libxml2 static
|
||||
# (--without-python --without-zlib --without-lzma) в $XARM и повтори.
|
||||
else
|
||||
echo "уже собран, пропускаю"
|
||||
fi
|
||||
|
||||
echo "=== [4/4] Итог ==="
|
||||
ls -la "$XARM/lib/" | grep -E "libfftw3f|libliquid|libiio" || true
|
||||
echo "Готово. Дальше: make check-env && make"
|
||||
42
scripts/deploy.sh
Normal file
42
scripts/deploy.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh — заливка бинарей на Pluto (обе или одна плата)
|
||||
# Использование:
|
||||
# scripts/deploy.sh # обе платы из toolchain.env
|
||||
# scripts/deploy.sh 192.168.2.1 # только одна плата
|
||||
# scripts/deploy.sh <ipA> <ipB> # явные адреса
|
||||
# scripts/deploy.sh bench <ip> # только бенчмарк
|
||||
# Прошивка v0.38: sftp-server отсутствует → обязателен scp -O (legacy).
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../toolchain.env"
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
# sshpass, если установлен, избавляет от ввода пароля (пароль: analog)
|
||||
if command -v sshpass >/dev/null; then
|
||||
SCP=(sshpass -p "$PLUTO_PASS" scp -O -o StrictHostKeyChecking=no)
|
||||
else
|
||||
SCP=(scp -O)
|
||||
fi
|
||||
|
||||
FILES=(build/transmitter build/receiver build/ofdm_bench)
|
||||
TARGETS=()
|
||||
|
||||
case "${1:-}" in
|
||||
bench) FILES=(build/ofdm_bench); TARGETS=("${2:-$PLUTO_A}") ;;
|
||||
"") TARGETS=("$PLUTO_A" "$PLUTO_B") ;;
|
||||
*) TARGETS=("$@") ;;
|
||||
esac
|
||||
|
||||
for f in "${FILES[@]}"; do
|
||||
[ -f "$f" ] || { echo "нет $f — сначала make"; exit 1; }
|
||||
done
|
||||
|
||||
for ip in "${TARGETS[@]}"; do
|
||||
echo "=== деплой на root@$ip:/tmp/ ==="
|
||||
if ! ping -c1 -W2 "$ip" >/dev/null 2>&1; then
|
||||
echo " ! $ip не пингуется, пропускаю"; continue
|
||||
fi
|
||||
"${SCP[@]}" "${FILES[@]}" "root@$ip:/tmp/"
|
||||
echo " ok: ${FILES[*]}"
|
||||
done
|
||||
|
||||
echo "Напоминание: rootfs платы в RAM — после перезагрузки залить заново."
|
||||
68
scripts/test_file_link.sh
Normal file
68
scripts/test_file_link.sh
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
# test_file_link.sh — e2e-тест: файл → Pluto A → эфир → Pluto B → md5
|
||||
# Использование: scripts/test_file_link.sh [ipA] [ipB] [размер_КБ]
|
||||
# По умолчанию: адреса из toolchain.env, файл 1024 КБ, симплекс 915 МГц.
|
||||
#
|
||||
# ВНИМАНИЕ: сначала кабель + аттенюатор 30–40 дБ (TX gain −40)!
|
||||
set -euo pipefail
|
||||
source "$(dirname "$0")/../toolchain.env"
|
||||
|
||||
A="${1:-$PLUTO_A}" # передатчик
|
||||
B="${2:-$PLUTO_B}" # приёмник
|
||||
SIZE_KB="${3:-1024}"
|
||||
|
||||
FREQ=915000000
|
||||
RATE=1920000 # НЕ поднимать: бюджет CPU, docs/BENCHMARK.md
|
||||
BW=1500000
|
||||
TXGAIN=-40 # для кабеля; антенны: −20…0
|
||||
TIMEOUT=$(( SIZE_KB / 100 + 30 )) # ~160 КБ/с + запас
|
||||
|
||||
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 "=== [1/5] Тестовый файл ${SIZE_KB} КБ ==="
|
||||
dd if=/dev/urandom of=/tmp/link_test.bin bs=1024 count="$SIZE_KB" status=none
|
||||
MD5_SRC=$(md5sum /tmp/link_test.bin | cut -d' ' -f1)
|
||||
echo "md5: $MD5_SRC"
|
||||
|
||||
echo "=== [2/5] Заливка файла на Pluto A ($A) ==="
|
||||
"${SCP[@]}" /tmp/link_test.bin "root@$A:/tmp/"
|
||||
|
||||
echo "=== [3/5] Старт приёмника на Pluto B ($B), таймаут ${TIMEOUT}с ==="
|
||||
"${SSH[@]}" "root@$B" \
|
||||
"rm -f /tmp/out.bin; timeout $TIMEOUT /tmp/receiver -f $FREQ -r $RATE \
|
||||
-b $BW -c rs8 -u local: > /tmp/out.bin 2>/tmp/rx.log" &
|
||||
RX_PID=$!
|
||||
sleep 3 # дать RX прогреться до старта TX
|
||||
|
||||
echo "=== [4/5] Передача с Pluto A ==="
|
||||
"${SSH[@]}" "root@$A" \
|
||||
"cat /tmp/link_test.bin | /tmp/transmitter -f $FREQ -r $RATE -b $BW \
|
||||
-g $TXGAIN -p 0 -c rs8 -u local: 2>/tmp/tx.log"
|
||||
sleep 3 # дохлебать хвост эфира
|
||||
"${SSH[@]}" "root@$B" "killall receiver 2>/dev/null || true"
|
||||
wait "$RX_PID" 2>/dev/null || true
|
||||
|
||||
echo "=== [5/5] Сверка ==="
|
||||
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 байт)"
|
||||
|
||||
if [ "$MD5_SRC" = "$MD5_DST" ]; then
|
||||
echo "РЕЗУЛЬТАТ: OK — файл передан без искажений"
|
||||
else
|
||||
echo "РЕЗУЛЬТАТ: FAIL"
|
||||
echo "Диагностика (README §11):"
|
||||
echo " - размер меньше исходного → потерянные кадры (нет ARQ, техдолг #6):"
|
||||
echo " смотри лог RX и разрывы seq"
|
||||
echo " - размер равен, md5 нет → техдолг #1 (header_len=12?) или #3"
|
||||
echo " - размер 0 → RX не поймал ничего: частота/усиление/кабель"
|
||||
"${SSH[@]}" "root@$B" "tail -5 /tmp/rx.log" || true
|
||||
fi
|
||||
Reference in New Issue
Block a user