mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(tci,cat): резерв бюджета переезжает писателю; строгий разбор полей ZZ-команд
Три замечания по79132f1. 1. [P2] Лимит памяти рекордеров обходился при SAVE. Take собирал сплошную копию записи, а DropData тут же возвращал исходные куски в бюджет — копия жила дальше в асинхронном TTCIWavWriter уже неучтённой. Один SAVE поднимал настоящее потребление примерно вдвое, а на медленном или зависшем сетевом каталоге очередь writer-потоков и их буферов росла мимо потолка вовсе. Теперь копия НАСЛЕДУЕТ резерв кусков, из которых собрана: Take отдаёт его out-параметром Reserved, писатель держит до конца записи и отпускает в ReleaseData — ровно один раз, сколько бы путей выхода ни было у Execute. Новых денег у бюджета копия не берёт, так что потолок теперь считает и очередь сохранений тоже. 2. [P2] Пять ZZ-команд проверяли длину поля, но не содержимое: StrToIntDef(s, 0) превращал любую нечисловую пару символов в индекс 0. ZZBSxx; переключал диапазон на нулевой вместо ?;, ZZBMxx; и ZZAUxx;/ZZBPxx; двигали VFO, ZZFIxx; выбирал фильтр 0. Разбор приведён к идиоме ZZFL/ZZFH: TryStrToInt, иначе ошибка формата. 3. [P3] Сообщение об отказе запуска TCI звало в Settings → Advanced, а настройки там уже не живут — вкладка CAT (переезд был вde0830f). Стенд 194/194: Take отдаёт резерв размером с копию, после Take занят ровно он, писатель возвращает его по окончании. Без фикса первая проверка краснеет. GUI (--ws=qt6) и демон зелёные. doc/TCI.md §2.5 и сводка стенда, doc/CAT_STATUS.md — таблица разбора. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -272,6 +272,7 @@ Thetis, у нас есть, ширины полей совпадают с `CATSt
|
||||
|---|---|
|
||||
| `TCATEngine.Parse` | команды без параметров не проверяли суффикс: `TXanything;` доходил до `CmdTX` и **поднимал передачу**; так же вели себя `RX UP DN BD BU QI RC ID IF`. Эталон отбраковывает лишний суффикс в парсере, по таблице ширин; у нас таблицы нет — список безаргументных команд теперь в `IsParamless` |
|
||||
| `ZZFL` / `ZZFH` | принимали поле любой длины от 4 символов и гнали его через `StrToIntDef`: `ZZFLabcd;` молча схлопывал кромку в ноль. Поле фиксированное — ровно 5 символов со знаком, разбор строгий |
|
||||
| `ZZAU` `ZZBP` `ZZBM` `ZZBS` `ZZFI` | длину поля проверяли, а содержимое — нет: `StrToIntDef(s, 0)` превращал любую нечисловую пару символов в индекс 0. То есть `ZZBSxx;` **переключал диапазон** на нулевой вместо `?;`, `ZZBMxx;` и `ZZAUxx;`/`ZZBPxx;` двигали VFO, а `ZZFIxx;` выбирал фильтр 0. Разбор приведён к идиоме `ZZFL`/`ZZFH`: `TryStrToInt`, иначе ошибка формата |
|
||||
| `KY` / `ZZKY` | текст не ограничивался; поле у Kenwood фиксированное, 25 символов. Длиннее — `?;`: очередь передачи не должна расти произвольно, иначе один пакет уводит станцию в эфир на неопределённое время |
|
||||
| `CATTcp.SendStr` | один `send` на ответ. TCP не обязан отдать весь буфер за раз — длинный ответ (`IF`, `ZZEB`, список режимов) мог уехать обрезанным, и молча: усечение здесь не ошибка. Теперь дописываем остаток в цикле |
|
||||
| `CATSerial` | порт помечался активным ДО `SerOpen`; при отказе он навсегда оставался «работающим» в `ActiveCount` и UI, а причина нигде не оседала. Открытие переехало из потока в `TCATSerialPort.Start` (синхронно), появилось свойство `LastError`, поток теперь только читает, а закрывает владелец в `Stop`. Заодно Andromeda-порт назначается только на реально поднявшийся порт |
|
||||
|
||||
+10
-2
@@ -528,7 +528,14 @@ ExpertSDR3 давно бы не было.
|
||||
2. **Общий бюджет `TCI_RECORD_MAX_BYTES` (128 МБ) на все рекордеры сразу.**
|
||||
Спрашивается при выделении каждого куска. Отказ не рушит запись: набранное
|
||||
остаётся сохраняемым, просто дальше она не растёт — иначе клиент терял бы
|
||||
уже записанное из-за чужой записи на другом приёмнике.
|
||||
уже записанное из-за чужой записи на другом приёмнике. ★`SAVE` бюджет не
|
||||
обходит: `Take` собирает куски в сплошную копию и **передаёт ей их резерв**
|
||||
(out-параметр `Reserved`), а не возвращает его сразу — копия живёт дальше в
|
||||
`TTCIWavWriter`, и отпускает место он же, когда данные больше не нужны
|
||||
(`ReleaseData` — ровно один раз, сколько бы путей выхода ни было у
|
||||
`Execute`). Иначе один `SAVE` поднимал бы настоящее потребление вдвое, а на
|
||||
медленном или зависшем сетевом каталоге очередь writer-потоков росла бы
|
||||
мимо потолка вовсе.
|
||||
3. **Освобождение по трём событиям, а не по одному.** Раньше срок проверял
|
||||
только `Feed`, то есть DSP-поток — а к мёртвому приёмнику он не приходит
|
||||
никогда, и `START` на несуществующий номер оставлял память навсегда.
|
||||
@@ -861,7 +868,8 @@ ExpertSDR3 давно бы не было.
|
||||
выделяет ни байта, бюджет растёт кусками по мере звука и возвращается по
|
||||
`Free`, потолок берётся целиком и сверх него следует отказ, при отказе запись
|
||||
не рушится, окно истекает по часам **без единого `Feed`** и отдаёт память
|
||||
само. ★Имя файла: простое имя ложится в каталог записей, а каталог из
|
||||
само, `Take` отдаёт резерв размером с копию и после него занят ровно он, а
|
||||
писатель возвращает этот резерв по окончании записи. ★Имя файла: простое имя ложится в каталог записей, а каталог из
|
||||
просьбы отбрасывается — абсолютный путь, `..` и буква диска наружу не
|
||||
выводят; пусто, `..`, не-`.wav`, управляющий символ и отсутствие каталога
|
||||
записей дают отказ; существующий файл писатель не перезаписывает.
|
||||
|
||||
Reference in New Issue
Block a user