mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Со времён прошлой правки CAT в EWSDR появились TX-профили со всей «звуковой» цепью и телеграф — команды, которые doc/CAT_STATUS.md объявлял незакрываемыми, стали рабочими. TX-тракт: MG/ZZMG (усиление микрофона), MO/ZZMO + ZZTM (монитор передачи и его уровень), ZZTL/ZZTH (кромки TX-фильтра), PR/ZZPK + ZZPL (речевой компрессор), ZZET + ZZEB (эквалайзер), ZZTO + ZZTU (мощность и кнопка настройки), ZZUT (2TON), ZZLI + ZZUS (PureSignal), ZZTP (выбор профиля), ZZFD (девиация). Телеграф (были проброшены только KS/KY/ZZKS/ZZKY): ZZCS скорость, ZZCL тон, ZZCI иамбик, ZZCB/ZZCD break-in и hang-time, ZZCM сайдтон. Ревизия подписей. Комментарии у заглушек писались по буквам кода, а не по Thetis, и врали примерно в 150 местах. Хуже: часть РАБОТАЮЩИХ команд была привязана не к своей функции — внешний софт получал осмысленный, но неверный ответ, что хуже честной заглушки. Всё сверено с CATCommands.cs: ZZMA режим -> кнопка MUT ZZNN заглушка -> SNB ZZRX переход в RX -> аттенюатор RX1 ZZNS SNB -> кнопка NR2 ZZRV версия ПО -> напряжение питания ZZVS алиас ZZSP -> операции с VFO ZZMV индекс режима-> счётчик памяти ZZBM режим -> VFO B вниз на nn ZZKM режим кейера -> запуск CW-макроса ZZFT всегда A -> TX-частота (split) ZZFI/ZZBS были алиасами -> сами держат фильтр и диапазон Ошибочные алиасы на громкость/мощность сняты (ZZAA ZZVG ZZOA ZZAP ZZDN ZZAC ZZBI ZZMB ZZVA ZZPD ZZPO ZZQM ZZSR ZZRD ZZRU) — теперь честные заглушки с указанием, где функция живёт на самом деле. Кенвудовские команды сверены отдельно, покрытие полное (все 40 из Thetis), ширины полей совпадают с CATStructs.xml. Исправлено: SM отдавал 4 цифры вместо 5; RD/RU перестраивали VFO, хотя это RIT; KY не срезал набивку поля пробелами и гнал её в эфир паузами; CT принимала любой символ и «CT9;» молча гасил тон; OF/OS несли реализацию сами, а ZZOT/ZZOS были заглушками — клиент Thetis обращается как раз к ZZ* и не получал ничего. Валидация. Команды без параметров не проверяли суффикс: «TXanything;» доходил до CmdTX и ПОДНИМАЛ ПЕРЕДАЧУ (так же RX UP DN BD BU QI RC ID IF) — эталон отбраковывает лишний суффикс в парсере, у нас теперь список в IsParamless. ZZTX поднимал передачу на любом значении кроме нуля («2=TUNE» — выдумка). ZZFL/ZZFH принимали поле любой длины от 4 символов и через StrToIntDef молча схлопывали кромку в ноль. ZZMG принимал 1-2 символа. KY/ZZKY не ограничивали текст 25 символами, и очередь передачи могла расти произвольно. Осознанные отклонения от эталона сведены в отдельную таблицу документа: ZZBS (индекс диапазона вместо кода), ZZMN (имя режима вместо пресетов фильтров), ZZST (шаг FM вместо размера шага настройки), ZZCD (потолок 2000 мс — наш предел, он же в поле HangDelay пакета DUC Specific). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
987 lines
38 KiB
ObjectPascal
987 lines
38 KiB
ObjectPascal
unit CATAdapter;
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// TCATAdapter — адаптер CAT (Kenwood TS-2000) поверх TRadioController.
|
|
//
|
|
// Равноправный клиент контроллера наряду с WebAdapter и будущей Arduino-панелью.
|
|
// Владеет CAT-движком (TCATEngine) + транспортами (serial/TCP) и строит TCATContext:
|
|
// • геттеры читают состояние FController напрямую (CAT-поток, read-only);
|
|
// • сеттеры/команды зовут команды контроллера, маршалинг через FController.Invoke
|
|
// (GUI = TThread.Synchronize; демон подставит свою очередь).
|
|
// Никаких обращений к MainForm/WebAdapter — CAT говорит только с контроллером.
|
|
//
|
|
// Конфиг serial/TCP применяется снаружи через ApplySettings (UI-настройки CAT
|
|
// остаются в MainForm/SettingsForm и зовут ApplySettings при изменении/connect).
|
|
// -----------------------------------------------------------------------------
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,
|
|
RadioController, CATEngine, CATSerial, CATTcp, CATSliceEndpoint, Settings,
|
|
WDSPEngine, AndromedaPanel;
|
|
|
|
type
|
|
TCATAdapter = class
|
|
private
|
|
FController: TRadioController;
|
|
FEngine: TCATEngine;
|
|
FSerial: TCATSerialManager;
|
|
FTcp: TCATTcpServer;
|
|
// CAT дополнительных слайсов: свой движок+TCP-порт на слот (B..). Порты
|
|
// главного (serial + FTcp) остаются за главным приёмником — слайс A.
|
|
FSliceEps: array[0..CAT_SLICE_SLOTS-1] of TCATSliceEndpoint;
|
|
FPanel: TAndromedaPanel; // передняя панель Andromeda/G2 (если включена)
|
|
// Параметры команды для маршалинга в поток контроллера (через Invoke).
|
|
FSyncFreq: Double;
|
|
FSyncInt: Integer;
|
|
FSyncBool: Boolean;
|
|
FSyncStr: string;
|
|
// Какое поле TX-настроек правит SyncTXField (значение — в FSyncInt/FSyncBool).
|
|
FSyncTXFld: (txfMicGain, txfFiltLow, txfFiltHigh, txfCompOn, txfCompGain,
|
|
txfEQOn, txfTUNLevel, txfFMDev);
|
|
FSyncEQ: TCATEQGains;
|
|
|
|
// ── Геттеры (CAT-поток, read-only) ──
|
|
function GetVfoA: Double;
|
|
function GetVfoB: Double;
|
|
function GetMode: Integer;
|
|
function GetActiveVfo: Integer;
|
|
function GetAGCMode: Integer;
|
|
function GetVolume: Integer;
|
|
function GetDriveLevel: Integer;
|
|
function GetFilterIdx: Integer;
|
|
function GetFilterBW: Integer;
|
|
function GetFilterLow: Integer;
|
|
function GetFilterHigh: Integer;
|
|
procedure SetFilterLow(V: Integer);
|
|
procedure SetFilterHigh(V: Integer);
|
|
function GetNRMode: Integer;
|
|
function GetNBMode: Integer;
|
|
function GetSNB: Boolean;
|
|
function GetANF: Boolean;
|
|
function GetTX: Boolean;
|
|
function GetRunning: Boolean;
|
|
function GetSMeter: Double;
|
|
function GetBand: Integer;
|
|
function GetSplit: Boolean;
|
|
function GetSquelchOn: Boolean;
|
|
function GetSquelchLevel: Integer;
|
|
function GetCTCSSOn: Boolean;
|
|
function GetCTCSSTone: Integer;
|
|
function GetFMRptDir: Integer;
|
|
function GetFMRptOffset: Double;
|
|
function GetFMStep: Integer;
|
|
function GetAGCTop: Integer;
|
|
function GetCTun: Boolean;
|
|
|
|
// ── Сеттеры/команды (из CAT-потока → Invoke в поток контроллера) ──
|
|
procedure SetVfoA(V: Double);
|
|
procedure SetVfoB(V: Double);
|
|
procedure SetMode(V: Integer);
|
|
procedure SetActiveVfo(V: Integer);
|
|
procedure SetAGCMode(V: Integer);
|
|
procedure SetVolume(V: Integer);
|
|
procedure SetDriveLevel(V: Integer);
|
|
procedure SetFilterIdx(V: Integer);
|
|
procedure SetNRMode(V: Integer);
|
|
procedure SetNBMode(V: Integer);
|
|
procedure SetSNB(V: Boolean);
|
|
procedure SetANF(V: Boolean);
|
|
procedure SetTransmitting(V: Boolean);
|
|
function GetCWSpeed: Integer;
|
|
procedure SetCWSpeed(V: Integer);
|
|
function GetCWKeyerMode: Integer;
|
|
procedure SetCWKeyerMode(V: Integer);
|
|
procedure SendCWText(const S: string);
|
|
function GetCWTextBusy: Boolean;
|
|
procedure SyncCWSpeed;
|
|
procedure SyncCWKeyerMode;
|
|
procedure SyncCWText;
|
|
// ── Телеграф: тон, break-in, сайдтон ──
|
|
function GetCWPitch: Integer;
|
|
procedure SetCWPitch(V: Integer);
|
|
function GetCWBreakIn: Boolean;
|
|
procedure SetCWBreakIn(V: Boolean);
|
|
function GetCWHangTime: Integer;
|
|
procedure SetCWHangTime(V: Integer);
|
|
function GetCWMonitor: Boolean;
|
|
procedure SetCWMonitor(V: Boolean);
|
|
procedure SyncCWPitch;
|
|
procedure SyncCWBreakIn;
|
|
procedure SyncCWHangTime;
|
|
procedure SyncCWMonitor;
|
|
// ── TX-тракт (активный TX-профиль + вкладка Transmit) ──
|
|
function GetMicGain: Integer;
|
|
procedure SetMicGain(V: Integer);
|
|
function GetTXFilterLow: Integer;
|
|
procedure SetTXFilterLow(V: Integer);
|
|
function GetTXFilterHigh: Integer;
|
|
procedure SetTXFilterHigh(V: Integer);
|
|
function GetCompOn: Boolean;
|
|
procedure SetCompOn(V: Boolean);
|
|
function GetCompGain: Integer;
|
|
procedure SetCompGain(V: Integer);
|
|
function GetTXEQOn: Boolean;
|
|
procedure SetTXEQOn(V: Boolean);
|
|
function GetTXEQ(out Gains: TCATEQGains): Integer;
|
|
procedure SetTXEQ(NumBands: Integer; const Gains: TCATEQGains);
|
|
function GetTUNLevel: Integer;
|
|
procedure SetTUNLevel(V: Integer);
|
|
function GetFMDeviation: Integer;
|
|
procedure SetFMDeviation(V: Integer);
|
|
function GetTXProfile: Integer;
|
|
procedure SetTXProfile(V: Integer);
|
|
function GetTXProfileCount: Integer;
|
|
function GetMonitorOn: Boolean;
|
|
procedure SetMonitorOn(V: Boolean);
|
|
function GetMonitorLevel: Integer;
|
|
procedure SetMonitorLevel(V: Integer);
|
|
function GetTuning: Boolean;
|
|
procedure SetTuning(V: Boolean);
|
|
function GetTwoTone: Boolean;
|
|
procedure SetTwoTone(V: Boolean);
|
|
function GetPureSignal: Boolean;
|
|
procedure SetPureSignal(V: Boolean);
|
|
procedure DoPSSingleCal;
|
|
// ── Приёмник и сервис ──
|
|
function GetMuted: Boolean;
|
|
procedure SetMuted(V: Boolean);
|
|
function GetAtten: Integer;
|
|
procedure SetAtten(V: Integer);
|
|
function GetSupplyVolts: Double;
|
|
procedure DoVfoSwap;
|
|
function GetMemoryCount: Integer;
|
|
procedure SendCWMacro(V: Integer);
|
|
procedure SyncMuted;
|
|
procedure SyncAtten;
|
|
procedure SyncVfoSwap;
|
|
procedure SyncCWMacro;
|
|
// Правка одного поля TX-настроек: копия записи, поле, SetTXSettings. Так же
|
|
// это делает вкладка Transmit — она тоже отдаёт запись целиком.
|
|
procedure SyncTXField;
|
|
procedure SyncTXEQ;
|
|
procedure SyncTXProfile;
|
|
procedure SyncMonitorOn;
|
|
procedure SyncMonitorLevel;
|
|
procedure SyncTuning;
|
|
procedure SyncTwoTone;
|
|
procedure SyncPureSignal;
|
|
procedure SyncPSSingleCal;
|
|
procedure DoBandUp;
|
|
procedure DoBandDown;
|
|
procedure DoTuneUp;
|
|
procedure DoTuneDown;
|
|
procedure DoBandByIndex(Idx: Integer);
|
|
procedure SetSplit(V: Boolean);
|
|
procedure SetSquelchOn(V: Boolean);
|
|
procedure SetSquelchLevel(V: Integer);
|
|
procedure SetCTCSSOn(V: Boolean);
|
|
procedure SetCTCSSTone(V: Integer);
|
|
procedure SetFMRptDir(V: Integer);
|
|
procedure SetFMRptOffset(V: Double);
|
|
procedure SetFMStep(V: Integer);
|
|
procedure SetAGCTop(V: Integer);
|
|
procedure SetCTun(V: Boolean);
|
|
|
|
// ── Andromeda: форвард callback'ов движка в панель (из потока транспорта) ──
|
|
procedure PanelVfoStep(V: Integer);
|
|
procedure PanelEncoder(Enc, Step: Integer);
|
|
procedure PanelButton(Btn: Integer; State, LongPress: Boolean);
|
|
procedure PanelVersion(V: Integer);
|
|
|
|
// ── Sync-методы (выполняются в потоке контроллера) ──
|
|
procedure SyncVfoA;
|
|
procedure SyncVfoB;
|
|
procedure SyncMode;
|
|
procedure SyncActiveVfo;
|
|
procedure SyncAGC;
|
|
procedure SyncVolume;
|
|
procedure SyncDrive;
|
|
procedure SyncFilterIdx;
|
|
procedure SyncNR;
|
|
procedure SyncNB;
|
|
procedure SyncSNB;
|
|
procedure SyncANF;
|
|
procedure SyncMOX;
|
|
procedure SyncBandUp;
|
|
procedure SyncBandDown;
|
|
procedure SyncTuneUp;
|
|
procedure SyncTuneDown;
|
|
procedure SyncBandByIndex;
|
|
procedure SyncSplit;
|
|
procedure SyncSquelchOn;
|
|
procedure SyncSquelchLevel;
|
|
procedure SyncCTCSSOn;
|
|
procedure SyncCTCSSTone;
|
|
procedure SyncFMRptDir;
|
|
procedure SyncFMRptOffset;
|
|
procedure SyncFMStep;
|
|
procedure SyncAGCTop;
|
|
procedure SyncCTun;
|
|
procedure ApplySliceSettings(const G: TGlobalSettings); // CAT-порты слайсов
|
|
public
|
|
constructor Create(AController: TRadioController);
|
|
destructor Destroy; override;
|
|
// Применить serial/TCP-конфиг из глобальных настроек (вызывает UI на change/connect).
|
|
procedure ApplySettings(const G: TGlobalSettings);
|
|
end;
|
|
|
|
implementation
|
|
|
|
constructor TCATAdapter.Create(AController: TRadioController);
|
|
var
|
|
Ctx: TCATContext;
|
|
i: Integer;
|
|
begin
|
|
inherited Create;
|
|
FController := AController;
|
|
|
|
FillChar(Ctx, SizeOf(Ctx), 0);
|
|
Ctx.GetVfoA := @GetVfoA;
|
|
Ctx.GetVfoB := @GetVfoB;
|
|
Ctx.GetMode := @GetMode;
|
|
Ctx.GetActiveVfo := @GetActiveVfo;
|
|
Ctx.GetAGCMode := @GetAGCMode;
|
|
Ctx.GetVolume := @GetVolume;
|
|
Ctx.GetDriveLevel := @GetDriveLevel;
|
|
Ctx.GetFilterIdx := @GetFilterIdx;
|
|
Ctx.GetFilterBW := @GetFilterBW;
|
|
// Кромки фильтра (ZZFL/ZZFH). Раньше у главного приёмника были nil (фильтр
|
|
// был индексным) — теперь он хранит те же знаковые кромки, что и слайс.
|
|
Ctx.GetFilterLow := @GetFilterLow;
|
|
Ctx.GetFilterHigh := @GetFilterHigh;
|
|
Ctx.GetNRMode := @GetNRMode;
|
|
Ctx.GetNBMode := @GetNBMode;
|
|
Ctx.GetSNBEnabled := @GetSNB;
|
|
Ctx.GetANFEnabled := @GetANF;
|
|
Ctx.GetTransmitting := @GetTX;
|
|
Ctx.GetRunning := @GetRunning;
|
|
Ctx.GetSMeter := @GetSMeter;
|
|
Ctx.GetCurrentBand := @GetBand;
|
|
Ctx.SetVfoA := @SetVfoA;
|
|
Ctx.SetVfoB := @SetVfoB;
|
|
Ctx.SetMode := @SetMode;
|
|
Ctx.SetActiveVfo := @SetActiveVfo;
|
|
Ctx.SetAGCMode := @SetAGCMode;
|
|
Ctx.SetVolume := @SetVolume;
|
|
Ctx.SetDriveLevel := @SetDriveLevel;
|
|
Ctx.SetFilterIdx := @SetFilterIdx;
|
|
Ctx.SetFilterLow := @SetFilterLow;
|
|
Ctx.SetFilterHigh := @SetFilterHigh;
|
|
Ctx.SetNRMode := @SetNRMode;
|
|
Ctx.SetNBMode := @SetNBMode;
|
|
Ctx.SetSNBEnabled := @SetSNB;
|
|
Ctx.SetANFEnabled := @SetANF;
|
|
Ctx.SetTransmitting := @SetTransmitting;
|
|
Ctx.DoBandUp := @DoBandUp;
|
|
Ctx.DoBandDown := @DoBandDown;
|
|
Ctx.DoTuneUp := @DoTuneUp;
|
|
Ctx.DoTuneDown := @DoTuneDown;
|
|
Ctx.DoBandByIndex := @DoBandByIndex;
|
|
Ctx.GetSplit := @GetSplit;
|
|
Ctx.SetSplit := @SetSplit;
|
|
Ctx.GetSquelchOn := @GetSquelchOn;
|
|
Ctx.SetSquelchOn := @SetSquelchOn;
|
|
Ctx.GetSquelchLevel := @GetSquelchLevel;
|
|
Ctx.SetSquelchLevel := @SetSquelchLevel;
|
|
Ctx.GetCTCSSOn := @GetCTCSSOn;
|
|
Ctx.SetCTCSSOn := @SetCTCSSOn;
|
|
Ctx.GetCTCSSTone := @GetCTCSSTone;
|
|
Ctx.SetCTCSSTone := @SetCTCSSTone;
|
|
Ctx.GetFMRptDir := @GetFMRptDir;
|
|
Ctx.SetFMRptDir := @SetFMRptDir;
|
|
Ctx.GetFMRptOffset := @GetFMRptOffset;
|
|
Ctx.SetFMRptOffset := @SetFMRptOffset;
|
|
Ctx.GetFMStep := @GetFMStep;
|
|
Ctx.SetFMStep := @SetFMStep;
|
|
Ctx.GetAGCTop := @GetAGCTop;
|
|
Ctx.SetAGCTop := @SetAGCTop;
|
|
Ctx.GetCTun := @GetCTun;
|
|
Ctx.SetCTun := @SetCTun;
|
|
// Телеграф: скорость/режим кейера и программная передача текста (KY/ZZKY).
|
|
Ctx.GetCWSpeed := @GetCWSpeed;
|
|
Ctx.SetCWSpeed := @SetCWSpeed;
|
|
Ctx.GetCWKeyerMode := @GetCWKeyerMode;
|
|
Ctx.SetCWKeyerMode := @SetCWKeyerMode;
|
|
Ctx.SendCWText := @SendCWText;
|
|
Ctx.CWTextBusy := @GetCWTextBusy;
|
|
// Телеграф: тон (ZZCL), break-in и его hang-time (ZZCB/ZZCD), сайдтон (ZZCM).
|
|
Ctx.GetCWPitch := @GetCWPitch;
|
|
Ctx.SetCWPitch := @SetCWPitch;
|
|
Ctx.GetCWBreakIn := @GetCWBreakIn;
|
|
Ctx.SetCWBreakIn := @SetCWBreakIn;
|
|
Ctx.GetCWHangTime := @GetCWHangTime;
|
|
Ctx.SetCWHangTime := @SetCWHangTime;
|
|
Ctx.GetCWMonitor := @GetCWMonitor;
|
|
Ctx.SetCWMonitor := @SetCWMonitor;
|
|
// TX-тракт: усиление микрофона, кромки TX-фильтра, компрессор, эквалайзер,
|
|
// TUN/2TON/PS и выбор TX-профиля.
|
|
Ctx.GetMicGain := @GetMicGain;
|
|
Ctx.SetMicGain := @SetMicGain;
|
|
Ctx.GetTXFilterLow := @GetTXFilterLow;
|
|
Ctx.SetTXFilterLow := @SetTXFilterLow;
|
|
Ctx.GetTXFilterHigh := @GetTXFilterHigh;
|
|
Ctx.SetTXFilterHigh := @SetTXFilterHigh;
|
|
Ctx.GetCompOn := @GetCompOn;
|
|
Ctx.SetCompOn := @SetCompOn;
|
|
Ctx.GetCompGain := @GetCompGain;
|
|
Ctx.SetCompGain := @SetCompGain;
|
|
Ctx.GetTXEQOn := @GetTXEQOn;
|
|
Ctx.SetTXEQOn := @SetTXEQOn;
|
|
Ctx.GetTXEQ := @GetTXEQ;
|
|
Ctx.SetTXEQ := @SetTXEQ;
|
|
Ctx.GetTUNLevel := @GetTUNLevel;
|
|
Ctx.SetTUNLevel := @SetTUNLevel;
|
|
Ctx.GetFMDeviation := @GetFMDeviation;
|
|
Ctx.SetFMDeviation := @SetFMDeviation;
|
|
Ctx.GetTXProfile := @GetTXProfile;
|
|
Ctx.SetTXProfile := @SetTXProfile;
|
|
Ctx.GetTXProfileCount := @GetTXProfileCount;
|
|
Ctx.GetMonitorOn := @GetMonitorOn;
|
|
Ctx.SetMonitorOn := @SetMonitorOn;
|
|
Ctx.GetMonitorLevel := @GetMonitorLevel;
|
|
Ctx.SetMonitorLevel := @SetMonitorLevel;
|
|
Ctx.GetTuning := @GetTuning;
|
|
Ctx.SetTuning := @SetTuning;
|
|
Ctx.GetTwoTone := @GetTwoTone;
|
|
Ctx.SetTwoTone := @SetTwoTone;
|
|
Ctx.GetPureSignal := @GetPureSignal;
|
|
Ctx.SetPureSignal := @SetPureSignal;
|
|
Ctx.DoPSSingleCal := @DoPSSingleCal;
|
|
// Приёмник и сервис: MUT (ZZMA), шаговый аттенюатор (ZZRX), напряжение
|
|
// питания (ZZRV), обмен VFO (ZZVS), счётчик памяти (ZZMV), CW-макрос (ZZKM).
|
|
Ctx.GetMuted := @GetMuted;
|
|
Ctx.SetMuted := @SetMuted;
|
|
Ctx.GetAtten := @GetAtten;
|
|
Ctx.SetAtten := @SetAtten;
|
|
Ctx.GetSupplyVolts := @GetSupplyVolts;
|
|
Ctx.DoVfoSwap := @DoVfoSwap;
|
|
Ctx.GetMemoryCount := @GetMemoryCount;
|
|
Ctx.SendCWMacro := @SendCWMacro;
|
|
Ctx.OnPanelVfoStep := @PanelVfoStep;
|
|
Ctx.OnPanelEncoder := @PanelEncoder;
|
|
Ctx.OnPanelButton := @PanelButton;
|
|
Ctx.OnPanelVersion := @PanelVersion;
|
|
|
|
FEngine := TCATEngine.Create(Ctx);
|
|
FSerial := TCATSerialManager.Create(FEngine);
|
|
FTcp := TCATTcpServer.Create(FEngine);
|
|
|
|
for i := 0 to CAT_SLICE_SLOTS - 1 do
|
|
FSliceEps[i] := TCATSliceEndpoint.Create(FController, i);
|
|
|
|
// Передняя панель: отправляет наружу через Andromeda-порт, слушает состояние.
|
|
FPanel := TAndromedaPanel.Create(FController, @FSerial.SendToAndromeda);
|
|
FController.AddStateListener(@FPanel.OnControllerState);
|
|
end;
|
|
|
|
destructor TCATAdapter.Destroy;
|
|
var i: Integer;
|
|
begin
|
|
for i := 0 to CAT_SLICE_SLOTS - 1 do FreeAndNil(FSliceEps[i]);
|
|
if Assigned(FTcp) then begin FTcp.Stop; FreeAndNil(FTcp); end;
|
|
if Assigned(FSerial) then begin FSerial.StopAll; FreeAndNil(FSerial); end;
|
|
FreeAndNil(FEngine);
|
|
FreeAndNil(FPanel);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TCATAdapter.ApplySettings(const G: TGlobalSettings);
|
|
var
|
|
Cfgs: array[0..3] of TCATSerialConfig;
|
|
i: Integer;
|
|
begin
|
|
for i := 0 to 3 do
|
|
begin
|
|
Cfgs[i].Enabled := G.CATSerialEnabled[i];
|
|
Cfgs[i].PortName := G.CATSerialPort[i];
|
|
Cfgs[i].BaudRate := G.CATSerialBaud[i];
|
|
Cfgs[i].DataBits := G.CATSerialDataBits[i];
|
|
Cfgs[i].StopBits := G.CATSerialStopBits[i];
|
|
case G.CATSerialParity[i] of
|
|
1: Cfgs[i].Parity := cspOdd;
|
|
2: Cfgs[i].Parity := cspEven;
|
|
else Cfgs[i].Parity := cspNone;
|
|
end;
|
|
Cfgs[i].Andromeda := G.CATSerialAndromeda[i];
|
|
end;
|
|
FSerial.ApplyConfig(Cfgs);
|
|
// Если назначен Andromeda-порт — запросить версию панели (рукопожатие ZZZS).
|
|
if FSerial.HasAndromeda and Assigned(FPanel) then FPanel.RequestVersion;
|
|
FTcp.Stop;
|
|
if G.CATTcpEnabled then
|
|
begin
|
|
FTcp.Port := G.CATTcpPort;
|
|
FTcp.Start;
|
|
end;
|
|
ApplySliceSettings(G);
|
|
end;
|
|
|
|
procedure TCATAdapter.ApplySliceSettings(const G: TGlobalSettings);
|
|
// CAT слайсов: Auto TX — в контроллер (его читают TX-логика и флаг слайса),
|
|
// порт — в свой эндпоинт. Совпадающие порты не поднимаем: второй bind всё
|
|
// равно упадёт, а так поведение предсказуемо (выигрывает слот меньшей буквы).
|
|
var
|
|
i, j: Integer;
|
|
Enable: Boolean;
|
|
begin
|
|
for i := 0 to CAT_SLICE_SLOTS - 1 do
|
|
begin
|
|
FController.SetSliceSlotAutoTx(i, G.CATSliceAutoTX[i]);
|
|
Enable := G.CATSliceEnabled[i] and (G.CATSlicePort[i] > 0);
|
|
if Enable and G.CATTcpEnabled and (G.CATSlicePort[i] = G.CATTcpPort) then
|
|
Enable := False;
|
|
for j := 0 to i - 1 do
|
|
if G.CATSliceEnabled[j] and (G.CATSlicePort[j] = G.CATSlicePort[i]) then
|
|
Enable := False;
|
|
FSliceEps[i].Apply(Enable, G.CATSlicePort[i]);
|
|
end;
|
|
end;
|
|
|
|
// ── Геттеры ──────────────────────────────────────────────────────────────────
|
|
function TCATAdapter.GetVfoA: Double; begin Result := FController.FVfoA; end;
|
|
function TCATAdapter.GetVfoB: Double; begin Result := FController.FVfoB; end;
|
|
function TCATAdapter.GetMode: Integer; begin Result := FController.FMode; end;
|
|
function TCATAdapter.GetActiveVfo: Integer; begin Result := FController.FActiveVfo; end;
|
|
function TCATAdapter.GetAGCMode: Integer; begin Result := FController.FAGCMode; end;
|
|
function TCATAdapter.GetVolume: Integer; begin Result := FController.FVolume; end;
|
|
function TCATAdapter.GetDriveLevel: Integer; begin Result := FController.FDrivePercent; end;
|
|
function TCATAdapter.GetFilterIdx: Integer; begin Result := FController.FFilter; end;
|
|
function TCATAdapter.GetFilterBW: Integer; begin Result := FController.FFilterBW; end;
|
|
function TCATAdapter.GetFilterLow: Integer; begin Result := FController.FilterLo; end;
|
|
function TCATAdapter.GetFilterHigh: Integer; begin Result := FController.FilterHi; end;
|
|
// Кромку меняем по одной — вторую держим текущей (контроллер уводит правку в
|
|
// VAR, поэтому пресеты внешняя программа не испортит).
|
|
procedure TCATAdapter.SetFilterLow(V: Integer);
|
|
begin FController.SetFilterEdges(V, FController.FilterHi); end;
|
|
procedure TCATAdapter.SetFilterHigh(V: Integer);
|
|
begin FController.SetFilterEdges(FController.FilterLo, V); end;
|
|
function TCATAdapter.GetNRMode: Integer; begin Result := FController.FNRMode; end;
|
|
function TCATAdapter.GetNBMode: Integer; begin Result := FController.FNBMode; end;
|
|
function TCATAdapter.GetSNB: Boolean; begin Result := FController.FSNB; end;
|
|
function TCATAdapter.GetANF: Boolean; begin Result := FController.FANF; end;
|
|
function TCATAdapter.GetTX: Boolean; begin Result := FController.FTransmitting; end;
|
|
function TCATAdapter.GetRunning: Boolean; begin Result := FController.FRunning; end;
|
|
function TCATAdapter.GetSMeter: Double; begin Result := FController.FLastSMeter; end;
|
|
function TCATAdapter.GetBand: Integer; begin Result := FController.FCurrentBand; end;
|
|
function TCATAdapter.GetSplit: Boolean; begin Result := FController.FSplitTxB; end;
|
|
function TCATAdapter.GetSquelchOn: Boolean; begin Result := FController.FFMSQOn; end;
|
|
function TCATAdapter.GetSquelchLevel: Integer; begin Result := FController.FFMSQLevel; end;
|
|
function TCATAdapter.GetCTCSSOn: Boolean; begin Result := FController.FFMCTCSSOn; end;
|
|
function TCATAdapter.GetCTCSSTone: Integer; begin Result := FController.FFMCTCSSToneIdx; end;
|
|
function TCATAdapter.GetFMRptDir: Integer; begin Result := FController.FFMRptDir; end;
|
|
function TCATAdapter.GetFMRptOffset: Double; begin Result := FController.FFMRptOffsetHz; end;
|
|
function TCATAdapter.GetFMStep: Integer; begin Result := FController.FFMStepIdx; end;
|
|
function TCATAdapter.GetAGCTop: Integer; begin Result := FController.FAGCTop; end;
|
|
function TCATAdapter.GetCTun: Boolean; begin Result := FController.FCTun; end;
|
|
|
|
// ── Сеттеры (маршалинг) ──────────────────────────────────────────────────────
|
|
procedure TCATAdapter.SetVfoA(V: Double);
|
|
begin FSyncFreq := V; FController.Invoke(@SyncVfoA); end;
|
|
|
|
procedure TCATAdapter.SyncVfoA;
|
|
begin
|
|
// A активен — полная перестройка (CTUN/band/сеть + канальная оркестрация через
|
|
// OnAfterTune). B активен — только сохраняем/отображаем A (приёмник на B).
|
|
if FController.FActiveVfo = 0 then FController.SetVfoA(FSyncFreq)
|
|
else FController.StoreVfoA(FSyncFreq);
|
|
end;
|
|
|
|
procedure TCATAdapter.SetVfoB(V: Double);
|
|
begin FSyncFreq := V; FController.Invoke(@SyncVfoB); end;
|
|
|
|
procedure TCATAdapter.SyncVfoB;
|
|
begin FController.SetVfoB(FSyncFreq); end;
|
|
|
|
procedure TCATAdapter.SetMode(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncMode); end;
|
|
|
|
procedure TCATAdapter.SyncMode;
|
|
begin
|
|
if (FSyncInt < MODE_MIN) or (FSyncInt > MODE_MAX) then Exit;
|
|
FController.SetMode(FSyncInt);
|
|
end;
|
|
|
|
procedure TCATAdapter.SetActiveVfo(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncActiveVfo); end;
|
|
|
|
procedure TCATAdapter.SyncActiveVfo;
|
|
begin FController.SetActiveVfo(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetAGCMode(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncAGC); end;
|
|
|
|
procedure TCATAdapter.SyncAGC;
|
|
begin FController.SetAGCMode(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetVolume(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncVolume); end;
|
|
|
|
procedure TCATAdapter.SyncVolume;
|
|
begin FController.SetVolume(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetDriveLevel(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncDrive); end;
|
|
|
|
procedure TCATAdapter.SyncDrive;
|
|
begin FController.SetDrive(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetFilterIdx(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncFilterIdx); end;
|
|
|
|
procedure TCATAdapter.SyncFilterIdx;
|
|
begin FController.SetFilterIdx(FSyncInt); end; // прямой индекс пресета
|
|
|
|
procedure TCATAdapter.SetNRMode(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncNR); end;
|
|
|
|
procedure TCATAdapter.SyncNR;
|
|
begin FController.SetNR(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetNBMode(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncNB); end;
|
|
|
|
procedure TCATAdapter.SyncNB;
|
|
begin FController.SetNB(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetSNB(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncSNB); end;
|
|
|
|
procedure TCATAdapter.SyncSNB;
|
|
begin FController.SetSNB(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.SetANF(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncANF); end;
|
|
|
|
procedure TCATAdapter.SyncANF;
|
|
begin FController.SetANF(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.SetTransmitting(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncMOX); end;
|
|
|
|
// ---- Телеграф (KS/KY/ZZKM/ZZKS/ZZKY) --------------------------------------
|
|
// Правки настроек и запуск передачи маршалим в поток контроллера, как всё
|
|
// остальное в адаптере: SetCWSettings трогает движок и пишет конфиг.
|
|
|
|
function TCATAdapter.GetCWSpeed: Integer;
|
|
begin Result := FController.CWSettings.Speed; end;
|
|
|
|
procedure TCATAdapter.SetCWSpeed(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncCWSpeed); end;
|
|
|
|
procedure TCATAdapter.SyncCWSpeed;
|
|
var C: TCWSettings;
|
|
begin
|
|
C := FController.CWSettings;
|
|
C.Speed := FSyncInt;
|
|
FController.SetCWSettings(C);
|
|
end;
|
|
|
|
function TCATAdapter.GetCWKeyerMode: Integer;
|
|
begin Result := FController.CWSettings.KeyerMode; end;
|
|
|
|
procedure TCATAdapter.SetCWKeyerMode(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncCWKeyerMode); end;
|
|
|
|
procedure TCATAdapter.SyncCWKeyerMode;
|
|
var C: TCWSettings;
|
|
begin
|
|
C := FController.CWSettings;
|
|
C.KeyerMode := FSyncInt;
|
|
FController.SetCWSettings(C);
|
|
end;
|
|
|
|
procedure TCATAdapter.SendCWText(const S: string);
|
|
begin FSyncStr := S; FController.Invoke(@SyncCWText); end;
|
|
|
|
procedure TCATAdapter.SyncCWText;
|
|
begin FController.CWXSend(FSyncStr); end;
|
|
|
|
function TCATAdapter.GetCWTextBusy: Boolean;
|
|
begin Result := FController.CWXBusy; end;
|
|
|
|
function TCATAdapter.GetCWPitch: Integer;
|
|
begin Result := FController.CWSettings.Pitch; end;
|
|
|
|
procedure TCATAdapter.SetCWPitch(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncCWPitch); end;
|
|
|
|
procedure TCATAdapter.SyncCWPitch;
|
|
var C: TCWSettings;
|
|
begin
|
|
C := FController.CWSettings;
|
|
C.Pitch := FSyncInt;
|
|
FController.SetCWSettings(C);
|
|
end;
|
|
|
|
function TCATAdapter.GetCWBreakIn: Boolean;
|
|
begin Result := FController.CWSettings.BreakIn; end;
|
|
|
|
procedure TCATAdapter.SetCWBreakIn(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncCWBreakIn); end;
|
|
|
|
procedure TCATAdapter.SyncCWBreakIn;
|
|
var C: TCWSettings;
|
|
begin
|
|
C := FController.CWSettings;
|
|
C.BreakIn := FSyncBool;
|
|
FController.SetCWSettings(C);
|
|
end;
|
|
|
|
function TCATAdapter.GetCWHangTime: Integer;
|
|
begin Result := FController.CWSettings.HangTimeMS; end;
|
|
|
|
procedure TCATAdapter.SetCWHangTime(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncCWHangTime); end;
|
|
|
|
procedure TCATAdapter.SyncCWHangTime;
|
|
var C: TCWSettings;
|
|
begin
|
|
C := FController.CWSettings;
|
|
C.HangTimeMS := FSyncInt;
|
|
FController.SetCWSettings(C);
|
|
end;
|
|
|
|
function TCATAdapter.GetCWMonitor: Boolean;
|
|
// Сайдтонов два, и они не взаимозаменяемы: аппаратный звучит в наушниках
|
|
// трансивера, программный — в звуковой карте PC. ZZCM правит тот, что отвечает
|
|
// за текущий источник манипуляции, иначе команда молча промахивалась бы мимо.
|
|
begin
|
|
if FController.CWLocalSource then Result := FController.CWSettings.SidetoneSW
|
|
else Result := FController.CWSettings.SidetoneHW;
|
|
end;
|
|
|
|
procedure TCATAdapter.SetCWMonitor(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncCWMonitor); end;
|
|
|
|
procedure TCATAdapter.SyncCWMonitor;
|
|
var C: TCWSettings;
|
|
begin
|
|
C := FController.CWSettings;
|
|
if FController.CWLocalSource then C.SidetoneSW := FSyncBool
|
|
else C.SidetoneHW := FSyncBool;
|
|
FController.SetCWSettings(C);
|
|
end;
|
|
|
|
// ── TX-тракт ─────────────────────────────────────────────────────────────────
|
|
// Геттеры читают живые TX-настройки контроллера (они же — активный профиль),
|
|
// сеттеры кладут значение в scratch и правят одно поле в потоке контроллера.
|
|
|
|
function TCATAdapter.GetMicGain: Integer;
|
|
begin Result := Round(FController.FTXSettings.MicGainDB); end;
|
|
|
|
procedure TCATAdapter.SetMicGain(V: Integer);
|
|
begin FSyncTXFld := txfMicGain; FSyncInt := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetTXFilterLow: Integer;
|
|
begin Result := FController.FTXSettings.FilterLow; end;
|
|
|
|
procedure TCATAdapter.SetTXFilterLow(V: Integer);
|
|
begin FSyncTXFld := txfFiltLow; FSyncInt := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetTXFilterHigh: Integer;
|
|
begin Result := FController.FTXSettings.FilterHigh; end;
|
|
|
|
procedure TCATAdapter.SetTXFilterHigh(V: Integer);
|
|
begin FSyncTXFld := txfFiltHigh; FSyncInt := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetCompOn: Boolean;
|
|
begin Result := FController.FTXSettings.CompressorOn; end;
|
|
|
|
procedure TCATAdapter.SetCompOn(V: Boolean);
|
|
begin FSyncTXFld := txfCompOn; FSyncBool := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetCompGain: Integer;
|
|
begin Result := Round(FController.FTXSettings.CompressorGain); end;
|
|
|
|
procedure TCATAdapter.SetCompGain(V: Integer);
|
|
begin FSyncTXFld := txfCompGain; FSyncInt := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetTXEQOn: Boolean;
|
|
begin Result := FController.FTXSettings.EQOn; end;
|
|
|
|
procedure TCATAdapter.SetTXEQOn(V: Boolean);
|
|
begin FSyncTXFld := txfEQOn; FSyncBool := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetTXEQ(out Gains: TCATEQGains): Integer;
|
|
var i: Integer;
|
|
begin
|
|
for i := 0 to High(Gains) do Gains[i] := Round(FController.FTXSettings.EQGains[i]);
|
|
Result := FController.FTXSettings.EQNumBands;
|
|
end;
|
|
|
|
procedure TCATAdapter.SetTXEQ(NumBands: Integer; const Gains: TCATEQGains);
|
|
begin
|
|
FSyncInt := NumBands;
|
|
FSyncEQ := Gains;
|
|
FController.Invoke(@SyncTXEQ);
|
|
end;
|
|
|
|
procedure TCATAdapter.SyncTXEQ;
|
|
// Частоты полос команда не несёт (их в формате Thetis попросту нет) — трогаем
|
|
// только усиления и число полос, сетка остаётся той, что настроена в UI.
|
|
var
|
|
T: TTXSettings;
|
|
i: Integer;
|
|
begin
|
|
T := FController.FTXSettings;
|
|
T.EQNumBands := FSyncInt;
|
|
for i := 0 to High(FSyncEQ) do
|
|
if i <= FSyncInt then T.EQGains[i] := FSyncEQ[i];
|
|
FController.SetTXSettings(T);
|
|
end;
|
|
|
|
function TCATAdapter.GetTUNLevel: Integer;
|
|
begin Result := FController.FTXSettings.TUNLevel; end;
|
|
|
|
procedure TCATAdapter.SetTUNLevel(V: Integer);
|
|
begin FSyncTXFld := txfTUNLevel; FSyncInt := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
function TCATAdapter.GetFMDeviation: Integer;
|
|
begin Result := Round(FController.FTXSettings.FMDeviation); end;
|
|
|
|
procedure TCATAdapter.SetFMDeviation(V: Integer);
|
|
begin FSyncTXFld := txfFMDev; FSyncInt := V; FController.Invoke(@SyncTXField); end;
|
|
|
|
procedure TCATAdapter.SyncTXField;
|
|
var T: TTXSettings;
|
|
begin
|
|
T := FController.FTXSettings;
|
|
case FSyncTXFld of
|
|
txfMicGain: T.MicGainDB := FSyncInt;
|
|
txfFiltLow: T.FilterLow := FSyncInt;
|
|
txfFiltHigh: T.FilterHigh := FSyncInt;
|
|
txfCompOn: T.CompressorOn := FSyncBool;
|
|
txfCompGain: T.CompressorGain := FSyncInt;
|
|
txfEQOn: T.EQOn := FSyncBool;
|
|
txfTUNLevel: T.TUNLevel := FSyncInt;
|
|
txfFMDev: T.FMDeviation := FSyncInt;
|
|
end;
|
|
FController.SetTXSettings(T);
|
|
end;
|
|
|
|
function TCATAdapter.GetTXProfile: Integer;
|
|
begin Result := FController.ActiveTXProfile; end;
|
|
|
|
procedure TCATAdapter.SetTXProfile(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncTXProfile); end;
|
|
|
|
procedure TCATAdapter.SyncTXProfile;
|
|
begin FController.SelectTXProfile(FSyncInt); end;
|
|
|
|
function TCATAdapter.GetTXProfileCount: Integer;
|
|
begin Result := FController.TXProfileCount; end;
|
|
|
|
function TCATAdapter.GetMonitorOn: Boolean;
|
|
begin Result := not FController.FRxMuteOnTx; end;
|
|
|
|
procedure TCATAdapter.SetMonitorOn(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncMonitorOn); end;
|
|
|
|
procedure TCATAdapter.SyncMonitorOn;
|
|
begin FController.SetRxMuteOnTx(not FSyncBool); end;
|
|
|
|
function TCATAdapter.GetMonitorLevel: Integer;
|
|
begin Result := FController.FTxMonVolume; end;
|
|
|
|
procedure TCATAdapter.SetMonitorLevel(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncMonitorLevel); end;
|
|
|
|
procedure TCATAdapter.SyncMonitorLevel;
|
|
begin FController.SetTXMonVolume(FSyncInt); end;
|
|
|
|
function TCATAdapter.GetTuning: Boolean;
|
|
begin Result := FController.FTuning; end;
|
|
|
|
procedure TCATAdapter.SetTuning(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncTuning); end;
|
|
|
|
procedure TCATAdapter.SyncTuning;
|
|
begin FController.SetTune(FSyncBool); end;
|
|
|
|
function TCATAdapter.GetTwoTone: Boolean;
|
|
begin Result := FController.FTwoTone; end;
|
|
|
|
procedure TCATAdapter.SetTwoTone(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncTwoTone); end;
|
|
|
|
procedure TCATAdapter.SyncTwoTone;
|
|
begin FController.SetTwoTone(FSyncBool); end;
|
|
|
|
function TCATAdapter.GetPureSignal: Boolean;
|
|
begin Result := FController.FPSEnabled; end;
|
|
|
|
procedure TCATAdapter.SetPureSignal(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncPureSignal); end;
|
|
|
|
procedure TCATAdapter.SyncPureSignal;
|
|
begin FController.SetPureSignal(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.DoPSSingleCal;
|
|
begin FController.Invoke(@SyncPSSingleCal); end;
|
|
|
|
procedure TCATAdapter.SyncPSSingleCal;
|
|
begin FController.PSSingleCal; end;
|
|
|
|
// ── Приёмник и сервис ────────────────────────────────────────────────────────
|
|
|
|
function TCATAdapter.GetMuted: Boolean;
|
|
begin Result := FController.FMuted; end;
|
|
|
|
procedure TCATAdapter.SetMuted(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncMuted); end;
|
|
|
|
procedure TCATAdapter.SyncMuted;
|
|
begin FController.SetMute(FSyncBool); end;
|
|
|
|
function TCATAdapter.GetAtten: Integer;
|
|
begin Result := FController.FAtten; end;
|
|
|
|
procedure TCATAdapter.SetAtten(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncAtten); end;
|
|
|
|
procedure TCATAdapter.SyncAtten;
|
|
begin FController.SetAtten(FSyncInt); end;
|
|
|
|
function TCATAdapter.GetSupplyVolts: Double;
|
|
// Телеметрия платы; -1 = данных ещё нет (движок отдаст ноль, как Thetis).
|
|
begin Result := FController.FLastSupplyV; end;
|
|
|
|
procedure TCATAdapter.DoVfoSwap;
|
|
begin FController.Invoke(@SyncVfoSwap); end;
|
|
|
|
procedure TCATAdapter.SyncVfoSwap;
|
|
begin FController.VfoSwap; end;
|
|
|
|
function TCATAdapter.GetMemoryCount: Integer;
|
|
begin
|
|
if Assigned(FController.FChannelStore) then Result := FController.FChannelStore.Count
|
|
else Result := 0;
|
|
end;
|
|
|
|
procedure TCATAdapter.SendCWMacro(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncCWMacro); end;
|
|
|
|
procedure TCATAdapter.SyncCWMacro;
|
|
// Макрос n (1..9) = ячейка памяти сообщений n. Ячеек восемь (F1..F8): девятая
|
|
// и пустые просто ничего не передают — очередь дёргать незачем.
|
|
var Idx: Integer;
|
|
begin
|
|
Idx := FSyncInt - 1;
|
|
if (Idx < 0) or (Idx >= CW_MSG_COUNT) then Exit;
|
|
if FController.CWSettings.Messages[Idx] = '' then Exit;
|
|
FController.CWXSend(FController.CWSettings.Messages[Idx]);
|
|
end;
|
|
|
|
procedure TCATAdapter.SyncMOX;
|
|
begin FController.SetMOX(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.DoBandUp;
|
|
begin FController.Invoke(@SyncBandUp); end;
|
|
|
|
procedure TCATAdapter.SyncBandUp;
|
|
begin FController.BandUp; end;
|
|
|
|
procedure TCATAdapter.DoBandDown;
|
|
begin FController.Invoke(@SyncBandDown); end;
|
|
|
|
procedure TCATAdapter.SyncBandDown;
|
|
begin FController.BandDown; end;
|
|
|
|
procedure TCATAdapter.DoTuneUp;
|
|
begin FController.Invoke(@SyncTuneUp); end;
|
|
|
|
procedure TCATAdapter.SyncTuneUp;
|
|
begin FController.TuneActiveBy(10); end;
|
|
|
|
procedure TCATAdapter.DoTuneDown;
|
|
begin FController.Invoke(@SyncTuneDown); end;
|
|
|
|
procedure TCATAdapter.SyncTuneDown;
|
|
begin FController.TuneActiveBy(-10); end;
|
|
|
|
procedure TCATAdapter.DoBandByIndex(Idx: Integer);
|
|
begin FSyncInt := Idx; FController.Invoke(@SyncBandByIndex); end;
|
|
|
|
procedure TCATAdapter.SyncBandByIndex;
|
|
begin FController.SetBand(FSyncInt); end;
|
|
|
|
// ── Split / FM (squelch, CTCSS, repeater, step) ───────────────────────────────
|
|
procedure TCATAdapter.SetSplit(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncSplit); end;
|
|
|
|
procedure TCATAdapter.SyncSplit;
|
|
begin FController.SetSplit(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.SetSquelchOn(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncSquelchOn); end;
|
|
|
|
procedure TCATAdapter.SyncSquelchOn;
|
|
begin FController.SetFMSquelch(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.SetSquelchLevel(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncSquelchLevel); end;
|
|
|
|
procedure TCATAdapter.SyncSquelchLevel;
|
|
begin FController.SetFMSquelchLevel(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetCTCSSOn(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncCTCSSOn); end;
|
|
|
|
procedure TCATAdapter.SyncCTCSSOn;
|
|
begin FController.SetFMCTCSS(FSyncBool); end;
|
|
|
|
procedure TCATAdapter.SetCTCSSTone(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncCTCSSTone); end;
|
|
|
|
procedure TCATAdapter.SyncCTCSSTone;
|
|
begin FController.SetFMCTCSSTone(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetFMRptDir(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncFMRptDir); end;
|
|
|
|
procedure TCATAdapter.SyncFMRptDir;
|
|
begin FController.SetFMRpt(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetFMRptOffset(V: Double);
|
|
begin FSyncFreq := V; FController.Invoke(@SyncFMRptOffset); end;
|
|
|
|
procedure TCATAdapter.SyncFMRptOffset;
|
|
begin FController.SetFMRptOffset(FSyncFreq); end;
|
|
|
|
procedure TCATAdapter.SetFMStep(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncFMStep); end;
|
|
|
|
procedure TCATAdapter.SyncFMStep;
|
|
begin FController.SetFMStep(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetAGCTop(V: Integer);
|
|
begin FSyncInt := V; FController.Invoke(@SyncAGCTop); end;
|
|
|
|
procedure TCATAdapter.SyncAGCTop;
|
|
begin FController.SetAGCTop(FSyncInt); end;
|
|
|
|
procedure TCATAdapter.SetCTun(V: Boolean);
|
|
begin FSyncBool := V; FController.Invoke(@SyncCTun); end;
|
|
|
|
procedure TCATAdapter.SyncCTun;
|
|
begin FController.SetCTun(FSyncBool); end;
|
|
|
|
// ── Andromeda: форвард в панель (сама маршалит действия в поток контроллера) ──
|
|
procedure TCATAdapter.PanelVfoStep(V: Integer);
|
|
begin if Assigned(FPanel) then FPanel.HandleVfoStep(V); end;
|
|
|
|
procedure TCATAdapter.PanelEncoder(Enc, Step: Integer);
|
|
begin if Assigned(FPanel) then FPanel.HandleEncoder(Enc, Step); end;
|
|
|
|
procedure TCATAdapter.PanelButton(Btn: Integer; State, LongPress: Boolean);
|
|
begin if Assigned(FPanel) then FPanel.HandleButton(Btn, State, LongPress); end;
|
|
|
|
procedure TCATAdapter.PanelVersion(V: Integer);
|
|
begin if Assigned(FPanel) then FPanel.HandleVersion(V); end;
|
|
|
|
end.
|