3dd02d4208
Server-side decoding makes client-side decoders redundant. Remove ~1000 lines of browser-side Bell 202 AFSK, AX.25/APRS parsing, and Goertzel CW decoding. The frontend now relies solely on the /decode SSE endpoint for decoded data. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
189 lines
8.9 KiB
HTML
189 lines
8.9 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>{pkg} v{ver}</title>
|
|
<link rel="icon" href="/favicon.ico" />
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource/dseg14-classic/400.css" />
|
|
<link rel="stylesheet" href="/style.css" />
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
</head>
|
|
<body>
|
|
<div class="card" id="card">
|
|
<div class="header">
|
|
<div>
|
|
<div class="title"><span id="rig-title">trx-rs</span></div>
|
|
<div class="subtitle" id="server-subtitle"></div>
|
|
<div class="subtitle">{pkg} v{ver}</div>
|
|
</div>
|
|
<img id="logo" class="header-logo" src="/logo.png?v=1" alt="trx logo" onerror="this.style.display='none'" />
|
|
</div>
|
|
<div class="tab-bar">
|
|
<button class="tab active" data-tab="main">Main</button>
|
|
<button class="tab" data-tab="plugins">Plugins</button>
|
|
<button class="tab" data-tab="about">About</button>
|
|
</div>
|
|
<div id="tab-main" class="tab-panel">
|
|
<div id="loading" style="text-align:center; padding:2rem 0;">
|
|
<div id="loading-title" style="margin-bottom:0.4rem; font-size:1.1rem; font-weight:600;">Initializing (rig)…</div>
|
|
<div id="loading-sub" style="color:#9aa4b5;"></div>
|
|
</div>
|
|
<div id="content" style="display:none;">
|
|
<div class="status">
|
|
<div class="full-row">
|
|
<div class="label">Frequency<span class="band-tag" id="band-label">--</span></div>
|
|
<div class="inline">
|
|
<input class="status-input" id="freq" type="text" value="--" />
|
|
<button id="freq-apply" type="button">Set</button>
|
|
</div>
|
|
<div class="jog-container">
|
|
<button id="jog-down" type="button" class="jog-btn">−</button>
|
|
<div class="jog-wheel" id="jog-wheel">
|
|
<div class="jog-indicator" id="jog-indicator"></div>
|
|
</div>
|
|
<button id="jog-up" type="button" class="jog-btn">+</button>
|
|
<div class="jog-step" id="jog-step">
|
|
<button type="button" data-step="1000000">MHz</button>
|
|
<button type="button" data-step="1000" class="active">kHz</button>
|
|
<button type="button" data-step="1">Hz</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="controls-row full-row">
|
|
<div>
|
|
<div class="label">Mode</div>
|
|
<div class="inline">
|
|
<select class="status-input" id="mode">
|
|
<option value="">--</option>
|
|
</select>
|
|
<button id="mode-apply" type="button">Set</button>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="label">Transmit / Power</div>
|
|
<div class="btn-grid">
|
|
<button id="ptt-btn" type="button">Toggle PTT</button>
|
|
<button id="power-btn" type="button">Toggle Power</button>
|
|
<button id="lock-btn" type="button">Lock</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="full-row" id="vfo-row">
|
|
<div class="label">VFO</div>
|
|
<div class="vfo-picker" id="vfo-picker"></div>
|
|
</div>
|
|
<div class="full-row">
|
|
<div class="label">Signal</div>
|
|
<div class="signal" style="gap: 1rem;">
|
|
<div class="signal-bar"><div class="signal-bar-fill" id="signal-bar"></div></div>
|
|
<div class="signal-value" id="signal-value">--</div>
|
|
</div>
|
|
<div class="signal-measure">
|
|
<button id="sig-measure-btn" type="button">Measure</button>
|
|
<button id="sig-clear-btn" type="button">Clear</button>
|
|
<span id="sig-result"></span>
|
|
</div>
|
|
</div>
|
|
<div class="full-row" id="tx-meters" style="display:none;">
|
|
<div class="label">TX Meters</div>
|
|
<div class="meter" style="gap: 1rem; margin-bottom: 0.4rem;">
|
|
<div class="meter-bar"><div class="meter-fill" id="pwr-bar"></div></div>
|
|
<div class="meter-value" id="pwr-value">PWR --</div>
|
|
</div>
|
|
<div class="meter" style="gap: 1rem;">
|
|
<div class="meter-bar"><div class="meter-fill" id="swr-bar"></div></div>
|
|
<div class="meter-value" id="swr-value">SWR --</div>
|
|
</div>
|
|
</div>
|
|
<div id="tx-limit-row" style="display:none;">
|
|
<div class="label">TX Limit — units depend on rig (percentage/watts)</div>
|
|
<div class="inline">
|
|
<input class="status-input" id="tx-limit" type="number" min="0" max="255" step="1" value="" placeholder="--" />
|
|
<button id="tx-limit-btn" type="button">Set</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="full-row" id="audio-row">
|
|
<div class="label">Audio</div>
|
|
<div class="inline" style="gap: 0.6rem; flex-wrap: wrap; align-items: center;">
|
|
<button id="rx-audio-btn" type="button">RX Audio</button>
|
|
<button id="tx-audio-btn" type="button">TX Audio</button>
|
|
<label class="vol-label">RX<input type="range" id="rx-vol" min="0" max="100" value="80" class="vol-slider" /><small class="vol-pct" id="rx-vol-pct">80%</small></label>
|
|
<label class="vol-label">TX<input type="range" id="tx-vol" min="0" max="100" value="80" class="vol-slider" /><small class="vol-pct" id="tx-vol-pct">80%</small></label>
|
|
<div id="audio-level" style="flex: 1 1 auto; height: 12px; border-radius: 999px; background: #1f2937; border: 1px solid #2d3748; overflow: hidden; min-width: 80px;">
|
|
<div id="audio-level-fill" style="height: 100%; width: 0%; background: linear-gradient(90deg, #00d17f, #f0ad4e); transition: width 100ms ease;"></div>
|
|
</div>
|
|
<small id="audio-status" style="min-width: 60px;">Off</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="tab-plugins" class="tab-panel" style="display:none;">
|
|
<div class="sub-tab-bar">
|
|
<button class="sub-tab active" data-subtab="overview">Overview</button>
|
|
<button class="sub-tab" data-subtab="map">Map</button>
|
|
<button class="sub-tab" data-subtab="aprs">APRS</button>
|
|
<button class="sub-tab" data-subtab="cw">CW</button>
|
|
</div>
|
|
<div id="subtab-overview" class="sub-tab-panel">
|
|
<div class="plugin-item">
|
|
<strong>APRS Decoder</strong>
|
|
<div style="color:var(--text-muted); font-size:0.85rem; margin-top:0.2rem;">
|
|
Decodes APRS packets from RX audio using Bell 202 AFSK (1200 baud).
|
|
</div>
|
|
</div>
|
|
<div class="plugin-item">
|
|
<strong>CW Decoder</strong>
|
|
<div style="color:var(--text-muted); font-size:0.85rem; margin-top:0.2rem;">
|
|
Decodes CW (Morse code) from RX audio.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="subtab-map" class="sub-tab-panel" style="display:none;">
|
|
<div id="aprs-map"></div>
|
|
</div>
|
|
<div id="subtab-aprs" class="sub-tab-panel" style="display:none;">
|
|
<div class="aprs-controls">
|
|
<button id="aprs-clear-btn" type="button">Clear</button>
|
|
<small id="aprs-status" style="color:var(--text-muted);">Waiting for server decode</small>
|
|
</div>
|
|
<div id="aprs-packets"></div>
|
|
</div>
|
|
<div id="subtab-cw" class="sub-tab-panel" style="display:none;">
|
|
<div class="cw-controls">
|
|
<button id="cw-clear-btn" type="button">Clear</button>
|
|
<small id="cw-status" style="color:var(--text-muted);">Waiting for server decode</small>
|
|
<div id="cw-signal-indicator" class="cw-signal-off"></div>
|
|
</div>
|
|
<div class="cw-config">
|
|
<label>WPM <input type="number" id="cw-wpm" min="5" max="40" value="15" readonly /></label>
|
|
<label>Tone (Hz) <input type="number" id="cw-tone" min="300" max="1200" value="700" readonly /></label>
|
|
</div>
|
|
<div id="cw-output"></div>
|
|
</div>
|
|
</div>
|
|
<div id="tab-about" class="tab-panel" style="display:none;">
|
|
<table class="about-table">
|
|
<tr><td>Server</td><td id="about-server-ver">--</td></tr>
|
|
<tr><td>Server address</td><td id="about-server-addr">--</td></tr>
|
|
<tr><td>Server callsign</td><td id="about-server-call">--</td></tr>
|
|
<tr><td>Rig</td><td id="about-rig-info">--</td></tr>
|
|
<tr><td>Rig connection</td><td id="about-rig-access">--</td></tr>
|
|
<tr><td>Supported modes</td><td id="about-modes">--</td></tr>
|
|
<tr><td>VFOs</td><td id="about-vfos">--</td></tr>
|
|
<tr><td>Client</td><td>{pkg} v{ver}</td></tr>
|
|
<tr><td>Connected clients</td><td id="about-clients">--</td></tr>
|
|
</table>
|
|
</div>
|
|
<div class="footer">
|
|
<div class="copyright">Built by <a href="https://www.qrzcq.com/call/SP2SJG" target="_blank" rel="noopener">SP2SJG</a> from <a href="https://haxx.space" target="_blank" rel="noopener">haxx.space</a> — <span id="copyright-year"></span></div>
|
|
<div class="hint" id="power-hint">Connecting…</div>
|
|
</div>
|
|
</div>
|
|
<script src="/app.js"></script>
|
|
<script src="/aprs.js"></script>
|
|
<script src="/cw.js"></script>
|
|
</body>
|
|
</html>
|