mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix: web spectrum tuning range from backend caps; remove dead code
Fix: dragging/wheeling the spectrum in the web UI clamped frequency to a hardcoded HF ceiling (vfoMax=60 MHz), so on Pluto VHF/UHF it snapped down to 60 MHz and couldn't pan up (only the VFO wheel worked, via a different limit). Push the backend's tuning range (BackendCaps.MinFreqHz/MaxFreqHz) to the web alongside the band plan; JS vfoMin/vfoMax use freq_min/freq_max from state. The transverter branch (XVTR_CUR>=0) is unchanged — it keeps the wide-open range since the displayed RF freq is translated to IF and clamped server-side. Dead-code cleanup (audit of this session's work): - SampleRateMode/TSampleRateMode: orphaned when the sample-rate unification replaced the srmContinuous branch in ApplyBackendCapsToUI; no readers left. Removed (+ now-unused PLUTO_MAX_SR). - Pre-existing write-only/unused: TBackendCaps.MaxSampleRate, SampleRateOverlay.SPAN_NAMES, MainForm.BAND_FREQ. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -631,8 +631,6 @@ begin
|
|||||||
Result.HasRFBandwidth := False;
|
Result.HasRFBandwidth := False;
|
||||||
Result.HasFullDuplex := True;
|
Result.HasFullDuplex := True;
|
||||||
Result.MinSampleRate := 48000;
|
Result.MinSampleRate := 48000;
|
||||||
Result.MaxSampleRate := 1536000;
|
|
||||||
Result.SampleRateMode := srmDiscrete;
|
|
||||||
// Бэкенд — единственный источник своих рейтов (общий для desktop/web UI).
|
// Бэкенд — единственный источник своих рейтов (общий для desktop/web UI).
|
||||||
SetLength(Result.RatePresets, 6);
|
SetLength(Result.RatePresets, 6);
|
||||||
Result.RatePresets[0] := 48000;
|
Result.RatePresets[0] := 48000;
|
||||||
|
|||||||
+1
-3
@@ -94,9 +94,6 @@ const
|
|||||||
|
|
||||||
BAND_NAMES: array[0..BAND_COUNT-1] of string = (
|
BAND_NAMES: array[0..BAND_COUNT-1] of string = (
|
||||||
'160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m');
|
'160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m');
|
||||||
BAND_FREQ: array[0..BAND_COUNT-1] of Double = (
|
|
||||||
1900000, 3750000, 5357000, 7100000, 10125000,
|
|
||||||
14200000, 18120000, 21200000, 24940000, 28500000, 50150000);
|
|
||||||
|
|
||||||
MODE_NAMES: array[0..MODE_COUNT-1] of string = (
|
MODE_NAMES: array[0..MODE_COUNT-1] of string = (
|
||||||
'LSB','USB','DSB','CWL','CWU','FM','AM','SAM');
|
'LSB','USB','DSB','CWL','CWU','FM','AM','SAM');
|
||||||
@@ -5397,6 +5394,7 @@ begin
|
|||||||
Freqs[i] := Plan[i].FreqHz;
|
Freqs[i] := Plan[i].FreqHz;
|
||||||
end;
|
end;
|
||||||
FWebServer.SetBands(Names, Freqs);
|
FWebServer.SetBands(Names, Freqs);
|
||||||
|
with FController.BackendCaps do FWebServer.SetFreqRange(MinFreqHz, MaxFreqHz);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMainForm.PushXvtrToWeb;
|
procedure TMainForm.PushXvtrToWeb;
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ implementation
|
|||||||
|
|
||||||
const
|
const
|
||||||
PLUTO_MIN_SR = 521000; // нижний предел AD936x sampling_frequency
|
PLUTO_MIN_SR = 521000; // нижний предел AD936x sampling_frequency
|
||||||
PLUTO_MAX_SR = 61440000;
|
|
||||||
PLUTO_MIN_HZ = 46875000; // AD9361 нативно (LibreSDR/AntSDR); AD9363 — 325 МГц
|
PLUTO_MIN_HZ = 46875000; // AD9361 нативно (LibreSDR/AntSDR); AD9363 — 325 МГц
|
||||||
PLUTO_MAX_HZ = 6000000000.0;
|
PLUTO_MAX_HZ = 6000000000.0;
|
||||||
PLUTO_DEF_SR = 1536000; // дефолтный rate если контроллер задал невалидный
|
PLUTO_DEF_SR = 1536000; // дефолтный rate если контроллер задал невалидный
|
||||||
@@ -389,8 +388,6 @@ begin
|
|||||||
Result.HasRFBandwidth := True;
|
Result.HasRFBandwidth := True;
|
||||||
Result.HasFullDuplex := True;
|
Result.HasFullDuplex := True;
|
||||||
Result.MinSampleRate := PLUTO_MIN_SR;
|
Result.MinSampleRate := PLUTO_MIN_SR;
|
||||||
Result.MaxSampleRate := PLUTO_MAX_SR;
|
|
||||||
Result.SampleRateMode := srmContinuous;
|
|
||||||
// Пресеты для SampleRateOverlay (все > 520 ksps, минимум AD936x).
|
// Пресеты для SampleRateOverlay (все > 520 ksps, минимум AD936x).
|
||||||
SetLength(Result.RatePresets, 8);
|
SetLength(Result.RatePresets, 8);
|
||||||
Result.RatePresets[0] := 576000;
|
Result.RatePresets[0] := 576000;
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
TBackendKind = (bkHPSDR, bkPluto);
|
TBackendKind = (bkHPSDR, bkPluto);
|
||||||
TSampleRateMode = (srmDiscrete, srmContinuous);
|
|
||||||
TBackendRateArray = array of Integer; // пресеты sample-rate (общий тип UI)
|
TBackendRateArray = array of Integer; // пресеты sample-rate (общий тип UI)
|
||||||
|
|
||||||
// Описание возможностей бэкенда. Контроллер гейтит UI/поведение по этим полям.
|
// Описание возможностей бэкенда. Контроллер гейтит UI/поведение по этим полям.
|
||||||
@@ -45,8 +44,6 @@ type
|
|||||||
HasRFBandwidth: Boolean; // настройка аналоговой RF-полосы (Pluto)
|
HasRFBandwidth: Boolean; // настройка аналоговой RF-полосы (Pluto)
|
||||||
HasFullDuplex: Boolean; // одновременный RX+TX (Pluto / QO-100)
|
HasFullDuplex: Boolean; // одновременный RX+TX (Pluto / QO-100)
|
||||||
MinSampleRate: Integer;
|
MinSampleRate: Integer;
|
||||||
MaxSampleRate: Integer;
|
|
||||||
SampleRateMode: TSampleRateMode;
|
|
||||||
RatePresets: TBackendRateArray; // пресеты для SampleRateOverlay
|
RatePresets: TBackendRateArray; // пресеты для SampleRateOverlay
|
||||||
MinFreqHz: Double;
|
MinFreqHz: Double;
|
||||||
MaxFreqHz: Double;
|
MaxFreqHz: Double;
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ implementation
|
|||||||
|
|
||||||
const
|
const
|
||||||
SPAN_RATES: array[0..5] of Integer = (48000, 96000, 192000, 384000, 768000, 1536000);
|
SPAN_RATES: array[0..5] of Integer = (48000, 96000, 192000, 384000, 768000, 1536000);
|
||||||
SPAN_NAMES: array[0..5] of string = ('48k', '96k', '192k', '384k', '768k', '1536k');
|
|
||||||
|
|
||||||
HIDE_W = 22;
|
HIDE_W = 22;
|
||||||
SPAN_H = 18;
|
SPAN_H = 18;
|
||||||
|
|||||||
+6
-2
@@ -455,6 +455,7 @@ begin
|
|||||||
|
|
||||||
'let stA=0,stAmem=100,stB=0,stBmem=100;' +
|
'let stA=0,stAmem=100,stB=0,stBmem=100;' +
|
||||||
'let freqMhzDigits=3,freqMaxHz=999999999;' +
|
'let freqMhzDigits=3,freqMaxHz=999999999;' +
|
||||||
|
'let freqMin=30000,freqMax=60000000;' + // диапазон бэкенда (из state.freq_min/max)
|
||||||
'function fmtVfo(hz,step){' +
|
'function fmtVfo(hz,step){' +
|
||||||
'const N=freqMhzDigits+6;' +
|
'const N=freqMhzDigits+6;' +
|
||||||
'const s=String(Math.max(0,Math.round(hz||0))).padStart(N,"0");' +
|
'const s=String(Math.max(0,Math.round(hz||0))).padStart(N,"0");' +
|
||||||
@@ -695,6 +696,7 @@ begin
|
|||||||
'if(msg.bands!=null&&Array.isArray(msg.bands)&&msg.bands.length){' +
|
'if(msg.bands!=null&&Array.isArray(msg.bands)&&msg.bands.length){' +
|
||||||
'const nn=msg.bands.map(function(b){return b.name;});' +
|
'const nn=msg.bands.map(function(b){return b.name;});' +
|
||||||
'if(JSON.stringify(nn)!==JSON.stringify(BAND_N)){BAND_N=nn;BAND_F=msg.bands.map(function(b){return b.freq;});rebuildBandSel();}}' +
|
'if(JSON.stringify(nn)!==JSON.stringify(BAND_N)){BAND_N=nn;BAND_F=msg.bands.map(function(b){return b.freq;});rebuildBandSel();}}' +
|
||||||
|
'if(msg.freq_min!=null)freqMin=msg.freq_min;if(msg.freq_max!=null)freqMax=msg.freq_max;' +
|
||||||
// Обновляем localCenter/localSpan из сервера только когда пользователь не тянет
|
// Обновляем localCenter/localSpan из сервера только когда пользователь не тянет
|
||||||
'if(!dragging&&Date.now()-wheelActiveTs>300){' +
|
'if(!dragging&&Date.now()-wheelActiveTs>300){' +
|
||||||
// В CTUN без DUP: TX-спектр WDSP центрирован по vfo_a_hz, а не по DDC LO.
|
// В CTUN без DUP: TX-спектр WDSP центрирован по vfo_a_hz, а не по DDC LO.
|
||||||
@@ -813,8 +815,10 @@ begin
|
|||||||
'function activeVfoHz(){return activeVfo==="A"?vfoA:vfoB;}' +
|
'function activeVfoHz(){return activeVfo==="A"?vfoA:vfoB;}' +
|
||||||
'function setActiveVfoHz(f){if(activeVfo==="A")vfoA=f;else vfoB=f;}' +
|
'function setActiveVfoHz(f){if(activeVfo==="A")vfoA=f;else vfoB=f;}' +
|
||||||
'function sendActiveFreq(f){if(activeVfo==="A")ws2({cmd:"freq",hz:f});else ws2({cmd:"freq",hz:f});}' +
|
'function sendActiveFreq(f){if(activeVfo==="A")ws2({cmd:"freq",hz:f});else ws2({cmd:"freq",hz:f});}' +
|
||||||
'function vfoMin(){return XVTR_CUR>=0?0:30000;}' +
|
// Границы перестройки берём из бэкенда (freqMin/freqMax из state), а не
|
||||||
'function vfoMax(){return XVTR_CUR>=0?999999999999:60000000;}' +
|
// хардкодим HF — иначе на Pluto (VHF/UHF) drag по спектру клампило в 60 МГц.
|
||||||
|
'function vfoMin(){return XVTR_CUR>=0?0:Math.max(30000,freqMin);}' +
|
||||||
|
'function vfoMax(){return XVTR_CUR>=0?999999999999:freqMax;}' +
|
||||||
'function doWheel(e){e.preventDefault();e.stopPropagation();audioKick();const dir=e.deltaY<0?1:-1,st=tuneStep(e),base=Math.floor(activeVfoHz()/st)*st;' +
|
'function doWheel(e){e.preventDefault();e.stopPropagation();audioKick();const dir=e.deltaY<0?1:-1,st=tuneStep(e),base=Math.floor(activeVfoHz()/st)*st;' +
|
||||||
'const nf=cl(dir>0?base+st:(Math.round(activeVfoHz())===base?base-st:base),vfoMin(),vfoMax());' +
|
'const nf=cl(dir>0?base+st:(Math.round(activeVfoHz())===base?base-st:base),vfoMin(),vfoMax());' +
|
||||||
'setActiveVfoHz(nf);wheelActiveTs=Date.now();' +
|
'setActiveVfoHz(nf);wheelActiveTs=Date.now();' +
|
||||||
|
|||||||
+21
-2
@@ -300,6 +300,8 @@ type
|
|||||||
FRatePresets: array of Integer; // sample-rate пресеты текущего бэкенда (для span-кнопок)
|
FRatePresets: array of Integer; // sample-rate пресеты текущего бэкенда (для span-кнопок)
|
||||||
FBandNames: array of string; // band-план текущего бэкенда (имена кнопок)
|
FBandNames: array of string; // band-план текущего бэкенда (имена кнопок)
|
||||||
FBandFreqs: array of Double; // band-план: дефолтные частоты (для подсветки selector)
|
FBandFreqs: array of Double; // band-план: дефолтные частоты (для подсветки selector)
|
||||||
|
FFreqMin: Double; // диапазон перестройки бэкенда (клампинг drag/wheel)
|
||||||
|
FFreqMax: Double;
|
||||||
FCurrentXvtr: Integer; // -1 = HF, иначе индекс активного XVTR
|
FCurrentXvtr: Integer; // -1 = HF, иначе индекс активного XVTR
|
||||||
FOnXvtrBand: TWebCmdXvtrBand;
|
FOnXvtrBand: TWebCmdXvtrBand;
|
||||||
|
|
||||||
@@ -397,6 +399,7 @@ type
|
|||||||
procedure SetDeviceList(const ADevices: TWebDeviceArray);
|
procedure SetDeviceList(const ADevices: TWebDeviceArray);
|
||||||
procedure SetRatePresets(const ARates: array of Integer);
|
procedure SetRatePresets(const ARates: array of Integer);
|
||||||
procedure SetBands(const ANames: array of string; const AFreqs: array of Double);
|
procedure SetBands(const ANames: array of string; const AFreqs: array of Double);
|
||||||
|
procedure SetFreqRange(AMin, AMax: Double);
|
||||||
property OnSpan: TWebCmdSpan read FOnSpan write FOnSpan;
|
property OnSpan: TWebCmdSpan read FOnSpan write FOnSpan;
|
||||||
property OnVolume: TWebCmdVolume read FOnVolume write FOnVolume;
|
property OnVolume: TWebCmdVolume read FOnVolume write FOnVolume;
|
||||||
property OnWfAGC: TWebCmdWfAGC read FOnWfAGC write FOnWfAGC;
|
property OnWfAGC: TWebCmdWfAGC read FOnWfAGC write FOnWfAGC;
|
||||||
@@ -546,6 +549,7 @@ begin
|
|||||||
SetBands(['160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m'],
|
SetBands(['160m','80m','60m','40m','30m','20m','17m','15m','12m','10m','6m'],
|
||||||
[1840000,3700000,5357000,7100000,10120000,14200000,
|
[1840000,3700000,5357000,7100000,10120000,14200000,
|
||||||
18130000,21300000,24940000,28400000,50150000]);
|
18130000,21300000,24940000,28400000,50150000]);
|
||||||
|
SetFreqRange(0, 61440000); // HPSDR bootstrap; хост перезапишет под бэкенд
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TWebServer.SetXvtrBands(const ABands: TWebXvtrArray; ACurrent: Integer);
|
procedure TWebServer.SetXvtrBands(const ABands: TWebXvtrArray; ACurrent: Integer);
|
||||||
@@ -606,6 +610,19 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TWebServer.SetFreqRange(AMin, AMax: Double);
|
||||||
|
// Диапазон перестройки текущего бэкенда (caps): web клампит drag/wheel/click по
|
||||||
|
// спектру в эти границы. HPSDR 0..61.44МГц / Pluto 46.875МГц..6ГГц.
|
||||||
|
begin
|
||||||
|
FStateLock.Enter;
|
||||||
|
try
|
||||||
|
FFreqMin := AMin;
|
||||||
|
FFreqMax := AMax;
|
||||||
|
finally
|
||||||
|
FStateLock.Leave;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
destructor TWebServer.Destroy;
|
destructor TWebServer.Destroy;
|
||||||
begin
|
begin
|
||||||
Stop;
|
Stop;
|
||||||
@@ -1646,7 +1663,8 @@ begin
|
|||||||
'"status_text":"%s","board_text":"%s","ip_text":"%s","supply_text":"%s",' +
|
'"status_text":"%s","board_text":"%s","ip_text":"%s","supply_text":"%s",' +
|
||||||
'"pll_text":"%s","rx_text":"%s","tx_text":"%s","seq_text":"%s",' +
|
'"pll_text":"%s","rx_text":"%s","tx_text":"%s","seq_text":"%s",' +
|
||||||
'"xvtr_current":%d,"xvtr_bands":%s,"freq_mhz_digits":%d,' +
|
'"xvtr_current":%d,"xvtr_bands":%s,"freq_mhz_digits":%d,' +
|
||||||
'"fmstep_idx":%d,"devices":%s,"rate_presets":%s,"bands":%s}',
|
'"fmstep_idx":%d,"devices":%s,"rate_presets":%s,"bands":%s,' +
|
||||||
|
'"freq_min":%.0f,"freq_max":%.0f}',
|
||||||
[FFreq, FVfoB, FActiveVfo,
|
[FFreq, FVfoB, FActiveVfo,
|
||||||
FMode, MODE_N[FMode mod 8],
|
FMode, MODE_N[FMode mod 8],
|
||||||
FFilterIdx, FFilterBW,
|
FFilterIdx, FFilterBW,
|
||||||
@@ -1675,7 +1693,8 @@ begin
|
|||||||
JsonEscape(FSupplyText), JsonEscape(FPLLText), JsonEscape(FRXText),
|
JsonEscape(FSupplyText), JsonEscape(FPLLText), JsonEscape(FRXText),
|
||||||
JsonEscape(FTXText), JsonEscape(FSeqText),
|
JsonEscape(FTXText), JsonEscape(FSeqText),
|
||||||
FCurrentXvtr, XvtrJson, FFreqMhzDigits,
|
FCurrentXvtr, XvtrJson, FFreqMhzDigits,
|
||||||
FFMStepIdx, DevJson, RateJson, BandJson
|
FFMStepIdx, DevJson, RateJson, BandJson,
|
||||||
|
FFreqMin, FFreqMax
|
||||||
], FS);
|
], FS);
|
||||||
finally
|
finally
|
||||||
FStateLock.Leave;
|
FStateLock.Leave;
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ begin
|
|||||||
Freqs[i] := Plan[i].FreqHz;
|
Freqs[i] := Plan[i].FreqHz;
|
||||||
end;
|
end;
|
||||||
FWeb.SetBands(Names, Freqs);
|
FWeb.SetBands(Names, Freqs);
|
||||||
|
with FCtrl.BackendCaps do FWeb.SetFreqRange(MinFreqHz, MaxFreqHz);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// --- Входящие web-команды (WS-поток) → маршалинг в главный поток ---
|
// --- Входящие web-команды (WS-поток) → маршалинг в главный поток ---
|
||||||
|
|||||||
Reference in New Issue
Block a user