mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
feat(oc): OC Control — Open Collector выходы Penny/Alex (эталон Thetis)
Byte 1401 High Priority packet: per-band (HF 160m-6m) и per-slot (XVTR) RX/TX-маски на 7 пинов + TX pin action (MOX/TUNE/2TON и комбинации). Только openHPSDR — у Pluto/AD936x такого выхода нет, вкладка Settings скрывается на этом бэкенде. Настройки — вкладка "OC Control" в SettingsForm. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+108
@@ -13,6 +13,16 @@ const
|
||||
SETTINGS_FILE = 'hpsdr_settings.json';
|
||||
CFG_BAND_COUNT = 12;
|
||||
CFG_XVTR_COUNT = 8; // количество XVTR-слотов (трансверторов)
|
||||
OC_PIN_COUNT = 7; // количество Open Collector выходов (Penny/Alex)
|
||||
// TX pin action (byte-константы, как TXPinActions в Thetis Penny.cs):
|
||||
// при каком состоянии передачи пин активен.
|
||||
OCA_MOX = 0; // только обычный TX (не TUNE, не 2TON)
|
||||
OCA_TUNE = 1; // только TUNE
|
||||
OCA_TWOTONE = 2; // только 2TON
|
||||
OCA_MOX_TUNE = 3; // TX или TUNE
|
||||
OCA_MOX_TWOTONE = 4; // TX или 2TON
|
||||
OCA_TUNE_TWOTONE = 5; // TUNE или 2TON
|
||||
OCA_MOX_TUNE_TWOTONE = 6; // любое из трёх (дефолт)
|
||||
CFG_MODE_MIN = RadioModes.MODE_MIN;
|
||||
CFG_MODE_MAX = RadioModes.MODE_MAX;
|
||||
CFG_PANS_MAX = 4; // потолок панадаптеров (пан 0 + доп.) — = WDSPEngine.MAX_PANS
|
||||
@@ -341,6 +351,26 @@ type
|
||||
EnableXvtrHf: Boolean; // режим XVTR HF
|
||||
end;
|
||||
|
||||
// OC Control (Open Collector выходы Penny/Alex, byte 1401 HP packet).
|
||||
// Только openHPSDR — у AD936x (Pluto/LibreSDR) такого выхода нет.
|
||||
// Хранятся в JSON-секции "oc" под MAC. Портировано из Thetis
|
||||
// (Console/setup.cs UpdateOCBits + Console/HPSDR/Penny.cs), объём сокращён:
|
||||
// без PA-override/hot-switching внешнего PA (в EWSDR нет такой концепции
|
||||
// на панели) и без split-pins VFO A/B (у EWSDR мультислайсы).
|
||||
// HF-группа — 11 диапазонов (0=160m..10=6m, как в TAlexSettings).
|
||||
// VHF-группа — 8 слотов XVTR (аналог Thetis VHF0-13, но по нашим слотам).
|
||||
TOCPinActions = array[0..OC_PIN_COUNT-1] of Byte; // OCA_* на пин
|
||||
|
||||
TOCSettings = record
|
||||
Enabled: Boolean;
|
||||
RxMaskHF: array[0..CFG_BAND_COUNT-1] of Byte; // 7-бит маска, биты 0..6 = пины 1..7
|
||||
TxMaskHF: array[0..CFG_BAND_COUNT-1] of Byte;
|
||||
ActionHF: TOCPinActions; // для HF TX-маски
|
||||
RxMaskXvtr: array[0..CFG_XVTR_COUNT-1] of Byte;
|
||||
TxMaskXvtr: array[0..CFG_XVTR_COUNT-1] of Byte;
|
||||
ActionXvtr: TOCPinActions; // для XVTR TX-маски
|
||||
end;
|
||||
|
||||
// Калибровки (вкладка Calibration): детектор мощности/КСВ Alex-моста,
|
||||
// напряжение/ток питания, S-метр. Модель детектора задаёт константы моста
|
||||
// (Vref/bridge_volt/ADC-offset, как в Thetis computeAlexFwdPower).
|
||||
@@ -526,6 +556,10 @@ type
|
||||
class procedure DefaultAlex(out A: TAlexSettings);
|
||||
function LoadAlex(const MAC: array of Byte; out A: TAlexSettings): Boolean;
|
||||
procedure SaveAlex(const MAC: array of Byte; const A: TAlexSettings);
|
||||
// OC Control settings per-device (JSON-секция "oc" под MAC).
|
||||
class procedure DefaultOC(out O: TOCSettings);
|
||||
function LoadOC(const MAC: array of Byte; out O: TOCSettings): Boolean;
|
||||
procedure SaveOC(const MAC: array of Byte; const O: TOCSettings);
|
||||
// XVTR (Transverter) settings per-device (JSON-секция "xvtr" под MAC).
|
||||
class procedure DefaultXvtr(out X: TXvtrSettings);
|
||||
function LoadXvtr(const MAC: array of Byte; out X: TXvtrSettings): Boolean;
|
||||
@@ -1567,6 +1601,80 @@ begin
|
||||
A.EnableXvtrHf := JB(O, 'enable_xvtr_hf', False);
|
||||
end;
|
||||
|
||||
class procedure TSettingsManager.DefaultOC(out O: TOCSettings);
|
||||
var i: Integer;
|
||||
begin
|
||||
FillChar(O, SizeOf(O), 0);
|
||||
O.Enabled := False;
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
O.RxMaskHF[i] := 0;
|
||||
O.TxMaskHF[i] := 0;
|
||||
end;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
begin
|
||||
O.RxMaskXvtr[i] := 0;
|
||||
O.TxMaskXvtr[i] := 0;
|
||||
end;
|
||||
for i := 0 to OC_PIN_COUNT - 1 do
|
||||
begin
|
||||
O.ActionHF[i] := OCA_MOX_TUNE_TWOTONE;
|
||||
O.ActionXvtr[i] := OCA_MOX_TUNE_TWOTONE;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TSettingsManager.LoadOC(const MAC: array of Byte;
|
||||
out O: TOCSettings): Boolean;
|
||||
var MacStr: string; DevObj, Obj: TJSONObject; i: Integer;
|
||||
begin
|
||||
DefaultOC(O);
|
||||
MacStr := MacToStr(MAC);
|
||||
Result := FRoot.Find(MacStr) <> nil;
|
||||
if not Result then Exit;
|
||||
DevObj := GetDevObj(MacStr);
|
||||
if DevObj.Find('oc') = nil then begin Result := False; Exit; end;
|
||||
Obj := EnsureObj(DevObj, 'oc');
|
||||
O.Enabled := JB(Obj, 'enabled', False);
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
O.RxMaskHF[i] := EnsureRange(JI(Obj, 'rx_hf_' + IntToStr(i), 0), 0, 127);
|
||||
O.TxMaskHF[i] := EnsureRange(JI(Obj, 'tx_hf_' + IntToStr(i), 0), 0, 127);
|
||||
end;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
begin
|
||||
O.RxMaskXvtr[i] := EnsureRange(JI(Obj, 'rx_xvtr_' + IntToStr(i), 0), 0, 127);
|
||||
O.TxMaskXvtr[i] := EnsureRange(JI(Obj, 'tx_xvtr_' + IntToStr(i), 0), 0, 127);
|
||||
end;
|
||||
for i := 0 to OC_PIN_COUNT - 1 do
|
||||
begin
|
||||
O.ActionHF[i] := EnsureRange(JI(Obj, 'action_hf_' + IntToStr(i), OCA_MOX_TUNE_TWOTONE), 0, 6);
|
||||
O.ActionXvtr[i] := EnsureRange(JI(Obj, 'action_xvtr_' + IntToStr(i), OCA_MOX_TUNE_TWOTONE), 0, 6);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TSettingsManager.SaveOC(const MAC: array of Byte;
|
||||
const O: TOCSettings);
|
||||
var Obj: TJSONObject; i: Integer;
|
||||
begin
|
||||
Obj := EnsureObj(GetDevObj(MacToStr(MAC)), 'oc');
|
||||
JW(Obj, 'enabled', O.Enabled);
|
||||
for i := 0 to CFG_BAND_COUNT - 1 do
|
||||
begin
|
||||
JW(Obj, 'rx_hf_' + IntToStr(i), Integer(O.RxMaskHF[i]));
|
||||
JW(Obj, 'tx_hf_' + IntToStr(i), Integer(O.TxMaskHF[i]));
|
||||
end;
|
||||
for i := 0 to CFG_XVTR_COUNT - 1 do
|
||||
begin
|
||||
JW(Obj, 'rx_xvtr_' + IntToStr(i), Integer(O.RxMaskXvtr[i]));
|
||||
JW(Obj, 'tx_xvtr_' + IntToStr(i), Integer(O.TxMaskXvtr[i]));
|
||||
end;
|
||||
for i := 0 to OC_PIN_COUNT - 1 do
|
||||
begin
|
||||
JW(Obj, 'action_hf_' + IntToStr(i), Integer(O.ActionHF[i]));
|
||||
JW(Obj, 'action_xvtr_' + IntToStr(i), Integer(O.ActionXvtr[i]));
|
||||
end;
|
||||
end;
|
||||
|
||||
class procedure TSettingsManager.DefaultAnt936x(out A: TAD936xAnt);
|
||||
var i: Integer;
|
||||
begin
|
||||
|
||||
Reference in New Issue
Block a user