feat: pluto telemetry — show both temperatures (transceiver + Zynq SoC)

Pluto exposes two temperature sensors: the AD9361 transceiver
(ad9361-phy temp0/input, milli-°C) and the Zynq SoC/FPGA (xadc temp0,
raw+offset+scale → C = (raw+offset)*scale/1000). Only the former was
read. Now both are read and shown as "Temp 37/53C" (chip/SoC) in the
desktop status bar and web UI.

- ReadTelemetry gains an out SocTempC param (base + Pluto override);
  Pluto reads xadc via the IIO context.
- Controller stores FLastPlutoSocTempC; SoC temp validated with a
  plausibility window (no slew-limit — stable local sensor, unlike the
  AD9361 sensor that spikes during mid-conversion).
- Status formatting handles one or both temps in MainForm and WebAdapter.
- Widen desktop status-bar field 3 (150→190) so both temps + RSSI fit;
  web layout unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-23 19:10:07 +03:00
co-authored by Claude Opus 4.8
parent 63c8c91152
commit 6375092741
6 changed files with 79 additions and 32 deletions
+36 -12
View File
@@ -128,7 +128,7 @@ type
procedure SetTxAtten(Db: Double); override;
procedure SendDUCIQ(const IData, QData: array of Integer); override;
procedure ClearDUCIQQueue; override;
function ReadTelemetry(out TempC, RSSIdB: Double): Boolean; override;
function ReadTelemetry(out TempC, SocTempC, RSSIdB: Double): Boolean; override;
end;
// Стабильный 6-байтовый ключ (synthetic MAC) из serial/URI — для per-device
@@ -904,19 +904,23 @@ begin
LeaveCriticalSection(FTxLock);
end;
function TPlutoBackend.ReadTelemetry(out TempC, RSSIdB: Double): Boolean;
// Опрос аппаратной телеметрии ad9361-phy (вызывается контроллером, не из RX-потока):
// temp0/input — температура чипа в миллиградусах C (longlong);
// voltage0/rssi — RSSI входного тракта в дБ (double; строка вида '12.34 dB',
// libiio парсит ведущее число). Валиден только во время приёма.
function TPlutoBackend.ReadTelemetry(out TempC, SocTempC, RSSIdB: Double): Boolean;
// Опрос аппаратной телеметрии (вызывается контроллером, не из RX-потока):
// ad9361-phy temp0/input — температура трансивера в миллиградусах C (longlong);
// xadc temp0 — температура Zynq SoC/FPGA; сырой raw + offset (longlong)
// + scale (double), C = (raw + offset) * scale / 1000;
// ad9361-phy voltage0/rssi — RSSI входного тракта в дБ (double; строка '12.34 dB',
// libiio парсит ведущее число). Валиден только во время приёма.
var
Ch: Piio_channel;
raw: clonglong;
d: cdouble;
Ch, ChX: Piio_channel;
XDev: Piio_device;
raw, offs: clonglong;
scale, d: cdouble;
begin
TempC := TELEMETRY_NONE;
RSSIdB := TELEMETRY_NONE;
Result := False;
TempC := TELEMETRY_NONE;
SocTempC := TELEMETRY_NONE;
RSSIdB := TELEMETRY_NONE;
Result := False;
if (not FConnected) or (FPhy = nil) or (not IIOLoaded) then Exit;
Ch := iio_device_find_channel(FPhy, 'temp0', 0);
@@ -926,6 +930,26 @@ begin
Result := True;
end;
// Температура Zynq SoC/FPGA — отдельное IIO-устройство 'xadc' (всегда присутствует).
// Канал отдаёт сырой код + offset + scale (в отличие от ad9361, дающего милли-°C):
// T(°C) = (raw + offset) * scale / 1000.
if FCtx <> nil then
begin
XDev := iio_context_find_device(FCtx, 'xadc');
if XDev <> nil then
begin
ChX := iio_device_find_channel(XDev, 'temp0', 0);
if (ChX <> nil) and Assigned(iio_channel_attr_read_double)
and (iio_channel_attr_read_longlong(ChX, 'raw', raw) = 0)
and (iio_channel_attr_read_longlong(ChX, 'offset', offs) = 0)
and (iio_channel_attr_read_double(ChX, 'scale', scale) = 0) then
begin
SocTempC := (raw + offs) * scale / 1000.0;
Result := True;
end;
end;
end;
// RSSI имеет смысл только при активном RX-стриме (иначе чтение даёт ошибку/мусор).
if FStreaming then
begin