Этап 3c — гибрид GF+ARQ, пересборка NACK, приёмка. Техдолг #6 закрыт
ARQ включён и для group-FEC. Паритет и ретрансмит перестали быть альтернативами: GF гасит одиночные потери без задержки, ARQ добирает то, что паритету не по силам (>2 стираний/группу). Дыру, закрытую паритетом, RX снимает с NACK сам — лишнего трафика нет. receiver.c: - group_route: кадр ложится в кольцо ДО любого bypass. Кольцо — единственный источник порядка и живёт независимо от сборки групп; иначе ретрансмит закрытой группы не занял бы свой слот и next_out встал бы на нём навсегда. Паритет получает слот нулевой длины: тратит seq, но в файл не идёт. - group_route: bypass для кадра уже закрытой группы (base < g.base, а также base == g.base при !active — группа финализирована по END). Без него ретрансмит преждевременно flush-ал активную группу, сбрасывая её стирания, либо «воскрешал» закрытую с одним элементом. - group_flush: под FDD пишет в кольцо ТОЛЬКО восстановленные паритетом кадры (g.fixed) и снимает их seq с NACK — принятые уже в кольце. Симплекс сохраняет прямой вывод группы: ретрансмитов там нет, переупорядочивать нечего. - process_end: досрочный group_flush последней группы. Штатно группа закрывается первым кадром следующей — для последней его не будет, и её восстановление случилось бы только при выходе потока C, то есть уже после COMPLETE. - process_end/miss_rebuild: NACK пересобирается из кольца на каждом END. Находка стресса 3b: miss_add при переполнении MISS_CAP молча терял seq, и вернуть его было некому (детектор дыр по нему второй раз не срабатывает) — приём заклинивало насмерть. Кольцо знает точно, каких кадров нет. - arq_check_complete: критерий единый (next_out == total_seq), временный gf_seen убран. transmitter.c: g_arq_on = 1 безусловно при -F; arq_service в GF-цикле как в legacy.
This commit is contained in:
56
README.md
56
README.md
@@ -277,7 +277,7 @@ ssh root@192.168.2.1 '/tmp/ofdm_bench 1.92'
|
||||
| 3 | `fec_decode()` liquid не сообщает о неисправимых RS-блоках → счётчик `rs_saved` фиктивен. Достоверный критерий — только CRC/md5 поверх данных | ✅ исправлено: CRC32 поверх данных до RS на TX, сверка после декода на RX; `rs_saved`/`rs_fail` достоверны (подтверждено loopback'ом, §12.2) |
|
||||
| 4 | Внешний NCO-CFO в receiver: `set_phase(0)` на границах буферов рвёт фазу; ofdmflexframesync и так компенсирует CFO сам | ✅ исправлено: внешний NCO удалён, CFO оставлен только как телеметрия |
|
||||
| 5 | TX пушит весь буфер 16384 сэмпла при кадре ~10300 → ~35% эфира впустую + паузы `-p` | ✅ исправлено: `iio_buffer_push_partial(idx)` + дренаж хвоста DMA перед закрытием |
|
||||
| 6 | Нет ARQ: потерянный кадр = молчаливая дыра в файле. seq в заголовке есть, но RX его игнорирует | ⚙️ частично: детектор пропусков seq (лог `[ПОТЕРЯ]` + счётчик) + **групповой стирающий FEC 16+2 закрывает ≤2 потери/группу на симплексе без обратного канала (§12.7, п.6)**; полный ARQ — на дуплексе (п.7) |
|
||||
| 6 | Нет ARQ: потерянный кадр = молчаливая дыра в файле. seq в заголовке есть, но RX его игнорирует | ✅ исправлено на FDD (§12.9, §10 п.7): детектор пропусков seq → NACK в STATUS → селективный ретрансмит из окна TX 2048 кадров + кольцо переупорядочивания на RX + хендшейк END/COMPLETE (хвостовые потери). 10 МБ байт-в-байт, A возвращает 0 только по подтверждённому COMPLETE. **На симплексе (без `-F`) ARQ невозможен** — там остаются детектор `[ПОТЕРЯ]` и групповой FEC 16+2 (≤2 потери/группу, §12.7, п.6) |
|
||||
|
||||
## 10. Дорожная карта
|
||||
|
||||
@@ -303,7 +303,15 @@ ssh root@192.168.2.1 '/tmp/ofdm_bench 1.92'
|
||||
байт-в-байт на рабочей точке `-p 4000`. Защита информации (лёгкий AEAD,
|
||||
+16 Б/кадр, <1% CPU) — отложена, требования ОКР «R-Link» нет; формат
|
||||
с резервом под неё.
|
||||
7. FDD 868/915 двусторонняя + ARQ с обратным каналом + меры из docs/NOTES.md
|
||||
7. ✅ **FDD 868/915 + обратный канал + ARQ** (§12.8, §12.9) — техдолг #6 закрыт.
|
||||
Этап 1: две несущие, A TX915/RX868, B зеркально. Этап 2: обратный канал
|
||||
STATUS (кумулятивный снимок RX: highest_seq + NACK-список), gate пройден —
|
||||
PER форварда не деградирует от обратного TX. Этап 3: EOF-хендшейк END/COMPLETE
|
||||
(хвостовые потери молчаливы — END несёт итог передачи) + селективный
|
||||
ретрансмит по NACK (окно TX 2048 кадров, повтор не чаще 400 мс) + кольцо
|
||||
переупорядочивания на RX (1024 кадра). **Побайтовый лосслесс на 10 МБ:
|
||||
44 потери вытянуты 45 ретрансмитами, md5 ==.** ARQ и group-FEC работают
|
||||
вместе: паритет гасит одиночные потери без задержки, ARQ добирает остальное.
|
||||
8. UDP-туннель поверх линка; затем web-настройка (libmicrohttpd)
|
||||
9. Видео (raw UDP, пакеты ≤1472 Б) — при устойчивом PER
|
||||
|
||||
@@ -580,6 +588,50 @@ TX-бёрстов (duty 57% при `-p 4000`), STATUS выживает в пау
|
||||
И PER₁≈PER₀), fallback TDD не требуется. Разбор — NOTES §2.2. Дальше — этап 3:
|
||||
селективный ретрансмит по NACK + END/COMPLETE-хендшейк.
|
||||
|
||||
### 12.9 ARQ: END/COMPLETE + селективный ретрансмит (§10 п.7, этап 3) — 2026-07-16
|
||||
|
||||
Закрытие техдолга #6. Три подэтапа, каждый принят на железе отдельно.
|
||||
|
||||
**Механизм.** (а) **END** (кадр `F0 E7`, payload 12 Б: total_seq + total_bytes):
|
||||
хвостовые потери молчаливы — у последних кадров нет следующего seq, по которому
|
||||
детектор увидел бы дыру. A шлёт END каждые 100 мс после EOF, пока не услышит
|
||||
COMPLETE (таймаут 10 с → **exit 2**). (б) **Окно TX** `txwin[2048]` на A хранит
|
||||
сырой payload: `phy_tx_frame` детерминирован, повтор уходит байт-в-байт.
|
||||
(в) **NACK** едут в кумулятивном STATUS (50 старейших seq); ретрансмит
|
||||
per-seq не чаще **400 мс** — расчёт петли потеря→STATUS→повтор→подтверждение при
|
||||
50% доставки STATUS (§12.8). (г) **Кольцо переупорядочивания** `rb[1024]` на B:
|
||||
ретрансмит приезжает вне очереди, в stdout уходит только непрерывный префикс
|
||||
(курсор `next_out`). COMPLETE ⇔ `next_out == total_seq`.
|
||||
|
||||
**Результаты** (кабель+аттенюатор, `TXGAIN −30`, `FBGAIN −15`, `-p 4000`):
|
||||
|
||||
| Прогон | Потери seq | Ретрансмитов | Итог |
|
||||
|---|---|---|---|
|
||||
| 1 МБ, GROUPFEC=0 | 4 / 1024 | 4 | md5 ==, COMPLETE за 88 мс, END × 1 |
|
||||
| 10 МБ, GROUPFEC=0 | 44 / 10240 | 45 | md5 ==, `NACK вне окна: 0`, STATUS 93% |
|
||||
| негатив, FBGAIN −89 | — | — | A честно **exit 2** за 10 с (раньше рапортовал успех) |
|
||||
|
||||
Окно TX на 10 МБ провернулось ~5 раз без единого «NACK вне окна», кольцо RX не
|
||||
переполнялось ни разу — оба расчётных риска закрыты замером. Доставка STATUS в
|
||||
END-фазе растёт до ~93% (эфир пуст, самоглушение A прекращается) — плато §12.8
|
||||
на хендшейк не влияет, как и предполагалось.
|
||||
|
||||
**Клифф канала.** Стресс `TXGAIN −38/−40/−45` бесполезен: канала там нет вовсе —
|
||||
`Заголовков 3322, CRC 0` (заголовок BPSK живёт, payload QPSK+RS падает первым).
|
||||
Переход −30 (PER 0.4%) → −38 (100%) резкий, промежуточной точки на кабеле почти
|
||||
нет. Поведение в обрыве корректное: A упёрся в расчётный потолок rate-limit
|
||||
(2246 ретрансмитов ≈ 50 × 18 с / 0.4 с — эфир не залит дублями), B не поднял
|
||||
COMPLETE, A вышел с 2. Настоящий PER-стресс — свипом в §12.4, не здесь.
|
||||
|
||||
**Симплекс идёт мимо кольца.** Без `-F` ретрансмитов нет, seq только растёт —
|
||||
переупорядочивать нечего, а дыру закрыть некому: кольцо лишь задержало бы вывод
|
||||
до EOF. Отсюда ветка `g_fb_fg ? rb : stdout` в `process_frame`/`group_flush`.
|
||||
|
||||
**Гибрид с group-FEC.** Паритет гасит одиночные потери без задержки (RX снимает
|
||||
восстановленные seq с NACK — ретрансмит не нужен), ARQ добирает то, что паритету
|
||||
не по силам (>2 стираний/группу). `grp_failed > 0` при целом md5 — норма: группа
|
||||
не собралась, но ARQ её дозакрыл.
|
||||
|
||||
---
|
||||
*Ввод в строй: 14–15-07-2026. Замеры CPU и базовые решения — 10-07-2026.
|
||||
Прошивка v0.38, liquid-dsp 1.8.0.*
|
||||
Reference in New Issue
Block a user