PlatformIO/Arduino firmware for WEMOS/LOLIN S2 Mini: - 6-bit GPIO control (GPIOs 1-6) with glitch-free register writes - REST API: /status, /set, /config, /sweep endpoints - Web UI with PCB green theme, slider, presets, pin visualization - NVS persistence of attenuation setting across power cycles - Sweep mode for automated attenuation stepping - mDNS (attenuator.local), OTA updates, watchdog
151 lines
6.4 KiB
HTML
151 lines
6.4 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>HMC472A Attenuator</title>
|
||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||
<link rel="stylesheet" href="/style.css">
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<header>
|
||
<h1>
|
||
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
|
||
</svg>
|
||
HMC472A
|
||
</h1>
|
||
<p class="subtitle">6-Bit RF Attenuator • DC–3.8 GHz</p>
|
||
</header>
|
||
|
||
<main>
|
||
<!-- Attenuation Display -->
|
||
<section class="display-section">
|
||
<div class="db-display">
|
||
<span id="db-value">0.0</span>
|
||
<span class="db-unit">dB</span>
|
||
</div>
|
||
<div class="step-display">
|
||
Step: <span id="step-value">0</span> / 63
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Slider Control -->
|
||
<section class="slider-section">
|
||
<input type="range" id="db-slider" min="0" max="63" step="1" value="0">
|
||
<div class="slider-labels">
|
||
<span>0 dB</span>
|
||
<span>31.5 dB</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Preset Buttons -->
|
||
<section class="presets-section">
|
||
<h2>Presets</h2>
|
||
<div class="preset-buttons">
|
||
<button class="preset-btn" data-db="0">0 dB</button>
|
||
<button class="preset-btn" data-db="3">3 dB</button>
|
||
<button class="preset-btn" data-db="6">6 dB</button>
|
||
<button class="preset-btn" data-db="10">10 dB</button>
|
||
<button class="preset-btn" data-db="20">20 dB</button>
|
||
<button class="preset-btn" data-db="31.5">31.5 dB</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Pin Visualization -->
|
||
<section class="pins-section">
|
||
<h2>Control Pins</h2>
|
||
<div class="pin-grid">
|
||
<div class="pin" id="pin-v1" data-pin="V1">
|
||
<div class="pin-indicator"></div>
|
||
<div class="pin-label">V1</div>
|
||
<div class="pin-db">16 dB</div>
|
||
</div>
|
||
<div class="pin" id="pin-v2" data-pin="V2">
|
||
<div class="pin-indicator"></div>
|
||
<div class="pin-label">V2</div>
|
||
<div class="pin-db">8 dB</div>
|
||
</div>
|
||
<div class="pin" id="pin-v3" data-pin="V3">
|
||
<div class="pin-indicator"></div>
|
||
<div class="pin-label">V3</div>
|
||
<div class="pin-db">4 dB</div>
|
||
</div>
|
||
<div class="pin" id="pin-v4" data-pin="V4">
|
||
<div class="pin-indicator"></div>
|
||
<div class="pin-label">V4</div>
|
||
<div class="pin-db">2 dB</div>
|
||
</div>
|
||
<div class="pin" id="pin-v5" data-pin="V5">
|
||
<div class="pin-indicator"></div>
|
||
<div class="pin-label">V5</div>
|
||
<div class="pin-db">1 dB</div>
|
||
</div>
|
||
<div class="pin" id="pin-v6" data-pin="V6">
|
||
<div class="pin-indicator"></div>
|
||
<div class="pin-label">V6</div>
|
||
<div class="pin-db">0.5 dB</div>
|
||
</div>
|
||
</div>
|
||
<div class="pin-legend">
|
||
<span class="legend-item">
|
||
<span class="legend-dot high"></span> HIGH (pass)
|
||
</span>
|
||
<span class="legend-item">
|
||
<span class="legend-dot low"></span> LOW (attenuate)
|
||
</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Sweep Controls -->
|
||
<section class="sweep-section">
|
||
<h2>Sweep</h2>
|
||
<div class="sweep-controls">
|
||
<button id="sweep-up" class="sweep-btn" title="Sweep Up">
|
||
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="m18 15-6-6-6 6"/>
|
||
</svg>
|
||
Up
|
||
</button>
|
||
<button id="sweep-down" class="sweep-btn" title="Sweep Down">
|
||
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="m6 9 6 6 6-6"/>
|
||
</svg>
|
||
Down
|
||
</button>
|
||
<button id="sweep-stop" class="sweep-btn stop" title="Stop Sweep">
|
||
<svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<rect x="6" y="6" width="12" height="12" rx="2"/>
|
||
</svg>
|
||
Stop
|
||
</button>
|
||
</div>
|
||
<div class="sweep-config">
|
||
<label>
|
||
Dwell:
|
||
<input type="number" id="sweep-dwell" min="10" max="10000" value="500" step="10">
|
||
ms
|
||
</label>
|
||
</div>
|
||
<div id="sweep-status" class="sweep-status"></div>
|
||
</section>
|
||
</main>
|
||
|
||
<footer>
|
||
<div class="status-bar">
|
||
<span id="hostname">attenuator.local</span>
|
||
<span id="ip-address">---.---.---.---</span>
|
||
<span id="rssi">-- dBm</span>
|
||
<span id="version">v--</span>
|
||
</div>
|
||
<div class="ota-section">
|
||
<button id="ota-btn" class="ota-btn">Enable OTA</button>
|
||
</div>
|
||
</footer>
|
||
</div>
|
||
|
||
<script src="/app.js"></script>
|
||
</body>
|
||
</html>
|