mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(cat): wire split/FM/CTUN/AGC-T CAT commands to controller
Реализованы команды, ранее бывшие заглушками — функционал уже был в TRadioController, но не пробрасывался в CAT: - Split TX: ZZSP/FT/FR + split-байт в IF (новый RadioController.SetSplit) - FM Squelch: SQ (0–255), ZZSQ (0–100%), ZZSO (on/off) - FM CTCSS: CT/ZZTA (on), CN (1-based)/ZZTB (0-based тон) - FM-репитер: OF (offset), OS (направление, с трансляцией Kenwood↔RPT_*) - FM step: ZZST (00–03) - CTUN: ZZCN; AGC-T/RF gain: ZZAR - ANF: ZZNT (раньше ошибочно алиас NB) - Шаги VFO: ZZAU/ZZBP (исправлен баг — были алиасы ZZFA/ZZAP), ZZSU TCATContext расширен callback'ами (split, squelch, CTCSS, repeater, step, AGC-T, CTUN); CATAdapter — геттеры/сеттеры/sync с маршалингом через Invoke. Добавлен doc/CAT_STATUS.md — полный статус CAT и план работ. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+270
-63
@@ -36,6 +36,10 @@ const
|
||||
MODE_CWL = 3; MODE_CWU = 4; MODE_FM = 5;
|
||||
MODE_AM = 6; MODE_SAM = 7;
|
||||
|
||||
// FM repeater offset directions — зеркало FMRepeater.RPT_* (значения должны
|
||||
// совпадать: контроллер хранит FFMRptDir в этих же кодах).
|
||||
RPT_NONE = 0; RPT_MINUS = 1; RPT_PLUS = 2;
|
||||
|
||||
type
|
||||
TCATGetDoubleFunc = function: Double of object;
|
||||
TCATGetIntFunc = function: Integer of object;
|
||||
@@ -81,6 +85,27 @@ type
|
||||
DoTuneUp: TCATProc;
|
||||
DoTuneDown: TCATProc;
|
||||
DoBandByIndex: TCATSetIntProc;
|
||||
// Split / FM (squelch, CTCSS, repeater, step)
|
||||
GetSplit: TCATGetBoolFunc;
|
||||
SetSplit: TCATSetBoolProc;
|
||||
GetSquelchOn: TCATGetBoolFunc;
|
||||
SetSquelchOn: TCATSetBoolProc;
|
||||
GetSquelchLevel: TCATGetIntFunc; // 0..100
|
||||
SetSquelchLevel: TCATSetIntProc; // 0..100
|
||||
GetCTCSSOn: TCATGetBoolFunc;
|
||||
SetCTCSSOn: TCATSetBoolProc;
|
||||
GetCTCSSTone: TCATGetIntFunc; // index 0..37
|
||||
SetCTCSSTone: TCATSetIntProc; // index 0..37
|
||||
GetFMRptDir: TCATGetIntFunc; // 0=none,1=minus,2=plus
|
||||
SetFMRptDir: TCATSetIntProc;
|
||||
GetFMRptOffset: TCATGetDoubleFunc; // Hz
|
||||
SetFMRptOffset: TCATSetDoubleProc; // Hz
|
||||
GetFMStep: TCATGetIntFunc; // index 0..3 (6.25/12.5/20/25 kHz)
|
||||
SetFMStep: TCATSetIntProc; // index 0..3
|
||||
GetAGCTop: TCATGetIntFunc; // AGC-T порог, dB
|
||||
SetAGCTop: TCATSetIntProc; // AGC-T порог, dB
|
||||
GetCTun: TCATGetBoolFunc; // Click-tune (CTUN) вкл/выкл
|
||||
SetCTun: TCATSetBoolProc;
|
||||
end;
|
||||
|
||||
TCATEngine = class
|
||||
@@ -111,6 +136,17 @@ type
|
||||
function SafeGetRunning: Boolean;
|
||||
function SafeGetSMeter: Double;
|
||||
function SafeGetBand: Integer;
|
||||
function SafeGetSplit: Boolean;
|
||||
function SafeGetSquelchOn: Boolean;
|
||||
function SafeGetSquelchLevel: Integer;
|
||||
function SafeGetCTCSSOn: Boolean;
|
||||
function SafeGetCTCSSTone: Integer;
|
||||
function SafeGetFMRptDir: Integer;
|
||||
function SafeGetFMRptOffset: Double;
|
||||
function SafeGetFMStep: Integer;
|
||||
function SafeGetAGCTop: Integer;
|
||||
function SafeGetCTun: Boolean;
|
||||
function StepIdxToHz(Idx: Integer): Double;
|
||||
|
||||
// command implementations
|
||||
function CmdAG(const s: string): string;
|
||||
@@ -165,8 +201,10 @@ type
|
||||
function ZZAR(const s: string): string;
|
||||
function ZZAS(const s: string): string;
|
||||
function ZZAT(const s: string): string;
|
||||
function ZZAU(const s: string): string;
|
||||
function ZZBA: string;
|
||||
function ZZBD: string;
|
||||
function ZZBP(const s: string): string;
|
||||
function ZZBE(const s: string): string;
|
||||
function ZZBI(const s: string): string;
|
||||
function ZZBM(const s: string): string;
|
||||
@@ -241,7 +279,7 @@ type
|
||||
function ZZSP(const s: string): string;
|
||||
function ZZSQ(const s: string): string;
|
||||
function ZZSR(const s: string): string;
|
||||
function ZZST: string;
|
||||
function ZZST(const s: string): string;
|
||||
function ZZSU: string;
|
||||
function ZZTA(const s: string): string;
|
||||
function ZZTB(const s: string): string;
|
||||
@@ -433,6 +471,55 @@ function TCATEngine.SafeGetBand: Integer;
|
||||
begin
|
||||
if Assigned(FCtx.GetCurrentBand) then Result := FCtx.GetCurrentBand else Result := 5;
|
||||
end;
|
||||
function TCATEngine.SafeGetSplit: Boolean;
|
||||
begin
|
||||
if Assigned(FCtx.GetSplit) then Result := FCtx.GetSplit else Result := False;
|
||||
end;
|
||||
function TCATEngine.SafeGetSquelchOn: Boolean;
|
||||
begin
|
||||
if Assigned(FCtx.GetSquelchOn) then Result := FCtx.GetSquelchOn else Result := False;
|
||||
end;
|
||||
function TCATEngine.SafeGetSquelchLevel: Integer;
|
||||
begin
|
||||
if Assigned(FCtx.GetSquelchLevel) then Result := FCtx.GetSquelchLevel else Result := 0;
|
||||
end;
|
||||
function TCATEngine.SafeGetCTCSSOn: Boolean;
|
||||
begin
|
||||
if Assigned(FCtx.GetCTCSSOn) then Result := FCtx.GetCTCSSOn else Result := False;
|
||||
end;
|
||||
function TCATEngine.SafeGetCTCSSTone: Integer;
|
||||
begin
|
||||
if Assigned(FCtx.GetCTCSSTone) then Result := FCtx.GetCTCSSTone else Result := 0;
|
||||
end;
|
||||
function TCATEngine.SafeGetFMRptDir: Integer;
|
||||
begin
|
||||
if Assigned(FCtx.GetFMRptDir) then Result := FCtx.GetFMRptDir else Result := 0;
|
||||
end;
|
||||
function TCATEngine.SafeGetFMRptOffset: Double;
|
||||
begin
|
||||
if Assigned(FCtx.GetFMRptOffset) then Result := FCtx.GetFMRptOffset else Result := 0;
|
||||
end;
|
||||
function TCATEngine.SafeGetFMStep: Integer;
|
||||
begin
|
||||
if Assigned(FCtx.GetFMStep) then Result := FCtx.GetFMStep else Result := 0;
|
||||
end;
|
||||
function TCATEngine.SafeGetAGCTop: Integer;
|
||||
begin
|
||||
if Assigned(FCtx.GetAGCTop) then Result := FCtx.GetAGCTop else Result := 0;
|
||||
end;
|
||||
function TCATEngine.SafeGetCTun: Boolean;
|
||||
begin
|
||||
if Assigned(FCtx.GetCTun) then Result := FCtx.GetCTun else Result := False;
|
||||
end;
|
||||
function TCATEngine.StepIdxToHz(Idx: Integer): Double;
|
||||
// Шаг настройки по индексу (0..14) — зеркало Thetis Step2Freq (в Гц).
|
||||
const Steps: array[0..14] of Double = (
|
||||
1, 10, 25, 50, 100, 250, 500, 1000, 5000, 9000,
|
||||
10000, 100000, 250000, 500000, 1000000);
|
||||
begin
|
||||
if (Idx < 0) or (Idx > 14) then Result := 0
|
||||
else Result := Steps[Idx];
|
||||
end;
|
||||
|
||||
{ ── Constructor / Destructor ─────────────────────────────────────────────── }
|
||||
|
||||
@@ -570,23 +657,27 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdCN(const s: string): string;
|
||||
// CN: CTCSS tone — STUB: FM sub-audible tones not implemented
|
||||
// CN: CTCSS tone number (2 digits, 1-based 01..38 по таблице CTCSS_TONES).
|
||||
var idx: Integer;
|
||||
begin
|
||||
if Length(s) = 2 then
|
||||
Result := ''
|
||||
else if Length(s) = 0 then
|
||||
Result := '00'
|
||||
if Length(s) = 2 then begin
|
||||
idx := EnsureRange(StrToIntDef(s, 1) - 1, 0, 37);
|
||||
if Assigned(FCtx.SetCTCSSTone) then FCtx.SetCTCSSTone(idx);
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := Pad(EnsureRange(SafeGetCTCSSTone, 0, 37) + 1, 2)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdCT(const s: string): string;
|
||||
// CT: CTCSS enable — STUB: not implemented
|
||||
// CT: CTCSS enable (1=on, 0=off) для FM-передачи.
|
||||
begin
|
||||
if Length(s) = 1 then
|
||||
Result := ''
|
||||
else if Length(s) = 0 then
|
||||
Result := '0'
|
||||
if Length(s) = 1 then begin
|
||||
if Assigned(FCtx.SetCTCSSOn) then FCtx.SetCTCSSOn(s = '1');
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := B2C(SafeGetCTCSSOn)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
@@ -622,13 +713,20 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdFR(const s: string): string;
|
||||
// FR: receive VFO — always VFO A, dummy for compat
|
||||
// FR: receive VFO (0=VFO A, 1=VFO B) — выбирает активный приёмный VFO.
|
||||
begin
|
||||
if Length(s) = 1 then
|
||||
Result := ''
|
||||
else if Length(s) = 0 then
|
||||
Result := '0'
|
||||
else
|
||||
if Length(s) = 1 then begin
|
||||
if (s = '0') or (s = '1') then begin
|
||||
if Assigned(FCtx.SetActiveVfo) then FCtx.SetActiveVfo(StrToIntDef(s, 0));
|
||||
Result := '';
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end else if Length(s) = 0 then begin
|
||||
if Assigned(FCtx.GetActiveVfo) then
|
||||
Result := IntToStr(EnsureRange(FCtx.GetActiveVfo, 0, 1))
|
||||
else
|
||||
Result := '0';
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
@@ -677,14 +775,14 @@ var
|
||||
m: Integer;
|
||||
begin
|
||||
freq := FreqToStr(SafeGetVfoA);
|
||||
step := '0000'; // step size — STUB: no step control
|
||||
step := '0000'; // step size — FM step не маппится на Kenwood-формат IF (см. ZZST)
|
||||
incr := '+00000'; // RIT/XIT value — STUB: no RIT/XIT
|
||||
rit := '0';
|
||||
xit := '0';
|
||||
m := ModeToK(SafeGetMode);
|
||||
mode := IntToStr(m);
|
||||
tx := B2C(SafeGetTX);
|
||||
split := '0'; // STUB: no split
|
||||
split := B2C(SafeGetSplit);
|
||||
Result := freq + step + incr + rit + xit + '000' + tx + mode + '0' + '0' + split + '0000';
|
||||
end;
|
||||
|
||||
@@ -765,19 +863,38 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdOF(const s: string): string;
|
||||
// OF: FM repeater offset frequency — STUB: no FM repeater
|
||||
// OF: FM repeater offset frequency (9 digits, Hz).
|
||||
begin
|
||||
if Length(s) = 9 then Result := ''
|
||||
else if Length(s) = 0 then Result := '000000000'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 9 then begin
|
||||
if Assigned(FCtx.SetFMRptOffset) then FCtx.SetFMRptOffset(StrToIntDef(s, 0));
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := Pad(Round(SafeGetFMRptOffset), 9)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdOS(const s: string): string;
|
||||
// OS: repeater offset direction — STUB
|
||||
// OS: repeater offset direction (Kenwood: 0=simplex, 1=plus, 2=minus).
|
||||
// Внутренние константы: RPT_NONE=0, RPT_MINUS=1, RPT_PLUS=2 → требуется трансляция.
|
||||
var dir: Integer;
|
||||
begin
|
||||
if Length(s) = 1 then Result := ''
|
||||
else if Length(s) = 0 then Result := '0'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 1 then begin
|
||||
case StrToIntDef(s, 0) of
|
||||
1: dir := RPT_PLUS;
|
||||
2: dir := RPT_MINUS;
|
||||
else dir := RPT_NONE;
|
||||
end;
|
||||
if Assigned(FCtx.SetFMRptDir) then FCtx.SetFMRptDir(dir);
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then begin
|
||||
case SafeGetFMRptDir of
|
||||
RPT_PLUS: Result := '1';
|
||||
RPT_MINUS: Result := '2';
|
||||
else Result := '0';
|
||||
end;
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdPC(const s: string): string;
|
||||
@@ -888,11 +1005,21 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdSQ(const s: string): string;
|
||||
// SQ: squelch — STUB: no squelch control
|
||||
// SQ: squelch. SET: <sel><lll> (sel=0/1 RX, lll=000–255). GET: <sel> → <sel><lll>.
|
||||
// Шкала Kenwood 0–255 маппится на внутренний уровень 0–100 %.
|
||||
var lvl255, lvl100: Integer;
|
||||
begin
|
||||
if Length(s) = 4 then Result := ''
|
||||
else if Length(s) = 1 then Result := '0000'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 4 then begin
|
||||
lvl255 := EnsureRange(StrToIntDef(Copy(s, 2, 3), 0), 0, 255);
|
||||
lvl100 := Round(lvl255 * 100 / 255);
|
||||
if Assigned(FCtx.SetSquelchLevel) then FCtx.SetSquelchLevel(lvl100);
|
||||
if Assigned(FCtx.SetSquelchOn) then FCtx.SetSquelchOn(lvl100 > 0);
|
||||
Result := '';
|
||||
end else if Length(s) = 1 then begin
|
||||
lvl255 := Round(EnsureRange(SafeGetSquelchLevel, 0, 100) * 255 / 100);
|
||||
Result := s + Pad(lvl255, 3);
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.CmdTX(const s: string): string;
|
||||
@@ -936,7 +1063,7 @@ begin
|
||||
else if ext = 'AR' then ans := ZZAR(s)
|
||||
else if ext = 'AS' then ans := ZZAS(s)
|
||||
else if ext = 'AT' then ans := ZZAT(s)
|
||||
else if ext = 'AU' then ans := ZZFA(s) // alias ZZFA
|
||||
else if ext = 'AU' then ans := ZZAU(s)
|
||||
else if ext = 'AY' then ans := '' // STUB: APF type
|
||||
else if ext = 'BA' then ans := ZZBA
|
||||
else if ext = 'BB' then ans := '' // STUB: band button state
|
||||
@@ -946,7 +1073,7 @@ begin
|
||||
else if ext = 'BG' then ans := '' // STUB: sub-RX gain
|
||||
else if ext = 'BI' then ans := ZZBI(s)
|
||||
else if ext = 'BM' then ans := ZZBM(s)
|
||||
else if ext = 'BP' then ans := ZZAP(s) // alias ZZAP
|
||||
else if ext = 'BP' then ans := ZZBP(s)
|
||||
else if ext = 'BR' then ans := '' // STUB: sub-RX enable
|
||||
else if ext = 'BS' then ans := ZZBS(s)
|
||||
else if ext = 'BT' then ans := '' // STUB: band TX
|
||||
@@ -1130,7 +1257,7 @@ begin
|
||||
else if ext = 'SQ' then ans := ZZSQ(s)
|
||||
else if ext = 'SR' then ans := ZZSR(s)
|
||||
else if ext = 'SS' then ans := '' // STUB: sub-RX
|
||||
else if ext = 'ST' then begin ZZST; ans := ''; end
|
||||
else if ext = 'ST' then ans := ZZST(s)
|
||||
else if ext = 'SU' then begin ZZSU; ans := ''; end
|
||||
else if ext = 'SV' then ans := '' // STUB: spectrum value
|
||||
else if ext = 'SW' then ans := '' // STUB: spectrum write
|
||||
@@ -1299,11 +1426,44 @@ function TCATEngine.ZZAP(const s: string): string;
|
||||
begin Result := ZZPC(s); end;
|
||||
|
||||
function TCATEngine.ZZAR(const s: string): string;
|
||||
// ZZAR: RIT enable — STUB: no RIT
|
||||
// ZZAR: RX1 AGC-T порог (RF gain). Формат: знак + 3 цифры (напр. "+020", "+120").
|
||||
// Контроллер клампит в свой диапазон (20..120 dB).
|
||||
var v: Integer;
|
||||
begin
|
||||
if Length(s) = 1 then Result := ''
|
||||
else if Length(s) = 0 then Result := '0'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 4 then begin
|
||||
v := StrToIntDef(s, 0); // StrToIntDef понимает ведущий +/-
|
||||
if Assigned(FCtx.SetAGCTop) then FCtx.SetAGCTop(v);
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then begin
|
||||
v := SafeGetAGCTop;
|
||||
if v >= 0 then Result := '+' + Pad(v, 3)
|
||||
else Result := '-' + Pad(-v, 3);
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZAU(const s: string): string;
|
||||
// ZZAU: сдвиг VFO A вверх на один шаг с индексом nn (00..14, см. StepIdxToHz).
|
||||
var idx: Integer;
|
||||
begin
|
||||
if Length(s) = 2 then begin
|
||||
idx := EnsureRange(StrToIntDef(s, 0), 0, 14);
|
||||
if Assigned(FCtx.SetVfoA) then FCtx.SetVfoA(SafeGetVfoA + StepIdxToHz(idx));
|
||||
Result := '';
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZBP(const s: string): string;
|
||||
// ZZBP: сдвиг VFO B вверх на один шаг с индексом nn (00..14, см. StepIdxToHz).
|
||||
var idx: Integer;
|
||||
begin
|
||||
if Length(s) = 2 then begin
|
||||
idx := EnsureRange(StrToIntDef(s, 0), 0, 14);
|
||||
if Assigned(FCtx.SetVfoB) then FCtx.SetVfoB(SafeGetVfoB + StepIdxToHz(idx));
|
||||
Result := '';
|
||||
end else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZAS(const s: string): string;
|
||||
@@ -1384,9 +1544,13 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZCN(const s: string): string;
|
||||
// ZZCN: compressor on — STUB: TX DSP not implemented
|
||||
// ZZCN: CTUN (click-tune) для RX1 вкл/выкл.
|
||||
begin
|
||||
if Length(s) = 1 then Result := '' else if Length(s) = 0 then Result := '0'
|
||||
if Length(s) = 1 then begin
|
||||
if Assigned(FCtx.SetCTun) then FCtx.SetCTun(s = '1');
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := B2C(SafeGetCTun)
|
||||
else Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
@@ -1712,8 +1876,15 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZNT(const s: string): string;
|
||||
// ZZNT: noise blanker type — STUB: maps to NB mode
|
||||
begin Result := ZZNB(s); end;
|
||||
// ZZNT: ANF (auto-notch) вкл/выкл.
|
||||
begin
|
||||
if Length(s) = 1 then begin
|
||||
if Assigned(FCtx.SetANFEnabled) then FCtx.SetANFEnabled(s = '1');
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := B2C(SafeGetANF)
|
||||
else Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZOA(const s: string): string;
|
||||
// ZZOA: RX1 output level — alias ZZAG
|
||||
@@ -1842,28 +2013,43 @@ begin
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZSO(const s: string): string;
|
||||
// ZZSO: sub-RX on — STUB: no RX2
|
||||
// ZZSO: squelch on/off (расширенный статус шумоподавителя). 0=off, иначе on.
|
||||
begin
|
||||
if Length(s) = 1 then Result := '' else if Length(s) = 0 then Result := '0'
|
||||
if Length(s) = 1 then begin
|
||||
if Assigned(FCtx.SetSquelchOn) then FCtx.SetSquelchOn(s <> '0');
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := B2C(SafeGetSquelchOn)
|
||||
else Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZSP(const s: string): string;
|
||||
// ZZSP: split mode — STUB: split VFO not yet implemented in ewsdr
|
||||
// ZZSP: split mode — 1=TX на VFO-B, 0=TX на VFO-A. TX-частоту радио берёт из
|
||||
// ActiveTXFreqHz (учитывает split), поэтому достаточно выставить флаг.
|
||||
begin
|
||||
if Length(s) = 1 then
|
||||
Result := '' // accepted, ignored — STUB: split VFO requires separate TX freq handling
|
||||
else if Length(s) = 0 then
|
||||
Result := '0'
|
||||
if Length(s) = 1 then begin
|
||||
if Assigned(FCtx.SetSplit) then FCtx.SetSplit(s = '1');
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := B2C(SafeGetSplit)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZSQ(const s: string): string;
|
||||
// ZZSQ: squelch — STUB
|
||||
// ZZSQ: squelch threshold (3 digits, 000–100 %). Уровень>0 включает шумоподавитель,
|
||||
// 000 — открывает (выключает). Маппится на FM-squelch контроллера.
|
||||
var v: Integer;
|
||||
begin
|
||||
if Length(s) = 3 then Result := '' else if Length(s) = 0 then Result := '000'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 3 then begin
|
||||
v := EnsureRange(StrToIntDef(s, 0), 0, 100);
|
||||
if Assigned(FCtx.SetSquelchLevel) then FCtx.SetSquelchLevel(v);
|
||||
if Assigned(FCtx.SetSquelchOn) then FCtx.SetSquelchOn(v > 0);
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := Pad(SafeGetSquelchLevel, 3)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZSR(const s: string): string;
|
||||
@@ -1874,26 +2060,47 @@ begin
|
||||
else Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZST: string;
|
||||
// ZZST: tuning step — STUB: returns 0000 (1 Hz step)
|
||||
begin Result := ''; end;
|
||||
function TCATEngine.ZZST(const s: string): string;
|
||||
// ZZST: FM tuning step index (2 digits): 00=6.25k, 01=12.5k, 02=20k, 03=25k.
|
||||
begin
|
||||
if Length(s) = 2 then begin
|
||||
if Assigned(FCtx.SetFMStep) then FCtx.SetFMStep(EnsureRange(StrToIntDef(s, 0), 0, 3));
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := Pad(EnsureRange(SafeGetFMStep, 0, 3), 2)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZSU: string;
|
||||
// ZZSU: sub-RX update — STUB
|
||||
begin Result := ''; end;
|
||||
// ZZSU: шаг настройки вверх (как колесо мыши) — сдвигает активный VFO вверх.
|
||||
begin
|
||||
if Assigned(FCtx.DoTuneUp) then FCtx.DoTuneUp;
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZTA(const s: string): string;
|
||||
// ZZTA: CTCSS on/off — STUB: FM CTCSS not implemented
|
||||
// ZZTA: CTCSS on/off (1=on, 0=off) для FM-передачи.
|
||||
begin
|
||||
if Length(s) = 1 then Result := '' else if Length(s) = 0 then Result := '0'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 1 then begin
|
||||
if Assigned(FCtx.SetCTCSSOn) then FCtx.SetCTCSSOn(s = '1');
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := B2C(SafeGetCTCSSOn)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZTB(const s: string): string;
|
||||
// ZZTB: CTCSS tone frequency index — STUB
|
||||
// ZZTB: CTCSS tone index (2 digits, 0-based 00..37 в таблице CTCSS_TONES).
|
||||
begin
|
||||
if Length(s) = 2 then Result := '' else if Length(s) = 0 then Result := '01'
|
||||
else Result := CAT_ERROR;
|
||||
if Length(s) = 2 then begin
|
||||
if Assigned(FCtx.SetCTCSSTone) then FCtx.SetCTCSSTone(EnsureRange(StrToIntDef(s, 0), 0, 37));
|
||||
Result := '';
|
||||
end else if Length(s) = 0 then
|
||||
Result := Pad(EnsureRange(SafeGetCTCSSTone, 0, 37), 2)
|
||||
else
|
||||
Result := CAT_ERROR;
|
||||
end;
|
||||
|
||||
function TCATEngine.ZZTX(const s: string): string;
|
||||
|
||||
Reference in New Issue
Block a user