mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
Add web status bar fields
This commit is contained in:
+67
-1
@@ -2943,6 +2943,8 @@ procedure TMainForm.SpectrumTimerTick(Sender: TObject);
|
||||
var
|
||||
NowTick: QWord;
|
||||
ElapsedTick: QWord;
|
||||
WebStatusText, WebBoardText, WebIPText, WebSupplyText: string;
|
||||
WebPLLText, WebRXText, WebTXText, WebSeqText: string;
|
||||
begin
|
||||
// Синхронизируем размеры если размер панели изменился (после ресайза).
|
||||
// Важно: проверяем только видимые панели — когда спектр скрыт,
|
||||
@@ -3072,6 +3074,67 @@ begin
|
||||
|
||||
// Пушим текущее состояние в веб-клиенты (если есть)
|
||||
if Assigned(FWebServer) then
|
||||
begin
|
||||
if FNetwork.Connected then
|
||||
begin
|
||||
if FRunning then
|
||||
WebStatusText := 'Running'
|
||||
else
|
||||
WebStatusText := 'Connected';
|
||||
WebBoardText := 'Board: ' + BoardTypeName(FNetwork.Device.BoardType);
|
||||
WebIPText := 'IP: ' + FNetwork.Device.IPAddress;
|
||||
end
|
||||
else
|
||||
begin
|
||||
WebStatusText := 'Disconnected';
|
||||
WebBoardText := 'Board --';
|
||||
WebIPText := 'IP --';
|
||||
end;
|
||||
|
||||
if not FRunning then
|
||||
begin
|
||||
WebSupplyText := 'Supply --';
|
||||
WebPLLText := 'PLL --';
|
||||
end
|
||||
else
|
||||
begin
|
||||
if FLastPLLLock then
|
||||
WebPLLText := 'PLL OK'
|
||||
else
|
||||
WebPLLText := 'PLL?';
|
||||
|
||||
if not BoardSupportsSupplyVoltage(FNetwork.Device.BoardType) then
|
||||
WebSupplyText := 'Supply n/a'
|
||||
else if FLastSupplyV >= 0 then
|
||||
begin
|
||||
if FLastSupplyA >= 0 then
|
||||
WebSupplyText := Format('Supply %.1fV %.1fA', [FLastSupplyV, FLastSupplyA])
|
||||
else
|
||||
WebSupplyText := Format('Supply %.1fV', [FLastSupplyV]);
|
||||
end
|
||||
else
|
||||
WebSupplyText := 'Supply --';
|
||||
end;
|
||||
|
||||
if FRunning then
|
||||
WebRXText := 'RX running'
|
||||
else
|
||||
WebRXText := 'RX idle';
|
||||
|
||||
if FTuning then
|
||||
WebTXText := 'TX tune'
|
||||
else if FTransmitting then
|
||||
WebTXText := 'TX active'
|
||||
else
|
||||
WebTXText := 'TX idle';
|
||||
|
||||
if FSeqErrorCount > 0 then
|
||||
WebSeqText := Format('SEQ ERR DDC%d', [FLastSeqErrorDDC])
|
||||
else if FRunning then
|
||||
WebSeqText := 'SEQ OK'
|
||||
else
|
||||
WebSeqText := 'SEQ --';
|
||||
|
||||
FWebServer.PushSpectrum(
|
||||
FSpectrumBuf, 1024,
|
||||
FWaterfallBuf,
|
||||
@@ -3087,7 +3150,10 @@ begin
|
||||
FVfoB, FActiveVfo,
|
||||
FTransmitting, TrkDrive.Position,
|
||||
FAtten, FTuning, FDisplayDuplex,
|
||||
FLastFwdW, FLastSWR, FPAMaxPower);
|
||||
FLastFwdW, FLastSWR, FPAMaxPower,
|
||||
WebStatusText, WebBoardText, WebIPText, WebSupplyText,
|
||||
WebPLLText, WebRXText, WebTXText, WebSeqText);
|
||||
end;
|
||||
end;
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
+24
-5
@@ -95,8 +95,11 @@ begin
|
||||
'.ruler-area canvas{position:absolute;top:0;left:0;width:100%;height:100%}' +
|
||||
'.wf-area{flex:0 0 405px;position:relative;background:#000;border:1px solid #252525;border-radius:3px;overflow:hidden}' +
|
||||
'.wf-area canvas{position:absolute;top:0;left:0;width:100%;height:100%}' +
|
||||
'.sbar{flex:0 0 16px;display:flex;align-items:center;padding:0 6px;gap:10px;background:#0e0e0e;border-top:1px solid #222;font-size:10px;color:#555}' +
|
||||
'#latEl{margin-left:auto}' +
|
||||
'.sbar{flex:0 0 24px;display:grid;grid-template-columns:minmax(120px,170px) minmax(190px,280px) minmax(120px,160px) minmax(135px,170px) minmax(70px,90px) minmax(120px,190px) minmax(120px,180px) minmax(90px,1fr) minmax(82px,96px) minmax(92px,112px);align-items:stretch;background:#0e0e0e;border-top:1px solid #222;font:10px Courier New,monospace;color:#ccc;overflow-x:auto;overflow-y:hidden}' +
|
||||
'.sb-cell{min-width:0;display:flex;align-items:center;padding:0 8px;border-left:1px solid #222;background:#181818;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' +
|
||||
'.sb-cell:first-child{border-left:0}' +
|
||||
'.sb-dim{color:#777}.sb-seq{color:#ffaa00}.sb-status{color:#90c090}.sb-time{justify-content:center;color:#bbb}.sb-lat{display:none}' +
|
||||
'@media screen and (max-width:640px){.sbar{grid-template-columns:minmax(72px,1fr) minmax(104px,1.25fr) minmax(74px,1fr) minmax(78px,1fr);overflow:hidden}.sbar #sbBoard,.sbar #sbIP,.sbar #sbPLL,.sbar #sbRX,.sbar #sbTX,.sbar #sbLocal{display:none}.sb-cell{padding:0 5px;font-size:9px}}' +
|
||||
'@media screen and (max-width:1300px) and (min-width:641px){' +
|
||||
'.tbar{gap:3px;padding-left:4px;padding-right:4px;}' +
|
||||
'button{padding:0 6px;font-size:10px;}' +
|
||||
@@ -227,7 +230,19 @@ begin
|
||||
'<div class="spec-area"><canvas id="spec"></canvas><div class="span-ov" id="spanOv"></div></div>' +
|
||||
'<div class="ruler-area"><canvas id="ruler"></canvas></div>' +
|
||||
'<div class="wf-area"><canvas id="wf"></canvas></div>' +
|
||||
'<div class="sbar"><span id="stEl">connecting...</span><span id="latEl"></span></div>' +
|
||||
'<div class="sbar">' +
|
||||
'<span class="sb-cell sb-status" id="stEl">connecting...</span>' +
|
||||
'<span class="sb-cell" id="sbBoard">Board --</span>' +
|
||||
'<span class="sb-cell" id="sbIP">IP --</span>' +
|
||||
'<span class="sb-cell" id="sbSupply">Supply --</span>' +
|
||||
'<span class="sb-cell" id="sbPLL">PLL --</span>' +
|
||||
'<span class="sb-cell sb-dim" id="sbRX">RX idle</span>' +
|
||||
'<span class="sb-cell sb-dim" id="sbTX">TX idle</span>' +
|
||||
'<span class="sb-cell sb-seq" id="sbSEQ">SEQ --</span>' +
|
||||
'<span class="sb-cell sb-time" id="sbUTC">UTC --:--:--</span>' +
|
||||
'<span class="sb-cell sb-time" id="sbLocal">Local --:--:--</span>' +
|
||||
'<span class="sb-lat" id="latEl"></span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
|
||||
'<script>' +
|
||||
@@ -257,6 +272,11 @@ begin
|
||||
'const cl=(v,a,b)=>Math.max(a,Math.min(b,v));' +
|
||||
'const q=id=>document.getElementById(id);' +
|
||||
'function sw(id,on){const b=q(id);if(b)b.classList.toggle("on",!!on);}' +
|
||||
'function sb(id,txt){const e=q(id);if(e){e.textContent=txt||"";e.title=txt||"";}}' +
|
||||
'function fmtTime(d,utc){const p=n=>String(n).padStart(2,"0");return(utc?p(d.getUTCHours()):p(d.getHours()))+":"+p(utc?d.getUTCMinutes():d.getMinutes())+":"+p(utc?d.getUTCSeconds():d.getSeconds());}' +
|
||||
'function updClock(){const d=new Date();sb("sbUTC","UTC "+fmtTime(d,true));sb("sbLocal","Local "+fmtTime(d,false));}' +
|
||||
'function updStatusBar(){sb("stEl",cur.status_text||((cur.connected?"OK":"OFF")+" | "+(cur.running?"RUN":"STOP")));sb("sbBoard",cur.board_text||"Board --");sb("sbIP",cur.ip_text||"IP --");sb("sbSupply",cur.supply_text||"Supply --");sb("sbPLL",cur.pll_text||"PLL --");sb("sbRX",cur.rx_text||"RX idle");sb("sbTX",cur.tx_text||"TX idle");sb("sbSEQ",cur.seq_text||"SEQ --");}' +
|
||||
'updClock();setInterval(updClock,1000);' +
|
||||
'function ws2(obj){if(ws&&ws.readyState===1)ws.send(JSON.stringify(obj));}' +
|
||||
'function cmd(c,v){ws2({cmd:c,on:v});}' +
|
||||
'function updNrBtn(){const b=q("nrBtn");if(!b)return;const m=cur.nr_mode|0;b.textContent=(m===2)?"NR2":(m===3)?"NR3":(m===4)?"NR4":"NR";sw("nrBtn",m!==0);}' +
|
||||
@@ -622,8 +642,7 @@ begin
|
||||
'if(!isPending("attn")){const at=q("attSel");if(at)at.value=cur.attn_idx||0;}' +
|
||||
'updBand(activeVfo==="A"?(cur.vfo_a_hz||0):(vfoB||0));updSpan(cur.span_hz||192000);' +
|
||||
'paintSM(Number(cur.smeter_dbm||-130));' +
|
||||
'const mn=cur.mode_name||(MODE_N[cur.mode||0]||"?");' +
|
||||
'stEl.textContent=(cur.connected?"OK":"OFF")+" | "+(cur.running?"RUN":"STOP")+" | "+(cur.transmitting?"TX":"RX")+" | "+mn+" | "+((activeVfoHz()/1e6).toFixed(3))+" MHz";' +
|
||||
'updStatusBar();' +
|
||||
'const nowTx=!!cur.transmitting;if(nowTx!==prevTx){prevTx=nowTx;if(nowTx)startTXMic();else stopTXMic();}}' +
|
||||
|
||||
'function pal(db){const v=Math.round(cl((db-wfLo)/Math.max(1,wfHi-wfLo),0,1)*255);const c=PAL[v]|0;return[(c>>16)&255,(c>>8)&255,c&255];}' +
|
||||
|
||||
+60
-8
@@ -284,6 +284,14 @@ type
|
||||
FFwdW: Double;
|
||||
FSWR: Double;
|
||||
FPAMaxPower: Double;
|
||||
FStatusText: string;
|
||||
FBoardText: string;
|
||||
FIPText: string;
|
||||
FSupplyText: string;
|
||||
FPLLText: string;
|
||||
FRXText: string;
|
||||
FTXText: string;
|
||||
FSeqText: string;
|
||||
|
||||
FWebClientActive: Boolean;
|
||||
|
||||
@@ -333,7 +341,9 @@ type
|
||||
VfoB: Double; ActiveVfo: Integer;
|
||||
Transmitting: Boolean; DriveLevel: Integer;
|
||||
AttnIdx: Integer; Tuning: Boolean; Duplex: Boolean;
|
||||
FwdW, SWRV, PAMaxPower: Double);
|
||||
FwdW, SWRV, PAMaxPower: Double;
|
||||
const StatusText, BoardText, IPText, SupplyText, PLLText,
|
||||
RXText, TXText, SeqText: string);
|
||||
|
||||
property WebClientActive: Boolean read FWebClientActive;
|
||||
property FreqMhzDigits: Integer read FFreqMhzDigits write FFreqMhzDigits;
|
||||
@@ -472,6 +482,14 @@ begin
|
||||
FFwdW := 0;
|
||||
FSWR := 1.0;
|
||||
FPAMaxPower := 100.0;
|
||||
FStatusText := 'Disconnected';
|
||||
FBoardText := 'Board --';
|
||||
FIPText := 'IP --';
|
||||
FSupplyText := 'Supply --';
|
||||
FPLLText := 'PLL --';
|
||||
FRXText := 'RX idle';
|
||||
FTXText := 'TX idle';
|
||||
FSeqText := 'SEQ --';
|
||||
FBandIdx := 5;
|
||||
FCurrentXvtr := -1;
|
||||
FFreqMhzDigits := 3;
|
||||
@@ -1406,6 +1424,25 @@ end;
|
||||
Формирование JSON-состояния
|
||||
═══════════════════════════════════════════════════════════════════════════ }
|
||||
|
||||
function JsonEscape(const S: string): string;
|
||||
var
|
||||
I: Integer;
|
||||
begin
|
||||
Result := '';
|
||||
for I := 1 to Length(S) do
|
||||
case S[I] of
|
||||
'\': Result := Result + '\\';
|
||||
'"': Result := Result + '\"';
|
||||
#8: Result := Result + '\b';
|
||||
#9: Result := Result + '\t';
|
||||
#10: Result := Result + '\n';
|
||||
#12: Result := Result + '\f';
|
||||
#13: Result := Result + '\r';
|
||||
else
|
||||
Result := Result + S[I];
|
||||
end;
|
||||
end;
|
||||
|
||||
function TWebServer.BuildStateJson: string;
|
||||
const
|
||||
MODE_N: array[0..7] of string =
|
||||
@@ -1438,10 +1475,12 @@ begin
|
||||
'"wf_agc":%s,"wf_nf":%s,"band_idx":%d,"smeter_dbm":%.1f,' +
|
||||
'"running":%s,"mute":%s,"ctun":%s,' +
|
||||
'"nr_mode":%d,"nr":%s,"nb_mode":%d,"nb":%s,"snb":%s,"anf":%s,"connected":%s,' +
|
||||
'"transmitting":%s,"drive":%d,"attn_idx":%d,"tuning":%s,"dup":%s,' +
|
||||
'"fwd_w":%.1f,"swr":%.2f,"pa_max_power":%.0f,' +
|
||||
'"xvtr_current":%d,"xvtr_bands":%s,"freq_mhz_digits":%d,' +
|
||||
'"fmstep_idx":%d}',
|
||||
'"transmitting":%s,"drive":%d,"attn_idx":%d,"tuning":%s,"dup":%s,' +
|
||||
'"fwd_w":%.1f,"swr":%.2f,"pa_max_power":%.0f,' +
|
||||
'"status_text":"%s","board_text":"%s","ip_text":"%s","supply_text":"%s",' +
|
||||
'"pll_text":"%s","rx_text":"%s","tx_text":"%s","seq_text":"%s",' +
|
||||
'"xvtr_current":%d,"xvtr_bands":%s,"freq_mhz_digits":%d,' +
|
||||
'"fmstep_idx":%d}',
|
||||
[FFreq, FVfoB, FActiveVfo,
|
||||
FMode, MODE_N[FMode mod 8],
|
||||
FFilterIdx, FFilterBW,
|
||||
@@ -1465,8 +1504,11 @@ begin
|
||||
FAttnIdx,
|
||||
BoolToStr(FTuning, 'true', 'false'),
|
||||
BoolToStr(FDuplex, 'true', 'false'),
|
||||
FFwdW, FSWR, FPAMaxPower,
|
||||
FCurrentXvtr, XvtrJson, FFreqMhzDigits,
|
||||
FFwdW, FSWR, FPAMaxPower,
|
||||
JsonEscape(FStatusText), JsonEscape(FBoardText), JsonEscape(FIPText),
|
||||
JsonEscape(FSupplyText), JsonEscape(FPLLText), JsonEscape(FRXText),
|
||||
JsonEscape(FTXText), JsonEscape(FSeqText),
|
||||
FCurrentXvtr, XvtrJson, FFreqMhzDigits,
|
||||
FFMStepIdx
|
||||
], FS);
|
||||
finally
|
||||
@@ -1533,7 +1575,9 @@ procedure TWebServer.PushSpectrum(
|
||||
VfoB: Double; ActiveVfo: Integer;
|
||||
Transmitting: Boolean; DriveLevel: Integer;
|
||||
AttnIdx: Integer; Tuning: Boolean; Duplex: Boolean;
|
||||
FwdW, SWRV, PAMaxPower: Double);
|
||||
FwdW, SWRV, PAMaxPower: Double;
|
||||
const StatusText, BoardText, IPText, SupplyText, PLLText,
|
||||
RXText, TXText, SeqText: string);
|
||||
var N, i: Integer;
|
||||
begin
|
||||
if not FRunning then Exit;
|
||||
@@ -1573,6 +1617,14 @@ begin
|
||||
FFwdW := FwdW;
|
||||
FSWR := SWRV;
|
||||
FPAMaxPower := PAMaxPower;
|
||||
FStatusText := StatusText;
|
||||
FBoardText := BoardText;
|
||||
FIPText := IPText;
|
||||
FSupplyText := SupplyText;
|
||||
FPLLText := PLLText;
|
||||
FRXText := RXText;
|
||||
FTXText := TXText;
|
||||
FSeqText := SeqText;
|
||||
finally
|
||||
FStateLock.Leave;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user