Crypto: - Replace broken ChaCha20 (static nonce) with ChaCha20-Poly1305 AEAD - HKDF-SHA256 key derivation from per-device factory NVS master keys - Random 12-byte nonce per message (ESP32 hardware RNG) - crypto_init/encrypt/decrypt API with mbedtls legacy (ESP-IDF v5.3.2) - Custom partition table with factory NVS (fctry at 0x10000) Firmware: - crypto.c full rewrite, messages.c device_id prefix + AEAD encrypt - crypto_init() at boot with esp_restart() on failure - Fix command_t initializations across all modules (sub/help fields) - Clean CMakeLists dependencies for ESP-IDF v5.3.2 C3PO (C2): - Rename tools/c2 + tools/c3po -> tools/C3PO - Per-device CryptoContext with HKDF key derivation - KeyStore (keys.json) for master key management - Transport parses device_id:base64(...) wire format Tools: - New tools/provisioning/provision.py for factory NVS key generation - Updated flasher with mbedtls config for v5.3.2 Docs: - Update all READMEs for new crypto, C3PO paths, provisioning - Update roadmap, architecture diagrams, security sections - Update CONTRIBUTING.md project structure
175 lines
7.4 KiB
HTML
175 lines
7.4 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}MLAT - ESPILON{% endblock %}
|
|
|
|
{% block head %}
|
|
<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>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="page-header">
|
|
<div class="page-title">MLAT <span>Multilateration Positioning</span></div>
|
|
<div class="view-toggle">
|
|
<button class="view-btn active" data-view="map" onclick="switchView('map')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<circle cx="12" cy="10" r="3"/><path d="M12 21.7C17.3 17 20 13 20 10a8 8 0 1 0-16 0c0 3 2.7 7 8 11.7z"/>
|
|
</svg>
|
|
Map
|
|
</button>
|
|
<button class="view-btn" data-view="plan" onclick="switchView('plan')">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/>
|
|
</svg>
|
|
Plan
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mlat-container">
|
|
<!-- Map/Plan View -->
|
|
<div class="mlat-view-wrapper">
|
|
<!-- Leaflet Map View -->
|
|
<div id="map-view" class="mlat-view active">
|
|
<div id="leaflet-map"></div>
|
|
</div>
|
|
|
|
<!-- Plan View (Canvas + Image) -->
|
|
<div id="plan-view" class="mlat-view">
|
|
<div class="plan-controls">
|
|
<input type="file" id="plan-upload" accept="image/*" style="display:none" onchange="uploadPlanImage(this)">
|
|
<button class="btn btn-sm" onclick="document.getElementById('plan-upload').click()">
|
|
Upload Plan
|
|
</button>
|
|
<button class="btn btn-sm" onclick="clearPlan()">
|
|
Clear
|
|
</button>
|
|
<div class="control-divider"></div>
|
|
<button class="btn btn-sm toggle-btn active" id="grid-toggle" onclick="toggleGrid()">
|
|
Grid
|
|
</button>
|
|
<button class="btn btn-sm toggle-btn active" id="labels-toggle" onclick="toggleLabels()">
|
|
Labels
|
|
</button>
|
|
<div class="control-divider"></div>
|
|
<span class="control-label">Zoom:</span>
|
|
<button class="btn btn-sm" onclick="zoomPlan(-1)" title="Zoom Out">-</button>
|
|
<span class="zoom-level" id="zoom-level">100%</span>
|
|
<button class="btn btn-sm" onclick="zoomPlan(1)" title="Zoom In">+</button>
|
|
<button class="btn btn-sm" onclick="resetZoom()" title="Reset View">Reset</button>
|
|
<div class="control-divider"></div>
|
|
<span class="control-label">Size:</span>
|
|
<button class="btn btn-sm" onclick="adjustPlanSize(-10)" title="Shrink Plan">-10m</button>
|
|
<span class="size-display" id="size-display">50x30m</span>
|
|
<button class="btn btn-sm" onclick="adjustPlanSize(10)" title="Enlarge Plan">+10m</button>
|
|
</div>
|
|
<div class="plan-canvas-wrapper">
|
|
<canvas id="plan-canvas"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="mlat-sidebar">
|
|
<!-- Target Position -->
|
|
<div class="mlat-panel">
|
|
<h3>Target Position</h3>
|
|
<div class="mlat-stat" id="target-coord1-row">
|
|
<span class="label" id="target-coord1-label">Latitude</span>
|
|
<span class="value" id="target-coord1">-</span>
|
|
</div>
|
|
<div class="mlat-stat" id="target-coord2-row">
|
|
<span class="label" id="target-coord2-label">Longitude</span>
|
|
<span class="value" id="target-coord2">-</span>
|
|
</div>
|
|
<div class="mlat-stat">
|
|
<span class="label">Confidence</span>
|
|
<span class="value" id="target-confidence">-</span>
|
|
</div>
|
|
<div class="mlat-stat">
|
|
<span class="label">Last Update</span>
|
|
<span class="value" id="target-age">-</span>
|
|
</div>
|
|
<div class="mlat-stat">
|
|
<span class="label">Mode</span>
|
|
<span class="value" id="coord-mode">GPS</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Active Scanners -->
|
|
<div class="mlat-panel">
|
|
<h3>Scanners (<span id="scanner-count">0</span>)</h3>
|
|
<div class="scanner-list" id="scanner-list">
|
|
<div class="empty">No scanners active</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Map Settings (GPS mode) -->
|
|
<div class="mlat-panel" id="map-settings">
|
|
<h3>Map Settings (GPS)</h3>
|
|
<div class="config-row">
|
|
<label>Center Lat</label>
|
|
<input type="number" id="map-center-lat" value="48.8566" step="0.0001">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Center Lon</label>
|
|
<input type="number" id="map-center-lon" value="2.3522" step="0.0001">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Zoom</label>
|
|
<input type="number" id="map-zoom" value="18" min="1" max="20">
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="centerMap()">Center Map</button>
|
|
<button class="btn btn-sm" onclick="fitMapToBounds()">Fit to Scanners</button>
|
|
</div>
|
|
|
|
<!-- Plan Settings (Local mode) -->
|
|
<div class="mlat-panel" id="plan-settings" style="display:none">
|
|
<h3>Plan Settings (Local)</h3>
|
|
<div class="config-row">
|
|
<label>Width (m)</label>
|
|
<input type="number" id="plan-width" value="50" min="1" step="1">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Height (m)</label>
|
|
<input type="number" id="plan-height" value="30" min="1" step="1">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Origin X (m)</label>
|
|
<input type="number" id="plan-origin-x" value="0" step="0.1">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Origin Y (m)</label>
|
|
<input type="number" id="plan-origin-y" value="0" step="0.1">
|
|
</div>
|
|
<button class="btn btn-primary btn-sm" onclick="applyPlanSettings()">Apply</button>
|
|
</div>
|
|
|
|
<!-- MLAT Configuration -->
|
|
<div class="mlat-panel">
|
|
<h3>MLAT Config</h3>
|
|
<div class="config-row">
|
|
<label>RSSI @ 1m</label>
|
|
<input type="number" id="config-rssi" value="-40" step="1">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Path Loss (n)</label>
|
|
<input type="number" id="config-n" value="2.5" step="0.1">
|
|
</div>
|
|
<div class="config-row">
|
|
<label>Smoothing</label>
|
|
<input type="number" id="config-smooth" value="5" min="1" max="20">
|
|
</div>
|
|
<div class="btn-group">
|
|
<button class="btn btn-primary btn-sm" onclick="saveConfig()">Save</button>
|
|
<button class="btn btn-secondary btn-sm" onclick="clearData()">Clear All</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script src="{{ url_for('static', filename='js/mlat.js') }}"></script>
|
|
{% endblock %}
|