Этап 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:
Maxim
2026-07-16 15:29:25 +03:00
parent 6294a472cd
commit ab1e87a17e
6 changed files with 224 additions and 49 deletions

View File

@@ -42,6 +42,8 @@ PHY: OFDM через liquid-dsp 1.8.0 + FFTW/NEON, FEC RS(255,223).
bit5 GF_Q (Q иначе P), bits4-0 idx кадра в группе (0..17). 0 = legacy-кадр.
Group-FEC 16+2: 16 кадров данных + P(⊕) + Q(Σgⁱ) над GF(256), закрывает ≤2
стёртых кадра/группу без обратного канала (src/group_fec.c). RX автодетект.
Сигнатура F0 E7 — END (этап 3): payload 12 Б, total_seq u32 + total_bytes u64,
маркер конца передачи для хендшейка END/COMPLETE (feedback.h, §12.9).
КРИТИЧНО: liquid по умолчанию передаёт 8 Б заголовка. Обязательно
`ofdmflexframegen_set_header_len(fg,12)` и
`ofdmflexframesync_set_header_len(fs,12)` на обеих сторонах.
@@ -55,7 +57,8 @@ TX LO: канал `altvoltage1` (output); RX LO: `altvoltage0` (output).
#1 header 12Б (см. выше) · #2 лимит nblocks ≤ 18, не 100 (стек recovered[4096])
· #3 fec_decode() liquid не сообщает об ошибках — rs_saved фиктивен
· #4 внешний NCO в receiver вреден, убрать · #5 TX пушит лишние сэмплы
· #6 нет детектора потерь по seq · #7 reciever.c → receiver.c
· #6 ✅ закрыт на FDD: ARQ (NACK→ретрансмит) + END/COMPLETE, §12.9. На симплексе
ARQ невозможен — там детектор [ПОТЕРЯ] + group-FEC · #7 reciever.c → receiver.c
## Команды
Сборка: `make` · Деплой: `make deploy` (scp -O! sftp на плате нет)