From d594b8fd94ebbeb0595829703e1b5d9fe89653a5 Mon Sep 17 00:00:00 2001 From: cbb <2625274797@qq.com> Date: Thu, 3 Sep 2026 01:56:29 +0800 Subject: [PATCH] =?UTF-8?q?init:=20DCU=20LAN9252=20EtherCAT=20=E4=B8=BB?= =?UTF-8?q?=E7=AB=99=E5=B7=A5=E5=85=B7=E9=9B=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 现有工具纳入版本管理: - ecat_tool.py: 一体化命令行主站(status/flash/eeprom/sdo/send) - ecat_server.py + ecat.html/css: 网页/桌面控制台(端口 8090) - ecat_scan.py / ecat_esc_regs.py / ecat_sniff.py: bring-up 扫描、 网络侧 ESC 寄存器诊断、裸帧抓包对照 - ecat_flash_eeprom.py: 经网线烧写 SII 镜像 + 逐字校验 - *.bat / *.vbs 启动入口 新增 .gitignore(排除 venv/ 与 __pycache__)、.gitattributes(不改写换行符)、 requirements.txt(锁定 pysoem 1.1.13 等依赖)、README.md。 --- .gitattributes | 2 + .gitignore | 23 + README.md | 43 ++ _repro_hang.py | 78 +++ ecat.bat | 8 + ecat.css | 797 ++++++++++++++++++++++++++++ ecat.html | 477 +++++++++++++++++ ecat_app.vbs | 12 + ecat_esc_regs.py | 281 ++++++++++ ecat_flash_eeprom.py | 125 +++++ ecat_scan.py | 120 +++++ ecat_server.py | 1196 ++++++++++++++++++++++++++++++++++++++++++ ecat_sniff.py | 92 ++++ ecat_tool.py | 562 ++++++++++++++++++++ ecat_web.bat | 7 + ecat_web.vbs | 8 + requirements.txt | 14 + run_scan.bat | 9 + 18 files changed, 3854 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 README.md create mode 100644 _repro_hang.py create mode 100644 ecat.bat create mode 100644 ecat.css create mode 100644 ecat.html create mode 100644 ecat_app.vbs create mode 100644 ecat_esc_regs.py create mode 100644 ecat_flash_eeprom.py create mode 100644 ecat_scan.py create mode 100644 ecat_server.py create mode 100644 ecat_sniff.py create mode 100644 ecat_tool.py create mode 100644 ecat_web.bat create mode 100644 ecat_web.vbs create mode 100644 requirements.txt create mode 100644 run_scan.bat diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3b3ecb8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# 该工具集在 Windows 下开发运行,保持文件换行符原样,避免 checkout/commit 时被改写 +* -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29a92c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +.pytest_cache/ + +# 虚拟环境(本地生成,勿入库) +venv/ +.venv/ +env/ + +# 日志与抓包产物 +*.log +*.pcap +*.pcapng +sniff_*.txt + +# 编辑器 / 系统 +.vscode/ +.idea/ +*.swp +Thumbs.db +desktop.ini diff --git a/README.md b/README.md new file mode 100644 index 0000000..c927c37 --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# ecat — DCU LAN9252 EtherCAT 主站工具集 + +在 Windows 上用 Python + pysoem(SOEM)直接从网卡驱动 DCU 的 LAN9252 EtherCAT 从站: +扫描总线、读写 SII EEPROM、CoE SDO 读写、PDO 循环收发,以及一个本地网页/桌面控制台。 + +## 环境准备 + +- Python 3.12(venv 不入库) +- [Npcap](https://npcap.com/):pysoem 收发裸 EtherCAT 帧的前提 +- 一块直连从站的物理网卡(示例中为 Intel I226) + +```bat +py -3.12 -m venv venv +venv\Scripts\python.exe -m pip install -r requirements.txt +``` + +## 目录内容 + +| 文件 | 说明 | +|------|------| +| `ecat_tool.py` | 一体化命令行主站:`adapters` / `status` / `flash` / `eeprom` / `sdo` / `send` 等子命令 | +| `ecat_server.py` | 网页控制台后端(REST API + 静态文件),默认端口 **8090**(8080 已被 ESP32 tools 占用) | +| `ecat.html` / `ecat.css` | 网页控制台前端 | +| `ecat_scan.py` | 最小化 bring-up 扫描:从站身份 + SII dump,`--op` 追加 PDO 测试 | +| `ecat_esc_regs.py` | 从**网络侧**直读 LAN9252 ESC 寄存器,绕开 GD32/PDI,用于判断 EEPROM 加载是否真的失败;支持 `--reload` | +| `ecat_flash_eeprom.py` | 通过网线烧写 `gen_eeprom.py` 生成的 SII 镜像,逐字回读校验(烧完需断电重启让 ESC 重新加载) | +| `ecat_sniff.py` | 旁路抓包,hexdump SOEM 自己发出的帧,用于对照裸帧格式 | +| `_repro_hang.py` | 复现 op/start 卡住→闪退的最小脚本,带 faulthandler 看门狗 | + +## 启动方式 + +| 入口 | 效果 | +|------|------| +| `ecat_app.vbs` | pywebview 桌面窗口,无控制台无浏览器标签(已针对部分 GPU 驱动白屏加 `--disable-gpu-compositing`) | +| `ecat_web.vbs` | 后台起服务并打开浏览器标签,无控制台窗口 | +| `ecat_web.bat` | 控制台模式,可见日志,调试用 | +| `ecat.bat` | 命令行工具入口,如 `ecat.bat status`、`ecat.bat flash` | +| `run_scan.bat` | 直接跑 bring-up 扫描,无参数则列出 Npcap 适配器 | + +## 注意 + +- 前端 CSS/JS 改动后记得 bump `?v=` 缓存版本,否则浏览器会加载旧代码。 +- EEPROM 烧写后必须断电冷启动,ESC 才会重新加载配置。 diff --git a/_repro_hang.py b/_repro_hang.py new file mode 100644 index 0000000..e2a30fc --- /dev/null +++ b/_repro_hang.py @@ -0,0 +1,78 @@ +"""_repro_hang.py — 复现 2026-09-03 01:40 "op/start 卡住→闪退"。 + +复刻 ecat.html 的 UI 操作序列(100ms 周期 + 2s pollSync + 手动 stop/start 节奏): + open → 循环 N 轮{ op/start → 立即 cycle+sync_diag → cycle@100ms → ~2s 后 op/stop } → close +faulthandler 45s 看门狗: 卡住时自动转储所有线程栈(op/start 有界 ~26s, 超过 45s = 真卡死)。 +退出码非 0xC0000005 之外的异常退出也会打印。 +""" +import faulthandler +import sys +import time + +faulthandler.enable() # 捕获原生访问违例(SEH)并打印 Python 栈 = 闪退根因现场 +faulthandler.dump_traceback_later(45, exit=False) + +import ecat_server as es + + +def t(): + return time.strftime("%H:%M:%S") + + +def show(res): + for line in res.get("log", []): + print(f" [{t()}] {line}", flush=True) + + +def main(): + rounds = int(sys.argv[1]) if len(sys.argv) > 1 else 30 + r = es.api_open({"substr": "I226"}) + show(r) + if not r.get("ok"): + print("open 失败, 退出", flush=True) + return 1 + + for i in range(rounds): + print(f"=== round {i} op/start ===", flush=True) + r = es.api_op_start({"dc_cycle_us": 0}) + show(r) + if not r.get("ok"): + print(f" [{t()}] op/start 失败, 继续下一轮", flush=True) + time.sleep(1.0) + continue + # 复刻 doCycle() 立即一次 + pollSync() 立即一次 + r = es.api_op_cycle({"outputs": ""}) + if not r.get("ok"): + show(r) + r = es.api_sync_diag({}) + if not r.get("ok"): + show(r) + # 100ms 周期跑 ~2s, 中途 2s 处再 pollSync 一次 + end = time.time() + 2.0 + synced = False + while time.time() < end: + r = es.api_op_cycle({"outputs": ""}) + if not r.get("ok"): + show(r) + break + if not synced and time.time() > end - 1.0: + synced = True + r = es.api_sync_diag({}) + if not r.get("ok"): + show(r) + time.sleep(0.1) + print(f" [{t()}] op/stop", flush=True) + r = es.api_op_stop({}) + show(r) + time.sleep(1.0) # 用户点击间隔 + + es.api_close({}) + print(f"[{t()}] 全部 {rounds} 轮完成, 无卡死", flush=True) + faulthandler.cancel_dump_traceback_later() + return 0 + + +if __name__ == "__main__": + rc = main() + print(f"EXIT rc={rc}", flush=True) + sys.exit(rc) diff --git a/ecat.bat b/ecat.bat new file mode 100644 index 0000000..e20d29b --- /dev/null +++ b/ecat.bat @@ -0,0 +1,8 @@ +@echo off +rem EtherCAT master tool for DCU LAN9252 (scan/flash/send/monitor) +rem Examples: ecat.bat status | ecat.bat flash | ecat.bat send --u64 0x1,0x2,0x3,0x4 --duration 5 +chcp 65001 >nul +set PYTHONUTF8=1 +cd /d "%~dp0" +"%~dp0venv\Scripts\python.exe" ecat_tool.py %* +pause diff --git a/ecat.css b/ecat.css new file mode 100644 index 0000000..ba4b0ed --- /dev/null +++ b/ecat.css @@ -0,0 +1,797 @@ +/* motor.css - 电机控制台页面样式 + * 由 motor.html 内联 + +
+ + +