mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(cat): align Andromeda panel mapping with real G2 hardware (Thetis)
Button/encoder indices follow Thetis MakeNewAndromedaDataset (our 0-based index = Thetis Number - 1), verified against andromeda_test/AndDecode.pas. The old map assumed sequential 0,1,2.. and truncated at 32; the real panel sends sparse indices up to 47. - AndromedaMap: AND_MAX_BUTTONS 32->48, renumbered button/encoder tables; new actions abVFOAtoB/abVFOBtoA/abVFOLock/abStartStop/abShift. - RadioController: VFO Lock (FVfoLock, rfVfoLock, SetVfoLock, gate in TuneActiveBy). - AndromedaPanel: wire A>B/B>A/SDR-ON/Lock; Shift band-keypad layer (#28 latch, #29..39 -> SetBand 160m..6m, non-sticky); aiVFOLock/aiShift indicators. - Filter High/Low (#4/#5) left as width approximation per decision. - doc/ANDROMEDA.md updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+75
-31
@@ -24,7 +24,12 @@ type
|
|||||||
TAndButton = (
|
TAndButton = (
|
||||||
abNone, abMOX, abTune, abBandUp, abBandDown, abModeUp, abModeDown,
|
abNone, abMOX, abTune, abBandUp, abBandDown, abModeUp, abModeDown,
|
||||||
abMute, abNB, abNR, abSNB, abANF, abVFOSplit, abVFOSwap, abCTUN,
|
abMute, abNB, abNR, abSNB, abANF, abVFOSplit, abVFOSwap, abCTUN,
|
||||||
abCTCSS, abSquelch, abFilterUp, abFilterDown);
|
abCTCSS, abSquelch, abFilterUp, abFilterDown,
|
||||||
|
abVFOAtoB, // копировать VFO A → B (Thetis eBBVFOAtoB)
|
||||||
|
abVFOBtoA, // копировать VFO B → A (Thetis eBBVFOBtoA)
|
||||||
|
abVFOLock, // блокировка перестройки VFO (Thetis eBBVFOLockOnOff)
|
||||||
|
abStartStop, // старт/стоп SDR (Thetis eBBStartStop)
|
||||||
|
abShift); // модификатор band-keypad (Thetis eBBShift) — обрабатывается в панели
|
||||||
|
|
||||||
// Параметр, управляемый поворотным энкодером панели.
|
// Параметр, управляемый поворотным энкодером панели.
|
||||||
TAndEncoder = (
|
TAndEncoder = (
|
||||||
@@ -39,43 +44,82 @@ type
|
|||||||
|
|
||||||
const
|
const
|
||||||
// Размеры дефолтных таблиц (кнопки/энкодеры нумеруются с 0 после разбора ZZZP/ZZZE).
|
// Размеры дефолтных таблиц (кнопки/энкодеры нумеруются с 0 после разбора ZZZP/ZZZE).
|
||||||
AND_MAX_BUTTONS = 32;
|
AND_MAX_BUTTONS = 48;
|
||||||
AND_MAX_ENCODERS = 20;
|
AND_MAX_ENCODERS = 20;
|
||||||
|
|
||||||
// Раскладка кнопок: индекс = номер кнопки (0-based), значение = действие.
|
// Раскладка кнопок: индекс = номер кнопки (0-based), значение = действие.
|
||||||
// Неназначенные → abNone. Дефолт ewsdr (правится при появлении конкретной панели).
|
// Нумерация совпадает с дефолтом Thetis (MakeNewAndromedaDataset): наш 0-based
|
||||||
|
// индекс = «Pushbutton Number» Thetis − 1. Проверено на реальной панели
|
||||||
|
// (см. andromeda_test/AndDecode.pas). Неназначенные / отсутствующий тракт → abNone.
|
||||||
AND_BUTTON_MAP: array[0..AND_MAX_BUTTONS-1] of TAndButton = (
|
AND_BUTTON_MAP: array[0..AND_MAX_BUTTONS-1] of TAndButton = (
|
||||||
abMOX, // 0
|
abMute, // 0 RX1 Mute
|
||||||
abTune, // 1
|
abNone, // 1
|
||||||
abBandUp, // 2
|
abNone, // 2 RX2 Mute — нет второго приёмника
|
||||||
abBandDown, // 3
|
abNone, // 3
|
||||||
abModeUp, // 4
|
abNone, // 4
|
||||||
abModeDown, // 5
|
abNone, // 5
|
||||||
abNB, // 6
|
abNone, // 6
|
||||||
abNR, // 7
|
abNone, // 7
|
||||||
abANF, // 8
|
abNone, // 8
|
||||||
abSNB, // 9
|
abNone, // 9
|
||||||
abVFOSplit, // 10
|
abNone, // 10
|
||||||
abVFOSwap, // 11
|
abNone, // 11
|
||||||
abCTUN, // 12
|
abNone, // 12
|
||||||
abMute, // 13
|
abNone, // 13
|
||||||
abCTCSS, // 14
|
abNone, // 14
|
||||||
abSquelch, // 15
|
abNone, // 15
|
||||||
abFilterUp, // 16
|
abNone, // 16
|
||||||
abFilterDown, // 17
|
abNone, // 17
|
||||||
abNone, abNone, abNone, abNone, abNone, abNone, abNone, abNone,
|
abNone, // 18
|
||||||
abNone, abNone, abNone, abNone, abNone, abNone);
|
abNone, // 19
|
||||||
|
abNone, // 20
|
||||||
|
abNone, // 21
|
||||||
|
abNone, // 22
|
||||||
|
abNone, // 23
|
||||||
|
abNone, // 24
|
||||||
|
abNone, // 25
|
||||||
|
abNone, // 26
|
||||||
|
abNone, // 27
|
||||||
|
abShift, // 28 Shift (band-keypad модификатор)
|
||||||
|
abBandUp, // 29 Band + (под shift → 160m)
|
||||||
|
abModeUp, // 30 Mode + (под shift → 80m)
|
||||||
|
abFilterUp, // 31 Filter + (под shift → 60m)
|
||||||
|
abBandDown, // 32 Band - (под shift → 40m)
|
||||||
|
abModeDown, // 33 Mode - (под shift → 30m)
|
||||||
|
abFilterDown, // 34 Filter - (под shift → 20m)
|
||||||
|
abVFOAtoB, // 35 A>B (под shift → 17m)
|
||||||
|
abVFOBtoA, // 36 B>A (под shift → 15m)
|
||||||
|
abVFOSplit, // 37 Split (под shift → 12m)
|
||||||
|
abNone, // 38 (под shift → 10m)
|
||||||
|
abNone, // 39 (под shift → 6m)
|
||||||
|
abNone, // 40 (под shift → GEN, нет в ewsdr)
|
||||||
|
abNone, // 41 RIT/XIT toggle — нет RIT/XIT
|
||||||
|
abVFOSwap, // 42 Toggle A/B
|
||||||
|
abVFOLock, // 43 VFO Lock
|
||||||
|
abCTUN, // 44 CTUNE
|
||||||
|
abStartStop, // 45 SDR ON (start/stop)
|
||||||
|
abMOX, // 46 MOX
|
||||||
|
abTune); // 47 TUN
|
||||||
|
|
||||||
// Раскладка энкодеров: индекс = номер энкодера (0-based), значение = параметр.
|
// Раскладка энкодеров: индекс = номер энкодера (0-based), значение = параметр.
|
||||||
|
// Нумерация = «Encoder Number» Thetis − 1 (дефолт MakeNewAndromedaDataset).
|
||||||
|
// Энкодер #1 в Thetis — AGC Level (слайдер RF), поэтому aeAGCLevel.
|
||||||
|
// #4/#5 на панели — Filter High/Low (независимые края), но в ewsdr фильтр
|
||||||
|
// только симметричный (SetFilterBW): #4 крутит ширину, #5 пока не задействован.
|
||||||
AND_ENCODER_MAP: array[0..AND_MAX_ENCODERS-1] of TAndEncoder = (
|
AND_ENCODER_MAP: array[0..AND_MAX_ENCODERS-1] of TAndEncoder = (
|
||||||
aeAFGain, // 0
|
aeAFGain, // 0 RX1 AF Gain
|
||||||
aeAGCLevel, // 1
|
aeAGCLevel, // 1 RX1 AGC Level (Thetis «RF»)
|
||||||
aeDrive, // 2
|
aeNone, // 2 RX2 AF — нет второго приёмника
|
||||||
aeSquelch, // 3
|
aeNone, // 3 RX2 AGC
|
||||||
aeFilterWidth, // 4
|
aeFilterWidth, // 4 Filter High → ширина фильтра (краёв нет)
|
||||||
aeNone, aeNone, aeNone, aeNone, aeNone,
|
aeNone, // 5 Filter Low — не реализован
|
||||||
aeNone, aeNone, aeNone, aeNone, aeNone,
|
aeNone, // 6 Diversity gain
|
||||||
aeNone, aeNone, aeNone, aeNone, aeMulti);
|
aeNone, // 7 Diversity phase
|
||||||
|
aeNone, // 8 RIT
|
||||||
|
aeNone, // 9 XIT
|
||||||
|
aeMulti, // 10 Multifunction
|
||||||
|
aeDrive, // 11 TX Drive
|
||||||
|
aeNone, aeNone, aeNone, aeNone, aeNone, aeNone, aeNone, aeNone);
|
||||||
|
|
||||||
// Номер LED (ZZZI nn) для каждого индикатора; 0 = панель этот индикатор не имеет.
|
// Номер LED (ZZZI nn) для каждого индикатора; 0 = панель этот индикатор не имеет.
|
||||||
// 1..11 — дефолт Thetis; 12..17 — функции ewsdr на свободных слотах.
|
// 1..11 — дефолт Thetis; 12..17 — функции ewsdr на свободных слотах.
|
||||||
|
|||||||
@@ -39,16 +39,20 @@ type
|
|||||||
FController: TRadioController;
|
FController: TRadioController;
|
||||||
FSend: TAndromedaSend;
|
FSend: TAndromedaSend;
|
||||||
FConnected: Boolean; // панель прислала версию (ZZZS)
|
FConnected: Boolean; // панель прислала версию (ZZZS)
|
||||||
|
FShiftActive: Boolean; // band-keypad модификатор (latched)
|
||||||
FIndState: array[0..20] of Integer; // кэш состояний LED: -1 неизв., 0/1
|
FIndState: array[0..20] of Integer; // кэш состояний LED: -1 неизв., 0/1
|
||||||
// scratch для маршалинга в поток контроллера
|
// scratch для маршалинга в поток контроллера
|
||||||
FPendingVfoSteps: Integer;
|
FPendingVfoSteps: Integer;
|
||||||
FPendingEnc: TAndEncoder;
|
FPendingEnc: TAndEncoder;
|
||||||
FPendingStep: Integer;
|
FPendingStep: Integer;
|
||||||
FPendingButton: TAndButton;
|
FPendingButton: TAndButton;
|
||||||
|
FPendingBand: Integer;
|
||||||
|
|
||||||
procedure SyncVfo;
|
procedure SyncVfo;
|
||||||
procedure SyncEncoder;
|
procedure SyncEncoder;
|
||||||
procedure SyncButton;
|
procedure SyncButton;
|
||||||
|
procedure SyncBand;
|
||||||
|
procedure SyncShiftLed;
|
||||||
|
|
||||||
procedure PushIndicator(Ind: TAndIndicator; State: Boolean);
|
procedure PushIndicator(Ind: TAndIndicator; State: Boolean);
|
||||||
procedure SendIndicatorNum(Num: Integer; State: Boolean);
|
procedure SendIndicatorNum(Num: Integer; State: Boolean);
|
||||||
@@ -126,15 +130,49 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAndromedaPanel.HandleButton(Btn: Integer; State, LongPress: Boolean);
|
procedure TAndromedaPanel.HandleButton(Btn: Integer; State, LongPress: Boolean);
|
||||||
|
// Раскладка зеркалит Thetis: кнопка Shift (0-based 28) — модификатор-защёлка;
|
||||||
|
// пока он активен, кнопки band-группы (29..40) выбирают диапазон напрямую
|
||||||
|
// (29→160m … 39→6m; 40=GEN в ewsdr нет). Остальные кнопки работают всегда,
|
||||||
|
// shift при их нажатии не снимается (non-sticky: снимается только band-нажатием).
|
||||||
var a: TAndButton;
|
var a: TAndButton;
|
||||||
begin
|
begin
|
||||||
if not State then Exit; // реагируем на нажатие; отпускание/long-press — позже
|
if not State then Exit; // реагируем на нажатие; отпускание/long-press — позже
|
||||||
a := ButtonAction(Btn);
|
a := ButtonAction(Btn);
|
||||||
|
|
||||||
|
if a = abShift then // toggle band-keypad
|
||||||
|
begin
|
||||||
|
FShiftActive := not FShiftActive;
|
||||||
|
FController.Invoke(@SyncShiftLed);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if FShiftActive and (Btn >= 29) and (Btn <= 40) then // band-keypad
|
||||||
|
begin
|
||||||
|
if (Btn >= 29) and (Btn <= 39) then // 160m..6m → SetBand 0..10
|
||||||
|
begin
|
||||||
|
FPendingBand := Btn - 29;
|
||||||
|
FController.Invoke(@SyncBand);
|
||||||
|
end;
|
||||||
|
FShiftActive := False; // non-sticky: снять shift
|
||||||
|
FController.Invoke(@SyncShiftLed);
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
if a = abNone then Exit;
|
if a = abNone then Exit;
|
||||||
FPendingButton := a;
|
FPendingButton := a;
|
||||||
FController.Invoke(@SyncButton);
|
FController.Invoke(@SyncButton);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TAndromedaPanel.SyncBand;
|
||||||
|
begin
|
||||||
|
FController.SetBand(FPendingBand);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TAndromedaPanel.SyncShiftLed;
|
||||||
|
begin
|
||||||
|
PushIndicator(aiShift, FShiftActive);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TAndromedaPanel.SyncButton;
|
procedure TAndromedaPanel.SyncButton;
|
||||||
begin
|
begin
|
||||||
case FPendingButton of
|
case FPendingButton of
|
||||||
@@ -151,6 +189,10 @@ begin
|
|||||||
abANF: FController.SetANF(not FController.FANF);
|
abANF: FController.SetANF(not FController.FANF);
|
||||||
abVFOSplit: FController.SetSplit(not FController.FSplitTxB);
|
abVFOSplit: FController.SetSplit(not FController.FSplitTxB);
|
||||||
abVFOSwap: FController.SetActiveVfo(1 - FController.FActiveVfo);
|
abVFOSwap: FController.SetActiveVfo(1 - FController.FActiveVfo);
|
||||||
|
abVFOAtoB: FController.VfoACopyB;
|
||||||
|
abVFOBtoA: FController.VfoBCopyA;
|
||||||
|
abVFOLock: FController.SetVfoLock(not FController.FVfoLock);
|
||||||
|
abStartStop: FController.StartStop;
|
||||||
abCTUN: FController.SetCTun(not FController.FCTun);
|
abCTUN: FController.SetCTun(not FController.FCTun);
|
||||||
abCTCSS: FController.SetFMCTCSS(not FController.FFMCTCSSOn);
|
abCTCSS: FController.SetFMCTCSS(not FController.FFMCTCSSOn);
|
||||||
abSquelch: FController.SetFMSquelch(not FController.FFMSQOn);
|
abSquelch: FController.SetFMSquelch(not FController.FFMSQOn);
|
||||||
@@ -191,6 +233,8 @@ begin
|
|||||||
PushIndicator(aiTune, FController.FTuning);
|
PushIndicator(aiTune, FController.FTuning);
|
||||||
PushIndicator(aiCTune, FController.FCTun);
|
PushIndicator(aiCTune, FController.FCTun);
|
||||||
PushIndicator(aiVFOAB, FController.FActiveVfo = 1);
|
PushIndicator(aiVFOAB, FController.FActiveVfo = 1);
|
||||||
|
PushIndicator(aiVFOLock, FController.FVfoLock);
|
||||||
|
PushIndicator(aiShift, FShiftActive);
|
||||||
PushIndicator(aiSplit, FController.FSplitTxB);
|
PushIndicator(aiSplit, FController.FSplitTxB);
|
||||||
PushIndicator(aiNB, FController.FNBMode > 0);
|
PushIndicator(aiNB, FController.FNBMode > 0);
|
||||||
PushIndicator(aiNR, FController.FNRMode > 0);
|
PushIndicator(aiNR, FController.FNRMode > 0);
|
||||||
@@ -206,6 +250,7 @@ begin
|
|||||||
rfTransmitting: PushIndicator(aiMOX, FController.FTransmitting);
|
rfTransmitting: PushIndicator(aiMOX, FController.FTransmitting);
|
||||||
rfTuning: PushIndicator(aiTune, FController.FTuning);
|
rfTuning: PushIndicator(aiTune, FController.FTuning);
|
||||||
rfCTun: PushIndicator(aiCTune, FController.FCTun);
|
rfCTun: PushIndicator(aiCTune, FController.FCTun);
|
||||||
|
rfVfoLock: PushIndicator(aiVFOLock, FController.FVfoLock);
|
||||||
rfActiveVfo: begin
|
rfActiveVfo: begin
|
||||||
PushIndicator(aiVFOAB, FController.FActiveVfo = 1);
|
PushIndicator(aiVFOAB, FController.FActiveVfo = 1);
|
||||||
PushIndicator(aiSplit, FController.FSplitTxB);
|
PushIndicator(aiSplit, FController.FSplitTxB);
|
||||||
|
|||||||
+13
-1
@@ -60,7 +60,7 @@ type
|
|||||||
|
|
||||||
// Поле, которое изменилось — для гранулярных уведомлений наружу.
|
// Поле, которое изменилось — для гранулярных уведомлений наружу.
|
||||||
TRadioField = (
|
TRadioField = (
|
||||||
rfVfoA, rfVfoB, rfActiveVfo,
|
rfVfoA, rfVfoB, rfActiveVfo, rfVfoLock,
|
||||||
rfMode, rfFilter, rfFilterBW,
|
rfMode, rfFilter, rfFilterBW,
|
||||||
rfAGCMode, rfAGCTop,
|
rfAGCMode, rfAGCTop,
|
||||||
rfRxGain, // Pluto: hw-gain (auto/manual dB)
|
rfRxGain, // Pluto: hw-gain (auto/manual dB)
|
||||||
@@ -217,6 +217,7 @@ type
|
|||||||
FTransmitting: Boolean;
|
FTransmitting: Boolean;
|
||||||
FTuning: Boolean;
|
FTuning: Boolean;
|
||||||
FSplitTxB: Boolean;
|
FSplitTxB: Boolean;
|
||||||
|
FVfoLock: Boolean; // блокировка перестройки VFO (Andromeda Lock)
|
||||||
FDisplayDuplex: Boolean;
|
FDisplayDuplex: Boolean;
|
||||||
// QO-100 full-duplex self-monitor: True — RX-аудио глушится на TX (по умолч.),
|
// QO-100 full-duplex self-monitor: True — RX-аудио глушится на TX (по умолч.),
|
||||||
// False — слышим свой downlink со спутника при передаче. Кнопка RX MUTE.
|
// False — слышим свой downlink со спутника при передаче. Кнопка RX MUTE.
|
||||||
@@ -515,6 +516,7 @@ type
|
|||||||
procedure SetMOX(On_: Boolean);
|
procedure SetMOX(On_: Boolean);
|
||||||
procedure SetTune(On_: Boolean); // TUN
|
procedure SetTune(On_: Boolean); // TUN
|
||||||
procedure SetSplit(TxOnB: Boolean); // split: TX на VFO-B (иначе VFO-A)
|
procedure SetSplit(TxOnB: Boolean); // split: TX на VFO-B (иначе VFO-A)
|
||||||
|
procedure SetVfoLock(On_: Boolean); // блокировка перестройки VFO
|
||||||
|
|
||||||
// FM
|
// FM
|
||||||
procedure SetFMStep(Idx: Integer);
|
procedure SetFMStep(Idx: Integer);
|
||||||
@@ -1899,6 +1901,7 @@ end;
|
|||||||
|
|
||||||
procedure TRadioController.TuneActiveBy(DeltaHz: Double);
|
procedure TRadioController.TuneActiveBy(DeltaHz: Double);
|
||||||
begin
|
begin
|
||||||
|
if FVfoLock then Exit; // VFO заблокирован — перестройку игнорируем
|
||||||
if FActiveVfo = 0 then SetVfoA(FVfoA + DeltaHz)
|
if FActiveVfo = 0 then SetVfoA(FVfoA + DeltaHz)
|
||||||
else SetVfoB(FVfoB + DeltaHz);
|
else SetVfoB(FVfoB + DeltaHz);
|
||||||
end;
|
end;
|
||||||
@@ -2712,6 +2715,15 @@ begin
|
|||||||
Changed(rfActiveVfo);
|
Changed(rfActiveVfo);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TRadioController.SetVfoLock(On_: Boolean);
|
||||||
|
// VFO Lock: пока включён, относительная перестройка (TuneActiveBy — энкодер VFO
|
||||||
|
// панели, CAT UP/DN) игнорируется. Подсветка — индикатор aiVFOLock (#11).
|
||||||
|
begin
|
||||||
|
if FVfoLock = On_ then Exit;
|
||||||
|
FVfoLock := On_;
|
||||||
|
Changed(rfVfoLock);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TRadioController.SetFMRpt(Dir: Integer);
|
procedure TRadioController.SetFMRpt(Dir: Integer);
|
||||||
begin
|
begin
|
||||||
FFMRptDir := Dir;
|
FFMRptDir := Dir;
|
||||||
|
|||||||
+46
-21
@@ -84,46 +84,66 @@ Andromeda — это **не отдельный набор команд**, а д
|
|||||||
|
|
||||||
## 3. Раскладка по умолчанию (AndromedaMap.pas)
|
## 3. Раскладка по умолчанию (AndromedaMap.pas)
|
||||||
|
|
||||||
Раскладка **зашита в коде** (первая версия). Правится в `AndromedaMap.pas`.
|
Раскладка **зашита в коде** и зеркалит дефолтную таблицу Thetis
|
||||||
|
(`MakeNewAndromedaDataset`): наш 0-based индекс = «Pushbutton/Encoder Number»
|
||||||
|
Thetis − 1. Номера **проверены на реальной панели** (см.
|
||||||
|
`andromeda_test/AndDecode.pas`). Правится в `AndromedaMap.pas`.
|
||||||
|
|
||||||
### Кнопки (`ZZZP`, индекс 0-based после разбора)
|
### Кнопки (`ZZZP`, индекс 0-based после разбора)
|
||||||
| # | Действие | # | Действие |
|
| # | Действие | # | Действие |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 0 | MOX | 9 | SNB |
|
| 0 | RX1 Mute | 35 | A>B (под shift → 17m) |
|
||||||
| 1 | Tune (TUN) | 10 | Split (TX VFO-B) |
|
| 28 | **Shift** (band-keypad) | 36 | B>A (под shift → 15m) |
|
||||||
| 2 | Band Up | 11 | VFO Swap (актив. A/B) |
|
| 29 | Band Up (под shift → 160m) | 37 | Split (под shift → 12m) |
|
||||||
| 3 | Band Down | 12 | CTUN |
|
| 30 | Mode Up (под shift → 80m) | 38 | *(под shift → 10m)* |
|
||||||
| 4 | Mode Up | 13 | Mute |
|
| 31 | Filter Up (под shift → 60m) | 39 | *(под shift → 6m)* |
|
||||||
| 5 | Mode Down | 14 | CTCSS |
|
| 32 | Band Down (под shift → 40m) | 42 | VFO Swap (toggle A/B) |
|
||||||
| 6 | NB | 15 | Squelch on/off |
|
| 33 | Mode Down (под shift → 30m) | 43 | **VFO Lock** |
|
||||||
| 7 | NR | 16 | Filter Up |
|
| 34 | Filter Down (под shift → 20m) | 44 | CTUN |
|
||||||
| 8 | ANF | 17 | Filter Down |
|
| | | 45 | SDR ON (start/stop) |
|
||||||
|
| | | 46 | MOX |
|
||||||
|
| | | 47 | TUN |
|
||||||
|
|
||||||
|
Не назначены (нет тракта в ewsdr): 2 (RX2 Mute), 40 (band GEN), 41 (RIT/XIT).
|
||||||
|
NB/NR/ANF/SNB/CTCSS/Squelch у реальной панели на кнопках не выведены
|
||||||
|
(в Thetis — на тачскрине), действия в enum сохранены для кастомной раскладки.
|
||||||
|
|
||||||
|
### Shift / band-keypad
|
||||||
|
|
||||||
|
Кнопка #28 — модификатор-защёлка (как `eBBShift` в Thetis). Пока активен
|
||||||
|
(LED `aiShift` #6), кнопки band-группы #29..39 выбирают диапазон напрямую
|
||||||
|
(`SetBand` 0..10: 160m…6m); #40 = GEN — в ewsdr отсутствует. Снимается
|
||||||
|
повторным Shift либо автоматически после выбора диапазона (non-sticky).
|
||||||
|
Логика — в `TAndromedaPanel.HandleButton`.
|
||||||
|
|
||||||
### Энкодеры (`ZZZE`, индекс 0-based)
|
### Энкодеры (`ZZZE`, индекс 0-based)
|
||||||
| # | Параметр | Шаг |
|
| # | Параметр | Шаг |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 0 | AF Gain (громкость) | ±1 |
|
| 0 | AF Gain (громкость) | ±1 |
|
||||||
| 1 | AGC-T | ±1 dB |
|
| 1 | AGC-T (в Thetis — слайдер «RF») | ±1 dB |
|
||||||
| 2 | Drive (мощность) | ±1 % |
|
| 4 | Filter High → ширина фильтра | ±50 Гц (`AND_BW_STEP_HZ`) |
|
||||||
| 3 | Squelch level | ±1 |
|
| 11 | Drive (мощность) | ±1 % |
|
||||||
| 4 | Filter width | ±50 Гц (`AND_BW_STEP_HZ`) |
|
|
||||||
| VFO | энкодер VFO (`ZZZU/ZZZD`) | ±10 Гц/шаг (`AND_VFO_STEP_HZ`) |
|
| VFO | энкодер VFO (`ZZZU/ZZZD`) | ±10 Гц/шаг (`AND_VFO_STEP_HZ`) |
|
||||||
|
|
||||||
|
> #4/#5 на панели — независимые края фильтра (Filter High/Low). В ewsdr фильтр
|
||||||
|
> симметричный (`SetFilterBW`), поэтому #4 крутит ширину, #5 пока не задействован.
|
||||||
|
> Энкодеры RX2 AF/AGC (#2/#3), diversity (#6/#7), RIT/XIT (#8/#9) — нет тракта.
|
||||||
|
|
||||||
### Индикаторы (`ZZZI`, номера зеркалят дефолт Thetis)
|
### Индикаторы (`ZZZI`, номера зеркалят дефолт Thetis)
|
||||||
| LED # | Индикатор | LED # | Индикатор |
|
| LED # | Индикатор | LED # | Индикатор |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 1 | MOX | 12 | Split |
|
| 1 | MOX | 12 | Split |
|
||||||
| 2 | ATU Ready *(нет в ewsdr)* | 13 | NB |
|
| 2 | ATU Ready *(нет в ewsdr)* | 13 | NB |
|
||||||
| 3 | Tune | 14 | NR |
|
| 3 | Tune | 14 | NR |
|
||||||
| 6 | Shift *(нет)* | 15 | SNB |
|
| 6 | Shift | 15 | SNB |
|
||||||
| 7 | CTUN | 16 | ANF |
|
| 7 | CTUN | 16 | ANF |
|
||||||
| 8/9 | RIT/XIT *(нет)* | 17 | Squelch |
|
| 8/9 | RIT/XIT *(нет)* | 17 | Squelch |
|
||||||
| 10 | VFO A/B | | |
|
| 10 | VFO A/B | | |
|
||||||
| 11 | VFO Lock *(нет)* | | |
|
| 11 | VFO Lock | | |
|
||||||
|
|
||||||
Драйвятся реально: **MOX, Tune, CTUN, VFO A/B, Split, NB, NR, SNB, ANF, Squelch**.
|
Драйвятся реально: **MOX, Tune, CTUN, VFO A/B, VFO Lock, Shift, Split, NB, NR,
|
||||||
Остальные слоты дефолтной таблицы Thetis (ATU/Shift/RIT/XIT/VFOLock) в ewsdr
|
SNB, ANF, Squelch**. Остальные слоты дефолтной таблицы Thetis (ATU/RIT/XIT)
|
||||||
функций не имеют и не зажигаются.
|
в ewsdr функций не имеют и не зажигаются.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -145,16 +165,21 @@ Andromeda — это **не отдельный набор команд**, а д
|
|||||||
|
|
||||||
## 5. Что сделано / что осталось
|
## 5. Что сделано / что осталось
|
||||||
|
|
||||||
### Сделано (первая версия)
|
### Сделано
|
||||||
- Транспорт: **serial** (USB CAT).
|
- Транспорт: **serial** (USB CAT).
|
||||||
- Вход: `ZZZD/ZZZU` (VFO), `ZZZE` (энкодеры), `ZZZP` (кнопки), `ZZZS` (рукопожатие).
|
- Вход: `ZZZD/ZZZU` (VFO), `ZZZE` (энкодеры), `ZZZP` (кнопки), `ZZZS` (рукопожатие).
|
||||||
- Выход: **`ZZZI`** — LED-индикаторы (push от `OnStateChanged`, дедуп повторов).
|
- Выход: **`ZZZI`** — LED-индикаторы (push от `OnStateChanged`, дедуп повторов).
|
||||||
- Раскладка — зашитый дефолт.
|
- Раскладка — зашитый дефолт, выверена по Thetis и реальной панели.
|
||||||
|
- **Shift / band-keypad** — прямой выбор диапазона (#29..39 → `SetBand`), LED `aiShift`.
|
||||||
|
- **VFO Lock** — блокировка перестройки (`SetVfoLock`, гейт в `TuneActiveBy`), LED `aiVFOLock`.
|
||||||
|
- A>B / B>A / Toggle A/B, SDR ON (start/stop) — на штатных кнопках панели.
|
||||||
- UI-чекбокс на каждый serial-порт + персист.
|
- UI-чекбокс на каждый serial-порт + персист.
|
||||||
|
|
||||||
### Осталось / возможные улучшения
|
### Осталось / возможные улучшения
|
||||||
| Задача | Заметки |
|
| Задача | Заметки |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
| **Filter High/Low (`ZZZE` #4/#5)** | независимые края фильтра; сейчас #4 = ширина, #5 не задействован. Нужны `FFilterLow/High` + переработка `ApplyModeFilter` и passband дисплея (sideband-aware, как в Thetis) |
|
||||||
|
| **Sticky shift** | сейчас shift всегда non-sticky (снимается band-нажатием); в Thetis есть `AndromedaStickyShift` |
|
||||||
| **`ZZMF`** — текст на LCD мультифункц. энкодера | кодировка: 15 ASCII-символов парами цифр (код−32) |
|
| **`ZZMF`** — текст на LCD мультифункц. энкодера | кодировка: 15 ASCII-символов парами цифр (код−32) |
|
||||||
| **TCP-транспорт (G2 V2 panel)** | сейчас только serial; нужен режим в `CATTcp` |
|
| **TCP-транспорт (G2 V2 panel)** | сейчас только serial; нужен режим в `CATTcp` |
|
||||||
| **Настраиваемая раскладка** | сейчас зашита; вынести в конфиг/UI (как `AndromedaEditForm` в Thetis) |
|
| **Настраиваемая раскладка** | сейчас зашита; вынести в конфиг/UI (как `AndromedaEditForm` в Thetis) |
|
||||||
|
|||||||
Reference in New Issue
Block a user