mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Remove legacy RF modes and add SignalID route/tests
This commit is contained in:
@@ -1,115 +0,0 @@
|
||||
<!-- FINGERPRINT MODE -->
|
||||
<div id="fingerprintMode" class="mode-content">
|
||||
|
||||
<!-- Intro -->
|
||||
<div class="section">
|
||||
<div style="font-size:11px; color:var(--text-dim); line-height:1.6;">
|
||||
RF Fingerprinting captures the baseline radio environment at a location.
|
||||
Record a baseline when the environment is "clean", then compare later to
|
||||
detect new transmitters, surveillance devices, or signal anomalies.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Workflow tab selector -->
|
||||
<div class="section">
|
||||
<h3>Workflow</h3>
|
||||
<div style="display:flex; gap:4px;">
|
||||
<button class="fp-tab-btn active" id="fpTabRecord" onclick="Fingerprint.showTab('record')">
|
||||
1 — Record
|
||||
</button>
|
||||
<button class="fp-tab-btn" id="fpTabCompare" onclick="Fingerprint.showTab('compare')">
|
||||
2 — Compare
|
||||
</button>
|
||||
</div>
|
||||
<div id="fpTabHint" style="margin-top:8px; font-size:11px; color:var(--text-dim); line-height:1.5;">
|
||||
Record a <strong style="color:var(--text-secondary);">baseline</strong> in a known-clean RF environment, then use <strong style="color:var(--text-secondary);">Compare</strong> later to detect new or anomalous signals.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Record tab -->
|
||||
<div id="fpRecordPanel">
|
||||
<div class="section">
|
||||
<h3>Step 1 — Select Device</h3>
|
||||
<div class="form-group">
|
||||
<label>SDR Device</label>
|
||||
<select id="fpDevice">
|
||||
<option value="">Loading…</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Step 2 — Scanner Status</h3>
|
||||
<div style="display:flex; align-items:center; gap:8px; padding:6px 0;">
|
||||
<span id="fpScannerDot" style="width:8px; height:8px; border-radius:50%; background:rgba(255,255,255,0.2); flex-shrink:0;"></span>
|
||||
<span id="fpScannerStatusText" style="font-size:11px; color:var(--text-secondary); flex:1;">Checking…</span>
|
||||
</div>
|
||||
<div style="display:flex; gap:6px;">
|
||||
<button class="run-btn" id="fpScannerStartBtn" onclick="Fingerprint.startScanner()" style="flex:1;">Start Scanner</button>
|
||||
<button class="stop-btn" id="fpScannerStopBtn" onclick="Fingerprint.stopScanner()" style="flex:1; display:none;">Stop Scanner</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Step 3 — Record Baseline</h3>
|
||||
<div class="form-group">
|
||||
<label>Session Name</label>
|
||||
<input type="text" id="fpSessionName" placeholder="e.g. Office — Mon morning">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Location <span style="color:var(--text-dim); font-weight:normal;">(optional)</span></label>
|
||||
<input type="text" id="fpSessionLocation" placeholder="e.g. 3rd floor, room 301">
|
||||
</div>
|
||||
<div style="display:flex; align-items:center; gap:10px; margin:6px 0;">
|
||||
<span style="font-size:10px; color:var(--text-dim); text-transform:uppercase; letter-spacing:.05em;">Observations</span>
|
||||
<span id="fpObsCount" style="font-size:14px; font-family:var(--font-mono); color:var(--accent-cyan, #4aa3ff);">0</span>
|
||||
</div>
|
||||
<div id="fpRecordStatus" style="font-size:11px; color:var(--text-dim); margin-bottom:6px; min-height:14px;"></div>
|
||||
<button class="run-btn" id="fpStartBtn" onclick="Fingerprint.startRecording()">Start Recording</button>
|
||||
<button class="stop-btn" id="fpStopBtn" style="display:none;" onclick="Fingerprint.stopRecording()">Stop & Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compare tab -->
|
||||
<div id="fpComparePanel" style="display:none;">
|
||||
<div class="section">
|
||||
<h3>How It Works</h3>
|
||||
<div style="font-size:11px; color:var(--text-dim); line-height:1.6;">
|
||||
<div style="display:flex; gap:8px; align-items:flex-start; margin-bottom:6px;">
|
||||
<span style="color:var(--accent-cyan); font-weight:700; flex-shrink:0;">1.</span>
|
||||
<span>Ensure the scanner is running (switch to Record tab to start it).</span>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px; align-items:flex-start; margin-bottom:6px;">
|
||||
<span style="color:var(--accent-cyan); font-weight:700; flex-shrink:0;">2.</span>
|
||||
<span>Select a previously recorded baseline below.</span>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px; align-items:flex-start; margin-bottom:6px;">
|
||||
<span style="color:var(--accent-cyan); font-weight:700; flex-shrink:0;">3.</span>
|
||||
<span>Click <strong style="color:var(--text-secondary);">Compare Now</strong> — a 3-second live scan is collected.</span>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px; align-items:flex-start;">
|
||||
<span style="color:var(--accent-cyan); font-weight:700; flex-shrink:0;">4.</span>
|
||||
<span>Anomalies are scored by z-score. <span style="color:#ef4444;">Red = strong deviation</span>, <span style="color:#a855f7;">purple = new signal</span>.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Baseline</h3>
|
||||
<div class="form-group">
|
||||
<label>Session</label>
|
||||
<select id="fpBaselineSelect">
|
||||
<option value="">No baselines saved yet</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="fpCompareStatus" style="font-size:11px; color:var(--text-dim); margin-bottom:6px; min-height:14px;"></div>
|
||||
<button class="run-btn" onclick="Fingerprint.compareNow()">Compare Now</button>
|
||||
</div>
|
||||
|
||||
<div class="section" id="fpAnomalyList" style="display:none;">
|
||||
<h3>Anomalies</h3>
|
||||
<div id="fpAnomalyItems"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,68 +0,0 @@
|
||||
<!-- LISTENING POST MODE -->
|
||||
<div id="listeningPostMode" class="mode-content">
|
||||
<div class="section">
|
||||
<h3>Status</h3>
|
||||
|
||||
<!-- Dependency Warning -->
|
||||
<div id="scannerToolsWarning" style="display: none; background: rgba(255, 100, 100, 0.1); border: 1px solid var(--accent-red); border-radius: 4px; padding: 10px; margin-bottom: 10px;">
|
||||
<p style="color: var(--accent-red); margin: 0; font-size: 0.85em;">
|
||||
<strong>Missing:</strong><br>
|
||||
<span id="scannerToolsWarningText"></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Quick Status -->
|
||||
<div style="background: rgba(0,0,0,0.3); border-radius: 6px; padding: 12px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Status</span>
|
||||
<span id="lpQuickStatus" style="font-size: 11px; color: var(--accent-cyan);">IDLE</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Frequency</span>
|
||||
<span id="lpQuickFreq" style="font-size: 14px; font-family: var(--font-mono); color: var(--text-primary);">---.--- MHz</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-size: 10px; color: var(--text-muted); text-transform: uppercase;">Signals</span>
|
||||
<span id="lpQuickSignals" style="font-size: 14px; font-weight: bold; color: var(--accent-green);">0</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Bookmarks</h3>
|
||||
<div style="display: flex; gap: 4px; margin-bottom: 8px;">
|
||||
<input type="text" id="bookmarkFreqInput" placeholder="Freq (MHz)" style="flex: 1; padding: 6px; background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 4px; font-size: 11px;">
|
||||
<button class="preset-btn" onclick="addFrequencyBookmark()" style="background: var(--accent-green); color: #000; padding: 6px 10px;">+</button>
|
||||
</div>
|
||||
<div id="bookmarksList" style="max-height: 150px; overflow-y: auto; font-size: 11px;">
|
||||
<div style="color: var(--text-muted); text-align: center; padding: 10px;">No bookmarks saved</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Recent Signals</h3>
|
||||
<div id="sidebarRecentSignals" style="max-height: 150px; overflow-y: auto; font-size: 11px;">
|
||||
<div style="color: var(--text-muted); text-align: center; padding: 10px;">No signals yet</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Signal Identification -->
|
||||
<div class="section">
|
||||
<h3>Signal Identification</h3>
|
||||
<div style="display: flex; gap: 4px; margin-bottom: 8px;">
|
||||
<input type="text" id="signalGuessFreqInput" placeholder="Freq (MHz)" style="flex: 1; padding: 6px; background: var(--bg-secondary); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 4px; font-size: 11px;">
|
||||
<button class="preset-btn" onclick="manualSignalGuess()" style="background: var(--accent-cyan); color: #000; padding: 6px 10px; font-weight: 600;">ID</button>
|
||||
</div>
|
||||
<div id="signalGuessPanel" style="display: none; background: rgba(0,0,0,0.3); border-radius: 6px; padding: 10px; font-size: 11px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px;">
|
||||
<span id="signalGuessLabel" style="font-weight: bold; color: var(--text-primary);"></span>
|
||||
<span id="signalGuessBadge" style="padding: 2px 8px; border-radius: 3px; font-size: 9px; font-weight: bold;"></span>
|
||||
</div>
|
||||
<div id="signalGuessExplanation" style="color: var(--text-muted); font-size: 10px; margin-bottom: 6px;"></div>
|
||||
<div id="signalGuessTags" style="display: flex; flex-wrap: wrap; gap: 3px;"></div>
|
||||
<div id="signalGuessAlternatives" style="margin-top: 6px; font-size: 10px; color: var(--text-muted);"></div>
|
||||
<div id="signalGuessSendTo" style="margin-top: 8px; display: none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,126 +0,0 @@
|
||||
<!-- RF HEATMAP MODE -->
|
||||
<div id="rfheatmapMode" class="mode-content">
|
||||
|
||||
<!-- What is this? -->
|
||||
<div class="section">
|
||||
<h3>RF Heatmap</h3>
|
||||
<div style="background:rgba(74,163,255,0.07); border:1px solid rgba(74,163,255,0.2); border-radius:6px; padding:10px; font-size:11px; color:var(--text-secondary); line-height:1.6;">
|
||||
Walk around with INTERCEPT running. Your GPS position and the current signal strength are saved as a point on the map every few metres. The result is a <strong style="color:var(--accent-cyan);">coverage heatmap</strong> — bright areas have strong signal, dark areas are weak or absent.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 1 — Signal source -->
|
||||
<div class="section">
|
||||
<h3><span style="color:var(--accent-cyan); margin-right:6px;">1</span>What to Map</h3>
|
||||
<div class="form-group">
|
||||
<label>Signal Source</label>
|
||||
<select id="rfhmSource" onchange="RFHeatmap.setSource(this.value); RFHeatmap.onSourceChange()">
|
||||
<option value="wifi">WiFi — RSSI of nearby networks</option>
|
||||
<option value="bluetooth">Bluetooth — RSSI of nearby devices</option>
|
||||
<option value="scanner">SDR Scanner — broadband RF power</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- SDR device picker — only shown for Scanner source -->
|
||||
<div id="rfhmDeviceGroup" style="display:none;">
|
||||
<div class="form-group">
|
||||
<label>SDR Device</label>
|
||||
<select id="rfhmDevice">
|
||||
<option value="">Loading…</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rfhmSourceHint" style="font-size:11px; color:var(--text-dim); margin-top:4px; line-height:1.5;">
|
||||
Walk near WiFi access points — their signal strength at each location is recorded.
|
||||
</div>
|
||||
|
||||
<!-- Source running status + inline start/stop -->
|
||||
<div id="rfhmSourceStatusRow" style="margin-top:10px; padding:8px 10px; background:rgba(0,0,0,0.3); border-radius:6px;">
|
||||
<div style="display:flex; align-items:center; gap:7px; margin-bottom:6px;">
|
||||
<span id="rfhmSourceDot" style="width:7px; height:7px; border-radius:50%; background:rgba(255,255,255,0.2); flex-shrink:0;"></span>
|
||||
<span id="rfhmSourceStatusText" style="font-size:11px; color:var(--text-dim);">Checking…</span>
|
||||
</div>
|
||||
<button id="rfhmSourceStartBtn" class="run-btn" style="padding:6px; font-size:11px;" onclick="RFHeatmap.startSource()">Start Scanner</button>
|
||||
<button id="rfhmSourceStopBtn" class="stop-btn" style="display:none; padding:6px; font-size:11px;" onclick="RFHeatmap.stopSource()">Stop Scanner</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2 — Location -->
|
||||
<div class="section">
|
||||
<h3><span style="color:var(--accent-cyan); margin-right:6px;">2</span>Your Location</h3>
|
||||
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:6px 0; border-bottom:1px solid rgba(255,255,255,0.06);">
|
||||
<span style="font-size:10px; color:var(--text-muted); text-transform:uppercase; letter-spacing:.05em;">GPS</span>
|
||||
<span id="rfhmGpsPill" style="font-family:var(--font-mono); font-size:11px; color:var(--text-dim);">No Fix</span>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:8px;">
|
||||
<div style="font-size:10px; color:var(--text-muted); margin-bottom:6px; line-height:1.5;">
|
||||
No GPS? Enter a fixed location to map signals from a stationary point.
|
||||
</div>
|
||||
<div style="display:flex; gap:6px;">
|
||||
<div class="form-group" style="flex:1; margin-bottom:0;">
|
||||
<label>Latitude</label>
|
||||
<input type="number" id="rfhmManualLat" step="0.0001" placeholder="37.7749" oninput="RFHeatmap.setManualCoords()">
|
||||
</div>
|
||||
<div class="form-group" style="flex:1; margin-bottom:0;">
|
||||
<label>Longitude</label>
|
||||
<input type="number" id="rfhmManualLon" step="0.0001" placeholder="-122.4194" oninput="RFHeatmap.setManualCoords()">
|
||||
</div>
|
||||
</div>
|
||||
<button class="preset-btn" onclick="RFHeatmap.useObserverLocation()" style="font-size:10px; margin-top:5px;">
|
||||
Use Saved Observer Location
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 — Verify live signal -->
|
||||
<div class="section">
|
||||
<h3><span style="color:var(--accent-cyan); margin-right:6px;">3</span>Live Signal</h3>
|
||||
<div style="background:rgba(0,0,0,0.3); border-radius:6px; padding:10px;">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px;">
|
||||
<span style="font-size:10px; color:var(--text-muted); text-transform:uppercase; letter-spacing:.05em;">Current</span>
|
||||
<span id="rfhmLiveSignal" style="font-family:var(--font-mono); font-size:16px; color:var(--text-dim);">— dBm</span>
|
||||
</div>
|
||||
<!-- Signal strength bar -->
|
||||
<div style="height:4px; background:rgba(255,255,255,0.08); border-radius:2px; overflow:hidden;">
|
||||
<div id="rfhmSignalBar" style="height:100%; width:0%; background:var(--accent-cyan); border-radius:2px; transition:width 0.3s ease;"></div>
|
||||
</div>
|
||||
<div id="rfhmSignalStatus" style="font-size:10px; color:var(--text-dim); margin-top:5px;">Waiting for signal data…</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 4 — Record -->
|
||||
<div class="section">
|
||||
<h3><span style="color:var(--accent-cyan); margin-right:6px;">4</span>Record</h3>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Sample Every</label>
|
||||
<div style="display:flex; align-items:center; gap:8px;">
|
||||
<input type="range" id="rfhmMinDist" min="1" max="50" value="5" step="1" style="flex:1;"
|
||||
oninput="document.getElementById('rfhmMinDistVal').textContent=this.value+'m'; RFHeatmap.setMinDist(parseInt(this.value))">
|
||||
<span id="rfhmMinDistVal" style="font-family:var(--font-mono); font-size:11px; color:var(--accent-cyan); min-width:28px; text-align:right;">5m</span>
|
||||
</div>
|
||||
<div style="font-size:10px; color:var(--text-dim); margin-top:3px;">A new point is added after you move this distance.</div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; padding:6px 0; margin-bottom:4px; border-top:1px solid rgba(255,255,255,0.06);">
|
||||
<span style="font-size:10px; color:var(--text-muted); text-transform:uppercase; letter-spacing:.05em;">Points Captured</span>
|
||||
<span id="rfhmPointCount" style="font-family:var(--font-mono); font-size:14px; color:var(--accent-cyan);">0</span>
|
||||
</div>
|
||||
|
||||
<button class="run-btn" id="rfhmRecordBtn" onclick="RFHeatmap.startRecording()">Start Recording</button>
|
||||
<button class="stop-btn" id="rfhmStopBtn" style="display:none;" onclick="RFHeatmap.stopRecording()">Stop Recording</button>
|
||||
</div>
|
||||
|
||||
<!-- Map actions -->
|
||||
<div class="section">
|
||||
<h3>Map</h3>
|
||||
<div style="display:flex; gap:6px;">
|
||||
<button class="preset-btn" style="flex:1;" onclick="RFHeatmap.clearPoints()">Clear</button>
|
||||
<button class="preset-btn" style="flex:1;" onclick="RFHeatmap.exportGeoJSON()">Export GeoJSON</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,10 +1,36 @@
|
||||
<!-- WATERFALL MODE -->
|
||||
<div id="waterfallMode" class="mode-content">
|
||||
<div class="section">
|
||||
<h3>Spectrum Waterfall</h3>
|
||||
<div style="font-size:11px; color:var(--text-secondary); line-height:1.45;">
|
||||
Click spectrum or waterfall to tune. Scroll to step-tune. Ctrl/Cmd + scroll to zoom span.
|
||||
<div id="waterfallMode" class="mode-content wf-side">
|
||||
<div class="section wf-side-hero">
|
||||
<div class="wf-side-hero-title-row">
|
||||
<div class="wf-side-hero-title">Spectrum Waterfall</div>
|
||||
<div class="wf-side-chip" id="wfHeroVisualStatus">CONNECTING</div>
|
||||
</div>
|
||||
<div class="wf-side-hero-subtext">
|
||||
Click spectrum/waterfall to tune. Scroll to step-tune. Ctrl/Cmd + scroll to zoom span.
|
||||
</div>
|
||||
<div class="wf-side-hero-stats">
|
||||
<div class="wf-side-stat">
|
||||
<div class="wf-side-stat-label">Tuned</div>
|
||||
<div class="wf-side-stat-value" id="wfHeroFreq">100.0000 MHz</div>
|
||||
</div>
|
||||
<div class="wf-side-stat">
|
||||
<div class="wf-side-stat-label">Mode</div>
|
||||
<div class="wf-side-stat-value" id="wfHeroMode">WFM</div>
|
||||
</div>
|
||||
<div class="wf-side-stat">
|
||||
<div class="wf-side-stat-label">Scan</div>
|
||||
<div class="wf-side-stat-value" id="wfHeroScan">Idle</div>
|
||||
</div>
|
||||
<div class="wf-side-stat">
|
||||
<div class="wf-side-stat-label">Hits</div>
|
||||
<div class="wf-side-stat-value" id="wfHeroHits">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wf-side-hero-actions">
|
||||
<button class="run-btn" id="wfStartBtn" onclick="Waterfall.start()">Start Waterfall</button>
|
||||
<button class="stop-btn" id="wfStopBtn" onclick="Waterfall.stop()" style="display:none;">Stop Waterfall</button>
|
||||
</div>
|
||||
<div id="wfStatus" class="wf-side-status-line"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
@@ -15,18 +41,18 @@
|
||||
<option value="">Loading devices...</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="wfDeviceInfo" style="display:none; background:rgba(0,0,0,0.32); border:1px solid rgba(74,163,255,0.22); border-radius:6px; padding:8px; margin-top:6px; font-size:11px;">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;">
|
||||
<span style="color:var(--text-muted); text-transform:uppercase; font-size:10px; letter-spacing:.05em;">Type</span>
|
||||
<span id="wfDeviceType" style="color:var(--accent-cyan); font-family:var(--font-mono);">--</span>
|
||||
<div id="wfDeviceInfo" class="wf-side-box" style="display:none;">
|
||||
<div class="wf-side-kv">
|
||||
<span class="wf-side-kv-label">Type</span>
|
||||
<span id="wfDeviceType" class="wf-side-kv-value">--</span>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:4px;">
|
||||
<span style="color:var(--text-muted); text-transform:uppercase; font-size:10px; letter-spacing:.05em;">Range</span>
|
||||
<span id="wfDeviceRange" style="color:var(--text-secondary); font-family:var(--font-mono);">--</span>
|
||||
<div class="wf-side-kv">
|
||||
<span class="wf-side-kv-label">Range</span>
|
||||
<span id="wfDeviceRange" class="wf-side-kv-value">--</span>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:space-between; align-items:center;">
|
||||
<span style="color:var(--text-muted); text-transform:uppercase; font-size:10px; letter-spacing:.05em;">Capture SR</span>
|
||||
<span id="wfDeviceBw" style="color:var(--text-secondary); font-family:var(--font-mono);">--</span>
|
||||
<div class="wf-side-kv">
|
||||
<span class="wf-side-kv-label">Capture SR</span>
|
||||
<span id="wfDeviceBw" class="wf-side-kv-value">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -41,7 +67,7 @@
|
||||
<label>Span (MHz)</label>
|
||||
<input type="number" id="wfSpanMhz" value="2.4" step="0.1" min="0.05" max="30">
|
||||
</div>
|
||||
<div class="button-group" style="display:grid; grid-template-columns:1fr 1fr; gap:6px;">
|
||||
<div class="wf-side-grid-2">
|
||||
<button class="preset-btn" onclick="Waterfall.applyPreset('fm')">FM Broadcast</button>
|
||||
<button class="preset-btn" onclick="Waterfall.applyPreset('air')">Airband</button>
|
||||
<button class="preset-btn" onclick="Waterfall.applyPreset('marine')">Marine</button>
|
||||
@@ -49,10 +75,178 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Quick Tune & Bookmarks</h3>
|
||||
<div class="wf-side-grid-2">
|
||||
<button class="preset-btn" onclick="Waterfall.quickTune(121.5, 'am')">121.5 Guard</button>
|
||||
<button class="preset-btn" onclick="Waterfall.quickTune(156.8, 'fm')">156.8 CH16</button>
|
||||
<button class="preset-btn" onclick="Waterfall.quickTune(145.5, 'fm')">145.5 2m</button>
|
||||
<button class="preset-btn" onclick="Waterfall.quickTune(98.1, 'wfm')">98.1 FM</button>
|
||||
<button class="preset-btn" onclick="Waterfall.quickTune(462.5625, 'fm')">462.56 FRS</button>
|
||||
<button class="preset-btn" onclick="Waterfall.quickTune(446.0, 'fm')">446.0 PMR</button>
|
||||
</div>
|
||||
<div class="wf-side-divider"></div>
|
||||
<div class="wf-bookmark-row">
|
||||
<input type="number" id="wfBookmarkFreqInput" step="0.0001" min="0.001" max="6000" placeholder="Frequency MHz">
|
||||
<select id="wfBookmarkMode">
|
||||
<option value="auto" selected>Auto</option>
|
||||
<option value="wfm">WFM</option>
|
||||
<option value="fm">NFM</option>
|
||||
<option value="am">AM</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="lsb">LSB</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wf-side-grid-2">
|
||||
<button class="preset-btn" onclick="Waterfall.useTuneForBookmark()">Use Tuned</button>
|
||||
<button class="preset-btn" onclick="Waterfall.addBookmarkFromInput()">Save Bookmark</button>
|
||||
</div>
|
||||
<div id="wfBookmarkList" class="wf-bookmark-list">
|
||||
<div class="wf-empty">No bookmarks saved</div>
|
||||
</div>
|
||||
<div class="wf-side-inline-label">Recent Hits</div>
|
||||
<div id="wfRecentSignals" class="wf-recent-list">
|
||||
<div class="wf-empty">No recent signal hits</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Handoff</h3>
|
||||
<div class="wf-side-help">
|
||||
Send current tuned frequency to another decoder/workflow.
|
||||
</div>
|
||||
<div class="wf-side-grid-2">
|
||||
<button class="preset-btn" onclick="Waterfall.handoff('pager')">To Pager</button>
|
||||
<button class="preset-btn" onclick="Waterfall.handoff('subghz')">To SubGHz</button>
|
||||
<button class="preset-btn" onclick="Waterfall.handoff('subghz433')">433 Profile</button>
|
||||
<button class="preset-btn" onclick="Waterfall.handoff('signalid')">Signal ID</button>
|
||||
</div>
|
||||
<div id="wfHandoffStatus" class="wf-side-status-line">Ready</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Signal Identification</h3>
|
||||
<div class="wf-side-help">
|
||||
Identify current frequency using local catalog and SigID Wiki matches.
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Frequency (MHz)</label>
|
||||
<input type="number" id="wfSigIdFreq" value="100.0000" step="0.0001" min="0.001" max="6000">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Mode Hint</label>
|
||||
<select id="wfSigIdMode">
|
||||
<option value="auto" selected>Auto (Current Mode)</option>
|
||||
<option value="wfm">WFM</option>
|
||||
<option value="fm">NFM</option>
|
||||
<option value="am">AM</option>
|
||||
<option value="usb">USB</option>
|
||||
<option value="lsb">LSB</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wf-side-grid-2">
|
||||
<button class="preset-btn" onclick="Waterfall.useTuneForSignalId()">Use Tuned</button>
|
||||
<button class="preset-btn" onclick="Waterfall.identifySignal()">Identify</button>
|
||||
</div>
|
||||
<div id="wfSigIdStatus" class="wf-side-status-line">Ready</div>
|
||||
<div id="wfSigIdResult" class="wf-side-box" style="display:none;"></div>
|
||||
<div id="wfSigIdExternal" class="wf-side-box wf-side-box-muted" style="display:none;"></div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Scan</h3>
|
||||
<div class="form-group">
|
||||
<label>Range Start (MHz)</label>
|
||||
<input type="number" id="wfScanStart" value="98.8000" step="0.001" min="0.001" max="6000">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Range End (MHz)</label>
|
||||
<input type="number" id="wfScanEnd" value="101.2000" step="0.001" min="0.001" max="6000">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Step (kHz)</label>
|
||||
<select id="wfScanStepKhz">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="12.5">12.5</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100" selected>100</option>
|
||||
<option value="200">200</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Dwell (ms)</label>
|
||||
<input type="number" id="wfScanDwellMs" value="450" min="60" max="10000" step="10">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Signal Threshold <span id="wfScanThresholdValue" class="wf-inline-value">170</span></label>
|
||||
<input type="range" id="wfScanThreshold" min="0" max="255" value="170">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Hold On Hit (ms)</label>
|
||||
<input type="number" id="wfScanHoldMs" value="2500" min="0" max="30000" step="100">
|
||||
</div>
|
||||
<div class="checkbox-group wf-scan-checkboxes">
|
||||
<label>
|
||||
<input type="checkbox" id="wfScanStopOnSignal" checked>
|
||||
Pause scan when signal is above threshold
|
||||
</label>
|
||||
</div>
|
||||
<div class="wf-side-grid-2 wf-side-grid-gap-top">
|
||||
<button class="preset-btn" onclick="Waterfall.setScanRangeFromView()">Use Current Span</button>
|
||||
<button class="preset-btn" id="wfScanStartBtn" onclick="Waterfall.startScan()">Start Scan</button>
|
||||
<button class="preset-btn" id="wfScanStopBtn" onclick="Waterfall.stopScan()" disabled>Stop Scan</button>
|
||||
</div>
|
||||
<div id="wfScanState" class="wf-side-status-line">Scan idle</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Scan Activity</h3>
|
||||
<div class="wf-scan-metric-grid">
|
||||
<div class="wf-scan-metric-card">
|
||||
<div class="wf-scan-metric-label">Signals</div>
|
||||
<div class="wf-scan-metric-value" id="wfScanSignalsCount">0</div>
|
||||
</div>
|
||||
<div class="wf-scan-metric-card">
|
||||
<div class="wf-scan-metric-label">Scanned</div>
|
||||
<div class="wf-scan-metric-value" id="wfScanStepsCount">0</div>
|
||||
</div>
|
||||
<div class="wf-scan-metric-card">
|
||||
<div class="wf-scan-metric-label">Cycles</div>
|
||||
<div class="wf-scan-metric-value" id="wfScanCyclesCount">0</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wf-side-grid-2 wf-side-grid-gap-top">
|
||||
<button class="preset-btn" onclick="Waterfall.exportScanLog()">Export Log</button>
|
||||
<button class="preset-btn" onclick="Waterfall.clearScanHistory()">Clear History</button>
|
||||
</div>
|
||||
<div class="wf-hit-table-wrap">
|
||||
<table class="wf-hit-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Frequency</th>
|
||||
<th>Level</th>
|
||||
<th>Mode</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="wfSignalHitsBody">
|
||||
<tr><td colspan="5" class="wf-empty">No signals detected</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="wfSignalHitCount" class="wf-side-inline-label">0 signals found</div>
|
||||
<div id="wfActivityLog" class="wf-activity-log">
|
||||
<div class="wf-empty">Ready</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h3>Capture</h3>
|
||||
<div class="form-group">
|
||||
<label>Gain <span style="color:var(--text-dim); font-weight:normal;">(dB or AUTO)</span></label>
|
||||
<label>Gain <span class="wf-inline-value">(dB or AUTO)</span></label>
|
||||
<input type="text" id="wfGain" value="AUTO" placeholder="AUTO or numeric">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -88,7 +282,7 @@
|
||||
<label>PPM Correction</label>
|
||||
<input type="number" id="wfPpm" value="0" step="1" min="-200" max="200" placeholder="0">
|
||||
</div>
|
||||
<div class="checkbox-group" style="margin-top:8px;">
|
||||
<div class="checkbox-group wf-scan-checkboxes">
|
||||
<label>
|
||||
<input type="checkbox" id="wfBiasT">
|
||||
Bias-T (antenna power)
|
||||
@@ -115,7 +309,7 @@
|
||||
<label>Ceiling (dB)</label>
|
||||
<input type="number" id="wfDbMax" value="-20" step="5" disabled>
|
||||
</div>
|
||||
<div class="checkbox-group" style="margin-top:8px;">
|
||||
<div class="checkbox-group wf-scan-checkboxes">
|
||||
<label>
|
||||
<input type="checkbox" id="wfPeakHold" onchange="Waterfall.togglePeakHold(this.checked)">
|
||||
Peak Hold
|
||||
@@ -130,13 +324,4 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<button class="run-btn" id="wfStartBtn" onclick="Waterfall.start()">Start Waterfall</button>
|
||||
<button class="stop-btn" id="wfStopBtn" style="display:none;" onclick="Waterfall.stop()">Stop Waterfall</button>
|
||||
<div id="wfStatus" style="margin-top:8px; font-size:11px; color:var(--text-dim);"></div>
|
||||
<div style="margin-top:6px; font-size:10px; color:var(--text-muted);">
|
||||
Tune with click. Use Monitor in the top strip for audio listen.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user