Этап 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:
@@ -109,6 +109,44 @@ PER₁≈PER₀ — **выполнен, этап 5 (fallback TDD, цена ~8% t
|
||||
FBGAIN=0 (они и дали три точки плато). Гипотеза компрессии входа при RSSI
|
||||
−33…−35 (см. §2.1) остаётся непроверенной, но gate она не блокирует.
|
||||
|
||||
### 2.3. Находки этапа 3 (ARQ, 2026-07-16)
|
||||
|
||||
**Клифф канала на кабеле — свипу PER здесь не место.** `TXGAIN −30` даёт
|
||||
PER 0.4%, `−38` — уже `CRC: 0` при живых `Заголовках: 3322`. Порог заголовка и
|
||||
порога payload разнесены: заголовок ofdmflexframe идёт BPSK с собственным FEC,
|
||||
payload — QPSK+RS(255,223), и падает он первым. Практический смысл: **живой
|
||||
счётчик «Заголовков» при нулевом CRC — это не «плохой канал», а его отсутствие**;
|
||||
диагностику по такому прогону строить нельзя, ARQ там нечего вытягивать.
|
||||
Аттенюатор даёт слишком грубый шаг — карта PER снята свипом в README §12.4.
|
||||
|
||||
**Направления несимметричны.** На одном и том же кабеле A→B даёт `RS битых: 0`,
|
||||
B→A — `RS битых: 20…28` на 1024 кадрах. Разброс устойчив между прогонами, то
|
||||
есть это не статистика, а свойство пары плат/тракта. Для ARQ безразлично
|
||||
(ретрансмит закроет), но при выборе направления для чувствительного трафика и
|
||||
при трактовке PER-замеров это надо помнить: цифры одного направления не
|
||||
переносятся на другое.
|
||||
|
||||
**Ловушка «битый кадр выпадает из NACK».** `miss_ack(seq)` по факту приёма кадра
|
||||
(до декода) — тихо ломает ARQ: кадр, не прошедший RS/CRC, снимался с NACK
|
||||
навсегда, A его не досылал, а RX считал файл собранным → **A рапортовал успех
|
||||
с битым md5**. Учёт NACK обязан идти ПОСЛЕ декода: `ok → miss_ack`,
|
||||
`!ok → miss_add_sorted`. Битый кадр — такая же дыра, как непришедший, просто
|
||||
обнаруженная не детектором seq. Не выстрелило на приёмке 3a лишь потому, что
|
||||
там случились `RS битых: 0`.
|
||||
|
||||
**Ловушка «COMPLETE съеден снимком».** STATUS на A забирается снимком
|
||||
(latest-wins, `fb_take` гасит флаг свежести). Если бы COMPLETE читался из
|
||||
снимка, `arq_service` съел бы тот самый STATUS, в котором он приехал, и A ушёл
|
||||
бы в 10-секундный таймаут на ЦЕЛОМ файле. COMPLETE поэтому — отдельная
|
||||
монотонная защёлка, взводимая прямо в `fb_callback`.
|
||||
|
||||
**Переполнение MISS_CAP — тупик без пересборки.** `miss_add` при переполнении
|
||||
молча теряет seq, и вернуть его в NACK уже некому: детектор дыр по нему второй
|
||||
раз не сработает (`highest_seq` ушёл вперёд). В тяжёлом канале это заклинивало
|
||||
приём насмерть. Лечится тем, что кольцо reorder знает точно, каких кадров нет:
|
||||
`miss_rebuild()` пересобирает NACK из кольца на каждом END (A шлёт их 10 Гц до
|
||||
самого COMPLETE, скан ≤1024 — сотые доли ядра).
|
||||
|
||||
## 3. Регуляторика (868/915 МГц в регионе ETSI)
|
||||
|
||||
- **868 МГц** — SRD-диапазон: ограничения на полосу канала (сотни кГц),
|
||||
|
||||
Reference in New Issue
Block a user