diff --git a/README.md b/README.md index f563245..fe83255 100644 --- a/README.md +++ b/README.md @@ -16,29 +16,47 @@ py -3.12 -m venv venv venv\Scripts\python.exe -m pip install -r requirements.txt ``` -## 目录内容 +## 目录结构 + +``` +ecat/ +├─ ecat_server.py 网页控制台后端(REST API + 静态文件), 默认端口 8090 +├─ ecat_tool.py 一体化命令行主站 +├─ ecat_flash_eeprom.py 经网线烧写 SII 镜像(被 ecat_tool flash 复用) +├─ test_motor_backend.py 电机后端自测(不接硬件) +├─ web/ 前端资源(URL 路径不变, 仍是 / 与 /motor.html) +├─ diag/ 独立诊断脚本(互不依赖, 直接单跑) +├─ launch/ 双击入口(.bat/.vbs) +└─ venv/ 本地虚拟环境(不入库) +``` + +根目录只放主程序:`ecat_tool.py` import `ecat_flash_eeprom`、 +`test_motor_backend.py` import `ecat_server`,这几个互相 import 的必须同层, +挪进子目录就得改 import 或加包,不值得。 | 文件 | 说明 | |------|------| | `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 自己发出的帧,用于对照裸帧格式 | -| `motor.html` / `motor.js` | 电机控制台:N1–N9 九节点,走 EtherCAT 过程数据(不经 WiFi/HTTP)。节点总览、8 种 Control_Mode、STATUS 实时解码、示波器曲线 | | `test_motor_backend.py` | 电机后端自测,**不接硬件**(假从站模拟 GD32 buildInput/processOutput)。跑法:`venv\Scripts\python.exe test_motor_backend.py` | +| `web/ecat.html` + `web/ecat.css` | 网页控制台前端 | +| `web/motor.html` + `web/motor.js` | 电机控制台:N1–N9 九节点,走 EtherCAT 过程数据(不经 WiFi/HTTP)。节点总览、8 种 Control_Mode、STATUS 实时解码、示波器曲线 | +| `diag/ecat_scan.py` | 最小化 bring-up 扫描:从站身份 + SII dump,`--op` 追加 PDO 测试 | +| `diag/ecat_esc_regs.py` | 从**网络侧**直读 LAN9252 ESC 寄存器,绕开 GD32/PDI,用于判断 EEPROM 加载是否真的失败;支持 `--reload` | +| `diag/ecat_sniff.py` | 旁路抓包,hexdump SOEM 自己发出的帧,用于对照裸帧格式 | ## 启动方式 +双击 `launch/` 里的入口即可(脚本自己会定位到项目根,不必在特定目录下运行): + | 入口 | 效果 | |------|------| -| `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 适配器 | +| `launch/ecat_app.vbs` | pywebview 桌面窗口,无控制台无浏览器标签(已针对部分 GPU 驱动白屏加 `--disable-gpu-compositing`) | +| `launch/ecat_web.vbs` | 后台起服务并打开浏览器标签,无控制台窗口 | +| `launch/ecat_web.bat` | 控制台模式,可见日志,调试用 | +| `launch/ecat.bat` | 命令行工具入口,如 `ecat.bat status`、`ecat.bat flash` | +| `launch/run_scan.bat` | 直接跑 bring-up 扫描,无参数则列出 Npcap 适配器 | 电机控制台在服务起来后从主页右上「电机控制台」进入,或直接访问 `/motor.html`。 它只读写 EtherCAT 过程数据,需先在主页点「连接」并让从站进入 OP。 @@ -52,5 +70,5 @@ venv\Scripts\python.exe -m pip install -r requirements.txt 断电才清零。固件 <1.5.52 无自愈需断电重启,1.5.52+ 有守护自动写回。 `config_map` 失败时后端会自动转储 4 个 SM 现场,可直接对照。 - 前端 CSS/JS 改动后记得 bump `?v=` 缓存版本,否则浏览器会加载旧代码。 - `ecat.css` 被 `ecat.html` 与 `motor.html` 共用,两处版本号要一起改。 + `web/ecat.css` 被 `web/ecat.html` 与 `web/motor.html` 共用,两处版本号要一起改。 - EEPROM 烧写后必须断电冷启动,ESC 才会重新加载配置。 diff --git a/ecat_esc_regs.py b/diag/ecat_esc_regs.py similarity index 100% rename from ecat_esc_regs.py rename to diag/ecat_esc_regs.py diff --git a/ecat_scan.py b/diag/ecat_scan.py similarity index 100% rename from ecat_scan.py rename to diag/ecat_scan.py diff --git a/ecat_sniff.py b/diag/ecat_sniff.py similarity index 100% rename from ecat_sniff.py rename to diag/ecat_sniff.py diff --git a/ecat_server.py b/ecat_server.py index 7dc2b96..b0c1f97 100644 --- a/ecat_server.py +++ b/ecat_server.py @@ -1552,15 +1552,17 @@ class Handler(BaseHTTPRequestHandler): # - .js 用 text/html 会被浏览器的严格 MIME 检查拒掉(module script 与 Worker # 都会直接报错不执行),这是加新页面最容易踩的坑; # - 只有 HTML 才注入 _RELOAD_SNIPPET(注入到 js/css 里会破坏文件)。 + # URL 路径保持不变(/、/ecat.css、/motor.html…),只是磁盘上挪进了 web/, + # 所以页面内的相对引用、书签、外部链接都不用改。 _STATIC_MAP = { - "/": "ecat.html", - "/ecat.html": "ecat.html", - "/index.html": "ecat.html", - "/ecat.css": "ecat.css", + "/": "web/ecat.html", + "/ecat.html": "web/ecat.html", + "/index.html": "web/ecat.html", + "/ecat.css": "web/ecat.css", # 电机控制台(EtherCAT 版)。样式直接复用 ecat.css —— 它本身就是 ESP32 # motor.css 的副本(md5 一致),再拷一份 motor.css 只会多出一处会漂移的副本。 - "/motor.html": "motor.html", - "/motor.js": "motor.js", + "/motor.html": "web/motor.html", + "/motor.js": "web/motor.js", } _CTYPE_BY_EXT = { ".html": "text/html; charset=utf-8", diff --git a/ecat_web.bat b/ecat_web.bat deleted file mode 100644 index a489858..0000000 --- a/ecat_web.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -rem DCU EtherCAT master web console (serves ecat.html + pysoem API) -chcp 65001 >nul -set PYTHONUTF8=1 -cd /d "%~dp0" -"%~dp0venv\Scripts\python.exe" ecat_server.py -pause diff --git a/ecat.bat b/launch/ecat.bat similarity index 55% rename from ecat.bat rename to launch/ecat.bat index e20d29b..0df69d9 100644 --- a/ecat.bat +++ b/launch/ecat.bat @@ -1,8 +1,10 @@ @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 +rem 本文件在 launch\ 下, %~dp0 指向 launch\, 故 ROOT 取其上一层。 chcp 65001 >nul set PYTHONUTF8=1 -cd /d "%~dp0" -"%~dp0venv\Scripts\python.exe" ecat_tool.py %* +set "ROOT=%~dp0.." +cd /d "%ROOT%" +"%ROOT%\venv\Scripts\python.exe" ecat_tool.py %* pause diff --git a/ecat_app.vbs b/launch/ecat_app.vbs similarity index 79% rename from ecat_app.vbs rename to launch/ecat_app.vbs index d3481ed..8a02396 100644 --- a/ecat_app.vbs +++ b/launch/ecat_app.vbs @@ -1,8 +1,10 @@ ' DCU EtherCAT desktop window (pywebview/WebView2). No console, no browser tab. ' Browser-tab launcher: ecat_web.vbs Console-mode debug launcher: ecat_web.bat +' 本文件在 launch\ 下: 先取自身所在目录, 再上一层拿到项目根。 Set sh = CreateObject("WScript.Shell") Set fso = CreateObject("Scripting.FileSystemObject") -base = fso.GetParentFolderName(WScript.ScriptFullName) +here = fso.GetParentFolderName(WScript.ScriptFullName) +base = fso.GetParentFolderName(here) sh.CurrentDirectory = base sh.Environment("PROCESS")("PYTHONUTF8") = "1" ' WebView2: keep GPU rasterization but disable GPU compositing. diff --git a/launch/ecat_web.bat b/launch/ecat_web.bat new file mode 100644 index 0000000..efabc7a --- /dev/null +++ b/launch/ecat_web.bat @@ -0,0 +1,9 @@ +@echo off +rem DCU EtherCAT master web console (serves web\ecat.html + pysoem API) +rem 本文件在 launch\ 下, %~dp0 指向 launch\, 故 ROOT 取其上一层。 +chcp 65001 >nul +set PYTHONUTF8=1 +set "ROOT=%~dp0.." +cd /d "%ROOT%" +"%ROOT%\venv\Scripts\python.exe" ecat_server.py +pause diff --git a/ecat_web.vbs b/launch/ecat_web.vbs similarity index 69% rename from ecat_web.vbs rename to launch/ecat_web.vbs index 72b5522..fa76ad6 100644 --- a/ecat_web.vbs +++ b/launch/ecat_web.vbs @@ -1,8 +1,10 @@ ' DCU EtherCAT web console - hidden launcher (no console window). ' Double-click me. Console-mode debug launcher (visible logs): ecat_web.bat +' 本文件在 launch\ 下: 先取自身所在目录, 再上一层拿到项目根。 Set sh = CreateObject("WScript.Shell") Set fso = CreateObject("Scripting.FileSystemObject") -base = fso.GetParentFolderName(WScript.ScriptFullName) +here = fso.GetParentFolderName(WScript.ScriptFullName) +base = fso.GetParentFolderName(here) sh.CurrentDirectory = base sh.Environment("PROCESS")("PYTHONUTF8") = "1" sh.Run """" & base & "\venv\Scripts\python.exe"" """ & base & "\ecat_server.py""", 0, False diff --git a/run_scan.bat b/launch/run_scan.bat similarity index 51% rename from run_scan.bat rename to launch/run_scan.bat index f24eb15..5352906 100644 --- a/run_scan.bat +++ b/launch/run_scan.bat @@ -2,8 +2,11 @@ rem EtherCAT master bring-up scan (LAN9252) rem Usage: run_scan.bat -> list Npcap adapters rem run_scan.bat I226 -> scan EtherCAT slaves (add --op for PDO test) +rem 本文件在 launch\ 下, %~dp0 指向 launch\, 故 ROOT 取其上一层; +rem 扫描脚本已挪进 diag\。 chcp 65001 >nul set PYTHONUTF8=1 -cd /d "%~dp0" -"%~dp0venv\Scripts\python.exe" ecat_scan.py %* +set "ROOT=%~dp0.." +cd /d "%ROOT%" +"%ROOT%\venv\Scripts\python.exe" diag\ecat_scan.py %* pause diff --git a/ecat.css b/web/ecat.css similarity index 100% rename from ecat.css rename to web/ecat.css diff --git a/ecat.html b/web/ecat.html similarity index 100% rename from ecat.html rename to web/ecat.html diff --git a/motor.html b/web/motor.html similarity index 100% rename from motor.html rename to web/motor.html diff --git a/motor.js b/web/motor.js similarity index 100% rename from motor.js rename to web/motor.js