Autarch/web/templates/hardware.html

539 lines
25 KiB
HTML
Raw Normal View History

{% extends "base.html" %}
{% block title %}Hardware - AUTARCH{% endblock %}
{% block extra_head %}{% endblock %}
{% block content %}
<div class="page-header">
<h1>Hardware Access</h1>
</div>
<!-- ── Connection Mode Toggle ── -->
<div class="hw-mode-bar">
<span class="hw-mode-label">Connection Mode:</span>
<div class="hw-mode-toggle">
<button id="hw-mode-server" class="hw-mode-btn active" onclick="hwSetMode('server')">
Server
<span class="hw-mode-desc">Device on AUTARCH host</span>
</button>
<button id="hw-mode-direct" class="hw-mode-btn" onclick="hwSetMode('direct')">
Direct (WebUSB)
<span class="hw-mode-desc">Device on this PC</span>
</button>
</div>
<div id="hw-mode-warning" class="hw-mode-warning" style="display:none"></div>
</div>
<!-- Status Cards (server mode) -->
<div id="hw-status-server" class="stats-grid" style="grid-template-columns:repeat(auto-fit,minmax(140px,1fr))">
<div class="stat-card">
<div class="stat-label">ADB</div>
<div class="stat-value small">
<span class="status-dot {{ 'active' if status.adb else 'inactive' }}"></span>
{{ 'Available' if status.adb else 'Not found' }}
</div>
</div>
<div class="stat-card">
<div class="stat-label">Fastboot</div>
<div class="stat-value small">
<span class="status-dot {{ 'active' if status.fastboot else 'inactive' }}"></span>
{{ 'Available' if status.fastboot else 'Not found' }}
</div>
</div>
<div class="stat-card">
<div class="stat-label">Serial</div>
<div class="stat-value small">
<span class="status-dot {{ 'active' if status.serial else 'warning' }}"></span>
{{ 'Available' if status.serial else 'Not installed' }}
</div>
</div>
<div class="stat-card">
<div class="stat-label">ESPTool</div>
<div class="stat-value small">
<span class="status-dot {{ 'active' if status.esptool else 'warning' }}"></span>
{{ 'Available' if status.esptool else 'Not installed' }}
</div>
</div>
</div>
<!-- Status Cards (direct mode) -->
<div id="hw-status-direct" class="stats-grid" style="grid-template-columns:repeat(auto-fit,minmax(140px,1fr)); display:none">
<div class="stat-card">
<div class="stat-label">WebUSB</div>
<div class="stat-value small">
<span id="hw-cap-webusb" class="status-dot inactive"></span>
<span id="hw-cap-webusb-text">Checking...</span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">Web Serial</div>
<div class="stat-value small">
<span id="hw-cap-webserial" class="status-dot inactive"></span>
<span id="hw-cap-webserial-text">Checking...</span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">ADB Device</div>
<div class="stat-value small">
<span id="hw-direct-adb-status" class="status-dot inactive"></span>
<span id="hw-direct-adb-text">Not connected</span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">Fastboot Device</div>
<div class="stat-value small">
<span id="hw-direct-fb-status" class="status-dot inactive"></span>
<span id="hw-direct-fb-text">Not connected</span>
</div>
</div>
</div>
<!-- Main Tabs -->
<div class="tab-bar">
<button class="tab active" data-tab-group="hw-main" data-tab="android" onclick="showTab('hw-main','android')">Android (ADB/Fastboot)</button>
<button class="tab" data-tab-group="hw-main" data-tab="esp32" onclick="showTab('hw-main','esp32')">ESP32 (Serial)</button>
<button class="tab" data-tab-group="hw-main" data-tab="factory" onclick="showTab('hw-main','factory')">Factory Flash</button>
</div>
<!-- ══ Android Tab ══ -->
<div class="tab-content active" data-tab-group="hw-main" data-tab="android">
<!-- Archon Server Bootstrap -->
<div id="hw-archon-section" class="section">
<h2>Archon Server Bootstrap</h2>
<p class="text-muted">Start the ArchonServer privileged process on a USB-connected Android device running the Archon companion app.</p>
<div class="tool-actions" style="margin-bottom:12px">
<button class="btn btn-primary" onclick="hwArchonBootstrap()">Bootstrap ArchonServer</button>
<button class="btn btn-small" onclick="hwArchonStatus()">Check Status</button>
<button class="btn btn-stop btn-small" onclick="hwArchonStop()">Stop Server</button>
</div>
<div id="hw-archon-output" class="output-panel scrollable" style="max-height:300px;overflow-y:auto;white-space:pre-wrap;word-wrap:break-word"></div>
</div>
<!-- Direct-mode ADB connect -->
<div id="hw-direct-adb-connect" class="section" style="display:none">
<h2>ADB Connection</h2>
<p class="text-muted">Connect to an Android device via USB. The device must have USB Debugging enabled.</p>
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwDirectAdbConnect()">Connect ADB Device</button>
<button class="btn btn-danger btn-small" id="hw-direct-adb-disconnect-btn" onclick="hwDirectAdbDisconnect()" style="display:none">Disconnect</button>
</div>
<div id="hw-direct-adb-msg" class="progress-text"></div>
</div>
<!-- ADB Devices (server mode: list from server, direct mode: show connected) -->
<div id="hw-adb-section" class="section">
<h2>ADB Devices</h2>
<div class="tool-actions" id="hw-adb-refresh-bar">
<button class="btn btn-primary btn-small" onclick="hwRefreshAdbDevices()">Refresh</button>
</div>
<div id="hw-adb-devices"></div>
</div>
<!-- Device Actions (shown when device selected) -->
<div id="hw-device-actions" style="display:none">
<!-- Device Info -->
<div class="section">
<h2>Device Info <span id="hw-selected-serial" style="color:var(--accent);font-size:0.85rem"></span></h2>
<div id="hw-device-info" class="device-info-grid"></div>
</div>
<!-- Shell -->
<div class="section">
<h2>ADB Shell</h2>
<div class="input-row">
<input type="text" id="hw-shell-cmd" placeholder="Enter command (e.g., ls /sdcard, getprop ro.product.model)" onkeydown="if(event.key==='Enter')hwShell()">
<button class="btn btn-primary" onclick="hwShell()">Run</button>
</div>
<div id="hw-shell-output" class="output-panel scrollable" style="max-height:300px"></div>
</div>
<!-- Reboot / Sideload / File Transfer -->
<div class="section">
<h2>Device Actions</h2>
<div class="tool-actions" style="margin-bottom:16px">
<button class="btn btn-warning btn-small" onclick="hwReboot('system')">Reboot System</button>
<button class="btn btn-warning btn-small" onclick="hwReboot('recovery')">Reboot Recovery</button>
<button class="btn btn-warning btn-small" onclick="hwReboot('bootloader')">Reboot Bootloader</button>
</div>
<h3>Sideload / Install</h3>
<!-- Server mode: text path input -->
<div id="hw-sideload-server" class="input-row">
<input type="text" id="hw-sideload-path" placeholder="Path to APK or ZIP file">
<button class="btn btn-primary" onclick="hwSideload()">Sideload</button>
</div>
<!-- Direct mode: file picker -->
<div id="hw-sideload-direct" class="input-row" style="display:none">
<input type="file" id="hw-sideload-file" accept=".apk,.zip">
<button class="btn btn-primary" onclick="hwSideloadDirect()">Install APK</button>
</div>
<div id="hw-sideload-progress" style="display:none">
<div class="hw-progress">
<div class="hw-progress-fill" id="hw-sideload-fill" style="width:0%">
<span class="hw-progress-text" id="hw-sideload-pct">0%</span>
</div>
</div>
<div class="progress-text" id="hw-sideload-msg"></div>
</div>
<h3 style="margin-top:16px">File Transfer</h3>
<!-- Server mode: text paths -->
<div id="hw-transfer-server">
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Local Path</label>
<input type="text" id="hw-push-local" placeholder="/path/to/local/file">
</div>
<div class="form-group">
<label>Remote Path</label>
<input type="text" id="hw-push-remote" placeholder="/sdcard/Download/">
</div>
</div>
<div class="tool-actions">
<button class="btn btn-small" onclick="hwPush()">Push to Device</button>
<button class="btn btn-small" onclick="hwPull()">Pull from Device</button>
</div>
</div>
<!-- Direct mode: file picker + remote path -->
<div id="hw-transfer-direct" style="display:none">
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>File to Push</label>
<input type="file" id="hw-push-file">
</div>
<div class="form-group">
<label>Remote Path</label>
<input type="text" id="hw-push-remote-direct" placeholder="/sdcard/Download/">
</div>
</div>
<div class="tool-actions">
<button class="btn btn-small" onclick="hwPushDirect()">Push to Device</button>
<button class="btn btn-small" onclick="hwPullDirect()">Pull from Device</button>
</div>
</div>
<div class="progress-text" id="hw-transfer-msg"></div>
<h3 style="margin-top:16px">Logcat</h3>
<div class="input-row">
<input type="number" id="hw-logcat-lines" value="50" min="10" max="1000" style="max-width:100px">
<button class="btn btn-small" onclick="hwLogcat()">Get Logcat</button>
</div>
<div id="hw-logcat-output" class="output-panel scrollable" style="max-height:250px;display:none"></div>
</div>
</div>
<!-- Direct-mode Fastboot connect -->
<div id="hw-direct-fb-connect" class="section" style="display:none">
<h2>Fastboot Connection</h2>
<p class="text-muted">Connect to a device in bootloader/fastboot mode via USB.</p>
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwDirectFbConnect()">Connect Fastboot Device</button>
<button class="btn btn-danger btn-small" id="hw-direct-fb-disconnect-btn" onclick="hwDirectFbDisconnect()" style="display:none">Disconnect</button>
</div>
<div id="hw-direct-fb-msg" class="progress-text"></div>
</div>
<!-- Fastboot Devices (server mode) -->
<div id="hw-fastboot-section" class="section">
<h2>Fastboot Devices</h2>
<div class="tool-actions" id="hw-fb-refresh-bar">
<button class="btn btn-primary btn-small" onclick="hwRefreshFastbootDevices()">Refresh</button>
</div>
<div id="hw-fastboot-devices"></div>
</div>
<!-- Fastboot Actions (shown when fastboot device selected) -->
<div id="hw-fastboot-actions" style="display:none">
<div class="section">
<h2>Fastboot Info <span id="hw-fb-selected" style="color:var(--accent);font-size:0.85rem"></span></h2>
<div id="hw-fastboot-info" class="device-info-grid"></div>
<h3 style="margin-top:16px">Flash Partition</h3>
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Partition</label>
<select id="hw-fb-partition">
<option value="boot">boot</option>
<option value="recovery">recovery</option>
<option value="system">system</option>
<option value="vendor">vendor</option>
<option value="vbmeta">vbmeta</option>
<option value="dtbo">dtbo</option>
<option value="vendor_boot">vendor_boot</option>
<option value="init_boot">init_boot</option>
<option value="radio">radio</option>
<option value="bootloader">bootloader</option>
</select>
</div>
<div class="form-group" id="hw-fb-firmware-server">
<label>Firmware Image</label>
<input type="text" id="hw-fb-firmware" placeholder="Path to firmware image file">
</div>
<div class="form-group" id="hw-fb-firmware-direct" style="display:none">
<label>Firmware Image</label>
<input type="file" id="hw-fb-firmware-file" accept=".img,.bin,.mbn">
</div>
</div>
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwFastbootFlash()">Flash</button>
</div>
<div id="hw-fb-flash-progress" style="display:none">
<div class="hw-progress">
<div class="hw-progress-fill" id="hw-fb-flash-fill" style="width:0%">
<span class="hw-progress-text" id="hw-fb-flash-pct">0%</span>
</div>
</div>
<div class="progress-text" id="hw-fb-flash-msg"></div>
</div>
<h3 style="margin-top:16px">Fastboot Actions</h3>
<div class="tool-actions">
<button class="btn btn-warning btn-small" onclick="hwFastbootReboot('system')">Reboot System</button>
<button class="btn btn-warning btn-small" onclick="hwFastbootReboot('bootloader')">Reboot Bootloader</button>
<button class="btn btn-warning btn-small" onclick="hwFastbootReboot('recovery')">Reboot Recovery</button>
<button class="btn btn-danger btn-small" onclick="hwFastbootUnlock()">OEM Unlock</button>
</div>
<div id="hw-fb-confirm" style="display:none" class="confirm-dialog">
<p>WARNING: OEM Unlock will erase all data on the device. This cannot be undone. Continue?</p>
<div class="tool-actions">
<button class="btn btn-danger btn-small" onclick="hwFastbootUnlockConfirm()">Yes, Unlock</button>
<button class="btn btn-small" onclick="document.getElementById('hw-fb-confirm').style.display='none'">Cancel</button>
</div>
</div>
<div class="progress-text" id="hw-fb-msg"></div>
</div>
</div>
</div>
<!-- ══ ESP32 Tab ══ -->
<div class="tab-content" data-tab-group="hw-main" data-tab="esp32">
<!-- Direct-mode serial connect -->
<div id="hw-direct-esp-connect" class="section" style="display:none">
<h2>Serial Connection</h2>
<p class="text-muted">Connect to an ESP32/ESP8266 device via USB serial. Select the device from the browser's serial port picker.</p>
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwDirectEspConnect()">Select Serial Port</button>
<button class="btn btn-danger btn-small" id="hw-direct-esp-disconnect-btn" onclick="hwDirectEspDisconnect()" style="display:none">Disconnect</button>
</div>
<div id="hw-direct-esp-msg" class="progress-text"></div>
</div>
<!-- Serial Ports (server mode) -->
<div id="hw-serial-section">
<div class="section">
<h2>Serial Ports</h2>
<div class="tool-actions">
<button class="btn btn-primary btn-small" onclick="hwRefreshSerialPorts()">Refresh</button>
</div>
<div id="hw-serial-ports"></div>
</div>
<!-- Chip Detection -->
<div class="section">
<h2>Chip Detection</h2>
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Port</label>
<select id="hw-detect-port"><option value="">Select port...</option></select>
</div>
<div class="form-group">
<label>Baud Rate</label>
<select id="hw-detect-baud">
<option value="115200" selected>115200</option>
<option value="9600">9600</option>
<option value="57600">57600</option>
<option value="230400">230400</option>
<option value="460800">460800</option>
<option value="921600">921600</option>
</select>
</div>
</div>
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwDetectChip()">Detect Chip</button>
</div>
<div id="hw-detect-result" class="progress-text"></div>
</div>
</div>
<!-- ESP32 Flash -->
<div class="section">
<h2>Flash Firmware</h2>
<!-- Server mode: port select + text path -->
<div id="hw-esp-flash-server">
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Port</label>
<select id="hw-flash-port"><option value="">Select port...</option></select>
</div>
<div class="form-group">
<label>Baud Rate</label>
<select id="hw-flash-baud">
<option value="460800" selected>460800</option>
<option value="115200">115200</option>
<option value="230400">230400</option>
<option value="921600">921600</option>
</select>
</div>
<div class="form-group">
<label>Firmware File</label>
<input type="text" id="hw-flash-firmware" placeholder="Path to firmware binary">
</div>
</div>
</div>
<!-- Direct mode: file picker + address -->
<div id="hw-esp-flash-direct" style="display:none">
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Baud Rate</label>
<select id="hw-flash-baud-direct">
<option value="460800" selected>460800</option>
<option value="115200">115200</option>
<option value="230400">230400</option>
<option value="921600">921600</option>
</select>
</div>
<div class="form-group">
<label>Firmware File</label>
<input type="file" id="hw-flash-firmware-file" accept=".bin,.elf">
</div>
<div class="form-group">
<label>Flash Address (hex)</label>
<input type="text" id="hw-flash-address" value="0x0" placeholder="0x0">
</div>
</div>
</div>
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwFlashEsp()">Flash</button>
</div>
<div id="hw-esp-flash-progress" style="display:none">
<div class="hw-progress">
<div class="hw-progress-fill" id="hw-esp-flash-fill" style="width:0%">
<span class="hw-progress-text" id="hw-esp-flash-pct">0%</span>
</div>
</div>
<div class="progress-text" id="hw-esp-flash-msg"></div>
</div>
</div>
<!-- Serial Monitor -->
<div class="section">
<h2>Serial Monitor</h2>
<!-- Server mode: port selector -->
<div id="hw-monitor-server">
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Port</label>
<select id="hw-monitor-port"><option value="">Select port...</option></select>
</div>
<div class="form-group">
<label>Baud Rate</label>
<select id="hw-monitor-baud">
<option value="115200" selected>115200</option>
<option value="9600">9600</option>
<option value="57600">57600</option>
<option value="230400">230400</option>
<option value="460800">460800</option>
<option value="921600">921600</option>
</select>
</div>
</div>
</div>
<!-- Direct mode: baud only (port already selected) -->
<div id="hw-monitor-direct" style="display:none">
<div class="form-row" style="margin-bottom:8px">
<div class="form-group">
<label>Baud Rate</label>
<select id="hw-monitor-baud-direct">
<option value="115200" selected>115200</option>
<option value="9600">9600</option>
<option value="57600">57600</option>
<option value="230400">230400</option>
<option value="460800">460800</option>
<option value="921600">921600</option>
</select>
</div>
</div>
</div>
<div class="tool-actions">
<button id="hw-monitor-start-btn" class="btn btn-primary btn-small" onclick="hwMonitorStart()">Start Monitor</button>
<button id="hw-monitor-stop-btn" class="btn btn-stop btn-small" onclick="hwMonitorStop()" style="display:none">Stop</button>
<button class="btn btn-small" onclick="hwMonitorClear()">Clear</button>
</div>
<div id="hw-monitor-output" class="serial-monitor"></div>
<div class="serial-input-row">
<input type="text" id="hw-monitor-input" placeholder="Send data..." onkeydown="if(event.key==='Enter')hwMonitorSend()">
<button class="btn btn-small" onclick="hwMonitorSend()">Send</button>
</div>
</div>
</div>
<!-- ══ Factory Flash Tab (Direct mode only) ══ -->
<div class="tab-content" data-tab-group="hw-main" data-tab="factory">
<div class="section">
<h2>Factory Image Flash</h2>
<p class="text-muted">Flash a complete factory image to an Android device. Inspired by PixelFlasher. Requires Direct mode with a device in fastboot.</p>
<div id="hw-factory-requires-direct" style="display:none">
<div class="hw-mode-warning">This feature requires Direct mode. Switch to Direct mode and connect a fastboot device first.</div>
</div>
<div id="hw-factory-controls">
<!-- Step 1: Select factory image -->
<div class="form-row" style="margin-bottom:16px">
<div class="form-group" style="flex:2">
<label>Factory Image ZIP</label>
<input type="file" id="hw-factory-zip" accept=".zip" onchange="hwFactoryZipSelected(this)">
</div>
</div>
<!-- Step 2: Flash plan (populated after ZIP selected) -->
<div id="hw-factory-plan" style="display:none">
<h3>Flash Plan</h3>
<div id="hw-factory-device-check" class="progress-text"></div>
<div id="hw-factory-plan-details"></div>
<!-- Options -->
<div class="form-row" style="margin:16px 0">
<label class="hw-checkbox"><input type="checkbox" id="hw-factory-skip-userdata" checked> Skip userdata (preserve data)</label>
<label class="hw-checkbox"><input type="checkbox" id="hw-factory-disable-vbmeta"> Disable vbmeta verification</label>
</div>
<!-- Step 3: Flash -->
<div class="tool-actions">
<button class="btn btn-primary" onclick="hwFactoryFlash()">Flash Factory Image</button>
</div>
</div>
<!-- Progress -->
<div id="hw-factory-progress" style="display:none">
<div class="hw-progress">
<div class="hw-progress-fill" id="hw-factory-fill" style="width:0%">
<span class="hw-progress-text" id="hw-factory-pct">0%</span>
</div>
</div>
<div class="progress-text" id="hw-factory-msg"></div>
<div id="hw-factory-log" class="output-panel scrollable" style="max-height:200px;margin-top:8px"></div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize mode from localStorage
var savedMode = localStorage.getItem('hw_connection_mode') || 'server';
hwSetMode(savedMode);
// Server mode: auto-refresh
if (savedMode === 'server') {
hwRefreshAdbDevices();
hwRefreshFastbootDevices();
hwRefreshSerialPorts();
}
});
</script>
{% endblock %}