diff --git a/README.md b/README.md index ab3e8bb..ce259bb 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,29 @@ tabs.html 标签外壳 = 工具入口(GET / 会 302 到这里) pages/ 主功能页,各自引用 ../css 与 ../js lab/ 自包含实验页,零外部依赖,删文件即可移除 css/ js/ 共享样式与 ES module -scripts/ 构建辅助脚本 +scripts/ 正式自测/测量脚本(清单见下;一次性探针不入库) +docs/compose/spec/ compose 功能规格 +docs/reports/ 历史调研报告(原根目录 ECAT_*/REPORT_*) esp32_server.py 本地页面服务 + 桌面窗口外壳 esp32_app.vbs esp32_web.vbs serve.bat 三个启动入口 ``` +## scripts/ 正式清单(仅保留这些) + +| 脚本 | 用途 | +|------|------| +| `build_mem.bat` | Git Bash 下构建 ESP32_COMM | +| `test_motor_transport.mjs` | 双链路传输契约 | +| `test_motor_refresh.mjs` | 刷新速度每链路一份(纯逻辑) | +| `test_ecat_autostart.mjs` | 自动接入链条(stub) | +| `test_app_lease.py` / `test_app_lease_e2e.mjs` | 关窗停总线 | +| `test_esf_pack.py` | PDO 快发 ESF1 打包 | +| `check_esf_latency.py` / `check_latency_breakdown.py` / `check_e2e_click_motion.py` | 快发与点击延迟测量 | +| `browser_check_{refresh,tick,floor,period}.mjs` | 浏览器侧 DOM/节拍实测 | +| `probe_ecat_slot_atomicity.py` / `probe_ecat_vs_wifi.py` | 可复用采样器(gitignore 白名单) | + +现场 `_tmp_*` / `skip_*` / `anal_*` 等一次性脚本**不入库**;历史报告在 `docs/reports/`。 + ## 页面 `tabs.html` 是单窗口多标签外壳,用**多 iframe 常驻保活**承载下列功能页:每个标签一个懒创建 iframe,切换只改可见性、不销毁文档(否则页内 WebSocket/轮询会随导航全灭)。激活标签记忆在 @@ -51,7 +69,12 @@ esp32_app.vbs esp32_web.vbs serve.bat 三个启动入口 ## 目录约定 - `css/` —— `base`(变量/基础)、`layout`、`components`、`can`、`motor`、`responsive`。 -- `js/common/` —— 跨页公用:`base-url`(设备 IP)、`connection`、`polling`、`log`、`toast`、`utils`、`heap-low-history`。 + **所有权**:`.btn` 共享 chrome 在 `layout.css`;`components.css` 管跨页 `.toast` + (居中单条);`motor.css` 的 `.btn` / `.toast-container` 是电机页主题覆盖与 + 堆叠 Toast,**不要**再往 layout/components 抄一份电机专用规则。 +- `js/common/` —— 跨页公用:`base-url`(设备 IP)、`connection`、`polling`、`log`、 + `toast`(居中)、`toast-stack`(容器堆叠,电机页)、`ecat-bus`(ECAT 接入策略单点)、 + `device-link`、`utils`、`heap-low-history`。 - `js/ota/`、`js/ble/`、`js/can/`、`js/motor/` —— 按功能域拆分的 ES module,跨域引用只走 `js/common/`。 - 子系统配色:ESP32 = 青绿 · GD32 = 琥珀 · BLE = 蓝 · CAN = 绿 · 内存/调试 = 紫。 diff --git a/css/components.css b/css/components.css index 7aed718..5f86a1b 100644 --- a/css/components.css +++ b/css/components.css @@ -613,7 +613,9 @@ } /* ================= Toast ================= */ +/* 跨页居中 Toast(#toast / #toastIco / #toastMsg)。电机页堆叠 Toast 见 motor.css .toast-container */ .toast { + position: fixed; top: 45%; left: 50%; transform: translateX(-50%) translateY(30px); z-index: 9999; diff --git a/css/layout.css b/css/layout.css index 70fffa2..23ae82d 100644 --- a/css/layout.css +++ b/css/layout.css @@ -196,7 +196,9 @@ select option { background: var(--bg-panel); color: var(--text); } .input-group .input { flex: 1; } /* ================= 按钮 ================= */ +/* 共享 .btn chrome(OTA/CAN 等页)。电机页主题按钮在 motor.css,勿互相复制。 */ .btn { + display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 9px 17px; border: none; border-radius: var(--radius-sm); font-family: var(--font-display); diff --git a/css/motor.css b/css/motor.css index fd0febb..3751a71 100644 --- a/css/motor.css +++ b/css/motor.css @@ -109,7 +109,9 @@ label { display: block; } border-color: var(--border-strong); } .toolbar-right a.btn:hover { color: var(--primary); border-color: color-mix(in srgb, var(--seed-primary) 40%, transparent); } +/* 电机页主题 .btn —— 与 layout.css 共享 chrome 刻意分离(页面级覆盖),勿抄进 components */ .btn { + display: inline-flex; align-items: center; gap: 6px; padding: 6px 14px; border-radius: var(--radius-sm); font-size: 0.85rem; font-weight: 550; letter-spacing: 0.02em; @@ -654,7 +656,9 @@ label { display: block; } .sb-last-send { margin-left: auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%; color: var(--fg-dim); } /* ═══════════════════════ TOAST & MODAL ═══════════════════════ */ +/* 电机页堆叠 Toast 容器 —— 与 components.css 居中 Toast 是两套 UI,勿合并。 */ .toast-container { + position: fixed; bottom: 60px; left: 50%; transform: translateX(-50%); display: flex; flex-direction: column; gap: var(--sp-2); z-index: 1000; pointer-events: none; diff --git a/ECAT_BEAT_TAIL_REPORT.html b/docs/reports/ECAT_BEAT_TAIL_REPORT.html similarity index 100% rename from ECAT_BEAT_TAIL_REPORT.html rename to docs/reports/ECAT_BEAT_TAIL_REPORT.html diff --git a/ECAT_RATE_TRADEOFF.html b/docs/reports/ECAT_RATE_TRADEOFF.html similarity index 100% rename from ECAT_RATE_TRADEOFF.html rename to docs/reports/ECAT_RATE_TRADEOFF.html diff --git a/ECAT_RATE_TRADEOFF.md b/docs/reports/ECAT_RATE_TRADEOFF.md similarity index 100% rename from ECAT_RATE_TRADEOFF.md rename to docs/reports/ECAT_RATE_TRADEOFF.md diff --git a/GD32_OTA_FLOW_COMPARE.html b/docs/reports/GD32_OTA_FLOW_COMPARE.html similarity index 100% rename from GD32_OTA_FLOW_COMPARE.html rename to docs/reports/GD32_OTA_FLOW_COMPARE.html diff --git a/REPORT_ecat_skip_opt_20260917.md b/docs/reports/REPORT_ecat_skip_opt_20260917.md similarity index 100% rename from REPORT_ecat_skip_opt_20260917.md rename to docs/reports/REPORT_ecat_skip_opt_20260917.md diff --git a/lab/ecat_integral_report.html b/docs/reports/ecat_integral_report.html similarity index 100% rename from lab/ecat_integral_report.html rename to docs/reports/ecat_integral_report.html diff --git a/lab/_last_gd32_sha.txt b/lab/_last_gd32_sha.txt deleted file mode 100644 index 4b342f8..0000000 --- a/lab/_last_gd32_sha.txt +++ /dev/null @@ -1 +0,0 @@ -c6827f84e9b8fa07288d0fc2081d0efc48a6ef2c5b8124b85a406f3a7a02042a \ No newline at end of file diff --git a/lab/ecat_calib.json b/lab/ecat_calib.json deleted file mode 100644 index 8135ea0..0000000 --- a/lab/ecat_calib.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "url": "http://127.0.0.1:8090", - "started_at": "2026-09-08 02:45:39", - "seconds": 20.0, - "sample_hz": 10.0, - "logical_cpus": 28, - "native_pid": 29284, - "native_pid_error": null, - "firmware": { - "ledger": "201832b5a8e258d6eec8d7f6620bab2c77d519e7321b25b80f7690ab2e3364ce", - "ledger_path": "G:\\Robot_v2\\DCU\\tools\\ESP32\\lab\\_last_gd32_sha.txt", - "match": null, - "candidates": [ - { - "path": "G:\\Robot_v2\\DCU\\DCU_APP\\out\\GD32E508_DCU_APP\\GD32E508VE\\Release\\GD32E508_DCU_APP.hex", - "sha256": "63d6ab9be96512cc", - "mtime": 1788805893 - }, - { - "path": "G:\\Robot_v2\\DCU\\DCU_APP\\out\\GD32E508_DCU_APP\\GD32E508VE\\Debug\\GD32E508_DCU_APP.hex", - "sha256": "e6a6e75fc5f746fc", - "mtime": 1788605679 - } - ], - "method": "hex_to_flat + sha256" - }, - "cadence": { - "n": 512, - "period_ms": 1, - "count_hist": { - "1": 2, - "2": 509, - "3": 1 - }, - "count_max": 3, - "lost_hist": { - "0": 512 - }, - "lost_max": 0, - "pending_hist": { - "0": 512 - }, - "pending_max": 0, - "backlog_hist": { - "0": 512 - }, - "backlog_max": 0, - "wkc_hist": { - "3": 512 - }, - "wkc_max": 3, - "span_ms": 511.0, - "lambda_per_s": 3998.0, - "gseq_per_s": 3998.0 - }, - "loop_start": { - "how": "已在跑", - "ok": true - }, - "period_ms_set": 1.0, - "pcore_mask": 16, - "psutil": true, - "dur_s": 20.08, - "iters": 200, - "errors": 0, - "drop_untrusted_samples": 0, - "period_ms_effective": 1.0, - "wkc": [ - 3, - 3 - ], - "wr_end": 0, - "native_pid_end": 29284, - "pid_stable": true, - "layout_seen": { - "win": 200 - }, - "rx_batch_count_hist_http": { - "2": 200 - }, - "window_coverage": { - "per_id": { - "131329": { - "n_obs": 584, - "span": 79949, - "coverage_pct": 0.73 - }, - "196865": { - "n_obs": 416, - "span": 79945, - "coverage_pct": 0.52 - } - }, - "ids": 2, - "note": "覆盖率仅说明观测密度,不可当丢帧率引用" - }, - "can_lambda_per_s": 3992.8, - "drop_per_s": 3992.8, - "drop_pct_of_lambda": 100.0, - "achieved_hz_p50": 998.2, - "achieve_pct": 99.8, - "skip_delta": 40, - "skip_per_s": 1.99, - "skip_total_cum": 449, - "rx_torn_delta": 0, - "rx_torn_capped": false, - "pdo_reentry_delta": 0, - "pdo_reentry_capped": false, - "cyc_us_total": { - "p50": 125.0, - "p90": 137.1, - "max": 2119.2 - }, - "cyc_us_late_lost_sample": { - "p50": 125.6, - "p90": 138.4, - "max": 1363.0 - }, - "gd32_load_pct_p50": 44.3, - "host_cpu_1core_p50": 100.8, - "host_cpu_total_p50": 3.6, - "per_cycle_cap_observed": 3, - "capacity_model": { - "lambda_per_s": 3992.8, - "per_cycle_cap": 3, - "drain_per_s_at_current_T": 3000.0, - "knee_ms_if_linear": 0.751, - "note": "cap 取自 cadence 环实测 count 峰值;拐点以扫描实测为准,此值仅供事后对照" - }, - "power": { - "drop_rx_queue": true, - "skip_total": true, - "achieve_deficit": false, - "rx_torn": false, - "pdo_reentry": false, - "cadence_lost_or_pending": false, - "cyc_us_late_lost": false - } -} \ No newline at end of file diff --git a/lab/ecat_rate_sweep.png b/lab/ecat_rate_sweep.png deleted file mode 100644 index 6cb4d32..0000000 Binary files a/lab/ecat_rate_sweep.png and /dev/null differ diff --git a/lab/ecat_rate_sweep_nocan.png b/lab/ecat_rate_sweep_nocan.png deleted file mode 100644 index 88fec1f..0000000 Binary files a/lab/ecat_rate_sweep_nocan.png and /dev/null differ diff --git a/lab/ecat_rate_sweep_nocan_vs.png b/lab/ecat_rate_sweep_nocan_vs.png deleted file mode 100644 index d27ebf7..0000000 Binary files a/lab/ecat_rate_sweep_nocan_vs.png and /dev/null differ diff --git a/pages/can.html b/pages/can.html index 9adf7a7..ef6dbc5 100644 --- a/pages/can.html +++ b/pages/can.html @@ -3,12 +3,12 @@
-