feat(gain): normalize gain controls across modes

- Pager and sensor gain inputs changed from unvalidated text fields to
  number inputs with min/max/step constraints
- ADS-B dashboard now exposes a gain input in the tracking strip;
  previously gain was hardcoded to 40 dB with no user control
- validate_gain() ceiling raised from 50 to 102 dB to support HackRF
  (LNA 40 + VGA 62 = 102 dB combined) and LimeSDR (73 dB)
- sdrCapabilities gain_max values corrected: HackRF 62→102, Airspy 21→45
- onSDRTypeChanged() now propagates gain_max to all mode gain inputs so
  HTML constraints match the selected SDR's actual range

Closes #162
This commit is contained in:
James Smith
2026-04-05 16:02:03 +01:00
parent ea80b5ebc3
commit 592e97719b
5 changed files with 22 additions and 7 deletions
+4
View File
@@ -339,6 +339,9 @@
<select id="adsbDeviceSelect" title="SDR device for ADS-B (1090 MHz)">
<option value="0">SDR 0</option>
</select>
<label title="SDR gain in dB (0 = auto)" style="display:flex;align-items:center;gap:3px;font-size:11px;">
Gain <input type="number" id="adsbGainInput" value="40" min="0" max="50" step="1" style="width:46px;" title="SDR gain in dB">
</label>
<label class="bias-t-label" title="Enable Bias-T power for external LNA/preamp"><input type="checkbox" id="adsbBiasT" onchange="saveAdsbBiasTSetting()"> Bias-T</label>
<button class="start-btn" id="startBtn" onclick="toggleTracking()">START</button>
</div>
@@ -2444,6 +2447,7 @@ sudo make install</code>
const requestBody = {
device: adsbDevice,
sdr_type: adsbSdrType,
gain: parseInt(document.getElementById('adsbGainInput')?.value || '40'),
bias_t: getBiasTEnabled()
};
if (remoteConfig) {
+8 -2
View File
@@ -6095,8 +6095,8 @@
'rtlsdr': { name: 'RTL-SDR', freq_min: 24, freq_max: 1766, gain_min: 0, gain_max: 50 },
'sdrplay': { name: 'SDRplay', freq_min: 0.001, freq_max: 2000, gain_min: 0, gain_max: 59 },
'limesdr': { name: 'LimeSDR', freq_min: 0.1, freq_max: 3800, gain_min: 0, gain_max: 73 },
'hackrf': { name: 'HackRF', freq_min: 1, freq_max: 6000, gain_min: 0, gain_max: 62 },
'airspy': { name: 'Airspy', freq_min: 24, freq_max: 1800, gain_min: 0, gain_max: 21 }
'hackrf': { name: 'HackRF', freq_min: 1, freq_max: 6000, gain_min: 0, gain_max: 102 }, // LNA(40)+VGA(62)
'airspy': { name: 'Airspy', freq_min: 24, freq_max: 1800, gain_min: 0, gain_max: 45 } // LNA(15)+Mix(15)+VGA(15)
};
// Current device list with SDR type info
@@ -6225,6 +6225,12 @@
if (caps) {
document.getElementById('capFreqRange').textContent = `${caps.freq_min}-${caps.freq_max} MHz`;
document.getElementById('capGainRange').textContent = `${caps.gain_min}-${caps.gain_max} dB`;
// Update max attribute on all mode gain inputs so constraints match the SDR
const gainMax = caps.gain_max;
['gain', 'sensorGain', 'aisGainInput', 'acarsGainInput', 'aprsStripGain', 'weatherSatGain'].forEach(id => {
const el = document.getElementById(id);
if (el) el.max = gainMax;
});
}
}
+1 -1
View File
@@ -32,7 +32,7 @@
<h3>Settings</h3>
<div class="form-group">
<label for="gain">Gain (dB, 0 = auto)</label>
<input type="text" id="gain" value="0" placeholder="0-49 or 0 for auto">
<input type="number" id="gain" value="0" min="0" max="50" step="0.5" placeholder="0 = auto">
</div>
<div class="form-group">
<label for="squelch">Squelch Level</label>
+1 -1
View File
@@ -18,7 +18,7 @@
<h3>Settings</h3>
<div class="form-group">
<label for="sensorGain">Gain (dB, 0 = auto)</label>
<input type="text" id="sensorGain" value="0" placeholder="0-49 or 0 for auto">
<input type="number" id="sensorGain" value="0" min="0" max="50" step="0.5" placeholder="0 = auto">
</div>
<div class="form-group">
<label for="sensorPpm">PPM Correction</label>
+8 -3
View File
@@ -93,11 +93,16 @@ def validate_rtl_tcp_port(port: Any) -> int:
def validate_gain(gain: Any) -> float:
"""Validate and return gain value."""
"""Validate and return gain value.
Accepts 0 (auto/minimum) up to 102 dB to cover multi-stage SDRs
(HackRF LNA+VGA = 40+62 = 102 dB max). RTL-SDR caps at 50 dB
internally; values above 50 are only meaningful for HackRF/LimeSDR.
"""
try:
gain_float = float(gain)
if not 0 <= gain_float <= 50:
raise ValueError(f"Gain must be between 0 and 50, got {gain_float}")
if not 0 <= gain_float <= 102:
raise ValueError(f"Gain must be between 0 and 102, got {gain_float}")
return gain_float
except (ValueError, TypeError) as e:
raise ValueError(f"Invalid gain: {gain}") from e