mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(tci): TCI 2.0 — EWSDR как сервер (команды и уведомления)
Протокол Expert Electronics поверх WebSocket, порт 40001. EWSDR слушает, клиенты — логгеры, скиммеры, цифровые программы. - TCIProtocol.pas — чистый слой протокола: разбор/сборка `имя:арг;`, экранирование `^ ~ *`, словарь видов связи, пересчёт громкости в дБ. - TCIServer.pas — WS-сервер поверх WebUtils/WsClient: accept-поток, поток на клиента, HTTP-Upgrade, фреймы, рассылка, тик 20 мс. - TCIAdapter.pas — мост к TRadioController по схеме CAT: геттеры читают поля напрямую, сеттеры через Invoke, уведомления через AddStateListener. Маппинг: приёмник TCI = панадаптер, канал A/B = VFO A/B (пан 0) либо первый/второй слайс (паны 1..). Попутно: TRadioController.RemoveStateListener (адаптер умирает раньше контроллера) и TDXSpotStore.RemoveCall (spot_delete). Настройки — секция "tci" в settings.json (умолчание: выключено, 127.0.0.1, так как авторизации в протоколе нет) и вкладка Advanced → TCI Server. Бинарные потоки (IQ/аудио) — этап 2. Статус, таблица команд и список осознанных эхо-заглушек — в doc/TCI.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -459,6 +459,15 @@ type
|
||||
SpecPixels: Integer;
|
||||
end;
|
||||
|
||||
// TCI-сервер (протокол Expert Electronics поверх WebSocket). Авторизации в
|
||||
// протоколе нет, поэтому умолчание слушает только петлю: логгеры и цифровые
|
||||
// программы обычно живут на том же ПК, а наружу порт открывается осознанно.
|
||||
TTCISettings = record
|
||||
Enabled: Boolean;
|
||||
Port: Integer; // 1..65535, умолчание 40001 (как у ExpertSDR3)
|
||||
BindAddr: string; // '127.0.0.1' или '0.0.0.0'
|
||||
end;
|
||||
|
||||
// Transverter (XVTR) entry — один трансвертер.
|
||||
// Видимая частота VFO в [FreqBegin..FreqEnd] транслируется в IF-частоту,
|
||||
// которую слышит трансивер: f_IF = f_visible - LOOffset + LOError.
|
||||
@@ -779,6 +788,10 @@ type
|
||||
class procedure DefaultWeb(out W: TWebSettings);
|
||||
procedure LoadWebSettings(out W: TWebSettings);
|
||||
procedure SaveWebSettings(const W: TWebSettings);
|
||||
// TCI-сервер — глобальные настройки (секция "tci" в корне JSON).
|
||||
class procedure DefaultTCI(out T: TTCISettings);
|
||||
procedure LoadTCISettings(out T: TTCISettings);
|
||||
procedure SaveTCISettings(const T: TTCISettings);
|
||||
// Тема — глобальная настройка, не привязана к устройству
|
||||
procedure SaveTheme(ALightTheme: Boolean);
|
||||
function LoadTheme: Boolean;
|
||||
@@ -2981,6 +2994,34 @@ begin
|
||||
Save;
|
||||
end;
|
||||
|
||||
class procedure TSettingsManager.DefaultTCI(out T: TTCISettings);
|
||||
begin
|
||||
T.Enabled := False; // включается осознанно, как CAT-транспорты
|
||||
T.Port := 40001;
|
||||
T.BindAddr := '127.0.0.1';
|
||||
end;
|
||||
|
||||
procedure TSettingsManager.LoadTCISettings(out T: TTCISettings);
|
||||
var O: TJSONObject;
|
||||
begin
|
||||
DefaultTCI(T);
|
||||
if FRoot.Find('tci') = nil then Exit;
|
||||
O := EnsureObj(FRoot, 'tci');
|
||||
T.Enabled := JB(O, 'enabled', False);
|
||||
T.Port := EnsureRange(JI(O, 'port', 40001), 1, 65535);
|
||||
T.BindAddr := JS(O, 'bind_addr', '127.0.0.1');
|
||||
end;
|
||||
|
||||
procedure TSettingsManager.SaveTCISettings(const T: TTCISettings);
|
||||
var O: TJSONObject;
|
||||
begin
|
||||
O := EnsureObj(FRoot, 'tci');
|
||||
JW(O, 'enabled', T.Enabled);
|
||||
JW(O, 'port', T.Port);
|
||||
JWS(O, 'bind_addr', T.BindAddr);
|
||||
Save;
|
||||
end;
|
||||
|
||||
procedure TSettingsManager.SaveTheme(ALightTheme: Boolean);
|
||||
var O: TJSONObject;
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user