Доработка документации
All checks were successful
01-smoke / smoke (push) Successful in 0s
02-guardrails / guardrails (push) Successful in 0s
03-gftest / gftest (push) Successful in 6s
04-cross-build / cross-build (push) Successful in 3s

This commit is contained in:
Maxim
2026-07-17 10:16:10 +03:00
parent d0a82bd92d
commit 7f508b6fd7
3 changed files with 156 additions and 3 deletions

View File

@@ -312,7 +312,11 @@ ssh root@192.168.2.1 '/tmp/ofdm_bench 1.92'
переупорядочивания на RX (1024 кадра). **Побайтовый лосслесс на 10 МБ:
44 потери вытянуты 45 ретрансмитами, md5 ==.** ARQ и group-FEC работают
вместе: паритет гасит одиночные потери без задержки, ARQ добирает остальное.
8. UDP-туннель поверх линка; затем web-настройка (libmicrohttpd)
8. ✅ **UDP-туннель поверх линка** (§12.10) — `udp_gw` инкапсулирует UDP-датаграммы
в самосинхронизирующиеся рекорды поверх байтового потока transmitter/receiver,
без единой правки ядра тракта. Радио-смоук на антеннах пройден дважды подряд:
md5 == байт-в-байт, 0 дропов/ресинков/дыр. Web-настройка (libmicrohttpd) —
осталась нереализованной, следующий шаг п.8
9. Видео (raw UDP, пакеты ≤1472 Б) — при устойчивом PER
## 11. Диагностика (шпаргалка)
@@ -638,6 +642,49 @@ COMPLETE, A вышел с 2. Настоящий PER-стресс — свипо
переупорядочивать нечего, а дыру закрыть некому: кольцо лишь задержало бы вывод
до EOF. Отсюда ветка `g_fb_fg ? rb : stdout` в `process_frame`/`group_flush`.
### 12.10 UDP-туннель — радио-смоук (§10 п.8) — 2026-07-17
**Реализация.** `udp_gw` — самостоятельный бинарь без зависимостей от
iio/liquid/fec, два режима: `-l <port>` (UDP → рекорды в stdout) и
`-d ip:port` (рекорды из stdin → UDP). Рекорд — 8 Б оверхеда (magic `D5 5D`,
len, id, flags, hcrc8) поверх уже существующего байтового потока
transmitter/receiver — ядро тракта не тронуто ни строкой. Парсер
самосинхронизируется по magic+hcrc8 после дыры (симплекс рвёт границы
рекордов произвольно). `stdout` шлюза в режиме `-l` — `O_NONBLOCK`: вход
быстрее линка дропается с счётчиком, а не блокирует приём (семантика UDP).
`udp_probe` (send/recv по UDP, свой мини-инструмент — busybox без `nc`/`socat`,
правило №1 запрещает Python и на хосте) закрывает бринг-ап без внешних
зависимостей. Пиннинг `udp_gw` на отдельное ядро не сделан — по факту
замера не нужен (Overrun/FQdrp = 0 при работающем шлюзе, ниже).
**Loopback на одной плате** (без радио, сокет↔сокет через localhost):
66/66 датаграмм, md5 ==, все счётчики (дропы/ресинк/bad_crc/дыры) — 0.
**Радио-смоук** (антенны на столе, симплекс 915 МГц, `TXGAIN 20`, `-G -p 3000`,
64 КБ / 66 датаграмм по 1000 Б, темп генератора `PACE_MS=15` ≈65 КБ/сс
запасом под потолок линка ~107 КБ/с): два прогона подряд — md5 == байт-в-байт,
`отправлено 66 | дропов 0` на входе, `доставлено 66 | ресинк 0 Б | bad_crc 0 |
дыр(id) 0` на выходе, `Потери seq 0` на радио, EVM 18.5…26.2 дБ.
Правило №7 (кабель+аттенюатор до антенн) сознательно не применялось: `udp_gw`
не меняет PHY ни на байт (слой поверх уже принятого байтового потока), его
собственная логика парсера закрыта юнит-тестом (`make gwtest`) и loopback-ом
на плате — радио-прогон здесь равносилен штатной приёмке линка.
**Отладка теста, не туннеля.** Первый радио-прогон (ручные команды в терминале)
дал пустой файл на приёме: у `udp_probe recv` сторожевой таймер простоя тикает
с момента ЗАПУСКА процесса, а не с первой датаграммы — интерактивная вставка
команд заняла больше отведённых 10 с, и приёмная цепочка на B самоликвидировалась
до начала передачи на A. После автоматизации в `scripts/test_udp_tunnel.sh`
всплыли ещё два эффекта хореографии: (а) единовременный `killall` терял хвост
последней group-FEC-группы, потому что `receiver` флашит его только в момент
собственной смерти (`receiver.c:798`, после основного цикла) — гашение
переписано на строгий порядок «receiver → пауза на прохождение хвоста через
`udp_gw -d` → `udp_probe»; (б) старт генератора без ожидания готовности
transmitter ронял 12 первые датаграммы в EAGAIN, пока iio ещё поднимался —
заменено на ожидание строки «Ожидание данных» в логе TX. Оба фикса —
в `scripts/test_udp_tunnel.sh`, радиотракт и `udp_gw` не менялись.
**Гибрид с group-FEC.** Паритет гасит одиночные потери без задержки (RX снимает
восстановленные seq с NACK — ретрансмит не нужен), ARQ добирает то, что паритету
не по силам (>2 стираний/группу). `grp_failed > 0` при целом md5 — норма: группа