mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 17:27:32 +00:00
fix(tci): пара «клиент+приёмник» только по факту передачи; перебор имён .part
[P1] FTxClient/FTxRx писались ДО Invoke, и команда, которая ничего не сделала,
всё равно их перебивала. Клиент, уже передающий с приёмника 1, шлёт
trx:0,true,tci — передатчик занят, SyncSetTRX не делает ничего (Started=False),
а маркеры ИДУЩЕЙ передачи с этого мига уходят под номером 0. MSHV такие блоки
отбрасывает (network.cpp:231), то есть передача просто замолкает. Теперь пара
назначается после Invoke и только при Started — тем же признаком, по которому
назначается хозяин эфира. Тот же гейт закрывает близнеца: trx:<N>,true без
',tci' поверх своей же передачи больше не снимает источник модуляции. Снятие
(',false') работает как прежде.
[P2] Имя временного файла (pid + счётчик) уникально внутри процесса, но не
между запусками: «.part», оставшийся от прошлой жизни (публиковать было
нечем), плюс повторно выданный системой pid дают EEXIST на создании — и
задание пропадало молча. TCICreateTempNear перебирает до 64 имён, но только
пока ошибка — «имя занято»: нет прав или каталога перебором не лечится.
Стенд test/tci: 219 проверок (было 217). Новое — занятое имя «.part» записи не
теряет (стенд занимает ровно то имя, которое возьмёт писатель) и пустая
команда TRX не меняет номер приёмника в маркерах. Негативный контроль на обе
правки. Попутно в тесте поправлены два комментария, описывавшие прежнюю
реализацию публикации.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+15
-5
@@ -503,7 +503,11 @@ TX-аудио не по своей воле, а строго в ответ на
|
||||
сидящий на **втором слайсе** (`tci_trx = 1`), маркеров не видел вовсе: эфир по
|
||||
`trx:1,true,tci` поднимался, а звука не было ни одного блока. Поэтому вместе с
|
||||
клиентом-модулятором запоминается номер приёмника из его же `TRX`
|
||||
(`FTxRx`), и маркеры идут под ним.
|
||||
(`FTxRx`), и маркеры идут под ним. ★Пара «клиент + приёмник» меняется **только
|
||||
когда команда и правда что-то сделала** (`Started`, тот же признак, по которому
|
||||
назначается хозяин эфира): иначе клиент, уже передающий с приёмника 1, своим же
|
||||
`trx:0,true,tci` — командой-пустышкой, потому что передатчик занят, — перевёл бы
|
||||
маркеры идущей передачи на номер 0 и замолчал.
|
||||
|
||||
**★`rfTransmitting` — не всегда «эфир изменился».** Контроллер шлёт это поле и
|
||||
просто «перерисуй TX-бейджи»: `SetTxSlice` заканчивается `Changed(rfTransmitting)`,
|
||||
@@ -580,7 +584,11 @@ ExpertSDR3 давно бы не было.
|
||||
1. данные пишутся во **временный файл** рядом (`<имя>.<pid>-<n>.part`,
|
||||
создаётся эксклюзивно и не по симлинку — `TCICreateNewFile`), циклом, с
|
||||
проверкой каждого вызова (короткая запись законна, её дописываем; 0 или
|
||||
-1 — провал);
|
||||
-1 — провал). ★Имя перебирается (`TCICreateTempNear`): pid со счётчиком
|
||||
уникальны внутри процесса, но не между запусками, и `.part`, оставшийся от
|
||||
прошлой жизни, вместе с повторно выданным системой pid дал бы `EEXIST` —
|
||||
занятое имя не повод терять запись, а вот другая ошибка (нет прав, нет
|
||||
каталога) перебором не лечится и обрывает попытку сразу;
|
||||
2. перед публикацией идёт `FileFlush`: на ext4 с отложенным размещением «нет
|
||||
места» приходит не в `write`, а именно здесь;
|
||||
3. и только после этого файл появляется под целевым именем — **одним вызовом
|
||||
@@ -954,7 +962,7 @@ ExpertSDR3 давно бы не было.
|
||||
движков и сети валится с AV — клиент получает `tci_error`, соединение живо) и
|
||||
неразрывность пачки инициализации под крутящейся ручкой.
|
||||
|
||||
### Стенд этапа 2 (бинарные потоки) — 217 проверок, все зелёные
|
||||
### Стенд этапа 2 (бинарные потоки) — 219 проверок, все зелёные
|
||||
|
||||
Отдельная программа (`test/tci/tcitest.pas`, прогон — `test/tci/run.sh`,
|
||||
внешних библиотек не требует) проверяет потоки на четырёх уровнях:
|
||||
@@ -988,7 +996,8 @@ ExpertSDR3 давно бы не было.
|
||||
возвращает резерв по окончании записи. ★Писатель: задание принимается и
|
||||
дописывается очередью, после удачи временного файла рядом не остаётся,
|
||||
неудачная запись (счёт обещает больше, чем есть в кусках) не оставляет НИ
|
||||
файла, НИ `.part`, за всё время записи 32 МБ целевое имя ни разу не видно
|
||||
файла, НИ `.part`, занятое имя `.part` (файл от прошлого запуска с тем же
|
||||
pid) записи не теряет, за всё время записи 32 МБ целевое имя ни разу не видно
|
||||
незаконченным, сверх потолка заданий следует отказ, после `Close` заданий не
|
||||
берут, а `TCIStopWriter` дожидается 32-МБ записи — файл цел сразу после его
|
||||
возврата, и **хвост очереди за ней дописан тоже** (это и есть проверка на
|
||||
@@ -1025,7 +1034,8 @@ ExpertSDR3 давно бы не было.
|
||||
аудио блоками с `receiver = 1`, ★по `trx:1,true,tci` берёт модуляцию из TCI
|
||||
(то есть просьбу не стирает `Changed(rfTransmitting)` из `SetTxSlice`) и шлёт
|
||||
маркеры `TX_CHRONO` **под номером 1** — оба этих места и ломали передачу
|
||||
MSHV, сидящего на втором слайсе, а после удаления слайса приёмник 1 замолкает
|
||||
MSHV, сидящего на втором слайсе; а `trx:0,true,tci` поверх этой же передачи
|
||||
(команда-пустышка) номер приёмника в маркерах не меняет, а после удаления слайса приёмник 1 замолкает
|
||||
целиком — вместо прежнего `vfo:1,0,0`.
|
||||
- **Сквозной прогон через живой WDSP:** синтетический 24-битный IQ подаётся
|
||||
в движок, а клиент по WebSocket получает блоки RX-аудио 12 кГц и IQ 48 кГц
|
||||
|
||||
Reference in New Issue
Block a user