docs: 新增 .qoder Repowiki 知识库文档

This commit is contained in:
cbb
2026-09-07 12:19:26 +08:00
parent 43d42ad891
commit ef9472334a
105 changed files with 1313322 additions and 263 deletions
@@ -0,0 +1,28 @@
schema_version: 1
module_path: scripts_and_tests
title: ECAT 调试、固件刷写与端到端测试脚本集
scope:
- scripts/
source_files: []
depends_on: []
related_to:
- path: python_server
reason: 脚本 test_app_lease_e2e.mjs 等连接本地页面服务器的 /ws/app-lease 端点做端到端断言(端口探测与 POST 触发)。
kk_module_id: adba262f-05b7-4a9b-ba4f-3edc007d80fb
kk_ordinal: 3
kk_cards:
architecture_design:
id: 51246f25-7864-40cd-812b-3af7b95b1e02
title: ECAT 调试、固件刷写与端到端测试脚本集
coding_conventions:
id: 86785324-6a18-4cc3-8952-47c808437f14
title: ECAT 调试、固件刷写与端到端测试脚本集
overview:
id: 13d0dd8e-2f0f-4d11-89de-5f07971aed07
title: ECAT 调试、固件刷写与端到端测试脚本集
tech_stack:
id: 70c89e3a-602b-425b-8570-86d077473604
title: ECAT 调试、固件刷写与端到端测试脚本集
unique_setup_and_commands:
id: f9104fb6-b2a4-4696-9135-8ed0b2ead005
title: ECAT 调试、固件刷写与端到端测试脚本集
@@ -0,0 +1 @@
纯 Python + Node.js + PowerShell + Batch;通过 urllib/socket/raw HTTP 轮询 ESP32 服务的 `/ota/*`、`/api/motor/state`、`/motor/state?bin=1` 以及 WebSocket 接口;ECAT 撕裂检测采用“同 seq 多份 payload”不变量 + 字段跳变 p99 尺度的双判据。
@@ -0,0 +1,5 @@
本模块为独立的辅助脚本集,按功能分为四层:
- 固件与设备操作层:`flash_gd32.py` 通过 HTTP 把 Intel HEX 展平 BIN 并经由 ESP32 OTA 中继写入 GD32,轮询 `/system/status` 确认 `GD32_COMPLETE` 后写台账 `_last_gd32_sha.txt`;`build_mem.bat` / `cpu_sample.ps1` / `wv2_roles.ps1` 分别负责 IDF 构建与 Windows 进程采样。
- ECAT 数据采集与诊断层:`rec_ecat_slots.py` 以固定频率轮询服务 `/api/motor/state`,去重落盘到 CSV(M/F/H 三类行),作为后续分析的唯一输入;`probe_ecat_slot_atomicity.py` 在此基础上做同一 seq 重复读的撕裂判定;`probe_ecat_vs_wifi.py` 将 ECAT 帧与 WiFi 二进制 `/motor/state?bin=1` 对照,逐字节验证一致性;`anal_ecat_jumps.py` 基于 p99 尺度+孤立尖峰形态检测撕裂,并提供 `--selftest` 注入混合帧的灵敏度自检。
- 服务端行为验证层:`test_app_lease.py` 通过 `sys.path.insert` 直接 import `esp32_server`,用假 `_ecat_post/_ecat_find_port` 启动真实 HTTP 服务,模拟 WS 租约建立/Grace 重连/进程退出等场景断言 EtherCAT 循环启停;Python 版的浏览器 E2E 用例由对应 `.mjs` 借助 CDP (`ws://127.0.0.1:9333`) 操控 WebView 页面执行断言。
- 依赖方向单向向外:所有脚本只读本地文件与服务 HTTP API,不反向修改业务代码;采集与分析脚本之间通过固定 CSV 格式(`ecat_slots_raw.csv`)解耦。
@@ -0,0 +1 @@
面向 DCU/ESP32 平台的运行期工具与测试集合:含 GD32 固件刷写、ECAT 撕裂检测与分析、内存批化仿真、浏览器 E2E 用例及 Windows 性能采样。
@@ -0,0 +1,5 @@
- 刷写 GD32:`python scripts/flash_gd32.py [期望版本]`,需先 `idf.py build` 产出 `DCU_APP/out/GD32E508_DCU_APP/GD32E508VE/Release/GD32E508_DCU_APP.hex`,并通过 `DCU_ESP_IP` 环境变量指定目标 IP
- ECAT 撕裂检测:先跑 `python scripts/rec_ecat_slots.py [秒数] [端口] [输出csv]` 生成原始流,再 `python scripts/probe_ecat_slot_atomicity.py [端口] [秒数]` 或 `python scripts/anal_ecat_jumps.py ecat_slots_raw.csv [--k 8] [--selftest]`
- ECAT vs WiFi 对比:`python scripts/probe_ecat_vs_wifi.py [秒数]`,要求本机同时提供 ECAT 状态 JSON 与 ESP32 WiFi 二进制接口
- 浏览器 E2E:先起 `node --inspect-brk` + Chrome DevTools,再以 CDP 端口 9333 连接后执行各 `browser_check_*.mjs`;`test_app_lease.py` 可直接 `python scripts/test_app_lease.py`
- Windows 性能:`scripts/cpu_sample.ps1` 统计 `msedgewebview2|ecat_native|pythonw|python` 进程 CPU/WorkingSet
@@ -0,0 +1,6 @@
- 脚本入口统一为 `if __name__ == "__main__": main()` 模式,命令行参数通过 `sys.argv` 顺序解析(支持可选的端口、时长等)。
- HTTP 客户端封装为顶层函数(如 `post/get` 或 `once()`),统一处理超时、`HTTPError` 与 UTF-8 解码替换,避免重复样板码。
- ECAT 数据采集类脚本使用 TCP socket 直接拼接 HTTP 请求头并发出 POST,收到空字节流后再 `partition(b"\r\n\r\n")` 解析 JSON 体。
- 长耗时运行通过 `while time.time() - t0 < DUR_S` 形式的时间窗口控制退出,错误路径一律 `except Exception: continue` 容错而非中断。
- 大量去重/缓存场景采用 dict/set 并配合定期截断(如 `len(seen_m) > 400000` 时取尾部 200000 项),控制内存增长上限。
- 断言式测试使用 `assert ... raise AssertionError(...)` 配合 PASS/INFO 日志串联用例,失败即非零退出码,便于 CI 集成。
@@ -0,0 +1,26 @@
schema_version: 1
module_path: js_frontend/ble
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
scope:
- js/ble/
source_files: []
depends_on: []
related_to: []
kk_module_id: e695976e-f72c-4d3a-867b-fb80827337d8
kk_ordinal: 2
kk_cards:
architecture_design:
id: e5ac84aa-1a14-4238-840f-63cc430d2c4c
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
coding_conventions:
id: a5fa8c1f-0636-432f-a5f4-9b973378b212
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
overview:
id: 4a0792d4-88cf-45fa-86ab-ddce531e07e2
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
tech_stack:
id: b1c611b2-296d-4545-adf6-acf77eeaa116
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
unique_setup_and_commands:
id: 5d391cf3-8e98-4ea3-90bb-b48da99b4259
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
@@ -0,0 +1 @@
Web Bluetooth API(navigator.bluetooth.requestDevice / GATT Server + Characteristic + notify),配合 File System Access API(showOpenFilePicker)支持热重载;通过 0xA1 ACK + 64 窗口 ACK_WINDOW 实现流控。
@@ -0,0 +1 @@
模块按职责划分为八个 ES 模块文件,依赖方向单向:`constants.js` 集中定义 GATT UUID、OTA 协议码(ACK/FINISH/SHA256/CTRL)及 `TARGETS.{esp32,gd32}` 配置,作为所有其他文件的常量来源;`state.js` 维护全局状态(device/server/characteristic 引用、上传标志、ackWaiter、会话标识等)并提供 DOM 元素缓存与通用工具(bleLog/toHex/sleep 等);`gatt.js` 实现 BLE 生命周期(connectBle/disconnectBle/readVersion/onDisconnected)以及 GATT notify 分发 `handleNotify`,将协议事件路由至 transfer/session/verify;`transfer.js` 实现数据面:buildPacket 打包 seq+totalSize+payload+CRC、ACK 等待 Promise 封装 waitForAck、进度刷新 updateProgressFromAck;`session.js` 管理多轮 OTA 结果等待(waitForOtaResult/nextOtaSessionId/finishBelongsToWaiter)与 abort 流程;`stages.js` 提供 1~6 阶段状态栏的 UI 操作(setBleStage/setBleStageError/updateBleStageLabels),被 gatt/transfer/file 共同消费驱动动画;`file.js` 统一文件入口,处理 HEX→BIN 转换、GD32 包身份检测、SHA-256 缓存,并在 upload 中屏蔽重复选择;`verify.js` 仅暴露 show/hide 校验信息面板的方法。跨通道(BLE/WiFi)通过 `connectionMode` 变量与共享 DOM id(progressFill/logScroll 等)协作,确保界面一致性。
@@ -0,0 +1 @@
基于 Web Bluetooth API 实现 ESP32/GD32 双目标设备的 BLE 固件在线升级,负责 GATT 连接、分包传输、ACK 窗口与 SHA-256 校验。
@@ -0,0 +1 @@
BLE 连接必须在用户手势内触发(click handler 中使用 `e.preventDefault()` 保证 navigator.bluetooth.requestDevice 合法);需浏览器启用 `web-bluetooth` 权限并过滤 namePrefix 为 'ESP32-OTA'。
@@ -0,0 +1,6 @@
- 协议常量集中声明于 constants.js,并以命名空间式导出(如 BLE_OTA_NOTIFY_ACK、BLE_OTA_FINISH_ERR_*、TARGETS.*),所有业务模块通过 import 使用而非魔法数字硬编码。
- DOM 节点在 state.js 启动时一次性缓存到 els 对象,高频路径直接读取属性,避免重复 getElementById;stages.js 对共用状态栏也采用首读缓存 + isConnected 失效回退模式。
- 阶段 UI 通过 stages.js 的 setBleStage(stageNum, detail, barState) 统一推进,错误路径使用 setBleStageError(detail) 将当前 active 节点标记 err,禁止各模块自行修改 className。
- 异步长耗时操作采用“waiter”模式:用 state.ackWaiter / state.otaResultWaiter 存储 resolve/reject + timer,超时或中止时主动清除并 reject,防止悬挂 Promise。
- 日志输出统一经 state.bleLog(tag, message, level) 封装后注入 common/log.js 的 addLog,标签前缀固定为 'BLE-*',便于侧边栏筛选。
- 跨通道状态判断使用 isBleUploading()(state.uploading || state.autoFlashing)与 window.isUploading 组合判定,避免单个通道上传时另一通道 UI 被意外重置。
@@ -0,0 +1,27 @@
schema_version: 1
module_path: js_frontend/can
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
scope:
- js/can/
- js/can_monitor.js
source_files: []
depends_on: []
related_to: []
kk_module_id: b5c93572-2980-4d8b-abcb-49299366edc6
kk_ordinal: 4
kk_cards:
architecture_design:
id: 8c1ea8cb-f95b-48ee-856a-50f8336e3eea
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
coding_conventions:
id: cee80565-5287-44a1-881b-e9087ff9c0ed
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
overview:
id: ee9c08d3-0aed-4e95-8a7f-f446a2debab4
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
tech_stack:
id: 7d94fd27-c122-4f4b-a175-b9c7ac60a3ad
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
unique_setup_and_commands:
id: 7b2bd04a-c5d6-4bce-954b-193adc49892a
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
@@ -0,0 +1 @@
纯浏览器端 JavaScript(ES Module),使用 TextDecoder('utf-8' | 'gb18030') 解析 DBC 文件、localStorage 会话存储、AbortController+setTimeout 双超时控制 fetch、Clipboard API 降级 execCommand 回退。
@@ -0,0 +1,8 @@
模块按职责拆分为五个 ES Module,依赖方向单向收敛于 `dbc.js`:
- `dbc.js` 为基础设施层,导出共享 state/el、IP 工具、字节格式化工具,以及 DBC 文本读取(UTF-8 / GB18030/BOM 自动回退)和 DBC 解析器(BO_/SG_/CM_/VAL_ 行 → { messages, nodeNames, messageMap }),不依赖其他 can 子模块。
- `messages.js` 负责报文列表渲染、关键字与发送节点筛选、节点过滤面板 UI 及批量选择。
- `signals.js` 基于 DBC 信号定义生成内联信号表格,维护 signalValues bag,处理 Motorola/Intel 位序、有符号/无符号、枚举、因子/偏移编解码,并维护当前选中报文的编码预览。
- `send.js` 作为 HTTP 出口,统一通过 `fetch(getBaseUrl() + '/can/send_batch')` 发原始帧或构造后的批量帧,封装错误码映射(CAN_SEND_ERR_DESC / GD32_ERR_DESC),维护发送历史与剪贴板复制。
- `persist.js` 将多 DBC 原文、signalValues、checkedKeys/expandedKeys、transmitterFilter、history、表单状态序列化到 localStorage(键 `dcu_can_session_v1`),并以防抖 `scheduleCanPersist()` + 失败时逐步砍历史/信号值的方式保证写入安全;恢复时逆向重建 DBC。
- `can_monitor.js` 是独立的 1Hz 轮询入口,调用 `/can/feedback` 获取 3 路 CAN 通道 RX/TX/Drop/Err/TEC/REC/bus_state/entries,渲染三卡片及 ID snap 表,可被 `can.html` 右侧抽屉复用。
模块间通过 ES Module live binding 共享 `state` 与 `el`,避免重复缓存 DOM 与状态副本。
@@ -0,0 +1 @@
实现浏览器端 CAN 调试工具的 DBC 文件解析、报文过滤/信号编辑、批量帧发送与会话持久化,并提供独立页的 CAN 通道反馈轮询监控。
@@ -0,0 +1 @@
无需构建步骤;直接由网页加载 ES Module。`readDbcText` 支持 UTF-8 优先、GB18030 回退并去除 BOM,用于本地拖入的 .dbc 文件;`parseDbc` 自行解析 BO_/SG_/CM_/VAL_ 标准 DBC 片段。
@@ -0,0 +1,6 @@
- 跨子模块共享可变状态与 DOM 引用集中放在 `dbc.js` 导出的 `state`/`el` 对象上,各子模块通过 import 获取同一引用,利用 ES Module live binding 保证同步。
- 对外部不可信文本一律使用 `escapeHtml`/`sanitizeHtml` 后再插入 innerHTML,所有数据属性赋值前先经 `escapeHtml`,禁止拼接 HTML 字符串直接使用用户输入。
- 网络请求统一使用 `new AbortController()` + `setTimeout` 双保险取消,防止在连接 reset 等边缘场景下 await 永久挂起。
- 高频本地持久化采用「收集事件 → scheduleCanPersist → 防抖定时器 → saveCanSessionNow」模式,并在 writePayload 失败时逐级减少 payload(压缩历史→清 signalValues)以容忍 localStorage 配额不足。
- DLC/字节数组输出统一走 `padHex(value, width)` 与 `bytesToHex(bytes)`,确保十六进制展示宽度一致、全大写。
- 错误信息分层展示:完整描述走 buildSendResponseText,简短文案走 buildSendResponseShort 去掉冗余前缀,使历史记录空间有限时仍保留核心原因。
@@ -0,0 +1,23 @@
schema_version: 1
module_path: js_frontend
title: ESP32 DCU 前端 Web 控制台集合
scope:
- js/
source_files: []
depends_on: []
related_to: []
kk_module_id: 34c369aa-9944-449c-bc32-3fb459da6f08
kk_ordinal: 2
kk_cards:
architecture_design:
id: 0226951f-1a73-43f5-adb5-ded1b74dbe63
title: ESP32 DCU 前端 Web 控制台集合
coding_conventions:
id: 66764ffe-f832-4992-a6b4-064aab166812
title: ESP32 DCU 前端 Web 控制台集合
overview:
id: 8298ce61-963b-4a66-b17b-8293a4472e54
title: ESP32 DCU 前端 Web 控制台集合
tech_stack:
id: 22e24b2a-6f8d-4d54-b181-e2ec9ff24243
title: ESP32 DCU 前端 Web 控制台集合
@@ -0,0 +1,28 @@
schema_version: 1
module_path: js_frontend/ota
title: 前端 OTA 刷写会话与进度管理
scope:
- js/ota/
source_files: []
depends_on: []
related_to:
- path: js_frontend/ble
reason: 两者均为浏览器端固件升级方案:js/ota 走 WiFi ESP32 HTTP(分块上传+SHA-256),js/ble 走 Web Bluetooth GATT(分包 ACK+窗口+SHA-256),同一业务目标的不同实现。
kk_module_id: 697d6afd-9c08-42a6-900d-2b51dd09c507
kk_ordinal: 1
kk_cards:
architecture_design:
id: 7e17f40a-f0ea-4d4d-bba0-99559868e617
title: 前端 OTA 刷写会话与进度管理
coding_conventions:
id: 79bc6166-c07c-4910-b704-f898340b0b69
title: 前端 OTA 刷写会话与进度管理
overview:
id: 95c1a351-1033-42a9-a77b-086cd3d5186c
title: 前端 OTA 刷写会话与进度管理
tech_stack:
id: b16589eb-b0da-4e30-960e-4a0d3b051ed3
title: 前端 OTA 刷写会话与进度管理
unique_setup_and_commands:
id: 93240d0d-1e8c-4a7d-9f5f-9e26a332988e
title: 前端 OTA 刷写会话与进度管理
@@ -0,0 +1 @@
纯浏览器端 JavaScript (ES Module),使用 IndexedDB 持久化 FileSystemFileHandle 实现刷新后热重载恢复;XHR+fetch 混合进行文件分块上传;通过 ES import 引入 ../common/*(log、toast、utils、connection)。
@@ -0,0 +1,5 @@
模块以**集中式会话状态机**(session.js)为核心,定义 IDLE→UPLOADING/VERIFYING/RELAYING/REBOOTING→DONE/FAILED 的状态流转,所有 UI、上传、轮询通过 window.* 全局总线共享 otaSessionState / otaSessionTarget / activeUploadChip 等标志,避免分散布尔位导致的“网络错误后轮询覆盖”问题。
- 入口编排:console-mode.js 接管 switchStageFlow,提供 WiFi/BLE/ESP32/GD32 多通道目标切换与共享固件文件同步;upload-esp32.js 作为统一入口 startUpload(chip) 处理互斥探测、热重载重读、XHR 分块上传、SHA-256 校验与设备重启。
- 后端协议:upload-gd32.js 仅负责 POST /ota/relay 触发 GD32 中继,并通过 emitRelayProgress/markGd32OtaUiComplete/startRelayProgressWatch 与 stages.js 中的 status 轮询路径协同;ECT 负载显示由独立的 ecat_load.js 基于 /ecat/api/app/load 退避轮询。
- UI 层:progress.js 维护折叠面板、阶段节点 es1..es6/s1..s6 与进度条;stages.js 把 relay_state/sys_state_code 映射到 GD32 阶段节点并调用 progress 更新仪表盘;file-handle.js 封装 HEX→BIN、IndexedDB FSAPI handle 持久化、localStorage 偏好(flashTarget、文件元信息)。
- 依赖方向单向:console-mode → upload-* → session + progress + file-handle,stages/ecat_load 消费 session/progress,无任何反向引用。
@@ -0,0 +1 @@
为 ESP32/GD32/DPU 提供浏览器侧的固件选择、分块上传、校验、中继触发与会话状态机,并渲染阶段节点与进度条。
@@ -0,0 +1 @@
无构建脚本——模块由 HTML 页面直接按模块加载;EtherCAT 负载显示需主站 esp32_server 打开 ECAT native 循环并提供 /api/app/load,本模块仅做 100ms 退避轮询(失败→5s→30s),不强制拉起后端。
@@ -0,0 +1,6 @@
- 跨模块共享可变状态统一挂载在 window.* 上(如 isUploading、activeXhr、otaSessionState、activeUploadChip),各模块通过导入函数访问,而非显式传参。
- 所有会话生命周期变更必须经由 session.js 的 otaSessionTransition() 驱动,禁止直接修改窗口标志,保证是Uploading/Verify/Reboot/Done/Fail 等终态时自动清理按钮、阶段与定时器。
- 失败路径统一调用 progress.cleanupAfterOtaFailure(reason) 进入 FAILED 态并清除残留 DOM/定时器/进程句柄,使后续 status 轮询不会覆盖失败 UI。
- DOM 写入采用「先比较后写入」模式(setNodeText/setNodeClass/setTitle)或缓存 lastDisplayedRelayState,避免每秒轮询时无条件赋值导致样式失效重排。
- 长耗时用户操作(选文件、热重载、请求)均包裹 try/catch 并以 addLog('W'/'E','OTA'/'文件',...) 记录,同时用 showToast 给出用户可见反馈,区分日志与提示。
- 轮询器以幂等的 start*/stop* 成对暴露(stopRelayProgressWatch、startUploadWaitHeartbeat、startEcatLoadPoller),内部持 timerId 并在页面无对应元素或已运行时直接 return,避免重复调度。
@@ -0,0 +1,22 @@
schema_version: 1
module_path: js_frontend/common
title: 前端公共工具库(连接/轮询/日志/Toast/IndexedDB)
scope:
- js/common/
source_files: []
depends_on: []
related_to: []
kk_module_id: 83fe5acc-8cc9-4cca-8aa5-93ffb96585bf
kk_cards:
architecture_design:
id: 985b41f4-d6f1-4ff0-b9c0-e6ccc216fdf4
title: 前端公共工具库(连接/轮询/日志/Toast/IndexedDB)
coding_conventions:
id: 3d9852ce-9b31-4829-af73-d79d122dc321
title: 前端公共工具库(连接/轮询/日志/Toast/IndexedDB)
overview:
id: f6c3b043-050f-4761-8bb6-2fac2945de55
title: 前端公共工具库(连接/轮询/日志/Toast/IndexedDB)
tech_stack:
id: 5488e585-4aad-4812-ae92-aafb6c8ac269
title: 前端公共工具库(连接/轮询/日志/Toast/IndexedDB)
@@ -0,0 +1 @@
ES Module (`export/import`);HTTP 轮询使用原生 `fetch` + `AbortController` 实现超时取消;WebSocket 长连接由 `app-lease.js` 自持;设备事件持久化走 IndexedDB (`IDBFactory.open('esp_dream_heap_low')`,版本 1);DOM 高频更新采用 `requestAnimationFrame` 合并写入与字符串对比去变更。
@@ -0,0 +1,9 @@
模块按职责拆分为独立 ES 模块,各文件通过 `import` 组合,不相互强耦合:
- `connection.js`:封装 DOM 渲染缓存(`elCache`、`set*IfChanged` 写前比较)和 `/system/status` UI 更新(连接胶囊、健康态、启动自检面板),是上层业务页渲染的核心。
- `polling.js`:基于递归 `setTimeout` 的轮询调度器,维护 `/system/status` 与 `/logs` 双通道 in-flight 锁、5s `AbortController` 超时、上传期暂停、Page Visibility 感知,并协调 OTA 状态机;导出 `startPolling / scheduleStatusPoll / pausePollingForUpload` 等生命周期 API。
- `log.js`:带去重 + 自动滚动 + 环形缓冲(`MAX_LOGS=1000`)+ rAF 批量滚动的控制台。
- `toast.js`:支持 success/error/warning 三类弹窗,含 5s 去重防抖 + 3s 自动隐藏。
- `heap-low-history.js`:基于 IndexedDB (`esp_dream_heap_low`) 持久化“最低空闲内存”创新低记录,含去重 key `(ts_ms|min_free_heap|free_heap|alloc_count)`、上限裁剪与离线可用保证。
- `app-lease.js`:自执行 IIFE 建立到 `/ws/app-lease` 的 WebSocket 长连接并 3~30s 递增退避重连,作为服务端停 EtherCAT 循环的窗口凭证。
- `base-url.js` / `utils.js`:纯函数辅助层(IP/URL 拼串、字节/时间/运行时间格式化、HTML 转义、hex 转换),被其他子模块复用,无浏览器副作用。
依赖方向:业务页 → connection/polling/log/toast → base-url/utils;只有 polling→connection 反向引用用于失败诊断,避免连接态被业务直接操作。
@@ -0,0 +1 @@
为 ESP32 DCU Web 管理端提供跨页面共享的连接状态、系统轮询、日志缓冲、提示框、IndexedDB 历史与基础 URL/格式化等通用能力。
@@ -0,0 +1,6 @@
- 对频繁读取的 DOM 节点在模块级以 `var elCache[id] = document.getElementById(id)` 方式缓存,并通过 `getEl()` 统一访问,避免每帧重复 `getElementById`。
- 文本/类名/宽度等 DOM 属性写入前先比较旧值(`textContent !== v`、`className !== cls`、元素上 `_lastW` 缓存宽度),仅在变化时才触碰样式,避免强制布局重排。
- 轮询器统一用递归 `setTimeout` 而非 `setInterval` 调度,并在每次回调末尾按 `max(0, interval - elapsed)` 重新挂载下一次任务,保证周期稳定且不会因慢响应重叠。
- 所有通过 `innerHTML` 渲染的用户可控文本均先经 `escapeHtml` 转义,防止注入。
- 需要幂等的 UI 绑定(如健康启动面板切换按钮)通过 HTML 自定义属性(如 `dataset.bootToggleBound === '1'`)标记是否已处理,避免重复 `addEventListener`。
- 可选 API(如 Toast、IndexedDB、autoScroll 按钮)在执行前做存在性判断,不存在时静吞错误,保证核心轮询逻辑在无 DOM/无痕模式环境下仍可工作。
@@ -0,0 +1,30 @@
schema_version: 1
module_path: js_frontend/app_entries
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
scope:
- js/app.js
- js/ble_ota.js
- js/can.js
source_files: []
depends_on: []
related_to:
- path: python_server
reason: OTA、BLE、CAN 控制台页面均由 python_server 的静态文件服务提供,并通过 base-url.js 中 localStorage 存储的 dcu_esp_ip 以同源请求访问设备 API。
kk_module_id: d15c38ec-fd6c-4494-8521-a48360031a6b
kk_ordinal: 5
kk_cards:
architecture_design:
id: 441b093f-3154-4236-87c1-714b50c314c2
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
coding_conventions:
id: b6fef608-2072-43c3-8b54-488a03451825
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
overview:
id: 41949d5a-6e02-4b39-a0d9-23dcc19a84ee
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
tech_stack:
id: 3d5e73da-051c-455f-a5d9-9d897c816023
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
unique_setup_and_commands:
id: b4aa8897-362a-45f5-9b97-fe13dbf1072a
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
@@ -0,0 +1 @@
ES Module (type="module") + Fetch API + Web Bluetooth (GATT) + DBC/CAN 报文解析
@@ -0,0 +1,5 @@
本模块由三个互相独立的入口脚本组成,均为薄编排层:
- `js/app.js`:ESP32 WiFi OTA 控制台入口,import `ota/*`、`common/*` 等子模块后把所有交互函数显式挂载到 `window.*`,以兼容 HTML 内联 `onclick`;同时承担顶层副作用(拖拽区绑定、SPI 输入监听、状态轮询)。通过共享状态对象 `otaSessionState`、`OtaSessionState` 在 ota 子模块间传递会话信息。
- `js/ble_ota.js`:BLE OTA 控制台入口,导出单一 `window.bleOta` API 对象(含 `init/state/disconnect/isUploading` 等),调用 `ble/session.bindEvents()` 和 `state` 完成初始化。
- `js/can.js`:CAN 诊断页面入口,导入 `can/dbc.js`、`can/messages.js`、`can/signals.js`、`can/send.js`、`can/persist.js` 以及 `common/utils`、`common/toast`,通过共享的 `el`/`state` 单例在各子模块间保持最新 DOM 引用与选中状态;使用带版本戳的 `?v=` 查询参数字面量强制缓存失效(如 `send.js?v=20260801f`),同时避免在 import 路径上加版本戳导致浏览器重复实例化单例。
依赖方向:三个入口只向上暴露到 `window`,被上层 HTML 或测试脚本消费;向下仅依赖各自子目录模块与 `common/*`,无横向耦合。
@@ -0,0 +1 @@
汇总 ESP32 WiFi OTA、BLE OTA 与 CAN 诊断三个控制台页面的入口脚本,通过 ES Module import 组装子模块并将函数挂载到 window,提供统一的事件绑定与 UI 初始化。
@@ -0,0 +1 @@
模块内 import 路径禁止加 `?v=` 版本号,版本戳仅出现在 HTML `<script src>` 标签上,以避免同一模块因不同 querystring 产生双份实例(破坏 state/toast 单例);CAN 页面中向特定文件追加硬编码 `?v=...` 以强制重新加载已发布过的模块。
@@ -0,0 +1,4 @@
- 入口脚本采用「薄编排 + window 挂载」模式:import 子模块函数后集中赋值给 `window.xxx`,供 HTML 内联事件处理器或外部脚本调用。
- 各入口先构造本地工具函数(如 `getBaseUrl`、`setConnectionState`、`resetSelectionState`),再执行 DOM cache 与事件绑定,最后调用统一的 `init` 入口完成启动。
- 子模块间的共享状态与 DOM 引用通过 ESM 导出的单例对象(`state`、`el`)传递,而非全局散落的闭包。
- 对 `common/utils`、`common/toast` 等通用能力按需要局部重名导入并立即挂载到 `window`,形成稳定的跨模块 API 边界。
@@ -0,0 +1 @@
ES Module + Web Browser API(Web Bluetooth/GATT、Web Worker、IndexedDB),运行于 ESP32 内置 Web Server 托管的静态资源环境,通过 HTTP 长轮询与服务端协议通信。
@@ -0,0 +1 @@
顶层目录以功能划分为若干独立子系统:common 提供跨子模块复用的 connection/polling/log/toast/utils;app_entries(js/app.js、can_monitor.js、ble_ota.js)作为单页应用入口,通过 ES Module import 将各子系统(ota/ble/motor/can)组合到 window 命名空间并绑定 UI 事件;各子系统内部自包含业务逻辑,如 ota 定义固件升级会话阶段,ble 基于 GATT 通道驱动同一流程,motor 通过 transport-ecat/wifi 可插拔传输层抽象驱动状态机。各子系统之间不直接互相 import,而是由浏览器加载的脚本各自按需引入 common,形成“入口聚合 + 功能隔离”的多页式架构。
@@ -0,0 +1 @@
汇聚 OTA、BLE、电机控制与 CAN 诊断等多个浏览器端控制台页面,共享连接、轮询、日志等公共能力并通过 app 入口聚合装配。
@@ -0,0 +1,27 @@
schema_version: 1
module_path: js_frontend/motor
title: 电机控制台多传输模块
scope:
- js/motor/
source_files: []
depends_on: []
related_to:
- path: js_frontend/can
reason: CAN 控制台与电机控制台均通过 POST /can/send_batch 发送帧到 ESP32 设备,但 CAN 用于通用报文编辑而电机用于特定 CMD/CONFIG 控制流程。
- path: python_server
reason: 电机控制台通过 /ecat/api/* 反向代理访问本地 ecat_native.exe 的 /api/motor/*(transport-ecat.js 中拼接路径发送)。
kk_module_id: 71087b31-4c6d-4a07-8d58-1f3e348444bf
kk_ordinal: 3
kk_cards:
architecture_design:
id: 00c57461-8294-47bf-88b9-8c362ac14bfc
title: 电机控制台多传输模块
coding_conventions:
id: 13ef69f8-0bc9-4b61-bd64-c0fa7a39ef2c
title: 电机控制台多传输模块
overview:
id: df61a7ec-5adc-4d4f-b0e9-a2867d026ab5
title: 电机控制台多传输模块
tech_stack:
id: 1dea780b-05c9-4fe6-ad60-ffef2d6854ec
title: 电机控制台多传输模块
@@ -0,0 +1 @@
原生 JavaScript ES Module,使用 Web Worker 作为定时节拍源;WiFi 链路通过 Fetch + AbortSignal.timeout 访问设备 HTTP 端点;EtherCAT 链路经本地页面服务器的同域反向代理(绑定 127.0.0.1,无 CORS)访问后端 `ecat_native.exe` 守护进程;二进制状态协议用 DataView 解析(魔数 0x4D53,v0.70/v0.74 双版本兼容)。
@@ -0,0 +1,9 @@
模块以 `main.js` 为 ES Module 入口(由 motor.html 外提),集中维护全局 `state`(连接态、刷新间隔、解码缓存、命令序列、版本缓存等)并通过工具栏在 `wifi` / `ecat` 两条链路之间切换。
内部按职责分层:
- 传输选择层 `transport.js` 导出 `createTransport(id, ctx)` 工厂,根据 id 创建具体实现,并以 `ctx` 注入 `getBaseUrl`、`recordSlow`、`isTransient` 避免循环依赖。
- 两路传输独立实现同一契约(见 `transport-ecat.js` 头注释列出的接口表):`transport-wifi.js` 调用 ESP32 的 HTTP API(`/system/status`、`/motor/state?bin=1`、`/can/send_batch` 等);`transport-ecat.js` 经本地页面服务器 `/ecat/api/*` 反向代理到 `tools/ecat` 的 C 守护进程,完成全自动接入(自动拉起服务、打开网卡、进入 OP、起 PDO 循环)并将 EtherCAT 过程数据形状补齐为 WiFi 契约(config_data、version seq、nodeIdReport)。
- `refresh-rate.js` 抽离为纯函数库,按链路各自管理默认值/最小值/钳制/旧键迁移,使刷新策略可脱离 DOM 自测。
- `tick.worker.js` 是一个 Dedicated Worker,仅负责按指定 interval 持续投递 `tick` 消息,规避浏览器后台标签页对 setTimeout/setInterval ≥1s 节流。
依赖方向单向收敛于 `main.js` → `transport.*`;上层解码器、节点列表、STATUS 面板、波形、命令序列和全部流控策略(互斥/退避/冷却/latest-wins)完全不感知底层链路差异。
@@ -0,0 +1 @@
提供电机控制台的业务逻辑入口,通过可插拔的 WiFi/HTTP 与 EtherCAT 传输层抽象,驱动状态轮询、帧发送、命令序列与波形等共享逻辑。
@@ -0,0 +1,5 @@
- 两种传输实现统一通过工厂 `createTransport` 产出,并按相同方法签名(probe/fetchStatus/fetchMotorState/sendFrames/fetchVersionNode 等)对外暴露,主流程只调用抽象接口。
- 传输层错误对象统一附加 `.transient` 标记与可选 `.status`,由 main.js 的失败计数与断线逻辑识别,区分瞬时错误与硬失败。
- 慢请求通过注入的 `recordSlow(url, ms, errMsg?)` 回调上报,所有 fetch/POST 路径都包裹计时与记录。
- 用户偏好状态写入 localStorage 时采用「按链路分组」的 Map 结构(如 `refreshByTp`、历史 `dcu_motor_transport`),新链路扩展只需改默认表而无需改动持久化格式。
- Worker 通信仅使用 `{type, ...}` 消息体(start/update/stop 对应 tick 启停),不传递复杂对象,保持轻量心跳协议。
@@ -0,0 +1,3 @@
- 每个子系统保持自包含目录结构(会话/状态/阶段/传输分离),仅通过 common 提供的工具函数与外部解耦
- UI 交互由入口脚本统一注册到 window,子模块不直接操作 DOM 全局对象
- 设备通信均通过 common 的 polling/connection 封装进行周期性数据推送,而非自行实现定时器
@@ -0,0 +1,27 @@
schema_version: 1
module_path: python_server
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
scope:
- esp32_server.py
- esp32_app.vbs
- esp32_web.vbs
source_files: []
depends_on: []
related_to: []
kk_module_id: e6df9393-2f7e-4478-8bd9-79e0f4f83b91
kk_cards:
architecture_design:
id: f440bf26-cce8-4839-9f95-db46b9d180db
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
coding_conventions:
id: e9f360b3-eb76-441e-9f4d-595c77cf8874
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
overview:
id: 2871bc12-68a1-4218-ab17-febc24f79968
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
tech_stack:
id: 6c6357bf-8885-499f-a9ab-ff7df848bde6
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
unique_setup_and_commands:
id: e191608a-80b0-4a83-b47a-c14460f54b3a
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
@@ -0,0 +1 @@
Python `http.server` + `threading` 线程型 HTTP 服务器;pywebview (WebView2) 桌面容器;VBS (`CreateObject('WScript.Shell')`) 调用 `pythonw.exe`;Windows Job Object 管理 ecat_native.exe 生命周期;原生 C/SOEM 后端 `build_native/ecat_native.exe`。
@@ -0,0 +1,7 @@
由单个 Python 进程构成,核心是 `http.server.ThreadingHTTPServer` + `SimpleHTTPRequestHandler` 派生类:
- 路由层:根路径 302 到 `/tabs.html`,`/pages/*`、`/css/*`、`/js/*` 等走内置目录静态映射;`/ws/app-lease` 实现基于全局计数器的 app 窗口租约协议(全部断开自动停止 EtherCAT PDO 循环并从站退回 INIT);`POST /api/shutdown` 终止本服务。
- EtherCAT 反向代理:`/ecat/api/<路径>` 通过 TCP 转发到 `tools/ecat/build_native/ecat_native.exe` 的 8090–8095 端口,首次命中时按进程 ID 复用已有实例,否则以 `--parent-pid` 拉起子进程并由 Job Object 连带回收。
- 单实例互斥:通过命名互斥量 + `/api/focus` HTTP 唤醒旧实例,避免双击重复弹出。
- 前端注入:响应 HTML 时在 `</body>` 前注入 `_RELOAD_SNIPPET`,为 pywebview 提供刷新按钮、F5/Ctrl+R 键盘拦截和返回主页行为。
- 启动外壳:`esp32_app.vbs` 使用 `pythonw.exe --window` 启动 pywebview 桌面窗口(无控制台),`esp32_web.vbs` 用相同入口但以隐藏方式启动并交由系统默认浏览器打开。
依赖方向单向向下:VBScript → Python HTTP 服务 → 可选拉起的 ecat_native.exe;所有业务 API 实际由 ESP32 设备 (80 端口) 提供,本服务不直接读写硬件。
@@ -0,0 +1 @@
提供 ESP32 调试 Web UI 的静态文件服务、EtherCAT 后端反向代理与 app 窗口租约管理,并通过 VBScript 启动 pywebview 桌面窗口或浏览器标签。
@@ -0,0 +1 @@
两个 VBS 入口:双击 `esp32_app.vbs` 启动带地址栏的 pywebview 桌面窗口(`--window`),双击 `esp32_web.vbs` 以隐藏窗口模式在默认浏览器中打开;Windows 环境变量 `PYTHONUTF8=1` 由 VBS 预先设置。EtherCAT 模式会按需自动检测并拉起 `tools/ecat/build_native/ecat_native.exe`(端口 8090–8095 探测)。
@@ -0,0 +1,5 @@
- 所有对外暴露能力集中在单一 Python 主进程内:路由处理、WebSocket 租约状态、子进程管理均以模块级全局变量(如 `g_mutex`、`g_httpd`、`g_ecat_child`、`g_win`)共享,不使用类实例或配置对象。
- 子进程生命周期统一通过 Windows Job Object + `--parent-pid` 参数管理,确保父进程退出后子进程被内核连带回收。
- 对外部资源访问(旧实例焦点、ECAT 端口探测、子进程启动)一律包裹 `try/except` 并用模块级锁串行化,避免因并发导致多实例或多线程竞争。
- 响应内容增强采用注入模式:将 JS/CSS 片段作为常量字符串定义并在发送 HTML 前通过 `<meta>` 或 `</body>` 标记插入,而非生成独立中间页。
- 跨组件通信约定保持一致:VBScript 通过 `pythonw.exe <脚本> [--window]` 命令行开关切换模式,HTTP 端点统一使用 JSON body + `application/json` content-type。
@@ -0,0 +1,27 @@
schema_version: 1
module_path: frontend_pages
title: ESP32/DCU 调试控制台前端页面集
scope:
- pages/
- css/
- tabs.html
source_files: []
depends_on: []
related_to:
- path: python_server
reason: esp32_server.py 作为静态文件服务器提供 tabs.html、pages/ 与 lab/ 目录下的 HTML,页面由本服务同源 serving。
kk_module_id: d0ed905a-8c06-4326-a9e3-22a026d276f7
kk_ordinal: 1
kk_cards:
architecture_design:
id: 921fdcb0-3189-46ef-963e-539b2f5e2b3b
title: ESP32/DCU 调试控制台前端页面集
coding_conventions:
id: 4a7606c7-8beb-455d-95f1-4605e6668630
title: ESP32/DCU 调试控制台前端页面集
overview:
id: 6eafe8be-cffd-4e08-9002-1332165ffedf
title: ESP32/DCU 调试控制台前端页面集
tech_stack:
id: eb3279e1-7af2-4ade-ba37-5bb6f4118b15
title: ESP32/DCU 调试控制台前端页面集
@@ -0,0 +1 @@
纯静态 HTML + CSS + 原生 JS (无构建工具、无框架);CAN DBC 解析、BLE/GAP 连接、OTA 传输逻辑交由 `js/` 目录下的模块脚本加载。
@@ -0,0 +1 @@
以 `tabs.html` 作为单窗口多标签的外壳,通过 `<iframe>` 嵌入 `pages/` 下各功能页(OTA 主页 `index.html`、CAN 通信 `can.html`、CAN 监控 `can_monitor.html`、电机控制 `motor.html`),并引用同级 `lab/` 下的实验页;标签列表由 JS 的 `TABS` 数组驱动,当前激活标签经由 iframe `load` 事件检测 pathname 后同步高亮并持久化至 localStorage (`dcu_tab`)。所有共享样式集中在 `css/`:`base.css` 定义深色设计令牌与全局重置;`layout.css` 提供 header-bar、卡片、表单、按钮、抽屉等布局组件;`components.css` 实现上传区、进度条、指标卡、阶段胶囊等原子组件;`responsive.css` 管理断点与合成器友好动画;`can.css`、`motor.css` 为各自功能的独立主题。每个 page HTML 通过 link 引用基础样式,其中 `motor.html` 自带完整 seed tokens 隔离主题,不依赖 `base.css` 颜色变量。页面内嵌 JavaScript 或通过 `<script type="module">` 加载 `../js/...` 逻辑脚本,与后端 ESP32 HTTP API (`/can/*`, `/ota/*`) 交互。
@@ -0,0 +1 @@
提供 ESP32/DCU 设备的 OTA 中继、CAN 发送/监控与电机控制等 Web 调试页面的静态外壳与样式体系。
@@ -0,0 +1,6 @@
- 每个页面 HTML 统一在 head 内引入空 favicon (`data:,`) 以避免浏览器请求导致本地静态服务 404。
- 页面间通过相对路径 `../css/...` 引用共享样式,并通过版本号 query 参数(如 `?v=857f83a5`)强制缓存失效。
- 状态指示使用 `.pill` + `.indicator` 元素组合,通过添加 `online/offline/processing/live/idle` 类切换状态颜色与呼吸灯效果。
- 卡片采用 `.card.card--<子系统>` 修饰类注入顶部色带与图标底色,子系统色来自 `--esp32 / --gd32 / --ble / --can / --motor / --mem` 等语义 token。
- 动画关键帧仅操作 transform/opacity 以保证合成器直通;box-shadow/background-position 等重绘型动画仅限短暂临时态(如 dragover、OTA 阶段)。
- 响应式行为通过 `@media (max-width: 1100px)` 与 `640px` 两档断点在 `responsive.css` 中集中维护,页面侧不重复定义布局断点。
@@ -0,0 +1,58 @@
schema_version: 1
module_path: root
title: ESP32 DCU 调试控制台仓库根
scope:
- README.md
- CHANGELOG.md
- .gitignore
- .gitattributes
- esp32_server.py
- esp32_app.vbs
- esp32_web.vbs
- tabs.html
- serve.bat
source_files: []
depends_on: []
related_to: []
kk_module_id: 217e0343-beda-41a9-bfc6-c01fb7f0cd43
kk_cards:
architecture_design:
id: c7e1b8bd-0f31-4088-802e-47c5fc6a78d7
title: ESP32 DCU 调试控制台仓库根
coding_conventions:
id: b42250fb-a810-4b88-87b4-8f7e6c2cbf3f
title: ESP32 DCU 调试控制台仓库根
overview:
id: 2d136a23-5904-4499-855b-80b1a32528d6
title: ESP32 DCU 调试控制台仓库根
tech_stack:
id: a3a9f3a6-78c7-40ee-ac5f-cc215e42fdd9
title: ESP32 DCU 调试控制台仓库根
unique_setup_and_commands:
id: 182bc6fc-a797-4b4d-b58f-e2c87fb9e1a1
title: ESP32 DCU 调试控制台仓库根
build_system:
id: 9014488e-3a7f-413b-bbbf-c2c013eaa659
title: Windows + ESP-IDF 多入口构建与部署体系
configuration_system:
id: 6302e196-7d4f-44d3-9757-72efd9035b99
title: 前端 localStorage + 命令行参数 + VBScript 启动参数的分层配置系统
dependency_management:
id: 1d5e10e6-d5cd-4510-9159-e554b8d2ea6c
title: 依赖管理:无第三方 Python/JS 包,纯内置模块 + 独立 ecat_native.exe 子进程
error_handling:
id: 6136fa8e-72aa-43f5-a824-5d5ba4a66cf4
title: 前端错误传播与 Toast/日志呈现,后端 Python 广泛 try/except 兜底
frontend_style:
id: 7f41416c-8e1a-47e9-a286-6e7ccc8c3a20
title: DCU Mission Control 前端样式体系:深色令牌、子系统语义色与 CSS 模块化
logging_system:
id: c72b9e5c-43ed-41d4-933a-189ddde135e2
title: 前端日志系统:去重环形缓冲 + /logs 服务端拉取 + 统一 addLog 接口
kk_repo_cards:
- build_system
- configuration_system
- dependency_management
- error_handling
- frontend_style
- logging_system
@@ -0,0 +1,50 @@
## 1. 采用的系统/方法
仓库是一个混合工程:Web 前端(HTML/CSS/JS)+ Python3 本地调试服务器,以及通过外部脚本触发的 ESP-IDF 固件构建。没有 Makefile、Dockerfile、CI 流水线或统一的包管理器;构建由**多个独立的 Windows 批处理脚本和 Python 启动器**拼凑而成,分别承担不同的构建目标。
### 1.1 前端静态服务与桌面窗口
- 核心运行体 `esp32_server.py` 用 stdlib `http.server.ThreadingHTTPServer` 在本地提供静态页面,并实现 `/ecat/api/*` 反向代理到 `tools/ecat/build_native/ecat_native.exe`(端口 8090–8095 自动探测)。
- 三种启动入口:
- `serve.bat`:控制台模式,默认端口 2625,输出日志方便调试。
- `esp32_app.vbs`:`pythonw.exe` 启动 pywebview 桌面窗口(无控制台),子进程承载 HTTP 服务,避免 pythonw 后台线程被杀。
- `esp32_web.vbs`:`pythonw.exe` 启动后默认打开浏览器标签页。
- 窗口模式下服务端向 HTML 响应注入 `_reload.html`,为 WebView2 补充 F5 / Ctrl+R 刷新能力。
### 1.2 ESP-IDF 固件构建
- `scripts/build_mem.bat` 通过 Git Bash 调用 `idf.py build` 构建 `G:\Robot_v2\DCU\ESP32_COMM` 下的 DCU/ESP32 固件。
- 预先 `unset MSYSTEM*` / `MINGW_*` 环境变量绕过 ESP-IDF 的 MSys 检测,并将工具链路径固定到 `C:\Espressif` 与 `F:\software\.espressif\v6.0\esp-idf\export.bat`——路径硬编码于脚本中。
### 1.3 GD32 OTA / 刷写
- `scripts/flash_gd32.py`:经本服务的 Web API 把 GD32 固件中继下载到设备侧 Flash。
- EtherCAT 链路依赖 `tools/ecat/build_native/ecat_native.exe`(由 `build_native.bat` 编译,需 VS2022 + Npcap),首次请求时由 `esp32_server.py` 的 `_ecat_autostart` 自动拉起(带 `--parent-pid` 防止清场已有实例),未找到时用端口扫描复用已运行的进程。
## 2. 关键文件
| 文件 | 角色 |
|------|------|
| `esp32_server.py` | 静态文件服务、EtherCAT 反向代理、app 窗口租约、ECAT 守护进程管理 |
| `serve.bat` | 控制台模式启动器(Python 标准输出可见) |
| `esp32_app.vbs` | pywebview 桌面窗口启动器(隐藏控制台) |
| `esp32_web.vbs` | 默认浏览器 tab 启动器(隐藏控制台) |
| `scripts/build_mem.bat` | 通过 ESP-IDF 构建 ESP32 端固件 |
| `scripts/flash_gd32.py` | 通过本服务中继刷写 GD32 固件 |
| `README.md` | 记录目录约定、双链路架构与三处构建依赖 |
## 3. 架构与约定
- **分层清晰**:前端是纯静态资源,不碰硬件;业务 API 跨域访问 ESP32 固件的 80 端口;只有 EtherCAT 后端需要本机 C/SOEM 守护进程。
- **同源代理解 CORS**:ECAT 后端绑 127.0.0.1 且禁止预检,所有 POST JSON 请求统一走 `/ecat/api/*` 同源转发,页面与两个仓库(前端 + ecat)互不耦合。
- **自动生命周期管理**:ECAT 守护进程首次代理时才拉起,`--parent-pid` 保证父退出后自杀;已存在进程直接复用(端口 8090–8095 轮询探测),避免重复拉起触发对从站的 INIT 清理。
- **单实例锁**:多双击 `esp32_app.vbs` 时通过 `/api/focus` 聚焦已有实例而非创建新窗口。
- **版本化缓存**:README 明确“改 CSS/JS 后必须 bump 引用处的 `?v=` 缓存版本”,否则浏览器加载旧代码。
- **模块组织**:新增功能页放 `pages/` 并在 `tabs.html` 的 TABS 数组登记;一次性实验页放 `lab/` 保持自包含。
## 4. 约束与规则
- **ESP32 固件构建依赖外仓路径**:`scripts/build_mem.bat` 将 `ESP_IDF_EXPORT` 指向 `F:\software\.espressif\v6.0\esp-idf\export.bat`,并 cd 到 `G:\Robot_v2\DCU\ESP32_COMM` 再 `idf.py build`——这要求开发者拥有与仓库一致的磁盘布局,不是可移植构建。
- **ECAT 后端必须先存在或可由本服务拉起**:若未找到 `tools/ecat/build_native/ecat_native.exe`,电机链路会报错提示“请先运行 tools\ecat\build_native.bat”;前端 `js/motor/main.js` 对错误消息中包含 `build_native`/Npcap 的情况做归类。
- **WebSocket 租约决定循环启停**:`ws/app-lease` 上所有 app 窗口断开则自动停止 EtherCAT PDO 循环并把从站退回 INIT。
- **刷新率上限与链路绑定**:WiFi 链路默认 250ms、最低 50ms;ECAT 链路默认 50ms、最低 1ms(受限于 Python Event.wait 与 GIL)。切链路时各记一份 `state.refreshByTp` 并立即重排节拍。
- **1ms ECAT 档位 ≠ 1000Hz**:底层以 UNTHROTTLED_MAX_MS=20 作为“不限速”阈值,1ms 档实际约 125 Hz;低于 20ms 要同时关掉理论值与 tickStuck 统计,否则界面会撒谎。
## 5. 不存在的内容
- 没有 Makefile / Gradle / npm scripts / Dockerfile / CI YAML — 该项目在 Windows 环境内用批处理与 VBScript 手工组装构建/发布流程。
- 无统一的版本号定义文件(版本号来源于 Git tag / changelog 和设备端 SHA-256)。
- 无交叉编译配置:ESP-IDF 构建路径硬编码,ECAT native 产物预期在 Windows 上由 VS2022 构建。
@@ -0,0 +1,46 @@
# ESP32 DCU 调试控制台 — 配置系统
## 1. 系统与分层
本仓库没有集中式的配置文件(无 `*.yaml`、`*.toml`、`*.env`),采用三层组合方式完成运行时配置:
- **用户偏好层**:浏览器端 `localStorage`,用于持久化设备 IP、电机传输链路、刷新率、CAN DBC 设置等。
- **进程/工具层**:Python 服务通过 `argparse` 解析命令行参数(`--port`、`--window`、`--no-browser`);Windows 批处理/VBScript 再提供默认值与启动入口。
- **外部依赖层**:通过调用外部子进程(`tools/ecat/build_native/ecat_native.exe`)并传入 `--parent-pid` 等方式传递进程间通信所需配置。
## 2. 关键文件
- `esp32_server.py`:服务端核心。HTTP 服务器(端口探测/绑定)、EtherCAT 反向代理、pywebview 窗口外壳、子进程生命周期管理,均通过 argparse 与模块级常量硬编码控制。
- `serve.bat`:控制台模式启动器,设 `PORT=2625` 后执行 `python esp32_server.py --port %PORT%`。
- `esp32_web.vbs` / `esp32_app.vbs`:分别以隐藏窗口/桌面窗(pywebview)方式启动 `esp32_server.py`,区别仅在于是否传 `--window`。
- `js/common/base-url.js`:统一封装设备 IP 的 `localStorage` key(`dcu_esp_ip`)与默认值(`DEFAULT_ESP_IP = '192.168.31.127'`)。注释明确“各页面共用”“只负责公共实现”。
- `js/motor/transport.js`:维护 ECAT/WiFi 传输切换状态,key 为 `dcu_motor_transport`。
- `js/motor/transport-ecat.js`:ECAT 传输配置,含网卡适配器、周期时间(4ms→250us 迁移标记 `LS_PERIOD_MIG`、`LS_SPIN`)等,全部落 localStorage。
- `js/can/persist.js`、`js/ota/file-handle.js`:各自功能页的偏好持久化(DBC、刷新目标 `LS_FLASH_TARGET`、最近固件元数据 `LS_FILE_META`)。
- `js/app.js`:主标签外壳页面,读写主页的共享设备 IP。
## 3. 架构与设计约定
### 3.1 设备发现与连接
- 所有页面向设备发起 API 请求的目标由 `getBaseUrl()` 计算:`http://` + 当前设备 IP,IP 从 `localStorage['dcu_esp_ip']` 取,无有效值回退到 `192.168.31.127`。
- 代码注释强调 “每个页面一致”“空值忽略”,对 `localStorage` 的访问被 try/catch 包裹(兼容隐私模式)。
### 3.2 端口与服务启动
- 端口优先级:`serve.bat` → `--port` → 默认 `2625` → `_bind_server` 自动递增重试(若占用则打印 `端口 xxx 已被占用, 尝试 xxx+1`)。
- 默认监听 `127.0.0.1`(不暴露公网)。
- Windows 下通过 Job Object 绑定子进程生命周期,父进程退出时内核连带杀掉服务子进程。
### 3.3 EtherCAT 后端自动发现与启动
- 使用内置端口数组 `ECAT_PORTS = (8090..8095)` 轮询检测正在运行的 `ecat_native.exe`。
- 首次需要时在 `g_ecat_lock` 保护下拉起子进程并传入 `--parent-pid`,避免独立实例清理逻辑误杀旧进程。
- 已运行实例通过 `_port_taken(p)` 复用,不再重复拉起。
### 3.4 多语言环境配置
- 所有中文字符串(日志、UI 文案、提示、注释中的路径与说明)均以 UTF-8 输出:`serve.bat` 先执行 `chcp 65001` 并将 `PYTHONUTF8=1` 写入子进程环境;`esp32_web.vbs` / `esp32_app.vbs` 同样设置 `PYTHONUTF8=1`。
- 前端 JS 侧无多语言文件,所有文案直接嵌入 HTML/JS 源文件中。
## 4. 约束与规则
- **设备 IP 键名唯一**:`dcu_esp_ip` 由 `js/common/base-url.js` 统一定义并通过 export 导出,所有功能页通过该共享 key 协作(OTA/CAN/电机页注释明确声明此约定)。
- **无外部配置文件的强制要求**:整个项目未使用 `.env`/`.yaml`/`*.cfg`/`*.ini` 等任何集中配置格式,如需调参必须修改源码常量或命令行参数。`esp32_server.py` 中除 `argparse` 外,其余行为均通过模块级变量(如 `ECAT_DIR`、`ECAT_PORTS`、`BASE_DIR`)与命令行参数组织。
- **安全边界**:服务默认仅监听 `127.0.0.1`;EtherCAT 原生后端也绑 `127.0.0.1` 且无 CORS,故页面需经本服务同源反向代理(`/ecat/api/*`)访问,避免跨域预检失败。
- **前端本地存储可容错**:每次 `localStorage.setItem/getItem` 都包裹 try/catch(应对无痕/隐私模式抛出异常);写前做 trim 校验,空值即忽略。
- **进程边界配置不可穿透**:VBScript 层通过命令行参数(`--window`)切换模式,但 Python 内部不会反查环境变量;子进程通过标准输出打印 `PORT={...}` 供父进程解析,而非通过共享配置文件通信。
## 5. 总结
这是一个**纯前端 + 简易 Python 静态服务器**场景下的轻量配置系统:设备地址和界面偏好完全落在浏览器的 `localStorage` 中,服务进程本身通过命令行参数与模块内常量硬编码驱动,不存在 YAML/环境变量等集中式配置机制。其优点是无依赖、可直连浏览器调试;代价是新增配置项需要同时修改多处 JS/Python 源码和脚本入口。
@@ -0,0 +1,26 @@
## 一、使用的依赖管理体系
本仓库**没有传统的包管理器**:根目录与所有子目录下不存在 `package.json`、`go.mod`、`requirements.txt`、`Pipfile*`、`*.lock`、`.npmrc` 等任何依赖声明文件;前端侧使用浏览器原生 ES module(`type="module"`)通过相对路径直接引用 `../css/*`、`../js/common/*`,不经过 npm/yarn/pnpm 解析。
Python 后端 (`esp32_server.py`) 仅依赖 Python **标准库**(`http.server.SimpleHTTPRequestHandler` / `ThreadingHTTPServer`、`socket`、`subprocess`、`ctypes`、`urllib.request`、`threading`、`hashlib` 等),以及一个可选的桌面外壳依赖 `pywebview`。该可选依赖在运行时探测缺失时回退到普通浏览器模式:`print("pywebview 未安装: pip install pywebview —— 回退浏览器模式")`,并通过 `serve.bat` / `esp32_web.vbs` 走无 GUI 路径。
非 Python 二进制依赖以独立可执行形式存在:EtherCAT 后端为编译后的单文件 `build_native/ecat_native.exe`(由外部脚本 `build_native.bat` 构建),由主服务按需在 8090–8095 端口范围内发现并启动(带 `--parent-pid` 实现父进程退出时自我结束),不属于当前仓库的包依赖图。
## 二、关键文件
- `esp32_server.py`:唯一 Python 入口;通过 `import http.server`、`ctypes`、`subprocess` 等标准库提供服务、反向代理、窗口管理与 ecat 子进程编排。
- `README.md`:文档化的启动方式(`esp32_app.vbs` / `esp32_web.vbs` / `serve.bat`),明确了 pywebview 可选性以及 ecat_native 的外部依赖关系。
- `scripts/build_mem.bat`:调用 ESP-IDF 构建 DCU/ESP32_COMM 固件的辅助脚本,不引入 Python/JS 依赖。
- `js/`、`pages/`、`css/`:纯前端资源,无任何 `<script src="node_modules/...">`,全部以相对 URL 引用。
## 三、架构与约定
1. **零打包策略**:`esp32_server.py` 直接 serve 静态 HTML/CSS/JS,页面内用 `<script type="module" src="../js/app.js">` 等加载,依赖解决完全由浏览器原生 ES module 完成。
2. **可选桌面外壳**:pywebview 作为可选依赖——有则用 `pythonw` + pywebview 开 WebView2 桌面窗口(无控制台窗体);缺则回退到系统默认浏览器标签页模式,由 `serve.bat` / `esp32_web.vbs` 启动。
3. **外置二进制子进程模式**:EtherCAT 能力不在 Python 进程中提供,而是通过子进程协议拉取 `tools/ecat/build_native/ecat_native.exe`,服务端做 `/ecat/api/*` 同源转发来绕过其无 CORS + 127.0.0.1 绑定问题。该二进制由另一个 Git 仓库产出,当前仓库只负责发现与生命周期管理。
4. **单实例互斥**:通过本地 API `/api/focus` 把新双击重定向到已有实例前台窗口,避免并发拉起多个服务端实例。
## 四、约定与约束
- **前端资源版本化**:修改 CSS/JS 后必须 bump 引用的 `?v=` 缓存参数(否则浏览器加载旧代码),这是 README 中明确记录的强制约定。
- **JS 模块内部引用须用 `import.meta.url`**:不能写文档相对路径(如 Worker 文件),页面层级变化会 404(见 `js/motor/main.js` 的 `TICK_WORKER_URL`)。
- **新增功能页必须在 `tabs.html` 的 `TABS` 数组登记**,实验性/一次性页面放 `lab/` 并保持自包含。
- **设备地址配置保存在 `localStorage.dcu_esp_ip`**(默认 `192.168.31.127`,见 `js/common/base-url.js`),本服务不持有设备 IP,业务 API 全部直连 ESP32 固件 80 端口。
- **Python 侧不得随意引入三方库**:当前仅依赖标准库与可选 `pywebview`;若需增加第三方包,应评估是否仍走“纯标准库 + 可选 GUI”的路径,因为仓库中没有 `requirements.txt` 或 `pip freeze` 产物,依赖变更无法通过 CI 锁定复现。
- **ECAT 子进程必须带 `--parent-pid`**:否则它会清理同端口段其他实例,且主服务退出后会留下孤儿进程占用 Npcap 适配器与端口(见注释阶段 4 迁移说明)。
@@ -0,0 +1,5 @@
## 1. 总体方法
本仓库的「错误处理」由三块构成:
- **Python 服务端 (esp32_server.py)**:大量使用裸 `except Exception:` 包裹每个 I/O / 子进程/线程入口,把网络/文件/Windows 句柄异常吞掉并继续运行;不存在自定义异常类型体系。
- **前端工具脚本 (scripts/*.py)**:通过 `raise SystemExit(...)` + `urllib.error.HTTPError` 区分成功/失败路径,主流程用 try 捕获异常后终止。**没有**统一的 Result/Either 封装。
- **浏览器前端 (js/…)**:采用「Promise + fetch AbortSignal.timeout → throw Error」的异步错误模型;所有可见故障统一经 `toast.js` 的 `showToast(msg, 'success'|'error'|'warning')` 在 UI 弹出(5s 去重),并通过 `log.js` 的 `addLog(level, tag, msg)` 结构化写入页面日志面板。BLE OTA、OTA 上传等长链路则在各自模块内维护状态机 (`stages.js` / `progress.js` / `session.js`),通过 `setBleStageError`、`cleanupAfterOtaFailure` 等函数显式转入错误阶段。
@@ -0,0 +1,39 @@
## 1. 整体方法与工具
- 纯原生 CSS,无 SCSS/Sass/Less、无 Tailwind、无 PostCSS 等构建管线;`pages/*.html` 直接以 `<link>` 引入静态 `.css`(带 `?v=<hash>` 缓存破坏参数)。
- 全局样式按职责拆为独立文件并通过 HTML 顺序引入:
- `css/base.css`:设计令牌(`:root` 变量)、全局 reset、背景网格与氛围光、滚动条、选区、focus 可见性。
- `css/layout.css`:header-bar、主布局 grid、卡片/表单/按钮/状态胶囊 (pill)。
- `css/components.css`:上传区、进度条、阶段切换胶囊 (progress-phase)、指标卡片、徽章、Toast、Tooltip 等可复用 UI 块。
- `css/can.css`:CAN 工作台专用样式,并派生 `motor-launch-card` 复用该布局仅换强调色。
- `css/responsive.css`:`@media` 断点(1100px / 640px)与全部关键帧动画 + 卡片入场交错延迟。
- `css/motor.css`:独立的「电机控制台」子主题,自带 seed tokens,不依赖 base/css 的共享令牌集。
- 无任何外部组件库或设计系统包,一切视觉规范通过 CSS Custom Properties 落地。
## 2. 关键文件
- `css/base.css` — 设计令牌中心,集中定义底色层级、子系统语义色、字体栈、圆角与阴影。
- `css/layout.css` — header-bar、main-layout、card、form、pill、card--{esp32,gd32,ble,can,motor,mem,status} 变体修饰类。
- `css/components.css` — upload-zone / progress-fill / metric-grid / badge-stat / progress-phase-row 等。
- `css/can.css` — can-launch-card / .can-grid / .can-header / .can-toolbar-grid 等,同时提供 motor-launch-card 变体。
- `css/responsive.css` — 断点 + @keyframes + 入口淡入交错延迟 + hover/拖拽微交互。
- `css/motor.css` — 独立的 seed token 主题(`--seed-*`),自给自足的 reset 和 toolbar/main-grid。
- `pages/index.html` — 统一引入 base/layout/components/can/responsive 样式的入口示例。
## 3. 架构与设计约定
- **设计令牌分层**:`base.css` 在 `:root` 下分组声明基础层(`--bg-root/--bg-panel/--bg-card`)、边框层、文字层、子系统语义色层(ESP32=青绿 `#2fd8c1`、GD32=琥珀 `#fcbf3f`、BLE=蓝 `#5fa8ff`、CAN=绿 `#43d97b`、motor=青 `#22d3ee`、mem=紫 `#a88bfa`)、状态层(green/amber/red),并以 `--accent/--accent-dim/--border-focus` 兼容旧引用。
- **子系统色彩编码**:通过在 card/pill/metric 上使用 `card--{esp32,gd32,ble,can,motor}` 等修饰类,配合 `--card-accent` 覆盖实现同一组件多色系复用;header-top 用三色渐变线暗示 ESP32→BLE→GD32 的子系统谱系。
- **排版与字体**:中文优先苹方/雅黑(`--font-display`),英文回退 Segoe UI/system-ui;数字/SHA/HEX/日志统一使用 `--font-mono`(SF Mono → Fira Code → Cascadia → Consolas)。`14px` 基准字号,`line-height: 1.55`。大量数值区域应用 `.tabular` 利用 `font-variant-numeric: tabular-nums` 对齐。
- **布局**:主容器 `max-width: 1480px`,默认两列 `grid-template-columns: 400px 1fr`,靠 `layout.css` 中的 `.main-layout` 组织,响应式在 `responsive.css` 中降为一列。
- **卡片与组件**:卡片顶部有 2px 渐变彩色强调带(由 `::before` 生成,颜色由 `--card-accent` 控制),hover 抬升并增强描边;按钮、输入框、选择器均走 `layout.css` 的统一 `.btn`/`.input`/`.form-label`。
- **响应式策略**:双断点 `1100px`(桌面窄屏)和 `640px`(移动端)切换 layout、badge 网格列数、抽屉宽度计算方式等;没有 mobile-first 媒体查询前缀,属于 progressive enhancement 思路。
- **动画性能约定**:注释中明确要求常驻无限动画只动 `transform/opacity`(合成器直通),禁止频繁触发重绘的 `box-shadow/background-position` 用于关键帧;例如 `shimmer`、`ringRipple`、`glowBreathFade`、`flowDash` 都遵循该规则。
- **独立子主题**:`css/motor.css` 拥有自己的 `:root { --seed-* }` 种子令牌派生一套颜色/字体/间距,并自带完整 reset,因此可以脱离 `base.css` 单独运行在 `pages/motor.html`——这是仓库内唯一采用“隔离主题”的方式。
- **页面级注入**:每个 HTML 通过 `<link rel="stylesheet" href="../css/*.css?v=...">` 注入;版本号哈希用于静态缓存破坏,未使用任何打包/热更新。
## 4. 约束与可观察到的规则
- 所有色调均来自 `base.css` 定义的 CSS Custom Properties,新增组件应优先引用 `var(--*)` 而非硬编码颜色值(已有组件如 pill、card、progress、metric 均如此)。
- 子系统色需从预定义的 `--esp32/--gd32/--ble/--can/--motor/--mem` 选取,避免自创新语义色;可通过 `*-hi`(高光)/ `*-dim`(半透明背景)组合完成 hover/accent 效果。
- 卡片必须携带 `card--{子系统}` 修饰类以正确填充顶部强调带与图标背景(`layout.css` 已为每类预定义 `--card-accent` 与 `--card-accent-dim`)。
- 按钮统一走 `.btn/.btn-primary/.btn-success/.btn-danger/.btn-outline/.btn-ghost` 家族,避免新建按钮样式;新增样式应在 `layout.css` 或 `components.css` 中扩展。
- 动画遵循 `responsive.css` 顶部注释的性能约定:常驻 animation 仅改变 `transform/opacity`;短暂态可使用 `box-shadow/background-position`。
- 响应式布局必须通过 `css/responsive.css` 中添加 `@media` 规则进行覆盖,不在页面 HTML 或 JS 中做 DOM 尺寸判断来切换样式。
- 如需全新独立页(如 motor 控制台),可仿照 `css/motor.css` 的 seed-token 模式创建隔离主题,但应尽量复用 base 组件类以保持一致的交互体验。
@@ -0,0 +1,59 @@
## 1. 使用的方案
项目在前端(ESP32/DCU Web 控制台)实现了自研轻量级日志子系统,位于 `js/common/log.js`。其职责是:**接收带标签的日志条目 → 去重/过滤 → 维护 DOM 面板 + 环形缓冲 → 按级别样式化渲染**。
日志数据并非由前端直接构造所有业务事件,而是通过 `js/common/polling.js` 以轮询方式从后端 ESP32 设备拉取 `/system/status` 与 `/logs` 两条流,把后端的结构化输出注入到统一的 UI 中;同时各模块通过 `addLog(level, tag, message)` 主动写入调试类日志。因此该“logging system”是 **后端实时日志拉取 + 前端集中式渲染** 的组合。
## 2. 核心文件
- `js/common/log.js` — 日志缓存、去重、DOM 渲染、过滤、自动滚动、条数上限裁剪的核心库(`addLog`、`clearLogs`、`setLogFilter`、`toggleAutoScroll` 四导出)
- `js/common/polling.js` — 定时递归 setTimeout 调度 `/system/status` 与 `/logs` 轮询,并将远端行 `^[DIEW] ([^|]+)\|(.*)$` 解析为 `addLog(m[1], m[2], m[3])`
- `css/motor.css`、`components.css`、`can.css`、`layout.css`、`responsive.css`、`base.css` — `.log-line`、`.lt/.lv/.lg/.lm` 等日志元素的 CSS 样式
- `pages/index.html`、`pages/can_monitor.html`、`pages/motor.html`、`tabs.html` — 包含 `#logScroll`、`#logCount`、`#autoScrollBtn`、`.log-filter` 按钮的页面骨架(由 `log.js` 通过 ID 直接操作)
- 消费端(导入 `addLog` 的模块举例):`js/app.js`、`js/common/connection.js`、`js/ble/state.js`、`js/ota/file-handle.js`、`js/ota/session.js`、`js/ota/upload-esp32.js`、`js/ota/upload-gd32.js`、`js/common/polling.js`、`js/ota/progress.js`
## 3. 架构与设计约定
### 日志条目结构
每个日志是一个三元组 `(level, tag, message)`,经 `formatTime` 加上本地时间戳,再被 HTML 转义(调用 `utils.escapeHtml` 防 XSS)后渲染为一行:
```
[时间] [级别] [TAG] 消息
```
其中级别 `lv` 使用 class `D|I|W|E`,tag 用 `lg`,消息用 `lm`。
### 去重策略
- 同一帧内相邻重复项:通过 `makeLogHash(level, tag, message)` 计算字符串哈希并与 `lastLogHash` 比较,完全相同的连续条目只写一次。
- 用于避免高频率状态上报产生刷屏。
### 缓冲与裁剪
- 内存采用普通数组 `logEntries`,`MAX_LOGS = 1000` 作为硬上限;超出时 `trimIfNeeded()` 移出最旧的 DOM 节点并 shift 掉对应 entry。
- 没有持久化历史到 localStorage。
### 过滤与 UI
- 全局 `logFilter` ∈ `{ all, D, I, W, E }`,由页面 `#autoScrollBtn` 与 `.log-filter` 控制。
- `setLogFilter` 会清空 `#logScroll` 并按当前 filter 重建 Fragment 显示,支持运行时切换。
- `toggleAutoScroll` 切换自动滚动开关,文字在 “🔽 自动滚动” / “⏸️ 暂停滚动” 间切换。
- 自动滚动使用 `requestAnimationFrame` 批量合并,防止每条日志都触发强制布局。
### 来源分流
- **后端实时流**:`polling.js` 周期性 GET `/logs`,将每行正则 `^(.) (.+)\|(.+)$` 解析为 level/tag/message,直接 `addLog(...)` 投递。
- **前端主动日志**:连接、OTA、BLE、文件处理等各模块遇到关键流程点(断线、重启、握手、校验失败、SHA 不匹配等)调用 `addLog`,按 `connection`/`系统`/`诊断`/`上传`/`文件`/`OTA`/`内存`/`BLE` 等 tag 区分领域。
### 后端协议契约(由 poller 侧 enforce)
- `/system/status` 返回 JSON,含 `sys_state_code`、`relay_state`、堆低水位等字段。
- `/logs` 返回文本行,格式约定为 `LEVEL TAG|MESSAGE`(首字符为 `D/I/W/E`,然后空格、tag、竖线、正文),这是前后端共享的契约,而非任何框架约定。
## 4. 约定与约束
- **唯一入口**:全仓库前端日志通过 `common/log.js` 暴露的四函数进出;外部模块仅 import/addLog,不允许自行创建日志 DOM。
- **必须带 tag**:所有调用均传入二级分类 tag(如 `'连接'`、`'诊断'`、`'上传'`、`'文件'`、`'内存'`、`'系统'`、`'BLE'`、`'OTA'`),以便后期按 tag 过滤或筛选。
- **级别限定**:level 严格为 `D`(debug)、`I`(info)、`W`(warn)、`E`(error) 其一;UI 据此设置 CSS 颜色与过滤器类别。
- **XSS 防护**:level/tag/message 插入 innerHTML 前全部经 `escapeHtml` 处理;新增内容也需遵循此规则。
- **性能约束**:单条日志路径禁用多次 DOM query;高频重复内容依赖去重;批量追加走 `DocumentFragment`(filter 重建时);自动滚动批量化到下一 rAF。
- **轮询间隔**:`status` 与 `logs` 轮询默认 1000ms,上传期间暂停(`pausePollingForUpload`),GD32 中继期临时降至 400ms(`setStatusPollIntervalMs(400)`)以减少日志滞后,结束后恢复。
- **页面前置条件**:页面需存在 `#logScroll`、`#logCount`、`#autoScrollBtn`、`.log-filter` 四个选择器目标,否则 `clearLogs`/`setLogFilter`/`toggleAutoScroll` 无作用但不会抛错。
- **未覆盖场景**:Node.js / Python 后端脚本目录(`scripts/*.py`、`scripts/*.mjs`)普遍使用原生 `console.*`(见 grep 结果),不使用前端日志系统——说明本日志系统限定于浏览器端控制台。
## 5. 总结
这是一个围绕前端 DOM 的微型日志子系统:通过统一的 `addLog(level,tag,message)` 接口汇聚多模块的调试信息,并以环形缓冲 + 去重 + 自动滚动的形式挂载到页面上;同时通过 `polling.js` 把后端 ESP32 的 `/logs` 实时串流入这个面板,形成“设备端打 log + 前端集中呈现”的统一调试窗口。
@@ -0,0 +1 @@
Python + pywebview 作为本地桌面容器,JavaScript (ES modules) 构成前端控制台,EtherCAT PDO/Slot 协议贯穿 JS 前端与 Python 后端通信,Windows VBScript/bat 作为统一启动外壳。
@@ -0,0 +1 @@
仓库以 Python 后端 `esp32_server.py` 为统一入口,通过 VBScript (`esp32_app.vbs` / `esp32_web.vbs`) 或批处理 (`serve.bat`) 在 Windows 上拉起 pywebview 桌面窗口或浏览器标签,将 `pages/`、`js/`、`lab/` 等静态资源暴露给前端;`pages/*` 是薄壳 HTML,实际逻辑落在 `js/motor`、`js/ota` 等子模块中,由 JS 前端通过 WebSocket 与服务端进行 EtherCAT/CAN/Ota 通信;`scripts/` 提供 ECAT 撕裂检测、GD32 固件刷写、浏览器 E2E 测试等运行时工具,面向同一服务端接口;`lab/` 提供离线诊断页面和原始抓包 CSV,供产线验证总线连通性。各子模块围绕同一套“本地 Web 服务器 + ECAT 反向代理”契约协作,无需独立部署。
@@ -0,0 +1 @@
汇聚 ESP32/DCU Web 调试服务、多页面前端、JS 客户端、ECAT 工具脚本与 lab 诊断资源的单仓调试控制台,提供本地启动与跨平台运行入口。
@@ -0,0 +1 @@
根目录 `serve.bat` 提供一键启动服务并在默认浏览器打开 `tabs.html`;VBScript (`esp32_app.vbs` / `esp32_web.vbs`) 可在无浏览器环境下以 pywebview 桌面窗口方式加载调试页面,实现双模式运行。
@@ -0,0 +1,3 @@
- 所有需要与服务端通信的页面统一通过 `tabs.html` 以 app 窗口租约形式加载,避免多窗口抢占 ECAT 循环
- 前端静态页面集中在 `pages/` 目录并以薄壳 HTML 形式存在,业务逻辑迁移到 `js/` 下的 ES module 文件组织
- 浏览器端测试与运行时诊断脚本集中于 `scripts/`,按功能(ECAT/CPU 采样/刷写)划分命名空间并可直接从仓库根执行
@@ -0,0 +1,27 @@
schema_version: 1
module_path: lab
title: 调试诊断与 EtherCAT 采样数据
scope:
- lab/
- ecat_slots_raw.csv
source_files: []
depends_on: []
related_to: []
kk_module_id: 3f11b5ed-b020-40ab-be49-36bfc4fea893
kk_ordinal: 4
kk_cards:
architecture_design:
id: a83bab26-0eaa-442b-8401-d73020dbf89c
title: 调试诊断与 EtherCAT 采样数据
coding_conventions:
id: a0e4b780-bcb8-4a6c-bf02-5152189b1dee
title: 调试诊断与 EtherCAT 采样数据
overview:
id: 19093973-5734-403e-b0e2-ace21e683cb1
title: 调试诊断与 EtherCAT 采样数据
tech_stack:
id: 86af3241-db34-4640-bc79-bed4bab9aace
title: 调试诊断与 EtherCAT 采样数据
unique_setup_and_commands:
id: 35ccbf10-bc4b-46d9-9446-49ef5d4be525
title: 调试诊断与 EtherCAT 采样数据
@@ -0,0 +1 @@
纯前端 HTML + 内联 CSS/JS(无外部依赖),通过浏览器 fetch 直接访问 ESP32/GD32 内置 HTTP 端点;EtherCAT 采样数据采用自定义 CSV 格式,字段含 kind(H/M/B/X)、微秒级时间戳及十六进制 PDO payload。
@@ -0,0 +1 @@
本模块由两部分互不耦合的资源组成:lab/ 下是独立、自包含的浏览器单文件测试页(spi_test.html 通过 GET /spi/speedtest 调用固件探针;continuity_test.html 通过 LAN9252 通断测试),它们不依赖项目其他 JS/CSS,通过 serve.bat 直接访问;ecat_slots_raw.csv 则是按固定列(kind、时间戳、设备/槽号等)记录的 EtherCAT PDO/Slot 原始采样日志,被 scripts/probe_ecat_* 等 Python 分析脚本消费。_last_gd32_sha.txt 用于记录最近一次 GD32 固件 SHA 以判断固件是否变更。整体无构建步骤,仅作为静态资源与数据采集产物存放区。
@@ -0,0 +1 @@
提供 SPI/以太网链路独立诊断 HTML 测试页及 EtherCAT PDO/Slot 原始抓包 CSV,用于产线和调试阶段的硬件连通性与总线吞吐验证。
@@ -0,0 +1 @@
使用仓库根目录 serve.bat 启动本地 HTTP 服务器后,在浏览器打开 http://localhost:2625/spi_test.html 或 continuity_test.html 即可运行诊断;测试前需确保设备 IP 正确并通过网线连接至同一网段。
@@ -0,0 +1,3 @@
- 每个诊断页均为自包含单文件 HTML,所有样式与脚本内联,不引入任何外部 css/js 依赖
- CSV 采样文件以紧凑列式文本表示 EtherCAT 周期帧,使用单字符 kind 标识 H/M/B/X 报文类型并附带带符号小数毫秒时间戳
- 临时工具文件头部注释明确标注功能标签(如「SPI-SPEEDTEST」)及删除方式,便于后续清理时对照固件端点一并移除
+154
View File
@@ -0,0 +1,154 @@
# 知识卡导出索引文件
schema_version: 1
locale: zh-CN
commit: 43d42ad891b652f79db1f37091141cb7a2b4e314
branch: main
exported_at: "2026-09-06T19:46:36Z"
modules:
frontend_pages:
dir_name: ESP32_DCU 调试控制台前端页面集
title: ESP32/DCU 调试控制台前端页面集
scope:
- pages/
- css/
- tabs.html
source_files: []
children: []
depends_on: []
related_to:
- path: python_server
reason: esp32_server.py 作为静态文件服务器提供 tabs.html、pages/ 与 lab/ 目录下的 HTML,页面由本服务同源 serving。
js_frontend:
dir_name: ESP32 DCU 前端 Web 控制台集合
title: ESP32 DCU 前端 Web 控制台集合
scope:
- js/
source_files: []
children:
- js_frontend/app_entries
- js_frontend/ble
- js_frontend/can
- js_frontend/common
- js_frontend/motor
- js_frontend/ota
depends_on: []
related_to: []
js_frontend/app_entries:
dir_name: 前端应用入口聚合层(ESP32 OTA _ BLE OTA _ CAN 诊断)
title: 前端应用入口聚合层(ESP32 OTA / BLE OTA / CAN 诊断)
scope:
- js/app.js
- js/ble_ota.js
- js/can.js
source_files: []
children: []
depends_on: []
related_to:
- path: python_server
reason: OTA、BLE、CAN 控制台页面均由 python_server 的静态文件服务提供,并通过 base-url.js 中 localStorage 存储的 dcu_esp_ip 以同源请求访问设备 API。
js_frontend/ble:
dir_name: BLE 通道 OTA 客户端(Web Bluetooth GATT)
title: BLE 通道 OTA 客户端(Web Bluetooth GATT)
scope:
- js/ble/
source_files: []
children: []
depends_on: []
related_to: []
js_frontend/can:
dir_name: CAN 控制台前端:DBC 解析、报文发送与接收监控
title: CAN 控制台前端:DBC 解析、报文发送与接收监控
scope:
- js/can/
- js/can_monitor.js
source_files: []
children: []
depends_on: []
related_to: []
js_frontend/common:
dir_name: 前端公共工具库(连接_轮询_日志_Toast_IndexedDB)
title: 前端公共工具库(连接/轮询/日志/Toast/IndexedDB)
scope:
- js/common/
source_files: []
children: []
depends_on: []
related_to: []
js_frontend/motor:
dir_name: 电机控制台多传输模块
title: 电机控制台多传输模块
scope:
- js/motor/
source_files: []
children: []
depends_on: []
related_to:
- path: js_frontend/can
reason: CAN 控制台与电机控制台均通过 POST /can/send_batch 发送帧到 ESP32 设备,但 CAN 用于通用报文编辑而电机用于特定 CMD/CONFIG 控制流程。
- path: python_server
reason: 电机控制台通过 /ecat/api/* 反向代理访问本地 ecat_native.exe 的 /api/motor/*(transport-ecat.js 中拼接路径发送)。
js_frontend/ota:
dir_name: 前端 OTA 刷写会话与进度管理
title: 前端 OTA 刷写会话与进度管理
scope:
- js/ota/
source_files: []
children: []
depends_on: []
related_to:
- path: js_frontend/ble
reason: 两者均为浏览器端固件升级方案:js/ota 走 WiFi ESP32 HTTP(分块上传+SHA-256),js/ble 走 Web Bluetooth GATT(分包 ACK+窗口+SHA-256),同一业务目标的不同实现。
lab:
dir_name: 调试诊断与 EtherCAT 采样数据
title: 调试诊断与 EtherCAT 采样数据
scope:
- lab/
- ecat_slots_raw.csv
source_files: []
children: []
depends_on: []
related_to: []
python_server:
dir_name: ESP32 调试控制台本地 Web 服务器与窗口外壳
title: ESP32 调试控制台本地 Web 服务器与窗口外壳
scope:
- esp32_server.py
- esp32_app.vbs
- esp32_web.vbs
source_files: []
children: []
depends_on: []
related_to: []
root:
dir_name: ESP32 DCU 调试控制台仓库根
title: ESP32 DCU 调试控制台仓库根
scope:
- README.md
- CHANGELOG.md
- .gitignore
- .gitattributes
- esp32_server.py
- esp32_app.vbs
- esp32_web.vbs
- tabs.html
- serve.bat
source_files: []
children:
- frontend_pages
- js_frontend
- lab
- python_server
- scripts_and_tests
depends_on: []
related_to: []
scripts_and_tests:
dir_name: ECAT 调试、固件刷写与端到端测试脚本集
title: ECAT 调试、固件刷写与端到端测试脚本集
scope:
- scripts/
source_files: []
children: []
depends_on: []
related_to:
- path: python_server
reason: 脚本 test_app_lease_e2e.mjs 等连接本地页面服务器的 /ws/app-lease 端点做端到端断言(端口探测与 POST 触发)。