Files
DCU_DesktopController/pages/index.html
T

585 lines
35 KiB
HTML
Raw Normal View History

<!--
index.html - ESP32 OTA 銝剔誧�批��唬蜓憿菟𢒰嚗㇄CU Mission Control 繚 蝢𤾸����
�舀� WiFi OTA嚗𠄌SP32 �祆㦤 + GD32 銝剔誧嚗匧� BLE OTA �屸�𡁻��箔辣��漣�?
�滚��𡁏𧋦嚗惨pp.js (WiFi OTA), ble_ota.js (BLE OTA)
摮鞟頂蝏罸��莎�ESP32=�垍遛 繚 GD32=�亦� 繚 BLE=�?繚 CAN=蝏?繚 ���/靚��=蝝?
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ESP32 OTA 銝剔誧�批��?/title>
<!-- 蝛?favicon嚗𡁻獈甇X�閫�膥�芸𢆡霂瑟� /favicon.ico嚗�𧋦�圈�����⊥�甇斗�隞嗡� 404嚗?-->
<link rel="icon" href="data:,">
<link rel="stylesheet" href="../css/base.css?v=857f83a5">
<link rel="stylesheet" href="../css/layout.css?v=20260924a">
<link rel="stylesheet" href="../css/components.css?v=20260924a">
<link rel="stylesheet" href="../css/can.css?v=c06f5688">
<link rel="stylesheet" href="../css/responsive.css?v=quiet20260919a">
</head>
<body>
<div class="container">
<!-- ====== HEADER: �賭誘�?====== -->
<header class="header-bar">
<div class="header-brand">
<span class="brand-logo" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<rect x="6" y="6" width="12" height="12" rx="2.5"/>
<rect x="9.5" y="9.5" width="5" height="5" rx="1" fill="currentColor" stroke="none" opacity=".85"/>
<path d="M9 2v3M15 2v3M9 19v3M15 19v3M2 9h3M2 15h3M19 9h3M19 15h3"/>
</svg>
</span>
<div class="brand-text">
<strong>ESP32 OTA 銝剔誧�批��?/strong>
<span class="brand-sub">DCU 繚 Robot_v2 繚 Relay</span>
</div>
</div>
<div class="header-status">
<span class="pill offline" id="pillConn"><span class="indicator"></span><span id="pillConnTxt">�芾��?/span></span>
<span class="pill" id="pillVer">v--</span>
<span class="pill" id="pillIP">--</span>
<span class="pill" id="pillRSSI">--</span>
<span class="pill" id="pillUptime">餈鞱� --</span>
</div>
<div class="header-sub">
<span class="pill">霈曉��? <b class="pill-val" id="deviceName">-</b></span>
<span class="pill">霈曉�ID: <b class="pill-val" id="deviceId">-</b></span>
</div>
</header>
<!-- ====== MAIN LAYOUT ====== -->
<div class="main-layout">
<!-- ====== LEFT: workflow ====== -->
<div>
<!-- 1. Connection -->
<div class="card card--ble">
<div class="card-head"><span class="ico">��</span> 霈曉�餈墧𦻖</div>
<div class="card-body">
<div class="target-tab-row" id="modeTabRow">
<button id="modeWifiBtn" class="btn target-tab-btn btn-primary" data-action="set-console-mode" data-arg="wifi" type="button">
<span class="target-tab-ico" aria-hidden="true">��</span>
<span class="target-tab-txt">WiFi OTA</span>
</button>
<button id="modeBleBtn" class="btn target-tab-btn btn-outline" data-action="set-console-mode" data-arg="ble" type="button">
<span class="target-tab-ico" aria-hidden="true">�摱</span>
<span class="target-tab-txt">BLE �萘�</span>
</button>
<button id="modeEcatBtn" class="btn target-tab-btn btn-outline" data-action="set-console-mode" data-arg="ecat" type="button">
<span class="target-tab-ico" aria-hidden="true">�?/span>
<span class="target-tab-txt">EtherCAT</span>
</button>
</div>
<div id="wifiModeCards">
<div class="form-row">
<label class="form-label" for="espIp">ESP32 IP �啣�</label>
<div class="input-group">
<input class="input" type="text" id="espIp" value="192.168.31.127" placeholder="颲枏� IP �啣�">
<button id="testConnBtn" class="btn btn-outline" data-action="test-connection">瘚贝�</button>
</div>
</div>
</div>
<!-- BLE 璅∪�嚗饝aunch 憌擧聢餈墧𦻖�厰僼嚗Ếheckbox 撽勗𢆡嚗𡁜㗲�?撌脰��伐� -->
<div id="bleModeCards" style="display:none;">
<div class="ble-launch-wrap">
<label class="ble-launch-btn" for="bleConnectToggle" data-ble-state="idle">
<input id="bleConnectToggle" type="checkbox">
<div class="back">
<div class="spot-shadow"></div>
<div class="mid">
<div class="spot-main"></div>
<div class="ble-dial">
<div class="spot-light"></div>
<div class="center">
<div class="icon">
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#bleIconGlow)">
<path d="M7 7 L17 17 L12 22 V2 L17 7 L7 17"
stroke="#BBE7E9" stroke-width="3"
stroke-linecap="round" stroke-linejoin="round" fill="none"
shape-rendering="geometricPrecision"/>
</g>
<defs>
<filter id="bleIconGlow" x="-50%" y="-50%" width="200%" height="200%"
filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="bg"/>
<feColorMatrix in="SourceAlpha" type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="a"/>
<feOffset/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="a" operator="out"/>
<feColorMatrix type="matrix"
values="0 0 0 0 0.37 0 0 0 0 0.66 0 0 0 0 1 0 0 0 0.88 0"/>
<feBlend mode="normal" in2="bg" result="g"/>
<feBlend mode="normal" in="SourceGraphic" in2="g" result="shape"/>
</filter>
</defs>
</svg>
</div>
<div class="launch">
<div style="--i:1">�?/div>
<div style="--i:2">�?/div>
<div style="--i:3">餈?/div>
<div style="--i:4">�?/div>
</div>
<div class="start">
<div class="text1">蝑匧�餈墧𦻖</div>
<div class="text2">
<span style="--n:0">撌?/span>
<span style="--n:1">餈?/span>
<span style="--n:2">�?/span>
<span style="--n:3">.</span>
<span style="--n:4">.</span>
<span style="--n:5">.</span>
</div>
<div class="text3">餈墧𦻖銝?..</div>
</div>
</div>
</div>
</div>
</div>
</label>
<div class="ble-launch-hint">�孵稬�厰僼餈墧𦻖 / �剖��萘�霈曉�</div>
</div>
</div>
<!-- EtherCAT 璅∪�嚗鋫PP �?BOOT 閫坿𠧧敺賜� + 銝��桀��?-->
<div id="ecatModeCards" style="display:none;">
<div class="jump-role-panel">
<div class="jump-role-badge" id="bootEcatRoleBadge" data-role="unknown"
data-action="boot-ecat-probe" role="button" tabindex="0"
title="�孵稬�齿鰵�X�撖寧垢閫坿𠧧嚗㇁PP / BOOT嚗?>
<span class="jump-role-label">敶枏�閫坿𠧧 繚 �孵稬�X�</span>
<strong id="bootEcatRoleTxt">�芣䔝瘚?/strong>
<span class="jump-role-sw" id="bootEcatRoleSw">�?/span>
</div>
<div class="jump-role-meta">
<div><span>霈曉��?0x1008</span><b id="bootEcatName">�?/b></div>
<div><span>頧臭辣��𧋦 0x100A</span><b id="bootEcatSw">�?/b></div>
<div><span>隞𡒊��曇�</span><b id="bootEcatArm">�?/b></div>
<div><span>銝餌�蝻枏� / 撌脣� flash</span><b id="bootEcatRecv">�?/b></div>
</div>
</div>
<button class="btn btn-primary btn-block jump-btn-primary" id="bootEcatRebootBtn"
data-action="boot-ecat-reboot"
title="�匧笆蝡航澈隞質䌊�券�㗇䲮�𡢅�APP�?x2502 餈?BOOT嚗𡰪OOT�?x2503 頝喳� APP">霈拙��典�撘訫紡蝔见�</button>
</div>
<!-- 餈墧𦻖����芸銁憿嗆� #pillConnTxt �曄內嚗峕迨憭���漤�憭?-->
</div>
</div>
<!-- ====== Shared Target + Firmware + Actions ====== -->
<div class="card card--gd32">
<div class="card-head"><span class="ico">�㴓</span> ��漣�格���𤐄隞嗆�隞嗡��扯��滢�</div>
<div class="card-body">
<div class="target-tab-row" id="targetTabRow">
<button id="targetGd32Tab" class="btn target-tab-btn btn-outline" data-action="select-flash-target" data-arg="gd32" type="button">
<span class="target-tab-ico" aria-hidden="true">�?/span>
<span class="target-tab-txt">GD32</span>
</button>
<button id="targetEsp32Tab" class="btn target-tab-btn btn-primary" data-action="select-flash-target" data-arg="esp32" type="button">
<span class="target-tab-ico" aria-hidden="true">�𣂎</span>
<span class="target-tab-txt">ESP32</span>
</button>
</div>
<div style="border-top:1px solid var(--border);margin:0 -16px 14px;padding-top:14px;padding-left:16px;padding-right:16px;">
<div id="wifiEsp32UploadPane">
<div class="upload-zone upload-zone-sm" id="uploadZoneEsp32" data-action="pick-shared-firmware" data-arg="esp32">
<div class="upload-ico">�㨩</div>
<h4>�孵稬�𡝗��?ESP32 �箔辣</h4>
</div>
<input type="file" id="fileInputEsp32" accept=".bin" style="display:none;">
<div class="file-info" id="fileInfoEsp32">
<div class="file-info-row">
<span style="font-weight:600;">�� <span id="fileNameEsp32">-</span></span>
<button class="btn btn-ghost btn-sm" data-action="clear-shared-firmware" data-arg="esp32">皜�膄</button>
</div>
<div class="file-info-grid">
<div class="file-meta-item"><span>蝐餃�</span><b id="fileTypeEsp32">-</b></div>
<div class="file-meta-item"><span>憭批�</span><b id="fileSizeEsp32">-</b></div>
</div>
<div class="file-meta-item" style="margin-top:6px;">
<span>SHA-256</span>
<b id="fileSha256Esp32" style="font-size:10px;word-break:break-all;font-family:monospace;">-</b>
</div>
</div>
</div>
<div id="wifiGd32UploadPane" style="display:none;">
<div class="upload-zone upload-zone-sm" id="uploadZoneGd32" data-action="pick-shared-firmware" data-arg="gd32">
<div class="upload-ico">�㨩</div>
<h4>�孵稬�𡝗��?GD32 �箔辣</h4>
<p>�舀� .bin �?.hex嚗�䌊�刻蓮�g�</p>
</div>
<input type="file" id="fileInputGd32" accept=".hex,.bin" style="display:none;">
<div class="file-info" id="fileInfoGd32">
<div class="file-info-row">
<span style="font-weight:600;">�� <span id="fileNameGd32">-</span></span>
<button class="btn btn-ghost btn-sm" data-action="clear-shared-firmware" data-arg="gd32">皜�膄</button>
</div>
<div class="file-info-grid">
<div class="file-meta-item"><span>蝐餃�</span><b id="fileTypeGd32">-</b></div>
<div class="file-meta-item"><span>憭批�</span><b id="fileSizeGd32">-</b></div>
</div>
<div class="file-meta-item" style="margin-top:6px;">
<span>SHA-256</span>
<b id="fileSha256Gd32" style="font-size:10px;word-break:break-all;font-family:monospace;">-</b>
</div>
</div>
</div>
<div id="bleUploadPane" style="display:none;">
<div class="upload-zone upload-zone-sm" id="uploadZone" style="margin-bottom:12px;" data-action="ble-pick-file">
<div class="upload-ico">�㨩</div>
<h4>�孵稬�𡝗��賣�隞嗅�甇文�</h4>
<p>�舀� .bin �?.hex �澆�</p>
</div>
<input id="firmwareFile" type="file" accept=".bin,.hex,application/octet-stream" style="display:none;">
<div class="file-info" id="fileInfo">
<div class="file-info-row">
<span style="font-weight:600;">�� <span id="fileName">-</span></span>
<button id="clearFileBtn" class="btn btn-outline btn-sm" data-action="ble-clear-file">皜�膄</button>
</div>
<div class="file-info-grid">
<div class="file-meta-item"><span>蝐餃�</span><b id="fileType">-</b></div>
<div class="file-meta-item"><span>憭批�</span><b id="fileSize">0 B</b></div>
<div class="file-meta-item"><span>�餃��?/span><b id="packetCount">0</b></div>
<div class="file-meta-item"><span>撌脣��?/span><b id="sentCount">0</b></div>
</div>
<div class="file-meta-item" style="margin-top:8px;">
<span>SHA-256</span>
<b id="fileSha256" style="font-size:10px;word-break:break-all;font-family:var(--font-mono);">-</b>
</div>
</div>
<div class="footer-note">撱箄悅雿輻鍂 Chrome / Edge����?Payload 銝舘圻�穃𦶢隞斤眏蝟餌��厩𤌍��䌊�刻挽蝵柴�?/div>
</div>
<div style="height:12px"></div>
<div id="wifiEsp32ActionPane">
<button class="btn btn-primary btn-block" id="uploadEsp32Btn" data-action="start-upload" data-arg="esp32" disabled>
銝𠹺�撟嗅�蝥?ESP32
</button>
</div>
<div id="wifiGd32ActionPane" style="display:none;">
<button class="btn btn-success btn-block" id="uploadGd32Btn" data-action="start-upload" data-arg="gd32" disabled>
GD32 OTA
</button>
</div>
<div class="row-2" id="bleActionPane" style="display:none;">
<button id="autoFlashBtn" class="btn btn-primary" disabled>銝��桀��?/button>
<button id="abortBtn" class="btn btn-danger" disabled>銝剜迫隞餃𦛚</button>
</div>
<!-- EtherCAT �渡��X踎嚗𡁜蘨�具�諹挽憭���?= EtherCAT�齿𧒄�曄內嚗ÒpplySharedModeUi �批�嚗剹�?
�箔辣憭滨鍂�䔶�銝?#fileInputGd32 銝𤾸�銝��?processFile 頧祆揢/�⊿�嚗?
��隞亥��䔶��箇緵蝚砌�隞?HEX 閫���剁�"�賭��賜�"�芰眏 BOOT �𣬚� ecatArmed()
鋆��嚗��蝡臭�憭滚��斗旿嚗�� js/ota/boot_ecat.js 憭湔釣嚗剹�?-->
<div id="bootEcatPane" style="display:none;">
<button class="btn btn-block" id="bootEcatRunBtn" data-action="boot-ecat-run" disabled>EtherCAT �瑕� APP</button>
<button class="btn btn-danger btn-block" id="bootEcatAbortBtn"
data-action="boot-ecat-abort" style="margin-top:8px;">�曉��祈蔭</button>
</div>
</div>
</div>
</div>
<!-- 4. Flash Progress + Stage Flow嚗ÁiFi/BLE/EtherCAT �梁鍂�䔶�撘㰘�摨血㨃嚗?-->
<div class="card card--esp32" id="progressCard">
<div class="card-head"><span class="ico">�?/span> �瑕�餈𥕦漲銝擧�蝔钅𧫴畾?/div>
<div class="card-body">
<!-- Phase step indicators -->
<div class="progress-phase-row">
<div class="pp-step active" id="ppEsp32"><span class="pp-ico">�𣑐</span><span class="pp-txt">ESP32 OTA</span></div>
<div class="pp-step" id="ppGd32Ota"><span class="pp-ico">�㨩</span><span class="pp-txt">GD32 OTA</span></div>
<div class="pp-step" id="ppEcatOta"><span class="pp-ico">�?/span><span class="pp-txt">EtherCAT</span></div>
</div>
<!-- Unified progress bar -->
<div class="progress-wrap show" id="progressWrap">
<div class="progress-track"><div class="progress-fill" id="progressFill"></div></div>
<div class="progress-text">
<span id="progressTxt">蝑匧��滢�...</span>
<span id="progressPct">0%</span>
</div>
</div>
<div style="height:14px"></div>
<!-- ESP32 OTA stages -->
<div class="stage-flow" id="esp32Stages" style="display:none;">
<div class="stage-node" id="es1"><div class="stage-dot">1</div><div class="stage-label">�箔辣銝𠹺�</div><div class="stage-detail" id="esd1"></div></div>
<div class="stage-node" id="es2"><div class="stage-dot">2</div><div class="stage-label">OTA �坔�</div><div class="stage-detail" id="esd2"></div></div>
<div class="stage-node" id="es3"><div class="stage-dot">3</div><div class="stage-label">SHA-256 �⊿�</div><div class="stage-detail" id="esd3"></div></div>
<div class="stage-node" id="es4"><div class="stage-dot">4</div><div class="stage-label">摨𠉛鍂�箔辣</div><div class="stage-detail" id="esd4"></div></div>
<div class="stage-node" id="es5"><div class="stage-dot">5</div><div class="stage-label">�滚鍳銝?/div><div class="stage-detail" id="esd5"></div></div>
<div class="stage-node" id="es6"><div class="stage-dot">6</div><div class="stage-label">�臬𢆡摰峕�</div><div class="stage-detail" id="esd6"></div></div>
</div>
<!-- BLE OTA stages -->
<div class="stage-flow" id="bleStages" style="display:none;">
<div class="stage-node" id="bs1"><div class="stage-dot">1</div><div class="stage-label">BLE 餈墧𦻖</div><div class="stage-detail" id="bsd1"></div></div>
<div class="stage-node" id="bs2"><div class="stage-dot">2</div><div class="stage-label">GATT ���</div><div class="stage-detail" id="bsd2"></div></div>
<div class="stage-node" id="bs3"><div class="stage-dot">3</div><div class="stage-label">��辣���</div><div class="stage-detail" id="bsd3"></div></div>
<div class="stage-node" id="bs4"><div class="stage-dot">4</div><div class="stage-label">�唳旿�坔�</div><div class="stage-detail" id="bsd4"></div></div>
<div class="stage-node" id="bs5"><div class="stage-dot">5</div><div class="stage-label" id="bsl5">�⊿�瘥𥪜笆</div><div class="stage-detail" id="bsd5"></div></div>
<div class="stage-node" id="bs6"><div class="stage-dot">6</div><div class="stage-label" id="bsl6">摰峕�閫血�</div><div class="stage-detail" id="bsd6"></div></div>
</div>
<!-- GD32 OTA stages -->
<div class="stage-flow" id="gd32Stages">
<div class="stage-node" id="s1"><div class="stage-dot">1</div><div class="stage-label">霈方��⊥�</div><div class="stage-detail" id="sd1"></div></div>
<div class="stage-node" id="s2"><div class="stage-dot">2</div><div class="stage-label">隡㰘��誩�</div><div class="stage-detail" id="sd2"></div></div>
<div class="stage-node" id="s3"><div class="stage-dot">3</div><div class="stage-label">�唳旿頧砍�</div><div class="stage-detail" id="sd3"></div></div>
<div class="stage-node" id="s4"><div class="stage-dot">4</div><div class="stage-label">�嗅偏撉諹�</div><div class="stage-detail" id="sd4"></div></div>
<div class="stage-node" id="s5"><div class="stage-dot">5</div><div class="stage-label">APP �臬𢆡</div><div class="stage-detail" id="sd5"></div></div>
<div class="stage-node" id="s6"><div class="stage-dot">6</div><div class="stage-label">OTA摰峕�</div><div class="stage-detail" id="sd6"></div></div>
</div>
<!-- EtherCAT �瑕� stages -->
<div class="stage-flow" id="ecatStages" style="display:none;">
<div class="stage-node" id="ec1"><div class="stage-dot">1</div><div class="stage-label">霂餃��𨅯�</div><div class="stage-detail" id="ecd1"></div></div>
<div class="stage-node" id="ec2"><div class="stage-dot">2</div><div class="stage-label">�典�銝餌�</div><div class="stage-detail" id="ecd2"></div></div>
<div class="stage-node" id="ec3"><div class="stage-dot">3</div><div class="stage-label">鈭斗𦻖餈?BOOT</div><div class="stage-detail" id="ecd3"></div></div>
<div class="stage-node" id="ec4"><div class="stage-dot">4</div><div class="stage-label">蝖株恕撘訫紡蝔见�</div><div class="stage-detail" id="ecd4"></div></div>
<div class="stage-node" id="ec5"><div class="stage-dot">5</div><div class="stage-label">�桃拳���</div><div class="stage-detail" id="ecd5"></div></div>
<div class="stage-node" id="ec6"><div class="stage-dot">6</div><div class="stage-label">隞𡒊�憭滢�</div><div class="stage-detail" id="ecd6"></div></div>
<div class="stage-node" id="ec7"><div class="stage-dot">7</div><div class="stage-label">�瑕�摰峕�</div><div class="stage-detail" id="ecd7"></div></div>
</div>
<div class="stage-status-bar" id="stageStatusBar">
<span class="ssb-dot" id="stageStatusDot"></span>
<span class="ssb-text" id="stageStatusText">敺�㦤</span>
</div>
<div class="stage-verify-info" id="stageVerifyInfo" style="display:none;">
<div class="svi-row"><span class="svi-key">�滨垢 SHA-256</span><span class="svi-val" id="sviFrontSha">-</span></div>
<div class="svi-row"><span class="svi-key">霈曉� SHA-256</span><span class="svi-val" id="sviDeviceSha">-</span></div>
<div class="svi-row"><span class="svi-key">�⊿�蝏𤘪�</span><span class="svi-val" id="sviResult">-</span></div>
</div>
<div style="margin-top:12px;">
<button class="btn btn-outline btn-block" data-action="restart-esp32">�滚鍳 ESP32</button>
</div>
</div>
</div>
</div>
<!-- ====== RIGHT: status + tools ====== -->
<div>
<!-- Primary status -->
<div class="card card--status">
<div class="card-head"><span class="ico">�摱</span> 霈曉��嗆�?/div>
<div class="card-body">
<div class="badge-grid">
<div class="badge-stat">
<div class="v err" id="bConn">蝳餌瑪</div>
<div class="k">餈墧𦻖�嗆�?/div>
</div>
<div class="badge-stat badge-stat-click" id="healthBadge"
role="button" tabindex="0" title="�孵稬�亦��臬𢆡�芣�"
aria-expanded="false" aria-controls="healthBootPanel">
<div class="v" id="mHealth">--</div>
<div class="k">�亙熒�嗆�?<span class="health-boot-hint">�?�芣�</span></div>
</div>
<div class="badge-stat">
<div class="v err" id="connBadge">offline</div>
<div class="k">BLE 餈墧𦻖</div>
</div>
<div class="badge-stat">
<div class="v" id="gattState" style="font-size:16px;">�芸停蝏?/div>
<div class="k">GATT �嗆�?/div>
</div>
</div>
<!-- �臬𢆡�芣�嚗𡁶��亙熒�嗆���撘�嚗屸�霈斗��?-->
<div class="health-boot-panel collapsed" id="healthBootPanel" hidden>
<div class="health-boot-head">
<span class="health-boot-title">�臬𢆡�芣�</span>
<span class="health-boot-summary" id="mBootResult">--</span>
</div>
<div class="health-boot-failed">憭梯揖/頝唾�嚗?b id="mBootFailed">--</b></div>
<div class="boot-module-list" id="bootModuleList" aria-label="�臬𢆡璅∪��𡑒”"></div>
</div>
</div>
</div>
<!-- Secondary metrics -->
<div class="card card--mem">
<div class="card-head"><span class="ico">��</span> 餈鞱����</div>
<div class="card-body">
<div class="metric-grid">
<div class="metric"><div class="k">ESP32 皜拙漲</div><div class="v" id="mTemp">--</div></div>
<div class="metric"><div class="k">GD32 皜拙漲</div><div class="v" id="mGd32Temp" title="SPI 0xC4嚗𤤿���萱摨?>--</div></div>
<div class="metric"><div class="k">GD32 韐蠘蝸</div><div class="v" id="mGd32Load" title="DCU_APP CPU 韐蠘蝸���銝剜鱏+�𧼮辣餈笔��?隞餃𦛚瘣曉�/OTA銝剔誧)�惩����嚗䔶��怠虜撘�頧株砭銝𡒊征頧穿�EtherCAT 颲枏� PDO 畾?嚗?s 蝒堒藁">--</div></div>
<div class="metric"><div class="k">颲枏� VCC</div><div class="v" id="mVcc" title="PA6 ����齿綫嚗间CC�?7k�𨀞DC�?.7k�浧ND">--</div></div>
<div class="metric"><div class="k">VDDA</div><div class="v" id="mVdda" title="��� VREFINT �齿綫�?MCU 璅⊥�靘𤤿㩞">--</div></div>
<div class="metric"><div class="k">GD32 APP</div><div class="v" id="mGd32App">--</div></div>
<div class="metric"><div class="k">GD32 BOOT</div><div class="v" id="mGd32Boot">--</div></div>
<div class="metric"><div class="k">GD32 �芣�</div><div class="v" id="mGd32Init" title="GD32 APP 銝羓㩞�嘥��𣇉𠶖���SPI 0xA3嚗𥟇��𦦵�憭梯揖璅∪�/憭滢�皞琜�">--</div></div>
</div>
</div>
</div>
<div class="card card--mem" style="display:none">
<div class="card-head">
<span class="ico">�屁</span> 蝟餌��嗆�?(/system/status)
<button class="btn btn-ghost btn-sm card-head-btn" data-action="refresh-system-status">�瑟鰵</button>
</div>
<div class="card-body">
<div class="status-kv-grid">
<div class="status-kv"><span class="k">OTA �嗆�?/span><b id="sOtaState">--</b></div>
<div class="status-kv"><span class="k">Relay �嗆�?/span><b id="sRelayState">--</b></div>
<div class="status-kv"><span class="k">�瑟鰵�園𡢿</span><b id="sStatusUpdated">--</b></div>
</div>
</div>
</div>
<!-- Log panel -->
<div class="card card--mem log-panel">
<div class="card-head" style="justify-content:space-between;">
<span><span class="ico">�棅儭?/span> 靚���亙�</span>
<span style="font-size:11px;font-weight:400;color:var(--text-label);text-transform:none;letter-spacing:0;font-family:var(--font-mono);">UDP :6666</span>
</div>
<div class="card-body">
<div class="log-toolbar">
<div class="log-filters">
<button class="log-filter active" onclick="setLogFilter('all', this)">�券�</button>
<button class="log-filter" onclick="setLogFilter('E', this)">�躰秤</button>
<button class="log-filter" onclick="setLogFilter('W', this)">霅血�</button>
<button class="log-filter" onclick="setLogFilter('I', this)">靽⊥�</button>
</div>
<button class="btn btn-ghost btn-sm" onclick="toggleAutoScroll()" id="autoScrollBtn" title="��揢�芸𢆡皛𡁜𢆡">�� �芸𢆡皛𡁜𢆡</button>
</div>
<div class="log-scroll" id="logScroll">
<div class="log-line"><span class="lt">[--:--:--]</span><span class="lv I">I</span><span class="lg">[蝟餌�]</span><span class="lm">蝑匧�銝𠹺��箄��?..</span></div>
</div>
<div class="log-foot">
<span>�?<span id="logCount">0</span> �?/span>
<button class="btn btn-ghost btn-sm" onclick="clearLogs()">皜�膄�亙�</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- �喃儒皛穃枂嚗𡁜�銝𦒘遙�⊥�嚗��霈日蠧�箔��∴��砍�撅訫�嚗?-->
<aside class="sys-drawer" id="sysDrawer" aria-label="���隞餃𦛚�?>
<div class="sys-drawer-rail" title="�砍�撅訫����隞餃𦛚�?>
<span class="sys-drawer-rail-ico">��</span>
<span class="sys-drawer-rail-text">���隞餃𦛚�?/span>
</div>
<div class="sys-drawer-panel card card--mem">
<div class="card-head sys-drawer-head">
<span class="ico">��</span> ���隞餃𦛚�?
<button class="btn btn-ghost btn-sm card-head-btn" type="button" onclick="refreshSystemStatusNow(event)">�瑟鰵</button>
</div>
<div class="card-body sys-drawer-body">
<div class="status-section-title">CPU �删鍂</div>
<div class="heap-group cpu-group">
<div class="heap-group-title">ESP32 Runtime <span style="font-weight:400;color:var(--text-dim);font-size:10px;">(FreeRTOS)</span></div>
<div class="heap-bar-row">
<span class="heap-bar-text" id="cpuUsageText">蝑匧���甅...</span>
<span class="heap-bar-track"><span class="heap-bar-fill cpu-fill" id="cpuUsageFill"></span></span>
<span class="heap-bar-pct" id="cpuUsagePct">--</span>
</div>
<div class="heap-detail-row">
<span>蝛粹𤦭: <b id="cpuIdlePct">--</b></span>
<span>蝒堒藁: <b id="cpuSampleMs">--</b></span>
<span>隞餃𦛚�? <b id="cpuTaskCount">--</b></span>
</div>
</div>
<div class="status-task-list cpu-task-list list-scroll-top3" id="cpuTaskList" title="�匧��券�摨𧶏�暺䁅恕�曄內�?3 憿對�銝𧢲��亦��嗡�">
<div class="status-empty">蝑匧�銝衤�甈∠𠶖����?..</div>
</div>
<div class="status-section-title">���璁��</div>
<div class="heap-group">
<div class="heap-group-title">�舐� SRAM �餉� <span style="font-weight:400;color:var(--text-dim);font-size:10px;">(ESP32-C3 繚 �蹱��挾�舀��?</span></div>
<div class="heap-bar-row">
<span class="heap-bar-text" id="memSramUsage">--</span>
<span class="heap-bar-track mem-sram-track" id="memSramTrack" title="蝝?IRAM 繚 璈?.data 繚 �?.bss 繚 �?��歇�?繚 �?��征�?>
<span class="mem-seg mem-seg-iram" id="memSegIram"></span>
<span class="mem-seg mem-seg-data" id="memSegData"></span>
<span class="mem-seg mem-seg-bss" id="memSegBss"></span>
<span class="mem-seg mem-seg-used" id="memSegUsed"></span>
<span class="mem-seg mem-seg-free" id="memSegFree"></span>
</span>
<span class="heap-bar-pct" id="memSramPct">--</span>
</div>
<div class="heap-legend">
<span class="heap-legend-item"><i class="mem-dot mem-dot-iram"></i>IRAM <b id="mIram">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-data"></i>.data <b id="mData">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-bss"></i>.bss <b id="mBss">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-used"></i>��歇�?<b id="mHeapUsed">--</b></span>
<span class="heap-legend-item"><i class="mem-dot mem-dot-free"></i>��征�?<b id="mHeapFree">--</b></span>
</div>
<div class="heap-detail-row">
<span>SOC 蝒堒藁: <b id="mSramSoc">--</b></span>
<span>撠暸�靽萘�: <b id="mReservedTail">--</b></span>
<span>隞餃𦛚���霈? <b id="mTaskStackTotal">--</b></span>
</div>
</div>
<div class="heap-group">
<div class="heap-group-title">��� DRAM �?<span style="font-weight:400;color:var(--text-dim);font-size:10px;">(malloc �唳旿�?</span></div>
<div class="heap-bar-row">
<span class="heap-bar-text" id="memInternalUsage">--</span>
<span class="heap-bar-track"><span class="heap-bar-fill" id="memInternalFill"></span></span>
<span class="heap-bar-pct" id="memInternalPct">--</span>
</div>
<div class="heap-detail-row">
<span>蝛粹𤦭: <b id="mInternalHeap">--</b></span>
<span>��雿𡒊征�? <b id="mInternalMinHeap">--</b></span>
<span>��憭批�: <b id="mInternalLargestBlock">--</b></span>
</div>
<div class="heap-detail-row">
<span>DMA 蝛粹𤦭: <b id="mDmaFree">--</b></span>
<span>RTC ��征�? <b id="mRtcFree">--</b></span>
<span>����埈㺭: <b id="mAllocBlocks">--</b></span>
</div>
</div>
<div class="status-section-title">隞餃𦛚��偌雿?<span style="font-weight:400;text-transform:none;letter-spacing:0;color:var(--text-dim);">嚗�陸�澆��?Top嚗䔶�皛烐䰻�页�</span></div>
<div class="status-task-list list-scroll-top3" id="taskStackList" title="�匧陸�澆��券�摨𧶏�暺䁅恕�曄內�?3 憿對�銝𧢲��亦��嗡�">
<div class="status-empty">蝑匧��嗆����?..</div>
</div>
<div class="status-subfold collapsed" id="statusJsonFold">
<div class="status-subfold-head" role="button" tabindex="0"
onclick="this.parentElement.classList.toggle('collapsed')"
onkeydown="if(event.key==='Enter'||event.key===' '){event.preventDefault();this.parentElement.classList.toggle('collapsed');}">
<span class="status-section-title status-subfold-title">�笔� JSON</span>
<span class="collapse-arrow">�?/span>
</div>
<div class="status-subfold-body">
<pre class="status-json" id="statusJson">--</pre>
</div>
</div>
</div>
</div>
</aside>
<!-- Toast -->
<div class="toast" id="toast">
<span class="toast-ico" id="toastIco">�?/span>
<span id="toastMsg">�滢��𣂼�</span>
</div>
<!-- app 蝒堒藁蝘毺漲嚗𡁏𧋦憿萎��芸𢆡�㕑絲 EtherCAT PDO 敺芰㴓嚗𠃑D32 韐蠘蝸嚗㚁�
敹�◆���蝘毺漲嚗�炏�蹱��∠垢�函�蝥血��嗅捐�鞉��𦒘��𠰴儐�臬��𨀣��?
銝?tabs.html / motor.html 撟嗅��嗉��交㺭>1嚗䔶�銝滚蔣�溻�?-->
<script src="../js/common/app-lease.js"></script>
<script type="module" src="../js/app.js?v=20260919a"></script>
<script type="module" src="../js/ota/console-mode.js?v=20260916d"></script>
<script type="module" src="../js/ble_ota.js?v=20260901d"></script>
<!-- ����𨅯�嚗𡁜�甇?BLE �厰僼 data-ble-state 銝?checkbox.checked
銝滢�韏?ES 璅∪�嚗��璅∪��航�鋡急�閫�膥蝻枏�銝箸唂���銝滚鉄 data-ble-state �餉�嚗剹�?
connecting ��眏 session.js click handler 霈曄蔭嚗峕迨憭�歲餈��閬���?-->
<script type="module">
setInterval(function() {
var btn = document.querySelector('.ble-launch-btn');
if (!btn || !btn.offsetParent) return;
var st = btn.getAttribute('data-ble-state');
if (st === 'connecting') return;
var toggle = document.getElementById('bleConnectToggle');
if (!toggle) return;
var expected = toggle.checked ? 'connected' : 'idle';
if (st !== expected) btn.setAttribute('data-ble-state', expected);
}, 500);
</script>
</body>
</html>