From d8050576a9991143dbe26c368080cadc077b4c27 Mon Sep 17 00:00:00 2001 From: Uladzimir Karpenka Date: Tue, 19 May 2026 12:29:45 +0300 Subject: [PATCH] Add supply current display for Orion MkII (Board 5) UserADC1 (bytes 55-56) carries current sensor data on the ANAN-8000DLE. Formula from Thetis: amps = ((adc/4095 * 5000) - 360) / 120 (Voff=360mV, Sens=120mV/A). Status bar now shows "Supply: 13.8V / 2.3A | PLL OK" when current is available. Co-Authored-By: Claude Sonnet 4.6 --- HPSDRProtocol.pas | 17 ++++++++++++++++ MainForm.pas | 50 +++++++++++++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 13 deletions(-) diff --git a/HPSDRProtocol.pas b/HPSDRProtocol.pas index c480085..42a92d1 100644 --- a/HPSDRProtocol.pas +++ b/HPSDRProtocol.pas @@ -392,6 +392,10 @@ function PhaseWordToFreq(PhaseWord: LongWord): Double; // Returns -1.0 if the board has no supply voltage measurement. function ADCToSupplyVolts(RawADC: Word; BoardType: Integer): Double; +// Convert raw ADC value to supply current in Amps (Board 5 / Orion MkII only) +// Uses UserADC1 (bytes 55-56). Returns -1 for unsupported boards. +function ADCToSupplyCurrent(RawADC: Word; BoardType: Integer): Double; + // Convert raw ADC value to RF power in Watts (ANAN-100) function ADCToWatts100(RawADC: Word): Double; @@ -454,6 +458,19 @@ begin end; end; +function ADCToSupplyCurrent(RawADC: Word; BoardType: Integer): Double; +begin + // Board 5 (Orion MkII): UserADC1, Vref=5V → mV = adc/4095*5000. + // Current sensor: Voff=360mV, Sens=120mV/A (Thetis defaults, ACS712-style). + // Formula: amps = (mV - Voff) / Sens. + if BoardType = 5 then + begin + Result := ((RawADC / 4095.0) * 5000.0 - 360.0) / 120.0; + if Result < 0.0 then Result := 0.0; + end else + Result := -1.0; +end; + function ADCToWatts100(RawADC: Word): Double; var V: Double; diff --git a/MainForm.pas b/MainForm.pas index bd360af..d55ccd4 100644 --- a/MainForm.pas +++ b/MainForm.pas @@ -148,10 +148,11 @@ type FFwdW: Double; FSWRV: Double; FSupplyV: Double; + FSupplyA: Double; FPLLLock: Boolean; FHWPTT: Boolean; public - constructor Create(AForm: TObject; FW, SW, SV: Double; PLL, HWPTT: Boolean); + constructor Create(AForm: TObject; FW, SW, SV, SA: Double; PLL, HWPTT: Boolean); procedure Execute; end; @@ -244,6 +245,7 @@ type // Эти значения приходят с HP Status пакетами (50..200 раз/с). UI обновляется // из MeterTimerTick (10 Гц), чтобы цифры/полоски не дёргались. FLastSupplyV: Double; + FLastSupplyA: Double; FLastPLLLock: Boolean; // ---- Spectrum / Waterfall view ---- @@ -460,7 +462,7 @@ type // Public UI update (called from sync objects) procedure DoAddDevice(const Dev: THPSDRDevice; const Entry: string); - procedure DoUpdateStatus(FwdW, SWRV, SupplyV: Double; PLLLock, HWPTT: Boolean); + procedure DoUpdateStatus(FwdW, SWRV, SupplyV, SupplyA: Double; PLLLock, HWPTT: Boolean); procedure UpdateTXMeters; procedure DoUpdateDDCSeq(DDCIdx: Integer; Seq: LongWord); procedure DoUpdateDDCSeqOrNoDevice(DDCIdx: Integer; Seq: LongWord); @@ -869,20 +871,21 @@ begin end; constructor TStatusUISync.Create(AForm: TObject; - FW, SW, SV: Double; PLL, HWPTT: Boolean); + FW, SW, SV, SA: Double; PLL, HWPTT: Boolean); begin inherited Create; FForm := AForm; FFwdW := FW; FSWRV := SW; FSupplyV := SV; + FSupplyA := SA; FPLLLock := PLL; FHWPTT := HWPTT; end; procedure TStatusUISync.Execute; begin - TMainForm(FForm).DoUpdateStatus(FFwdW, FSWRV, FSupplyV, FPLLLock, FHWPTT); + TMainForm(FForm).DoUpdateStatus(FFwdW, FSWRV, FSupplyV, FSupplyA, FPLLLock, FHWPTT); end; constructor TDDCSeqSync.Create(AForm: TObject; Idx: Integer; Seq: LongWord); @@ -1298,6 +1301,7 @@ begin FLastFwdW := 0; FLastSWR := 1; FLastSupplyV:= -1; + FLastSupplyA:= -1; FLastPLLLock:= False; FDeviceCount := 0; FDeviceDialog := TDeviceDialog.Create(Self); @@ -3088,7 +3092,7 @@ const SWR_CAP = 9.9; var ExcPwr, FwdPwr, RevPwr: Word; - SupplyV, FwdW, SWRV, Rho: Double; + SupplyV, SupplyA, FwdW, SWRV, Rho: Double; IsTx: Boolean; Sync: TStatusUISync; M: TThreadMethod; @@ -3096,16 +3100,23 @@ begin ExcPwr := (Status.ExciterPwr0Hi shl 8) or Status.ExciterPwr0Lo; FwdPwr := (Status.FwdPwrAlex0Hi shl 8) or Status.FwdPwrAlex0Lo; RevPwr := (Status.RevPwrAlex0Hi shl 8) or Status.RevPwrAlex0Lo; - // Board 5 (Orion MkII) measures supply voltage via UserADC0 (bytes 57-58), - // not the supply_volts field (bytes 49-50) — matching Thetis behaviour. + // Board 5 (Orion MkII): voltage on UserADC0 (bytes 57-58), + // current on UserADC1 (bytes 55-56) — matching Thetis behaviour. if FNetwork.Device.BoardType = 5 then + begin SupplyV := ADCToSupplyVolts( (Status.UserADC0Hi shl 8) or Status.UserADC0Lo, - FNetwork.Device.BoardType) - else + FNetwork.Device.BoardType); + SupplyA := ADCToSupplyCurrent( + (Status.UserADC1Hi shl 8) or Status.UserADC1Lo, + FNetwork.Device.BoardType); + end else + begin SupplyV := ADCToSupplyVolts( (Status.SupplyVoltsHi shl 8) or Status.SupplyVoltsLo, FNetwork.Device.BoardType); + SupplyA := -1.0; + end; // FLastSMeter обновляется только из WDSP (GetSMeterDBm) в SpectrumTimerTick — // ExciterPwr это мощность TX, не уровень принятого сигнала. FwdW := ADCToWatts100(FwdPwr); @@ -3132,7 +3143,7 @@ begin end else SWRV := 1.0; if not IsTx then FwdW := 0; - Sync := TStatusUISync.Create(Self, FwdW, SWRV, SupplyV, + Sync := TStatusUISync.Create(Self, FwdW, SWRV, SupplyV, SupplyA, (Status.StatusBits and HPS_PLL_LOCKED) <> 0, (Status.StatusBits and HPS_PTT) <> 0); try @@ -3143,7 +3154,7 @@ begin end; end; -procedure TMainForm.DoUpdateStatus(FwdW, SWRV, SupplyV: Double; PLLLock, HWPTT: Boolean); +procedure TMainForm.DoUpdateStatus(FwdW, SWRV, SupplyV, SupplyA: Double; PLLLock, HWPTT: Boolean); const // Thetis/piHPSDR PEP-style баллистика для FwdW и SWR: атака мгновенная // (peak-hold), спад медленный — стрелка «висит» на пике и плавно опускается. @@ -3177,6 +3188,13 @@ begin else FLastSupplyV := ALPHA_SUPPLY * SupplyV + (1.0 - ALPHA_SUPPLY) * FLastSupplyV; end; + if SupplyA >= 0 then + begin + if FLastSupplyA < 0 then + FLastSupplyA := SupplyA + else + FLastSupplyA := ALPHA_SUPPLY * SupplyA + (1.0 - ALPHA_SUPPLY) * FLastSupplyA; + end; FLastPLLLock := PLLLock; // Hardware PTT (foot switch / mic PTT) — обнаружение фронта (нужно делать @@ -3200,8 +3218,14 @@ var begin if FLastPLLLock then PLLStr := 'PLL OK' else PLLStr := 'PLL?'; if FLastSupplyV >= 0 then - StatusBar1.Panels[2].Text := Format('Supply: %.1fV | %s', [FLastSupplyV, PLLStr]) - else + begin + if FLastSupplyA >= 0 then + StatusBar1.Panels[2].Text := + Format('Supply: %.1fV / %.1fA | %s', [FLastSupplyV, FLastSupplyA, PLLStr]) + else + StatusBar1.Panels[2].Text := + Format('Supply: %.1fV | %s', [FLastSupplyV, PLLStr]); + end else StatusBar1.Panels[2].Text := PLLStr; end;