mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 19:45:09 +00:00
Восемь дефектов, найденных прогоном настоящего TCI-клиента (три приёмника: NFM, DIGU, FMRAW) и его отчётом. 1. UI доп. панорам не перерисовывался: rfSliceState рассылался, но ветки в MainForm.OnControllerState не было (частоту несёт отдельный rfSliceFreq). 2. Stream.length у аудио — сэмплы НА КАНАЛ (§4.3), у IQ — вещественные отсчёты (§3.4: комплексных = length/channels). Было ×каналы везде, у стерео получалось вдвое больше. Развилка в TCIFillHeader + разбор TX-аудио в HandleBinary. 3+4. Дыры в маршрутах аудио движка: demod-тап звался только для DMR/FMRAW (у DIGU не было RX_AUDIO), а пост-громкостный — только для нецифровых (у FMRAW не было LINEOUT). Плюс мьют слайса больше не убивает RX_AUDIO: движку сообщают SetAudioTapsActive. 5. Клиент, поставивший TRX, уходил — MOX оставался. FTrxOwner + StopTxOf; TCIMicRequested снимается и по окончании любой передачи. 6. Гонка снятия IQ-тапа: SetIQTap(nil) возвращался раньше, чем DSP-поток выходил из вызова. FIQTapLock (порядок FSliceLock → FIQTapLock). 7. Рекордер был кольцом «последние N секунд», а §4.3 говорит про МАКСИМАЛЬНОЕ время записи с удалением по истечении. Переделан в линейный буфер с окном по часам от START. 8. TCIServer.HandleClient считал recv = 0 таймаутом: ноль — это EOF, errno при нём не трогается и несёт EAGAIN от прошлого истёкшего TCI_POLL_MS. Обычный TCP-разрыв без close-кадра не освобождал слот до остановки сервера, и после нескольких аварийных отключений новые клиенты упирались в TCI_MAX_CLIENTS. Теперь R = 0 рвёт связь безусловно, errno спрашивается только при R < 0. Попутно: MainForm.RecreateDSPEngine (смена sample rate до START) терял внутренние колбэки контроллера — введён AttachEngineCallbacks. Стенд test/tci заведён в репозиторий (run.sh, 126/126 зелёных, включая сквозной прогон через живой WDSP), доп. проверки на оба пути отключения клиента. doc/TCI.md приведена в соответствие: правило про recv = 0 в §1.1, единицы Stream.length, линейный буфер рекордера. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
30 lines
2.0 KiB
Bash
Executable File
30 lines
2.0 KiB
Bash
Executable File
#!/bin/sh
|
||
# Стенд TCI: сборка и прогон. Запускать откуда угодно — скрипт сам перейдёт
|
||
# в свой каталог. Возвращает ненулевой код, если хоть одна проверка провалена.
|
||
#
|
||
# Флаги те же, что у демона (см. build-ewsdrd.sh), и по тем же причинам:
|
||
# -Mobjfpc — командный режим по умолчанию: включает вложенные комментарии.
|
||
# С -Mdelphi {$MODE Delphi} внутри шапки WebUtils.pas закрывает
|
||
# комментарий раньше времени, и компиляция падает на
|
||
# «illegal character». Юниты дальше сами ставят свой {$mode}.
|
||
# -dHEADLESS — PlatformUtils не тянет Forms (LCL): стенду виджетсет не нужен,
|
||
# а без этого сборка требует всю LCL.
|
||
# ★Каталог .ppu — свой, с именем НЕ «lib», и путь абсолютный. Относительное
|
||
# «lib/<cpu>-<os>» компилятор ищет и относительно -Fu, то есть находит units
|
||
# GUI-сборки в корне проекта — а там PlatformUtils собран с LCL, и стенд падает
|
||
# на линковке с «undefined reference to TC_$FORMS_$$_SCREEN».
|
||
# libwdsp нужна только части E (сквозной прогон через движок); без неё эта
|
||
# часть сообщает о пропуске, а остальные идут как обычно.
|
||
set -e
|
||
cd "$(dirname "$0")"
|
||
HERE=$(pwd)
|
||
CPU=$(fpc -iTP)
|
||
OS=$(fpc -iTO)
|
||
OUTUNITS="$HERE/units/${CPU}-${OS}"
|
||
OUT="$HERE/bin/${CPU}-${OS}"
|
||
mkdir -p "$OUTUNITS" "$OUT"
|
||
fpc -Mobjfpc -O2 -dHEADLESS \
|
||
-Fu../.. -FU"$OUTUNITS" -k-L/usr/local/lib \
|
||
-o"$OUT/tcitest" tcitest.pas
|
||
exec "$OUT/tcitest" "$@"
|